Changeset 30179 in webkit


Ignore:
Timestamp:
Feb 12, 2008 3:54:39 PM (16 years ago)
Author:
mitz@apple.com
Message:

Reviewed by Adam Roben.

Revised the system fallback font lookup logic to use MLang font linking
again. To avoid reintroducing bug 16548 and <rdar://problem/5280188>,
for CJK characters, try linking based on a single code page at a time,
starting with the user's default code page (if it is one of the CJK
code pages) followed by the other CJK code pages in a prescribed order
that matches what Firefox does.

  • platform/graphics/win/FontCacheWin.cpp: (WebCore::getCJKCodePageMasks): Added. Returns the search order for CJK code pages, with the user's default code page first. (WebCore::currentFontContainsCharacter): Factored out of getFontDataForCharacters(). (WebCore::createMLangFont): Ditto. (WebCore::FontCache::getFontDataForCharacters):
Location:
trunk/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r30175 r30179  
     12008-02-12  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Adam Roben.
     4
     5        - fix http://bugs.webkit.org/show_bug.cgi?id=17041
     6          <rdar://problem/5709660> Eastern Asian fonts do not display without specific box in Control Panel
     7
     8        Revised the system fallback font lookup logic to use MLang font linking
     9        again. To avoid reintroducing bug 16548 and <rdar://problem/5280188>,
     10        for CJK characters, try linking based on a single code page at a time,
     11        starting with the user's default code page (if it is one of the CJK
     12        code pages) followed by the other CJK code pages in a prescribed order
     13        that matches what Firefox does.
     14
     15        * platform/graphics/win/FontCacheWin.cpp:
     16        (WebCore::getCJKCodePageMasks): Added. Returns the search order for CJK
     17        code pages, with the user's default code page first.
     18        (WebCore::currentFontContainsCharacter): Factored out of
     19        getFontDataForCharacters().
     20        (WebCore::createMLangFont): Ditto.
     21        (WebCore::FontCache::getFontDataForCharacters):
     22
    1232008-02-12  Rodney Dawes  <dobey@wayofthemonkey.com>
    224
  • trunk/WebCore/platform/graphics/win/FontCacheWin.cpp

    r29250 r30179  
    3333#include "SimpleFontData.h"
    3434#include "StringHash.h"
     35#include "UnicodeRange.h"
    3536#include <windows.h>
    3637#include <mlang.h>
     
    115116}
    116117
     118static const Vector<DWORD, 4>& getCJKCodePageMasks()
     119{
     120    // The default order in which we look for a font for a CJK character. If the user's default code page is
     121    // one of these, we will use it first.
     122    static const UINT CJKCodePages[] = {
     123        932, /* Japanese */
     124        936, /* Simplified Chinese */
     125        950, /* Traditional Chinese */
     126        949  /* Korean */
     127    };
     128
     129    static Vector<DWORD, 4> codePageMasks;
     130    static bool initialized;
     131    if (!initialized) {
     132        initialized = true;
     133        IMLangFontLink2* langFontLink = FontCache::getFontLinkInterface();
     134        if (!langFontLink)
     135            return codePageMasks;
     136
     137        UINT defaultCodePage;
     138        DWORD defaultCodePageMask = 0;
     139        if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE, reinterpret_cast<LPWSTR>(&defaultCodePage), sizeof(defaultCodePage)))
     140            langFontLink->CodePageToCodePages(defaultCodePage, &defaultCodePageMask);
     141
     142        if (defaultCodePage == CJKCodePages[0] || defaultCodePage == CJKCodePages[1] || defaultCodePage == CJKCodePages[2] || defaultCodePage == CJKCodePages[3])
     143            codePageMasks.append(defaultCodePageMask);
     144        for (unsigned i = 0; i < 4; ++i) {
     145            if (defaultCodePage != CJKCodePages[i]) {
     146                DWORD codePageMask;
     147                langFontLink->CodePageToCodePages(CJKCodePages[i], &codePageMask);
     148                codePageMasks.append(codePageMask);
     149            }
     150        }
     151    }
     152    return codePageMasks;
     153}
     154
     155static bool currentFontContainsCharacter(HDC hdc, UChar character)
     156{
     157    static Vector<char, 512> glyphsetBuffer;
     158    glyphsetBuffer.resize(GetFontUnicodeRanges(hdc, 0));
     159    GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(glyphsetBuffer.data());
     160    GetFontUnicodeRanges(hdc, glyphset);
     161
     162    // FIXME: Change this to a binary search.
     163    unsigned i = 0;
     164    while (i < glyphset->cRanges && glyphset->ranges[i].wcLow <= character)
     165        i++;
     166
     167    return i && glyphset->ranges[i - 1].wcLow + glyphset->ranges[i - 1].cGlyphs > character;
     168}
     169
     170static HFONT createMLangFont(IMLangFontLink2* langFontLink, HDC hdc, DWORD codePageMask, UChar character = 0)
     171{
     172    HFONT MLangFont;
     173    HFONT hfont = 0;
     174    if (SUCCEEDED(langFontLink->MapFont(hdc, codePageMask, character, &MLangFont)) && MLangFont) {
     175        LOGFONT lf;
     176        GetObject(MLangFont, sizeof(LOGFONT), &lf);
     177        langFontLink->ReleaseFont(MLangFont);
     178        hfont = CreateFontIndirect(&lf);
     179    }
     180    return hfont;
     181}
     182
    117183const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
    118184{
     185    UChar character = characters[0];
    119186    SimpleFontData* fontData = 0;
    120187    HDC hdc = GetDC(0);
    121     HFONT primaryFont = font.primaryFont()->fontDataForCharacter(characters[0])->m_font.hfont();
     188    HFONT primaryFont = font.primaryFont()->fontDataForCharacter(character)->platformData().hfont();
    122189    HGDIOBJ oldFont = SelectObject(hdc, primaryFont);
    123190    HFONT hfont = 0;
    124191
    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);
    134             LOGFONT lf;
    135             GetObject(mLangFont, sizeof(LOGFONT), &lf);
    136             langFontLink->ReleaseFont(mLangFont);
    137             hfont = CreateFontIndirect(&lf);
    138         }
    139     } else {
     192    if (IMLangFontLink2* langFontLink = getFontLinkInterface()) {
     193        // Try MLang font linking first.
     194        DWORD codePages = 0;
     195        langFontLink->GetCharCodePages(character, &codePages);
     196
     197        if (codePages && findCharUnicodeRange(character) == cRangeSetCJK) {
     198            // The CJK character may belong to multiple code pages. We want to
     199            // do font linking against a single one of them, preferring the default
     200            // code page for the user's locale.
     201            const Vector<DWORD, 4>& CJKCodePageMasks = getCJKCodePageMasks();
     202            unsigned numCodePages = CJKCodePageMasks.size();
     203            for (unsigned i = 0; i < numCodePages && !hfont; ++i) {
     204                hfont = createMLangFont(langFontLink, hdc, CJKCodePageMasks[i]);
     205                if (hfont && !(codePages & CJKCodePageMasks[i])) {
     206                    // We asked about a code page that is not one of the code pages
     207                    // returned by MLang, so the font might not contain the character.
     208                    SelectObject(hdc, hfont);
     209                    if (!currentFontContainsCharacter(hdc, character)) {
     210                        DeleteObject(hfont);
     211                        hfont = 0;
     212                    }
     213                    SelectObject(hdc, primaryFont);
     214                }
     215            }
     216        } else
     217            hfont = createMLangFont(langFontLink, hdc, codePages, character);
     218    }
     219
     220    // A font returned from MLang is trusted to contain the character.
     221    bool containsCharacter = hfont;
     222
     223    if (!hfont) {
    140224        // To find out what font Uniscribe would use, we make it draw into a metafile and intercept
    141225        // calls to CreateFontIndirect().
     
    172256        GetTextFace(hdc, LF_FACESIZE, name);
    173257        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])
     258
     259        if (containsCharacter || currentFontContainsCharacter(hdc, character))
    184260            break;
    185261
     
    200276        linkedFontIndex++;
    201277    }
    202    
     278
    203279    if (hfont) {
    204280        if (!familyName.isEmpty()) {
Note: See TracChangeset for help on using the changeset viewer.