Changeset 23539

Show
Ignore:
Timestamp:
2007-06-14 14:58:39 (1 year ago)
Author:
hyatt
Message:

Fix for missing text in non-English Windows installs.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/WebCore/ChangeLog

    r23536 r23539  
     12007-06-14  Dave Hyatt  <hyatt@apple.com> 
     2 
     3        Fix for Bugzilla bug 14806, missing text for bold/italic fonts in non-English Windows installs. 
     4         
     5        This patch adds an additional step after the lookup by full name fails.  It will then look up 
     6        a PostScript name in a (localized full name) -> (PostScript name) cache.  If the name is not 
     7        found, then the font's name table is obtained and searched for a PostScript name (and the 
     8        result is cached). 
     9         
     10        If lookup on PostScript name fails too, then we now properly fall back to the next font in the 
     11        list (so text should never be missing). 
     12 
     13        Reviewed by Darin (thoroughly reviewed, super reviewed even) 
     14 
     15        * platform/win/FontCacheWin.cpp: 
     16        * platform/win/FontPlatformDataWin.cpp: 
     17 
    1182007-06-14  Anders Carlsson  <andersca@apple.com> 
    219 
  • trunk/WebCore/platform/win/FontCacheWin.cpp

    r23462 r23539  
    159159    } 
    160160     
    161     return new FontPlatformData(hfont, fontDescription.computedPixelSize(), 
    162         fontDescription.bold(), fontDescription.italic()); 
     161    FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(), 
     162                                                    fontDescription.bold(), fontDescription.italic()); 
     163    if (!result->cgFont()) { 
     164        // The creation of the CGFontRef failed for some reason.  We already asserted in debug builds, but to make 
     165        // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next 
     166        // font. 
     167        delete result; 
     168        DeleteObject(hfont); 
     169        return 0; 
     170    }         
     171 
     172    return result; 
    163173} 
    164174 
  • trunk/WebCore/platform/win/FontPlatformDataWin.cpp

    r23462 r23539  
    2424#include "config.h" 
    2525#include "FontPlatformData.h" 
     26 
     27#include "PlatformString.h" 
     28#include "StringHash.h" 
    2629#include <ApplicationServices/ApplicationServices.h> 
     30#include <wtf/HashMap.h> 
     31#include <wtf/RetainPtr.h> 
     32#include <wtf/Vector.h> 
    2733 
    2834using std::min; 
     
    3339static const int Italic = (1 << 1); 
    3440static const int BoldOblique = (1 << 2); 
     41 
     42static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; } 
     43 
     44static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc) 
     45{ 
     46    const DWORD cMaxNameTableSize = 1024 * 1024; 
     47 
     48    static HashMap<String, RetainPtr<CFStringRef> > nameMap; 
     49 
     50    // Check our hash first. 
     51    String faceString(faceName); 
     52    RetainPtr<CFStringRef> result = nameMap.get(faceString); 
     53    if (result) 
     54        return result.get(); 
     55 
     56    // We need to obtain the PostScript name from the name table and use it instead,. 
     57    DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards 
     58    if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize) 
     59        return NULL; 
     60    
     61    Vector<BYTE> bufferVector(bufferSize); 
     62    BYTE* buffer = bufferVector.data(); 
     63    if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR) 
     64        return NULL; 
     65 
     66    if (bufferSize < 6) 
     67        return NULL; 
     68 
     69    USHORT numberOfRecords = readBigEndianWord(buffer + 2); 
     70    UINT stringsOffset = readBigEndianWord(buffer + 4); 
     71    if (bufferSize < stringsOffset) 
     72        return NULL; 
     73 
     74    BYTE* strings = buffer + stringsOffset; 
     75 
     76    // Now walk each name record looking for a Mac or Windows PostScript name. 
     77    UINT offset = 6; 
     78    for (int i = 0; i < numberOfRecords; i++) { 
     79        if (bufferSize < offset + 12) 
     80            return NULL; 
     81 
     82        USHORT platformID = readBigEndianWord(buffer + offset); 
     83        USHORT encodingID = readBigEndianWord(buffer + offset + 2); 
     84        USHORT languageID = readBigEndianWord(buffer + offset + 4); 
     85        USHORT nameID = readBigEndianWord(buffer + offset + 6); 
     86        USHORT length = readBigEndianWord(buffer + offset + 8); 
     87        USHORT nameOffset = readBigEndianWord(buffer + offset + 10); 
     88 
     89        if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) { 
     90            // This is a Windows PostScript name and is therefore UTF-16. 
     91            // Pass Big Endian as the encoding. 
     92            if (bufferSize < stringsOffset + nameOffset + length) 
     93                return NULL; 
     94            result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false)); 
     95            break; 
     96        } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) { 
     97            // This is a Mac PostScript name and is therefore ASCII. 
     98            // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html 
     99            if (bufferSize < stringsOffset + nameOffset + length) 
     100                return NULL; 
     101            result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false)); 
     102            break; 
     103        } 
     104 
     105        offset += 12; 
     106    } 
     107 
     108    if (result) 
     109        nameMap.set(faceString, result); 
     110    return result.get(); 
     111} 
    35112 
    36113static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam) 
     
    67144    ASSERT_WITH_MESSAGE(bufferSize != 0, "Bitmap fonts not supported with CoreGraphics."); 
    68145 
    69     if (bufferSize != 0) 
    70     { 
     146    if (bufferSize != 0) { 
    71147        OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize); 
    72148 
     
    103179        } 
    104180 
    105         CFStringRef cfName = CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)); 
    106         m_cgFont = CGFontCreateWithFontName(cfName); 
    107         ASSERT(m_cgFont); 
    108         CFRelease(cfName); 
    109          
     181        // Try the face name first.  Windows may end up localizing this name, and CG doesn't know about 
     182        // the localization.  If the create fails, we'll try the PostScript name. 
     183        RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName))); 
     184        m_cgFont = CGFontCreateWithFontName(fullName.get()); 
     185        if (!m_cgFont) { 
     186            CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc); 
     187            if (postScriptName) { 
     188                m_cgFont = CGFontCreateWithFontName(postScriptName); 
     189                ASSERT(m_cgFont); 
     190            } 
     191        } 
    110192        free(metrics); 
    111193    }