summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/win/FontCacheWin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/win/FontCacheWin.cpp')
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp289
1 files changed, 192 insertions, 97 deletions
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 502863b..49b3d76 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,8 +35,10 @@
#include "UnicodeRange.h"
#include <windows.h>
#include <mlang.h>
+#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
+#endif
using std::min;
@@ -45,7 +47,9 @@ namespace WebCore
void FontCache::platformInit()
{
+#if PLATFORM(CG)
wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
+#endif
}
IMLangFontLink2* FontCache::getFontLinkInterface()
@@ -304,55 +308,169 @@ FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fo
return getCachedFontPlatformData(fontDescription, timesStr);
}
-bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+static LONG toGDIFontWeight(FontWeight fontWeight)
{
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. The logical size constant is 32.
- winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
-#if PLATFORM(CG)
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ static LONG gdiFontWeights[] = {
+ FW_THIN, // FontWeight100
+ FW_EXTRALIGHT, // FontWeight200
+ FW_LIGHT, // FontWeight300
+ FW_NORMAL, // FontWeight400
+ FW_MEDIUM, // FontWeight500
+ FW_SEMIBOLD, // FontWeight600
+ FW_BOLD, // FontWeight700
+ FW_EXTRABOLD, // FontWeight800
+ FW_HEAVY // FontWeight900
+ };
+ return gdiFontWeights[fontWeight];
+}
+
+static inline bool isGDIFontWeightBold(LONG gdiFontWeight)
+{
+ return gdiFontWeight >= FW_SEMIBOLD;
+}
+
+static LONG adjustedGDIFontWeight(LONG gdiFontWeight, const String& family)
+{
+ static AtomicString lucidaStr("Lucida Grande");
+ if (equalIgnoringCase(family, lucidaStr)) {
+ if (gdiFontWeight == FW_NORMAL)
+ return FW_MEDIUM;
+ if (gdiFontWeight == FW_BOLD)
+ return FW_SEMIBOLD;
+ }
+ return gdiFontWeight;
+}
+
+struct MatchImprovingProcData {
+ MatchImprovingProcData(LONG desiredWeight, bool desiredItalic)
+ : m_desiredWeight(desiredWeight)
+ , m_desiredItalic(desiredItalic)
+ , m_hasMatched(false)
+ {
+ }
+
+ LONG m_desiredWeight;
+ bool m_desiredItalic;
+ bool m_hasMatched;
+ LOGFONT m_chosen;
+};
+
+static int CALLBACK matchImprovingEnumProc(CONST LOGFONT* candidate, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ MatchImprovingProcData* matchData = reinterpret_cast<MatchImprovingProcData*>(lParam);
+
+ if (!matchData->m_hasMatched) {
+ matchData->m_hasMatched = true;
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ if (!candidate->lfItalic != !matchData->m_chosen.lfItalic) {
+ if (!candidate->lfItalic == !matchData->m_desiredItalic)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+ }
+
+ unsigned chosenWeightDeltaMagnitude = abs(matchData->m_chosen.lfWeight - matchData->m_desiredWeight);
+ unsigned candidateWeightDeltaMagnitude = abs(candidate->lfWeight - matchData->m_desiredWeight);
+
+ // If both are the same distance from the desired weight, prefer the candidate if it is further from regular.
+ if (chosenWeightDeltaMagnitude == candidateWeightDeltaMagnitude && abs(candidate->lfWeight - FW_NORMAL) > abs(matchData->m_chosen.lfWeight - FW_NORMAL)) {
+ matchData->m_chosen = *candidate;
+ return 1;
+ }
+
+ // Otherwise, prefer the one closer to the desired weight.
+ if (candidateWeightDeltaMagnitude < chosenWeightDeltaMagnitude)
+ matchData->m_chosen = *candidate;
+
+ return 1;
+}
+
+static HFONT createGDIFont(const AtomicString& family, LONG desiredWeight, bool desiredItalic, int size)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(family.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, family.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ MatchImprovingProcData matchData(desiredWeight, desiredItalic);
+ EnumFontFamiliesEx(hdc, &logFont, matchImprovingEnumProc, reinterpret_cast<LPARAM>(&matchData), 0);
+
+ ReleaseDC(0, hdc);
+
+ if (!matchData.m_hasMatched)
+ return 0;
+
+ matchData.m_chosen.lfHeight = -size;
+ matchData.m_chosen.lfWidth = 0;
+ matchData.m_chosen.lfEscapement = 0;
+ matchData.m_chosen.lfOrientation = 0;
+ matchData.m_chosen.lfUnderline = false;
+ matchData.m_chosen.lfStrikeOut = false;
+ matchData.m_chosen.lfCharSet = DEFAULT_CHARSET;
+#if PLATFORM(CG) || PLATFORM(CAIRO)
+ matchData.m_chosen.lfOutPrecision = OUT_TT_ONLY_PRECIS;
#else
- winfont.lfOutPrecision = OUT_TT_PRECIS;
+ matchData.m_chosen.lfOutPrecision = OUT_TT_PRECIS;
#endif
- winfont.lfQuality = 5; // Force cleartype.
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- static AtomicString lucidaStr("Lucida Grande");
- if (equalIgnoringCase(family, lucidaStr))
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- DeleteObject(hfont);
-
- return !wcsicmp(winfont.lfFaceName, name);
+ matchData.m_chosen.lfQuality = DEFAULT_QUALITY;
+ matchData.m_chosen.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ return CreateFontIndirect(&matchData.m_chosen);
+}
+
+struct TraitsInFamilyProcData {
+ TraitsInFamilyProcData(const AtomicString& familyName)
+ : m_familyName(familyName)
+ {
+ }
+
+ const AtomicString& m_familyName;
+ HashSet<unsigned> m_traitsMasks;
+};
+
+static int CALLBACK traitsInFamilyEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
+{
+ TraitsInFamilyProcData* procData = reinterpret_cast<TraitsInFamilyProcData*>(lParam);
+
+ unsigned traitsMask = 0;
+ traitsMask |= logFont->lfItalic ? FontStyleItalicMask : FontStyleNormalMask;
+ traitsMask |= FontVariantNormalMask;
+ LONG weight = adjustedGDIFontWeight(logFont->lfWeight, procData->m_familyName);
+ traitsMask |= weight == FW_THIN ? FontWeight100Mask :
+ weight == FW_EXTRALIGHT ? FontWeight200Mask :
+ weight == FW_LIGHT ? FontWeight300Mask :
+ weight == FW_NORMAL ? FontWeight400Mask :
+ weight == FW_MEDIUM ? FontWeight500Mask :
+ weight == FW_SEMIBOLD ? FontWeight600Mask :
+ weight == FW_BOLD ? FontWeight700Mask :
+ weight == FW_EXTRABOLD ? FontWeight800Mask :
+ FontWeight900Mask;
+ procData->m_traitsMasks.add(traitsMask);
+ return 1;
+}
+void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks)
+{
+ HDC hdc = GetDC(0);
+
+ LOGFONT logFont;
+ logFont.lfCharSet = DEFAULT_CHARSET;
+ unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1));
+ memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar));
+ logFont.lfFaceName[familyLength] = 0;
+ logFont.lfPitchAndFamily = 0;
+
+ TraitsInFamilyProcData procData(familyName);
+ EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0);
+ copyToVector(procData.m_traitsMasks, traitsMasks);
+
+ ReleaseDC(0, hdc);
}
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
@@ -364,57 +482,34 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
- LOGFONT winfont;
-
- // The size here looks unusual. The negative number is intentional. The logical size constant is 32. We do this
- // for subpixel precision when rendering using Uniscribe. This masks rounding errors related to the HFONT metrics being
- // different from the CGFont metrics.
- // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't look as nice. That may be solvable though.
- winfont.lfHeight = -fontDescription.computedPixelSize() * (useGDI ? 1 : 32);
- winfont.lfWidth = 0;
- winfont.lfEscapement = 0;
- winfont.lfOrientation = 0;
- winfont.lfUnderline = false;
- winfont.lfStrikeOut = false;
- winfont.lfCharSet = DEFAULT_CHARSET;
- winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
- winfont.lfQuality = DEFAULT_QUALITY;
- winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
- winfont.lfItalic = fontDescription.italic();
-
- // FIXME: Support weights for real. Do our own enumeration of the available weights.
- // We can't rely on Windows here, since we need to follow the CSS2 algorithm for how to fill in
- // gaps in the weight list.
- // FIXME: Hardcoding Lucida Grande for now. It uses different weights than typical Win32 fonts
- // (500/600 instead of 400/700).
- if (isLucidaGrande) {
- winfont.lfWeight = fontDescription.bold() ? 600 : 500;
- useGDI = false; // Never use GDI for Lucida Grande.
- } else
- winfont.lfWeight = fontDescription.bold() ? 700 : 400;
- int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
- memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
- winfont.lfFaceName[len] = '\0';
-
- HFONT hfont = CreateFontIndirect(&winfont);
- // Windows will always give us a valid pointer here, even if the face name is non-existent. We have to double-check
- // and see if the family name was really used.
- HDC dc = GetDC(0);
- SaveDC(dc);
- SelectObject(dc, hfont);
- WCHAR name[LF_FACESIZE];
- GetTextFace(dc, LF_FACESIZE, name);
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
-
- if (_wcsicmp(winfont.lfFaceName, name)) {
- DeleteObject(hfont);
+ // The logical size constant is 32. We do this for subpixel precision when rendering using Uniscribe.
+ // This masks rounding errors related to the HFONT metrics being different from the CGFont metrics.
+ // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't
+ // look as nice. That may be solvable though.
+ LONG weight = adjustedGDIFontWeight(toGDIFontWeight(fontDescription.weight()), family);
+ HFONT hfont = createGDIFont(family, weight, fontDescription.italic(), fontDescription.computedPixelSize() * (useGDI ? 1 : 32));
+
+ if (!hfont)
return 0;
- }
-
- FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
- fontDescription.bold(), fontDescription.italic(), useGDI);
- if (!result->cgFont()) {
+
+ if (isLucidaGrande)
+ useGDI = false; // Never use GDI for Lucida Grande.
+
+ LOGFONT logFont;
+ GetObject(hfont, sizeof(LOGFONT), &logFont);
+
+ bool synthesizeBold = isGDIFontWeightBold(weight) && !isGDIFontWeightBold(logFont.lfWeight);
+ bool synthesizeItalic = fontDescription.italic() && !logFont.lfItalic;
+
+ FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), synthesizeBold, synthesizeItalic, useGDI);
+
+#if PLATFORM(CG)
+ bool fontCreationFailed = !result->cgFont();
+#elif PLATFORM(CAIRO)
+ bool fontCreationFailed = !result->fontFace();
+#endif
+
+ if (fontCreationFailed) {
// The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make
// absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
// font.