Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Computer, Inc.
      3  * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "config.h"
     33 #include "platform/fonts/FontCache.h"
     34 
     35 #include "SkFontMgr.h"
     36 #include "SkTypeface_win.h"
     37 #include "platform/RuntimeEnabledFeatures.h"
     38 #include "platform/fonts/FontDescription.h"
     39 #include "platform/fonts/SimpleFontData.h"
     40 #include "platform/fonts/harfbuzz/FontPlatformDataHarfbuzz.h"
     41 #include "platform/fonts/win/FontFallbackWin.h"
     42 
     43 namespace WebCore {
     44 
     45 HashMap<String, SkTypeface*>* FontCache::s_sideloadedFonts = 0;
     46 
     47 // static
     48 void FontCache::addSideloadedFontForTesting(SkTypeface* typeface)
     49 {
     50     if (!s_sideloadedFonts)
     51         s_sideloadedFonts = new HashMap<String, SkTypeface*>;
     52     SkString name;
     53     typeface->getFamilyName(&name);
     54     s_sideloadedFonts->set(name.c_str(), typeface);
     55 }
     56 
     57 FontCache::FontCache()
     58     : m_purgePreventCount(0)
     59 {
     60     SkFontMgr* fontManager;
     61 
     62     if (s_useDirectWrite) {
     63         fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory);
     64         s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled();
     65     } else {
     66         fontManager = SkFontMgr_New_GDI();
     67         // Subpixel text positioning is not supported by the GDI backend.
     68         s_useSubpixelPositioning = false;
     69     }
     70 
     71     ASSERT(fontManager);
     72     m_fontManager = adoptPtr(fontManager);
     73 }
     74 
     75 static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character)
     76 {
     77     SkPaint paint;
     78     fontData->setupPaint(&paint);
     79     paint.setTextEncoding(SkPaint::kUTF32_TextEncoding);
     80 
     81     uint16_t glyph;
     82     paint.textToGlyphs(&character, sizeof(character), &glyph);
     83     return glyph;
     84 }
     85 
     86 // Given the desired base font, this will create a SimpleFontData for a specific
     87 // font that can be used to render the given range of characters.
     88 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 character, const SimpleFontData*)
     89 {
     90     // FIXME: Consider passing fontDescription.dominantScript()
     91     // to GetFallbackFamily here.
     92     UScriptCode script;
     93     const wchar_t* family = getFallbackFamily(character,
     94         fontDescription.genericFamily(),
     95         &script,
     96         m_fontManager.get());
     97     FontPlatformData* data = 0;
     98     if (family)
     99         data = getFontPlatformData(fontDescription,  AtomicString(family, wcslen(family)));
    100 
    101     // Last resort font list : PanUnicode. CJK fonts have a pretty
    102     // large repertoire. Eventually, we need to scan all the fonts
    103     // on the system to have a Firefox-like coverage.
    104     // Make sure that all of them are lowercased.
    105     const static wchar_t* const cjkFonts[] = {
    106         L"arial unicode ms",
    107         L"ms pgothic",
    108         L"simsun",
    109         L"gulim",
    110         L"pmingliu",
    111         L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users.
    112         L"ar pl shanheisun uni",
    113         L"ar pl zenkai uni",
    114         L"han nom a", // Complete CJK Ext. A coverage.
    115         L"code2000" // Complete CJK Ext. A coverage.
    116         // CJK Ext. B fonts are not listed here because it's of no use
    117         // with our current non-BMP character handling because we use
    118         // Uniscribe for it and that code path does not go through here.
    119     };
    120 
    121     const static wchar_t* const commonFonts[] = {
    122         L"tahoma",
    123         L"arial unicode ms",
    124         L"lucida sans unicode",
    125         L"microsoft sans serif",
    126         L"palatino linotype",
    127         // Six fonts below (and code2000 at the end) are not from MS, but
    128         // once installed, cover a very wide range of characters.
    129         L"dejavu serif",
    130         L"dejavu sasns",
    131         L"freeserif",
    132         L"freesans",
    133         L"gentium",
    134         L"gentiumalt",
    135         L"ms pgothic",
    136         L"simsun",
    137         L"gulim",
    138         L"pmingliu",
    139         L"code2000"
    140     };
    141 
    142     const wchar_t* const* panUniFonts = 0;
    143     int numFonts = 0;
    144     if (script == USCRIPT_HAN) {
    145         panUniFonts = cjkFonts;
    146         numFonts = WTF_ARRAY_LENGTH(cjkFonts);
    147     } else {
    148         panUniFonts = commonFonts;
    149         numFonts = WTF_ARRAY_LENGTH(commonFonts);
    150     }
    151     // Font returned from getFallbackFamily may not cover |character|
    152     // because it's based on script to font mapping. This problem is
    153     // critical enough for non-Latin scripts (especially Han) to
    154     // warrant an additional (real coverage) check with fontCotainsCharacter.
    155     int i;
    156     for (i = 0; (!data || !fontContainsCharacter(data, family, character)) && i < numFonts; ++i) {
    157         family = panUniFonts[i];
    158         data = getFontPlatformData(fontDescription, AtomicString(family, wcslen(family)));
    159     }
    160 
    161     // When i-th font (0-base) in |panUniFonts| contains a character and
    162     // we get out of the loop, |i| will be |i + 1|. That is, if only the
    163     // last font in the array covers the character, |i| will be numFonts.
    164     // So, we have to use '<=" rather than '<' to see if we found a font
    165     // covering the character.
    166     if (i <= numFonts)
    167         return fontDataFromFontPlatformData(data, DoNotRetain);
    168 
    169     return nullptr;
    170 }
    171 
    172 static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b)
    173 {
    174     return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str()));
    175 }
    176 
    177 static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family)
    178 {
    179     SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
    180     bool matchesRequestedFamily = false;
    181     SkTypeface::LocalizedString actualFamily;
    182 
    183     while (actualFamilies->next(&actualFamily)) {
    184         if (equalIgnoringCase(family, actualFamily.fString)) {
    185             matchesRequestedFamily = true;
    186             break;
    187         }
    188     }
    189     actualFamilies->unref();
    190 
    191     // getFamilyName may return a name not returned by the createFamilyNameIterator.
    192     // Specifically in cases where Windows substitutes the font based on the
    193     // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries.
    194     if (!matchesRequestedFamily) {
    195         SkString familyName;
    196         tf->getFamilyName(&familyName);
    197         if (equalIgnoringCase(family, familyName))
    198             matchesRequestedFamily = true;
    199     }
    200 
    201     return matchesRequestedFamily;
    202 }
    203 
    204 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family, float fontSize)
    205 {
    206     CString name;
    207     RefPtr<SkTypeface> tf = createTypeface(fontDescription, family, name);
    208     if (!tf)
    209         return 0;
    210 
    211     // Windows will always give us a valid pointer here, even if the face name
    212     // is non-existent. We have to double-check and see if the family name was
    213     // really used.
    214     // FIXME: Do we need to use predefined fonts "guaranteed" to exist
    215     // when we're running in layout-test mode?
    216     if (!typefacesMatchesFamily(tf.get(), family)) {
    217         return 0;
    218     }
    219 
    220     FontPlatformData* result = new FontPlatformData(tf,
    221         name.data(),
    222         fontSize,
    223         fontDescription.weight() >= FontWeightBold && !tf->isBold() || fontDescription.isSyntheticBold(),
    224         fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(),
    225         fontDescription.orientation(),
    226         s_useSubpixelPositioning);
    227 
    228     struct FamilyMinSize {
    229         const wchar_t* family;
    230         unsigned minSize;
    231     };
    232     const static FamilyMinSize minAntiAliasSizeForFont[] = {
    233         { L"simsun", 16 },
    234         { L"dotum", 12 },
    235         { L"gulim", 12 }
    236     };
    237     size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont);
    238     for (size_t i = 0; i < numFonts; i++) {
    239         FamilyMinSize entry = minAntiAliasSizeForFont[i];
    240         if (typefacesMatchesFamily(tf.get(), entry.family)) {
    241             result->setMinSizeForAntiAlias(entry.minSize);
    242             break;
    243         }
    244     }
    245 
    246     return result;
    247 }
    248 
    249 }
    250