diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-18 19:06:41 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-18 19:06:41 +0000 |
commit | a550199c6f37e1b05a386ea57eee4c40cc91d84d (patch) | |
tree | 8f72fe5b45998fafd610330e4992faf9b7182b48 /src/ports | |
parent | ea6f6832dd1c1af5db1a2ff43df627347b3fb8ab (diff) |
CreateTypefaceFromStream for GDI.
http://codereview.appspot.com/5616047/
git-svn-id: http://skia.googlecode.com/svn/trunk@4001 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/ports')
-rwxr-xr-x | src/ports/SkFontHost_win.cpp | 209 |
1 files changed, 172 insertions, 37 deletions
diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index 20c54a3c89..cf23e93828 100755 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -6,23 +6,23 @@ * found in the LICENSE file. */ - -#include "SkColorFilter.h" -#include "SkString.h" -#include "SkEndian.h" -#include "SkFontHost.h" -#include "SkDescriptor.h" #include "SkAdvancedTypefaceMetrics.h" +#include "SkBase64.h" +#include "SkData.h" +#include "SkDescriptor.h" +#include "SkFontHost.h" +#include "SkOTUtils.h" #include "SkStream.h" +#include "SkString.h" #include "SkThread.h" #include "SkTypeface_win.h" #include "SkTypefaceCache.h" #include "SkUtils.h" -#ifdef WIN32 -#include "windows.h" -#include "tchar.h" -#include "usp10.h" +#include "SkTypes.h" +#include <tchar.h> +#include <usp10.h> +#include <objbase.h> // always packed xxRRGGBB typedef uint32_t SkGdiRGB; @@ -158,16 +158,47 @@ public: } }; +class FontMemResourceTypeface : public LogFontTypeface { +public: + /** + * Takes ownership of fontMemResource. + */ + FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : + LogFontTypeface(style, fontID, lf), fFontMemResource(fontMemResource) {} + + HANDLE fFontMemResource; + + /** + * The created FontMemResourceTypeface takes ownership of fontMemResource. + */ + static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) { + SkTypeface::Style style = get_style(lf); + SkFontID fontID = SkTypefaceCache::NewFontID(); + return new FontMemResourceTypeface(style, fontID, lf, fontMemResource); + } + +protected: + virtual void weak_dispose() const SK_OVERRIDE { + RemoveFontMemResourceEx(fFontMemResource); + //SkTypefaceCache::Remove(this); + INHERITED::weak_dispose(); + } + +private: + typedef LogFontTypeface INHERITED; +}; + static const LOGFONT& get_default_font() { static LOGFONT gDefaultFont; return gDefaultFont; } static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { - LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face); + LogFontTypeface* lface = static_cast<LogFontTypeface*>(face); const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); - return get_style(lface->fLogFont) == requestedStyle && + return lface && + get_style(lface->fLogFont) == requestedStyle && !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); } @@ -187,13 +218,24 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { } /** + * The created SkTypeface takes ownership of fontMemResource. + */ +SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) { + LOGFONT lf = origLF; + make_canonical(&lf); + FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource); + SkTypefaceCache::Add(face, get_style(lf), false); + return face; +} + +/** * This guy is public */ void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) { if (NULL == face) { *lf = get_default_font(); } else { - *lf = ((const LogFontTypeface*)face)->fLogFont; + *lf = static_cast<const LogFontTypeface*>(face)->fLogFont; } } @@ -205,14 +247,14 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { } static void ensure_typeface_accessible(SkFontID fontID) { - LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID); + LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID)); if (face) { SkFontHost::EnsureTypefaceAccessible(*face); } } static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) { - LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID); + LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID)); if (face) { *lf = face->fLogFont; } else { @@ -1291,11 +1333,122 @@ Error: return info; } +//Dummy representation of a Base64 encoded GUID from create_unique_font_name. +#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX" +//Length of GUID representation from create_id, including NULL terminator. +#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID) + +SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize); + +/** + NameID 6 Postscript names cannot have the character '/'. + It would be easier to hex encode the GUID, but that is 32 bytes, + and many systems have issues with names longer than 28 bytes. + The following need not be any standard base64 encoding. + The encoded value is never decoded. +*/ +static const char postscript_safe_base64_encode[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_="; + +/** + Formats a GUID into Base64 and places it into buffer. + buffer should have space for at least BASE64_GUID_ID_LEN characters. + The string will always be null terminated. + XXXXXXXXXXXXXXXXXXXXXXXX0 + */ +static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) { + SkASSERT(bufferSize >= BASE64_GUID_ID_LEN); + size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode); + SkASSERT(written < LF_FACESIZE); + buffer[written] = '\0'; +} + +/** + Creates a Base64 encoded GUID and places it into buffer. + buffer should have space for at least BASE64_GUID_ID_LEN characters. + The string will always be null terminated. + XXXXXXXXXXXXXXXXXXXXXXXX0 + */ +static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) { + GUID guid = {}; + if (FAILED(CoCreateGuid(&guid))) { + return E_UNEXPECTED; + } + format_guid_b64(guid, buffer, bufferSize); + + return S_OK; +} + +/** + Introduces a font to GDI. On failure will return NULL. The returned handle + should eventually be passed to RemoveFontMemResourceEx. +*/ +static HANDLE activate_font(SkData* fontData) { + DWORD numFonts = 0; + //AddFontMemResourceEx just copies the data, but does not specify const. + HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()), + fontData->size(), + 0, + &numFonts); + + if (fontHandle != NULL && numFonts < 1) { + RemoveFontMemResourceEx(fontHandle); + return NULL; + } + + return fontHandle; +} + +static void logfont_for_name(const char* familyName, LOGFONT& lf) { + memset(&lf, 0, sizeof(LOGFONT)); +#ifdef UNICODE + // Get the buffer size needed first. + size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, + -1, NULL, 0); + // Allocate a buffer (str_len already has terminating null + // accounted for). + wchar_t *wideFamilyName = new wchar_t[str_len]; + // Now actually convert the string. + ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, + wideFamilyName, str_len); + ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); + delete [] wideFamilyName; + lf.lfFaceName[LF_FACESIZE-1] = L'\0'; +#else + ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); + lf.lfFaceName[LF_FACESIZE-1] = '\0'; +#endif +} + SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { + // Create a unique and unpredictable font name. + // Avoids collisions and access from CSS. + char familyName[BASE64_GUID_ID_LEN]; + const int familyNameSize = SK_ARRAY_COUNT(familyName); + if (FAILED(create_unique_font_name(familyName, familyNameSize))) { + return NULL; + } + + // Change the name of the font. + SkData* rewrittenFontData = SkOTUtils::RenameFont(stream, familyName, familyNameSize-1); + if (NULL == rewrittenFontData) { + return NULL; + } + SkAutoUnref aur = SkAutoUnref(rewrittenFontData); - //Should not be used on Windows, keep linker happy - SkASSERT(false); - return SkCreateTypefaceFromLOGFONT(get_default_font()); + // Register the font with GDI. + HANDLE fontReference = activate_font(rewrittenFontData); + if (NULL == fontReference) { + return NULL; + } + + // Create the typeface. + LOGFONT lf; + logfont_for_name(familyName, lf); + + return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference); } SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { @@ -1358,23 +1511,7 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, LogFontTypeface* face = (LogFontTypeface*)familyFace; lf = face->fLogFont; } else { - memset(&lf, 0, sizeof(LOGFONT)); -#ifdef UNICODE - // Get the buffer size needed first. - size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, - -1, NULL, 0); - // Allocate a buffer (str_len already has terminating null - // accounted for). - wchar_t *wideFamilyName = new wchar_t[str_len]; - // Now actually convert the string. - ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, - wideFamilyName, str_len); - ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); - delete [] wideFamilyName; -#else - ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); -#endif - lf.lfFaceName[LF_FACESIZE-1] = '\0'; + logfont_for_name(familyName, lf); } setStyle(&lf, style); return SkCreateTypefaceFromLOGFONT(lf); @@ -1446,5 +1583,3 @@ void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { } #endif } - -#endif // WIN32 |