Changeset 29140 in webkit


Ignore:
Timestamp:
Jan 3, 2008, 6:04:24 PM (17 years ago)
Author:
mitz@apple.com
Message:

Reviewed by Darin Adler.

  • platform/graphics/win/FontCacheWin.cpp: (WebCore::linkedFontEnumProc): Added. This callback is used to fetch a valid LOGFONT for a given family. (WebCore::getLinkedFonts): Added. Returns a vector of font families linked to the given font family by the Windows registry key HKLM\Software\...\FontLink\SystemLink. The registry values typically differ based on the installed language version of Windows. (WebCore::FontCache::getFontDataForCharacters): Changed to not use MLang font mapping, which is Windows code page based, except for characters in the range U+2000..U+200F. Instead, this function gets the font Uniscribe would use for the character. However, that font might not actually contain the character, in which case GDI font linking would substitute a different font. Therefore, this function walks the linked font list until it finds a font that actually contains the character.
Location:
trunk/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r29138 r29140  
     12008-01-03  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        - fix http://bugs.webkit.org/show_bug.cgi?id=16548
     6          <rdar://problem/5659452> REGRESSION(r28810): Font style and sizes are weird for Japanese text
     7
     8        * platform/graphics/win/FontCacheWin.cpp:
     9        (WebCore::linkedFontEnumProc): Added. This callback is used to fetch
     10        a valid LOGFONT for a given family.
     11        (WebCore::getLinkedFonts): Added. Returns a vector of font families
     12        linked to the given font family by the Windows registry key
     13        HKLM\Software\...\FontLink\SystemLink. The registry values typically
     14        differ based on the installed language version of Windows.
     15        (WebCore::FontCache::getFontDataForCharacters): Changed to not use MLang
     16        font mapping, which is Windows code page based, except for characters in
     17        the range U+2000..U+200F. Instead, this function gets the font Uniscribe
     18        would use for the character. However, that font might not actually
     19        contain the character, in which case GDI font linking would substitute a
     20        different font. Therefore, this function walks the linked font list
     21        until it finds a font that actually contains the character.
     22
    1232008-01-03  Darin Adler  <darin@apple.com>
    224
  • trunk/WebCore/platform/graphics/win/FontCacheWin.cpp

    r28867 r29140  
    3232#include "FontData.h"
    3333#include "Font.h"
     34#include "StringHash.h"
    3435#include <windows.h>
    3536#include <mlang.h>
     
    7374}
    7475
     76static int CALLBACK linkedFontEnumProc(CONST LOGFONT* logFont, CONST TEXTMETRIC* metrics, DWORD fontType, LPARAM hfont)
     77{
     78    *reinterpret_cast<HFONT*>(hfont) = CreateFontIndirect(logFont);
     79    return false;
     80}
     81
     82static const Vector<String>* getLinkedFonts(String& family)
     83{
     84    static HashMap<String, Vector<String>*> systemLinkMap;
     85    Vector<String>* result = systemLinkMap.get(family);
     86    if (result)
     87        return result;
     88
     89    result = new Vector<String>;
     90    systemLinkMap.set(family, result);
     91    HKEY fontLinkKey;
     92    if (FAILED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink", 0, KEY_READ, &fontLinkKey)))
     93        return result;
     94
     95    DWORD linkedFontsBufferSize = 0;
     96    RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, NULL, &linkedFontsBufferSize);
     97    WCHAR* linkedFonts = reinterpret_cast<WCHAR*>(malloc(linkedFontsBufferSize));
     98    if (SUCCEEDED(RegQueryValueEx(fontLinkKey, family.charactersWithNullTermination(), 0, NULL, reinterpret_cast<BYTE*>(linkedFonts), &linkedFontsBufferSize))) {
     99        unsigned i = 0;
     100        unsigned length = linkedFontsBufferSize / sizeof(*linkedFonts);
     101        while (i < length) {
     102            while (i < linkedFontsBufferSize && linkedFonts[i] != ',')
     103                i++;
     104            i++;
     105            unsigned j = i;
     106            while (j < linkedFontsBufferSize && linkedFonts[j])
     107                j++;
     108            result->append(String(linkedFonts + i, j - i));
     109            i = j + 1;
     110        }
     111    }
     112    free(linkedFonts);
     113    RegCloseKey(fontLinkKey);
     114    return result;
     115}
     116
    75117const FontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
    76118{
    77     // IMLangFontLink::MapFont Method does what we want.
    78     IMLangFontLink2* langFontLink = getFontLinkInterface();
    79     if (!langFontLink)
    80         return 0;
    81 
    82119    FontData* fontData = 0;
    83120    HDC hdc = GetDC(0);
     
    86123    HFONT hfont = 0;
    87124
    88     DWORD acpCodePages;
    89     langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
    90 
    91     DWORD actualCodePages;
    92     long cchActual;
    93     langFontLink->GetStrCodePages(characters, length, acpCodePages, &actualCodePages, &cchActual);
    94     if (cchActual) {
    95         // If simplified Chinese is one of the actual code pages, make one call to MapFont() asking for
    96         // simplified Chinese only (and ignore the result). This ensures that we get consistent answers
    97         // for characters that are in the simplified Chinese code page as well as other code pages and
    98         // characters that are exclusively in the simplified Chinese code page.
    99         // FIXME: This needs to be done only once per primary font. We could set a bit in the FontPlatformData
    100         // indicating that we have done this.
    101         const UINT simplifiedChineseCP = 936;
    102         UINT codePage;
    103         HFONT result;
    104         if (actualCodePages && SUCCEEDED(langFontLink->CodePagesToCodePage(actualCodePages, simplifiedChineseCP, &codePage)) && codePage == simplifiedChineseCP) {
    105             DWORD simplifiedChineseCodePages;
    106             langFontLink->CodePageToCodePages(simplifiedChineseCP, &simplifiedChineseCodePages);
    107             langFontLink->MapFont(hdc, simplifiedChineseCodePages, characters[0], &result);
    108             langFontLink->ReleaseFont(result);
    109         }
    110         if (langFontLink->MapFont(hdc, actualCodePages, characters[0], &result) == S_OK) {
    111             // Fill in a log font with the returned font from MLang, and then use that to create a new font.
     125    // Special-case characters in the range U+2000..U+200F (spaces, zero width joiner and non-joiner,
     126    // right to left and left to right marks). Uniscribe does not tell us what font it will use for these
     127    // (presumably because it never renders their glyphs), so we use MapFont to find a font that contains
     128    // them.
     129    if (characters[0] >= 0x2000 && characters[0] <= 0x200F) {
     130        IMLangFontLink2* langFontLink = getFontLinkInterface();
     131        if (langFontLink) {
     132            HFONT mLangFont;
     133            langFontLink->MapFont(hdc, 0, characters[0], &mLangFont);
    112134            LOGFONT lf;
    113             GetObject(result, sizeof(LOGFONT), &lf);
    114             langFontLink->ReleaseFont(result);
     135            GetObject(mLangFont, sizeof(LOGFONT), &lf);
     136            langFontLink->ReleaseFont(mLangFont);
    115137            hfont = CreateFontIndirect(&lf);
    116138        }
    117     }
    118 
    119     if (!hfont) {
    120         // Font linking failed but Uniscribe might still be able to find a fallback font.
    121         // To find out what Uniscribe would do, we make it draw into a metafile and intercept
     139    } else {
     140        // To find out what font Uniscribe would use, we make it draw into a metafile and intercept
    122141        // calls to CreateFontIndirect().
    123142        HDC metaFileDc = CreateEnhMetaFile(hdc, NULL, NULL, NULL);
    124         SelectObject(metaFileDc, hfont ? hfont : primaryFont);
     143        SelectObject(metaFileDc, primaryFont);
    125144
    126145        bool scriptStringOutSucceeded = false;
     
    145164    }
    146165
    147     if (hfont) {
     166    String familyName;
     167    const Vector<String>* linkedFonts = 0;
     168    unsigned linkedFontIndex = 0;
     169    while (hfont) {
    148170        SelectObject(hdc, hfont);
    149171        WCHAR name[LF_FACESIZE];
    150172        GetTextFace(hdc, LF_FACESIZE, name);
    151 
    152         String familyName(name);
     173        familyName = name;
     174        // Check if the font contains the desired character.
     175        static Vector<char, 512> glyphsetBuffer;
     176        glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, NULL));
     177        GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
     178        GetFontUnicodeRanges(hdc, glyphset);
     179        // FIXME: Change this to a binary search.
     180        unsigned i = 0;
     181        while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= characters[0])
     182            i++;
     183        if (i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > characters[0])
     184            break;
     185
     186        if (!linkedFonts)
     187            linkedFonts = getLinkedFonts(familyName);
     188        SelectObject(hdc, oldFont);
     189        DeleteObject(hfont);
     190        hfont = 0;
     191
     192        if (linkedFonts->size() <= linkedFontIndex)
     193            break;
     194
     195        LOGFONT logFont;
     196        logFont.lfCharSet = DEFAULT_CHARSET;
     197        memcpy(logFont.lfFaceName, linkedFonts->at(linkedFontIndex).characters(), linkedFonts->at(linkedFontIndex).length() * sizeof(WCHAR));
     198        logFont.lfFaceName[linkedFonts->at(linkedFontIndex).length()] = 0;
     199        EnumFontFamiliesEx(hdc, &logFont, linkedFontEnumProc, reinterpret_cast<LPARAM>(&hfont), 0);
     200        linkedFontIndex++;
     201    }
     202   
     203    if (hfont) {
    153204        if (!familyName.isEmpty()) {
    154205            FontPlatformData* result = getCachedFontPlatformData(font.fontDescription(), familyName);
Note: See TracChangeset for help on using the changeset viewer.