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/FontFaceCreationParams.h"
     40 #include "platform/fonts/FontPlatformData.h"
     41 #include "platform/fonts/SimpleFontData.h"
     42 #include "platform/fonts/win/FontFallbackWin.h"
     43 
     44 namespace blink {
     45 
     46 HashMap<String, RefPtr<SkTypeface> >* FontCache::s_sideloadedFonts = 0;
     47 
     48 // static
     49 void FontCache::addSideloadedFontForTesting(SkTypeface* typeface)
     50 {
     51     if (!s_sideloadedFonts)
     52         s_sideloadedFonts = new HashMap<String, RefPtr<SkTypeface> >;
     53     SkString name;
     54     typeface->getFamilyName(&name);
     55     s_sideloadedFonts->set(name.c_str(), adoptRef(typeface));
     56 }
     57 
     58 FontCache::FontCache()
     59     : m_purgePreventCount(0)
     60 {
     61     SkFontMgr* fontManager;
     62 
     63     if (s_useDirectWrite) {
     64         fontManager = SkFontMgr_New_DirectWrite(s_directWriteFactory);
     65         s_useSubpixelPositioning = RuntimeEnabledFeatures::subpixelFontScalingEnabled();
     66     } else {
     67         fontManager = SkFontMgr_New_GDI();
     68         // Subpixel text positioning is not supported by the GDI backend.
     69         s_useSubpixelPositioning = false;
     70     }
     71 
     72     ASSERT(fontManager);
     73     m_fontManager = adoptPtr(fontManager);
     74 }
     75 
     76 
     77 // Given the desired base font, this will create a SimpleFontData for a specific
     78 // font that can be used to render the given range of characters.
     79 PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(
     80     const FontDescription& fontDescription, UChar32 character,
     81     const SimpleFontData* originalFontData)
     82 {
     83     // First try the specified font with standard style & weight.
     84     if (fontDescription.style() == FontStyleItalic
     85         || fontDescription.weight() >= FontWeightBold) {
     86         RefPtr<SimpleFontData> fontData = fallbackOnStandardFontStyle(
     87             fontDescription, character);
     88         if (fontData)
     89             return fontData;
     90     }
     91 
     92     // FIXME: Consider passing fontDescription.dominantScript()
     93     // to GetFallbackFamily here.
     94     UScriptCode script;
     95     const wchar_t* family = getFallbackFamily(character,
     96         fontDescription.genericFamily(),
     97         &script,
     98         m_fontManager.get());
     99     FontPlatformData* data = 0;
    100     if (family) {
    101         FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
    102         data = getFontPlatformData(fontDescription, createByFamily);
    103     }
    104 
    105     // Last resort font list : PanUnicode. CJK fonts have a pretty
    106     // large repertoire. Eventually, we need to scan all the fonts
    107     // on the system to have a Firefox-like coverage.
    108     // Make sure that all of them are lowercased.
    109     const static wchar_t* const cjkFonts[] = {
    110         L"arial unicode ms",
    111         L"ms pgothic",
    112         L"simsun",
    113         L"gulim",
    114         L"pmingliu",
    115         L"wenquanyi zen hei", // Partial CJK Ext. A coverage but more widely known to Chinese users.
    116         L"ar pl shanheisun uni",
    117         L"ar pl zenkai uni",
    118         L"han nom a", // Complete CJK Ext. A coverage.
    119         L"code2000" // Complete CJK Ext. A coverage.
    120         // CJK Ext. B fonts are not listed here because it's of no use
    121         // with our current non-BMP character handling because we use
    122         // Uniscribe for it and that code path does not go through here.
    123     };
    124 
    125     const static wchar_t* const commonFonts[] = {
    126         L"tahoma",
    127         L"arial unicode ms",
    128         L"lucida sans unicode",
    129         L"microsoft sans serif",
    130         L"palatino linotype",
    131         // Six fonts below (and code2000 at the end) are not from MS, but
    132         // once installed, cover a very wide range of characters.
    133         L"dejavu serif",
    134         L"dejavu sasns",
    135         L"freeserif",
    136         L"freesans",
    137         L"gentium",
    138         L"gentiumalt",
    139         L"ms pgothic",
    140         L"simsun",
    141         L"gulim",
    142         L"pmingliu",
    143         L"code2000"
    144     };
    145 
    146     const wchar_t* const* panUniFonts = 0;
    147     int numFonts = 0;
    148     if (script == USCRIPT_HAN) {
    149         panUniFonts = cjkFonts;
    150         numFonts = WTF_ARRAY_LENGTH(cjkFonts);
    151     } else {
    152         panUniFonts = commonFonts;
    153         numFonts = WTF_ARRAY_LENGTH(commonFonts);
    154     }
    155     // Font returned from getFallbackFamily may not cover |character|
    156     // because it's based on script to font mapping. This problem is
    157     // critical enough for non-Latin scripts (especially Han) to
    158     // warrant an additional (real coverage) check with fontCotainsCharacter.
    159     int i;
    160     for (i = 0; (!data || !data->fontContainsCharacter(character)) && i < numFonts; ++i) {
    161         family = panUniFonts[i];
    162         FontFaceCreationParams createByFamily(AtomicString(family, wcslen(family)));
    163         data = getFontPlatformData(fontDescription, createByFamily);
    164     }
    165 
    166     // For font fallback we want to match the subpixel behavior of the original
    167     // font. Mixing subpixel and non-subpixel in the same text run looks really
    168     // odd and causes problems with preferred width calculations.
    169     if (data && originalFontData) {
    170         const FontPlatformData& platformData = originalFontData->platformData();
    171         data->setMinSizeForAntiAlias(platformData.minSizeForAntiAlias());
    172         data->setMinSizeForSubpixel(platformData.minSizeForSubpixel());
    173     }
    174 
    175     // When i-th font (0-base) in |panUniFonts| contains a character and
    176     // we get out of the loop, |i| will be |i + 1|. That is, if only the
    177     // last font in the array covers the character, |i| will be numFonts.
    178     // So, we have to use '<=" rather than '<' to see if we found a font
    179     // covering the character.
    180     if (i <= numFonts)
    181         return fontDataFromFontPlatformData(data, DoNotRetain);
    182 
    183     return nullptr;
    184 }
    185 
    186 static inline bool equalIgnoringCase(const AtomicString& a, const SkString& b)
    187 {
    188     return equalIgnoringCase(a, AtomicString::fromUTF8(b.c_str()));
    189 }
    190 
    191 static bool typefacesMatchesFamily(const SkTypeface* tf, const AtomicString& family)
    192 {
    193     SkTypeface::LocalizedStrings* actualFamilies = tf->createFamilyNameIterator();
    194     bool matchesRequestedFamily = false;
    195     SkTypeface::LocalizedString actualFamily;
    196 
    197     while (actualFamilies->next(&actualFamily)) {
    198         if (equalIgnoringCase(family, actualFamily.fString)) {
    199             matchesRequestedFamily = true;
    200             break;
    201         }
    202     }
    203     actualFamilies->unref();
    204 
    205     // getFamilyName may return a name not returned by the createFamilyNameIterator.
    206     // Specifically in cases where Windows substitutes the font based on the
    207     // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes registry entries.
    208     if (!matchesRequestedFamily) {
    209         SkString familyName;
    210         tf->getFamilyName(&familyName);
    211         if (equalIgnoringCase(family, familyName))
    212             matchesRequestedFamily = true;
    213     }
    214 
    215     return matchesRequestedFamily;
    216 }
    217 
    218 static bool typefacesHasWeightSuffix(const AtomicString& family,
    219     AtomicString& adjustedName, FontWeight& variantWeight)
    220 {
    221     struct FamilyWeightSuffix {
    222         const wchar_t* suffix;
    223         size_t length;
    224         FontWeight weight;
    225     };
    226     // Mapping from suffix to weight from the DirectWrite documentation.
    227     // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368082.aspx
    228     const static FamilyWeightSuffix variantForSuffix[] = {
    229         { L" thin", 5,  FontWeight100 },
    230         { L" extralight", 11,  FontWeight200 },
    231         { L" ultralight", 11,  FontWeight200 },
    232         { L" light", 6,  FontWeight300 },
    233         { L" medium", 7,  FontWeight500 },
    234         { L" demibold", 9,  FontWeight600 },
    235         { L" semibold", 9,  FontWeight600 },
    236         { L" extrabold", 10,  FontWeight800 },
    237         { L" ultrabold", 10,  FontWeight800 },
    238         { L" black", 6,  FontWeight900 },
    239         { L" heavy", 6,  FontWeight900 }
    240     };
    241     size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix);
    242     bool caseSensitive = false;
    243     for (size_t i = 0; i < numVariants; i++) {
    244         const FamilyWeightSuffix& entry = variantForSuffix[i];
    245         if (family.endsWith(entry.suffix, caseSensitive)) {
    246             String familyName = family.string();
    247             familyName.truncate(family.length() - entry.length);
    248             adjustedName = AtomicString(familyName);
    249             variantWeight = entry.weight;
    250             return true;
    251         }
    252     }
    253 
    254     return false;
    255 }
    256 
    257 static bool typefacesHasStretchSuffix(const AtomicString& family,
    258     AtomicString& adjustedName, FontStretch& variantStretch)
    259 {
    260     struct FamilyStretchSuffix {
    261         const wchar_t* suffix;
    262         size_t length;
    263         FontStretch stretch;
    264     };
    265     // Mapping from suffix to stretch value from the DirectWrite documentation.
    266     // http://msdn.microsoft.com/en-us/library/windows/desktop/dd368078.aspx
    267     // Also includes Narrow as a synonym for Condensed to to support Arial
    268     // Narrow and other fonts following the same naming scheme.
    269     const static FamilyStretchSuffix variantForSuffix[] = {
    270         { L" ultracondensed", 15,  FontStretchUltraCondensed },
    271         { L" extracondensed", 15,  FontStretchExtraCondensed },
    272         { L" condensed", 10,  FontStretchCondensed },
    273         { L" narrow", 7,  FontStretchCondensed },
    274         { L" semicondensed", 14,  FontStretchSemiCondensed },
    275         { L" semiexpanded", 13,  FontStretchSemiExpanded },
    276         { L" expanded", 9,  FontStretchExpanded },
    277         { L" extraexpanded", 14,  FontStretchExtraExpanded },
    278         { L" ultraexpanded", 14,  FontStretchUltraExpanded }
    279     };
    280     size_t numVariants = WTF_ARRAY_LENGTH(variantForSuffix);
    281     bool caseSensitive = false;
    282     for (size_t i = 0; i < numVariants; i++) {
    283         const FamilyStretchSuffix& entry = variantForSuffix[i];
    284         if (family.endsWith(entry.suffix, caseSensitive)) {
    285             String familyName = family.string();
    286             familyName.truncate(family.length() - entry.length);
    287             adjustedName = AtomicString(familyName);
    288             variantStretch = entry.stretch;
    289             return true;
    290         }
    291     }
    292 
    293     return false;
    294 }
    295 
    296 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const FontFaceCreationParams& creationParams, float fontSize)
    297 {
    298     ASSERT(creationParams.creationType() == CreateFontByFamily);
    299 
    300     CString name;
    301     RefPtr<SkTypeface> tf = createTypeface(fontDescription, creationParams, name);
    302     // Windows will always give us a valid pointer here, even if the face name
    303     // is non-existent. We have to double-check and see if the family name was
    304     // really used.
    305     if (!tf || !typefacesMatchesFamily(tf.get(), creationParams.family())) {
    306         AtomicString adjustedName;
    307         FontWeight variantWeight;
    308         FontStretch variantStretch;
    309 
    310         if (typefacesHasWeightSuffix(creationParams.family(), adjustedName,
    311             variantWeight)) {
    312             FontFaceCreationParams adjustedParams(adjustedName);
    313             FontDescription adjustedFontDescription = fontDescription;
    314             adjustedFontDescription.setWeight(variantWeight);
    315             tf = createTypeface(adjustedFontDescription, adjustedParams, name);
    316             if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName))
    317                 return 0;
    318 
    319         } else if (typefacesHasStretchSuffix(creationParams.family(),
    320             adjustedName, variantStretch)) {
    321             FontFaceCreationParams adjustedParams(adjustedName);
    322             FontDescription adjustedFontDescription = fontDescription;
    323             adjustedFontDescription.setStretch(variantStretch);
    324             tf = createTypeface(adjustedFontDescription, adjustedParams, name);
    325             if (!tf || !typefacesMatchesFamily(tf.get(), adjustedName))
    326                 return 0;
    327 
    328         } else {
    329             return 0;
    330         }
    331     }
    332 
    333     FontPlatformData* result = new FontPlatformData(tf,
    334         name.data(),
    335         fontSize,
    336         fontDescription.weight() >= FontWeight600 && !tf->isBold() || fontDescription.isSyntheticBold(),
    337         fontDescription.style() == FontStyleItalic && !tf->isItalic() || fontDescription.isSyntheticItalic(),
    338         fontDescription.orientation(),
    339         s_useSubpixelPositioning);
    340 
    341     struct FamilyMinSize {
    342         const wchar_t* family;
    343         unsigned minSize;
    344     };
    345     const static FamilyMinSize minAntiAliasSizeForFont[] = {
    346         { L"simsun", 11 },
    347         { L"dotum", 12 },
    348         { L"gulim", 12 },
    349         { L"pmingliu", 11 }
    350     };
    351     size_t numFonts = WTF_ARRAY_LENGTH(minAntiAliasSizeForFont);
    352     for (size_t i = 0; i < numFonts; i++) {
    353         FamilyMinSize entry = minAntiAliasSizeForFont[i];
    354         if (typefacesMatchesFamily(tf.get(), entry.family)) {
    355             result->setMinSizeForAntiAlias(entry.minSize);
    356             break;
    357         }
    358     }
    359 
    360     // List of fonts that look bad with subpixel text rendering at smaller font
    361     // sizes. This includes all fonts in the Microsoft Core fonts for the Web
    362     // collection.
    363     const static wchar_t* noSubpixelForSmallSizeFont[] = {
    364         L"andale mono",
    365         L"arial",
    366         L"comic sans",
    367         L"courier new",
    368         L"georgia",
    369         L"impact",
    370         L"lucida console",
    371         L"tahoma",
    372         L"times new roman",
    373         L"trebuchet ms",
    374         L"verdana",
    375         L"webdings"
    376     };
    377     const static float minSizeForSubpixelForFont = 16.0f;
    378     numFonts = WTF_ARRAY_LENGTH(noSubpixelForSmallSizeFont);
    379     for (size_t i = 0; i < numFonts; i++) {
    380         const wchar_t* family = noSubpixelForSmallSizeFont[i];
    381         if (typefacesMatchesFamily(tf.get(), family)) {
    382             result->setMinSizeForSubpixel(minSizeForSubpixelForFont);
    383             break;
    384         }
    385     }
    386 
    387     return result;
    388 }
    389 
    390 } // namespace blink
    391