Chromium Code Reviews| Index: third_party/WebKit/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp |
| =================================================================== |
| --- third_party/WebKit/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp (revision 7512) |
| +++ third_party/WebKit/WebCore/platform/graphics/chromium/FontCustomPlatformData.cpp (working copy) |
| @@ -21,34 +21,205 @@ |
| #include "config.h" |
| #include "FontCustomPlatformData.h" |
| -#include "SharedBuffer.h" |
| +#if PLATFORM(WIN_OS) |
| +#include "Base64.h" |
| +#include "ChromiumBridge.h" |
| +#include "OpenTypeUtilities.h" |
| +#endif |
| + |
| #include "FontPlatformData.h" |
| #include "NotImplemented.h" |
| +#include "SharedBuffer.h" |
| +#if PLATFORM(WIN_OS) |
| +#include <objbase.h> |
| +#include <t2embapi.h> |
| +#pragma comment(lib, "t2embed") |
| +#endif |
| + |
| namespace WebCore { |
| FontCustomPlatformData::~FontCustomPlatformData() |
| { |
| - // FIXME: Release the HFONT ref? |
| +#if PLATFORM(WIN_OS) |
| + if (m_fontReference) { |
| + if (m_name.isNull()) { |
| + ULONG status; |
| + TTDeleteEmbeddedFont(m_fontReference, 0, &status); |
| + } else |
| + RemoveFontMemResourceEx(m_fontReference); |
| + } |
| +#endif |
| } |
| -FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic) |
| +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, |
| + bool bold, |
| + bool italic, |
| + FontRenderingMode mode) |
| { |
| - return FontPlatformData(m_font, size); |
| +#if PLATFORM(WIN_OS) |
| + ASSERT(m_fontReference); |
| + |
| + LOGFONT logFont; |
| + if (m_name.isNull()) |
| + TTGetNewFontName(&m_fontReference, logFont.lfFaceName, |
| + LF_FACESIZE, 0, 0); |
| + else { |
| + // m_name comes from createUniqueFontName, which, in turn, gets |
| + // it from base64-encoded uuid (128-bit). So, m_name |
| + // can never be longer than LF_FACESIZE (32). |
| + if (m_name.length() >= LF_FACESIZE) { |
|
eroman
2009/01/06 02:17:05
I think this check should be against m_name.length
|
| + ASSERT_NOT_REACHED(); |
| + return FontPlatformData(); |
| + } |
| + memcpy(logFont.lfFaceName, m_name.charactersWithNullTermination(), |
| + sizeof(logFont.lfFaceName[0]) * (1 + m_name.length())); |
| + } |
| + |
| + // FIXME: almost identical to FillLogFont in FontCacheWin.cpp. |
| + // Need to refactor. |
| + logFont.lfHeight = -size; |
| + logFont.lfWidth = 0; |
| + logFont.lfEscapement = 0; |
| + logFont.lfOrientation = 0; |
| + logFont.lfUnderline = false; |
| + logFont.lfStrikeOut = false; |
| + logFont.lfCharSet = DEFAULT_CHARSET; |
| + logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; |
| + logFont.lfQuality = ChromiumBridge::layoutTestMode() ? |
| + NONANTIALIASED_QUALITY : |
| + DEFAULT_QUALITY; // Honor user's desktop settings. |
| + logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; |
| + logFont.lfItalic = italic; |
| + logFont.lfWeight = bold ? 700 : 400; |
| + |
| + HFONT hfont = CreateFontIndirect(&logFont); |
| + return FontPlatformData(hfont, size); |
| +#else |
| + notImplemented(); |
| + return FontPlatformData(); |
| +#endif |
| } |
| +#if PLATFORM(WIN_OS) |
| +// FIXME: EOTStream class and static functions in this #if block are |
| +// duplicated from platform/graphics/win/FontCustomplatformData.cpp |
| +// and need to be shared. |
| + |
| +// Streams the concatenation of a header and font data. |
| +class EOTStream { |
| +public: |
| + EOTStream(const Vector<UInt8, 512>& eotHeader, const SharedBuffer* fontData, size_t overlayDst, size_t overlaySrc, size_t overlayLength) |
| + : m_eotHeader(eotHeader) |
| + , m_fontData(fontData) |
| + , m_overlayDst(overlayDst) |
| + , m_overlaySrc(overlaySrc) |
| + , m_overlayLength(overlayLength) |
| + , m_offset(0) |
| + , m_inHeader(true) |
| + { |
| + } |
| + |
| + size_t read(void* buffer, size_t count); |
| + |
| +private: |
| + const Vector<UInt8, 512>& m_eotHeader; |
| + const SharedBuffer* m_fontData; |
| + size_t m_overlayDst; |
| + size_t m_overlaySrc; |
| + size_t m_overlayLength; |
| + size_t m_offset; |
| + bool m_inHeader; |
| +}; |
| + |
| +size_t EOTStream::read(void* buffer, size_t count) |
| +{ |
| + size_t bytesToRead = count; |
| + if (m_inHeader) { |
| + size_t bytesFromHeader = std::min(m_eotHeader.size() - m_offset, count); |
| + memcpy(buffer, m_eotHeader.data() + m_offset, bytesFromHeader); |
| + m_offset += bytesFromHeader; |
| + bytesToRead -= bytesFromHeader; |
| + if (m_offset == m_eotHeader.size()) { |
| + m_inHeader = false; |
| + m_offset = 0; |
| + } |
| + } |
| + if (bytesToRead && !m_inHeader) { |
| + size_t bytesFromData = std::min(m_fontData->size() - m_offset, bytesToRead); |
| + memcpy(buffer, m_fontData->data() + m_offset, bytesFromData); |
| + if (m_offset < m_overlayDst + m_overlayLength && m_offset + bytesFromData >= m_overlayDst) { |
| + size_t dstOffset = std::max<int>(m_overlayDst - m_offset, 0); |
| + size_t srcOffset = std::max<int>(0, m_offset - m_overlayDst); |
| + size_t bytesToCopy = std::min(bytesFromData - dstOffset, m_overlayLength - srcOffset); |
| + memcpy(reinterpret_cast<char*>(buffer) + dstOffset, m_fontData->data() + m_overlaySrc + srcOffset, bytesToCopy); |
| + } |
| + m_offset += bytesFromData; |
| + bytesToRead -= bytesFromData; |
| + } |
| + return count - bytesToRead; |
| +} |
| + |
| +static unsigned long WINAPIV readEmbedProc(void* stream, void* buffer, unsigned long length) |
| +{ |
| + return static_cast<EOTStream*>(stream)->read(buffer, length); |
| +} |
| + |
| +// Creates a unique and unpredictable font name, in order to avoid collisions and to |
| +// not allow access from CSS. |
| +static String createUniqueFontName() |
| +{ |
| + Vector<char> fontUuid(sizeof(GUID)); |
| + CoCreateGuid(reinterpret_cast<GUID*>(fontUuid.data())); |
| + |
| + Vector<char> fontNameVector; |
| + base64Encode(fontUuid, fontNameVector); |
| + ASSERT(fontNameVector.size() < LF_FACESIZE); |
| + return String(fontNameVector.data(), fontNameVector.size()); |
| +} |
| +#endif |
| + |
| FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) |
| { |
| ASSERT_ARG(buffer, buffer); |
| #if PLATFORM(WIN_OS) |
| - HFONT font = 0; |
| - // FIXME: Figure out some way to get Windows to give us back a font object. |
| - if (!font) |
| + // Introduce the font to GDI. AddFontMemResourceEx cannot be used, because it will pollute the process's |
| + // font namespace (Windows has no API for creating an HFONT from data without exposing the font to the |
| + // entire process first). TTLoadEmbeddedFont lets us override the font family name, so using a unique name |
| + // we avoid namespace collisions. |
| + |
| + String fontName = createUniqueFontName(); |
| + |
| + // TTLoadEmbeddedFont works only with Embedded OpenType (.eot) data, |
| + // so we need to create an EOT header and prepend it to the font data. |
| + Vector<UInt8, 512> eotHeader; |
| + size_t overlayDst; |
| + size_t overlaySrc; |
| + size_t overlayLength; |
| + |
| + if (!getEOTHeader(buffer, eotHeader, overlayDst, overlaySrc, overlayLength)) |
| return 0; |
| - return new FontCustomPlatformData(font); |
| + |
| + HANDLE fontReference; |
| + ULONG privStatus; |
| + ULONG status; |
| + EOTStream eotStream(eotHeader, buffer, overlayDst, overlaySrc, overlayLength); |
| + |
| + LONG loadEmbeddedFontResult = TTLoadEmbeddedFont(&fontReference, TTLOAD_PRIVATE, &privStatus, LICENSE_PREVIEWPRINT, &status, readEmbedProc, &eotStream, const_cast<LPWSTR>(fontName.charactersWithNullTermination()), 0, 0); |
| + if (loadEmbeddedFontResult == E_NONE) |
| + fontName = String(); |
| + else { |
| + fontReference = renameAndActivateFont(buffer, fontName); |
| + if (!fontReference) { |
| + return 0; |
| + } |
| + } |
| + |
| + return new FontCustomPlatformData(fontReference, fontName); |
| #else |
| - notImplemented(); |
| + notImplemented();; |
| + return 0; |
| #endif |
| } |