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/FontPlatformData.h"
     34 
     35 #include "platform/LayoutTestSupport.h"
     36 #include "platform/fonts/FontCache.h"
     37 #if USE(HARFBUZZ)
     38 #include "platform/fonts/harfbuzz/HarfBuzzFace.h"
     39 #endif
     40 #include "platform/fonts/skia/SkiaFontWin.h"
     41 #include "platform/graphics/GraphicsContext.h"
     42 #include "platform/win/HWndDC.h"
     43 #include "public/platform/Platform.h"
     44 #include "public/platform/win/WebSandboxSupport.h"
     45 #include "wtf/PassOwnPtr.h"
     46 #include "wtf/StdLibExtras.h"
     47 #include <mlang.h>
     48 #include <objidl.h>
     49 #include <windows.h>
     50 
     51 namespace WebCore {
     52 
     53 void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
     54 {
     55     const float ts = m_textSize >= 0 ? m_textSize : 12;
     56     paint->setTextSize(SkFloatToScalar(m_textSize));
     57     paint->setTypeface(typeface());
     58     paint->setFakeBoldText(m_fakeBold);
     59     paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
     60     paint->setSubpixelText(m_useSubpixelPositioning);
     61 
     62     int textFlags = paintTextFlags();
     63     // Only set painting flags when we're actually painting.
     64     if (context && !context->couldUseLCDRenderedText()) {
     65         textFlags &= ~SkPaint::kLCDRenderText_Flag;
     66         // If we *just* clear our request for LCD, then GDI seems to
     67         // sometimes give us AA text, and sometimes give us BW text. Since the
     68         // original intent was LCD, we want to force AA (rather than BW), so we
     69         // add a special bit to tell Skia to do its best to avoid the BW: by
     70         // drawing LCD offscreen and downsampling that to AA.
     71         textFlags |= SkPaint::kGenA8FromLCD_Flag;
     72     }
     73 
     74     static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
     75         SkPaint::kLCDRenderText_Flag |
     76         SkPaint::kGenA8FromLCD_Flag;
     77 
     78     SkASSERT(!(textFlags & ~textFlagsMask));
     79     uint32_t flags = paint->getFlags();
     80     flags &= ~textFlagsMask;
     81     flags |= textFlags;
     82     paint->setFlags(flags);
     83 }
     84 
     85 // Lookup the current system settings for font smoothing.
     86 // We cache these values for performance, but if the browser has a way to be
     87 // notified when these change, we could re-query them at that time.
     88 static uint32_t getDefaultGDITextFlags()
     89 {
     90     static bool gInited;
     91     static uint32_t gFlags;
     92     if (!gInited) {
     93         BOOL enabled;
     94         gFlags = 0;
     95         if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
     96             gFlags |= SkPaint::kAntiAlias_Flag;
     97 
     98             UINT smoothType;
     99             if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
    100                 if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
    101                     gFlags |= SkPaint::kLCDRenderText_Flag;
    102             }
    103         }
    104         gInited = true;
    105     }
    106     return gFlags;
    107 }
    108 
    109 static bool isWebFont(const LOGFONT& lf)
    110 {
    111     // web-fonts have artifical names constructed to always be
    112     // 1. 24 characters, followed by a '\0'
    113     // 2. the last two characters are '=='
    114     return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
    115 }
    116 
    117 static int computePaintTextFlags(const LOGFONT& lf)
    118 {
    119     int textFlags = 0;
    120     switch (lf.lfQuality) {
    121     case NONANTIALIASED_QUALITY:
    122         textFlags = 0;
    123         break;
    124     case ANTIALIASED_QUALITY:
    125         textFlags = SkPaint::kAntiAlias_Flag;
    126         break;
    127     case CLEARTYPE_QUALITY:
    128         textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
    129         break;
    130     default:
    131         textFlags = getDefaultGDITextFlags();
    132         break;
    133     }
    134 
    135     // only allow features that SystemParametersInfo allows
    136     textFlags &= getDefaultGDITextFlags();
    137 
    138     /*
    139      *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
    140      *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
    141      *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
    142      *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
    143      *
    144      *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
    145      *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
    146      *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
    147      */
    148     if (isWebFont(lf) && !isRunningLayoutTest())
    149         textFlags |= SkPaint::kAntiAlias_Flag;
    150     return textFlags;
    151 }
    152 
    153 #if !USE(HARFBUZZ)
    154 PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
    155 {
    156     LOGFONT info;
    157     GetObject(hfont, sizeof(info), &info);
    158     if (size) {
    159         int height = info.lfHeight;
    160         if (height < 0)
    161             height = -height;
    162         *size = height;
    163     }
    164     if (paintTextFlags)
    165         *paintTextFlags = computePaintTextFlags(info);
    166     return adoptRef(SkCreateTypefaceFromLOGFONT(info));
    167 }
    168 #endif
    169 
    170 FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    171     : m_textSize(-1)
    172     , m_fakeBold(false)
    173     , m_fakeItalic(false)
    174     , m_orientation(Horizontal)
    175     , m_typeface(adoptRef(SkTypeface::RefDefault()))
    176     , m_paintTextFlags(0)
    177     , m_isHashTableDeletedValue(true)
    178     , m_useSubpixelPositioning(false)
    179 {
    180 #if !USE(HARFBUZZ)
    181     m_font = 0;
    182     m_scriptCache = 0;
    183 #endif
    184 }
    185 
    186 FontPlatformData::FontPlatformData()
    187     : m_textSize(0)
    188     , m_fakeBold(false)
    189     , m_fakeItalic(false)
    190     , m_orientation(Horizontal)
    191     , m_typeface(adoptRef(SkTypeface::RefDefault()))
    192     , m_paintTextFlags(0)
    193     , m_isHashTableDeletedValue(false)
    194     , m_useSubpixelPositioning(false)
    195 {
    196 #if !USE(HARFBUZZ)
    197     m_font = 0;
    198     m_scriptCache = 0;
    199 #endif
    200 }
    201 
    202 #if ENABLE(GDI_FONTS_ON_WINDOWS) && !USE(HARFBUZZ)
    203 FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    204     : m_font(RefCountedHFONT::create(font))
    205     , m_textSize(size)
    206     , m_fakeBold(false)
    207     , m_fakeItalic(false)
    208     , m_orientation(orientation)
    209     , m_scriptCache(0)
    210     , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    211     , m_isHashTableDeletedValue(false)
    212     , m_useSubpixelPositioning(false)
    213 {
    214 }
    215 #endif
    216 
    217 // FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
    218 FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    219     : m_textSize(size)
    220     , m_fakeBold(false)
    221     , m_fakeItalic(false)
    222     , m_orientation(Horizontal)
    223     , m_typeface(adoptRef(SkTypeface::RefDefault()))
    224     , m_paintTextFlags(0)
    225     , m_isHashTableDeletedValue(false)
    226     , m_useSubpixelPositioning(false)
    227 {
    228 #if !USE(HARFBUZZ)
    229     m_font = 0;
    230     m_scriptCache = 0;
    231 #endif
    232 }
    233 
    234 FontPlatformData::FontPlatformData(const FontPlatformData& data)
    235     : m_textSize(data.m_textSize)
    236     , m_fakeBold(data.m_fakeBold)
    237     , m_fakeItalic(data.m_fakeItalic)
    238     , m_orientation(data.m_orientation)
    239     , m_typeface(data.m_typeface)
    240     , m_paintTextFlags(data.m_paintTextFlags)
    241     , m_isHashTableDeletedValue(false)
    242     , m_useSubpixelPositioning(data.m_useSubpixelPositioning)
    243 {
    244 #if !USE(HARFBUZZ)
    245     m_font = data.m_font;
    246     m_scriptCache = 0;
    247 #endif
    248 }
    249 
    250 FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    251     : m_textSize(textSize)
    252     , m_fakeBold(data.m_fakeBold)
    253     , m_fakeItalic(data.m_fakeItalic)
    254     , m_orientation(data.m_orientation)
    255     , m_typeface(data.m_typeface)
    256     , m_paintTextFlags(data.m_paintTextFlags)
    257     , m_isHashTableDeletedValue(false)
    258     , m_useSubpixelPositioning(data.m_useSubpixelPositioning)
    259 {
    260 #if !USE(HARFBUZZ)
    261     m_font = data.m_font;
    262     m_scriptCache = 0;
    263 #endif
    264 }
    265 
    266 FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family,
    267     float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation,
    268     bool useSubpixelPositioning)
    269     : m_textSize(textSize)
    270     , m_fakeBold(fakeBold)
    271     , m_fakeItalic(fakeItalic)
    272     , m_orientation(orientation)
    273     , m_typeface(tf)
    274     , m_isHashTableDeletedValue(false)
    275     , m_useSubpixelPositioning(useSubpixelPositioning)
    276 {
    277     // FIXME: This can be removed together with m_font once the last few
    278     // uses of hfont() has been eliminated.
    279     LOGFONT logFont;
    280     SkLOGFONTFromTypeface(m_typeface.get(), &logFont);
    281     logFont.lfHeight = -textSize;
    282     m_paintTextFlags = computePaintTextFlags(logFont);
    283 
    284 #if !USE(HARFBUZZ)
    285     HFONT hFont = CreateFontIndirect(&logFont);
    286     m_font = hFont ? RefCountedHFONT::create(hFont) : 0;
    287     m_scriptCache = 0;
    288 #endif
    289 }
    290 
    291 FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
    292 {
    293     if (this != &data) {
    294         m_textSize = data.m_textSize;
    295         m_fakeBold = data.m_fakeBold;
    296         m_fakeItalic = data.m_fakeItalic;
    297         m_orientation = data.m_orientation;
    298         m_typeface = data.m_typeface;
    299         m_paintTextFlags = data.m_paintTextFlags;
    300 
    301 #if !USE(HARFBUZZ)
    302         m_font = data.m_font;
    303         // The following fields will get re-computed if necessary.
    304         ScriptFreeCache(&m_scriptCache);
    305         m_scriptCache = 0;
    306         m_scriptFontProperties.clear();
    307 #endif
    308     }
    309     return *this;
    310 }
    311 
    312 FontPlatformData::~FontPlatformData()
    313 {
    314 #if !USE(HARFBUZZ)
    315     ScriptFreeCache(&m_scriptCache);
    316     m_scriptCache = 0;
    317 #endif
    318 }
    319 
    320 String FontPlatformData::fontFamilyName() const
    321 {
    322 #if ENABLE(GDI_FONTS_ON_WINDOWS)
    323     HWndDC dc(0);
    324     HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    325     WCHAR name[LF_FACESIZE];
    326     unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    327     if (resultLength > 0)
    328         resultLength--; // ignore the null terminator
    329     SelectObject(dc, oldFont);
    330     return String(name, resultLength);
    331 #else
    332     // FIXME: This returns the requested name, perhaps a better solution would be to
    333     // return the list of names provided by SkTypeface::createFamilyNameIterator.
    334     ASSERT(typeface());
    335     SkString familyName;
    336     typeface()->getFamilyName(&familyName);
    337     return String::fromUTF8(familyName.c_str());
    338 #endif
    339 }
    340 
    341 bool FontPlatformData::isFixedPitch() const
    342 {
    343 #if ENABLE(GDI_FONTS_ON_WINDOWS)
    344     // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    345     HWndDC dc(0);
    346     HGDIOBJ oldFont = SelectObject(dc, hfont());
    347 
    348     // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    349     // is *not* fixed pitch. Unbelievable but true.
    350     TEXTMETRIC textMetric = { 0 };
    351     if (!GetTextMetrics(dc, &textMetric)) {
    352         if (ensureFontLoaded(hfont())) {
    353             // Retry GetTextMetrics.
    354             // FIXME: Handle gracefully the error if this call also fails.
    355             // See http://crbug.com/6401.
    356             if (!GetTextMetrics(dc, &textMetric))
    357                 WTF_LOG_ERROR("Unable to get the text metrics after second attempt");
    358         }
    359     }
    360 
    361     bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);
    362 
    363     SelectObject(dc, oldFont);
    364 
    365     return treatAsFixedPitch;
    366 #else
    367     return typeface() && typeface()->isFixedPitch();
    368 #endif
    369 }
    370 
    371 bool FontPlatformData::operator==(const FontPlatformData& a) const
    372 {
    373     return SkTypeface::Equal(m_typeface.get(), a.m_typeface.get())
    374         && m_textSize == a.m_textSize
    375         && m_fakeBold == a.m_fakeBold
    376         && m_fakeItalic == a.m_fakeItalic
    377         && m_orientation == a.m_orientation
    378         && m_isHashTableDeletedValue == a.m_isHashTableDeletedValue;
    379 }
    380 
    381 #if USE(HARFBUZZ)
    382 HarfBuzzFace* FontPlatformData::harfBuzzFace() const
    383 {
    384     if (!m_harfBuzzFace)
    385         m_harfBuzzFace = HarfBuzzFace::create(const_cast<FontPlatformData*>(this), uniqueID());
    386 
    387     return m_harfBuzzFace.get();
    388 }
    389 
    390 #else
    391 FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
    392 {
    393     DeleteObject(m_hfont);
    394 }
    395 
    396 SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
    397 {
    398     if (!m_scriptFontProperties) {
    399         m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
    400         memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
    401         m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
    402         HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
    403         if (result == E_PENDING) {
    404             HWndDC dc(0);
    405             HGDIOBJ oldFont = SelectObject(dc, hfont());
    406             HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
    407             if (S_OK != hr) {
    408                 if (FontPlatformData::ensureFontLoaded(hfont())) {
    409                     // FIXME: Handle gracefully the error if this call also fails.
    410                     hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
    411                     if (S_OK != hr) {
    412                         WTF_LOG_ERROR("Unable to get the font properties after second attempt");
    413                     }
    414                 }
    415             }
    416 
    417             SelectObject(dc, oldFont);
    418         }
    419     }
    420     return m_scriptFontProperties.get();
    421 }
    422 
    423 bool FontPlatformData::ensureFontLoaded(HFONT font)
    424 {
    425     blink::WebSandboxSupport* sandboxSupport = blink::Platform::current()->sandboxSupport();
    426     // if there is no sandbox, then we can assume the font
    427     // was able to be loaded successfully already
    428     return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
    429 }
    430 #endif
    431 
    432 bool FontPlatformData::defaultUseSubpixelPositioning()
    433 {
    434 #if OS(WIN) && !ENABLE(GDI_FONTS_ON_WINDOWS)
    435     return FontCache::fontCache()->useSubpixelPositioning();
    436 #else
    437     return false;
    438 #endif
    439 }
    440 
    441 #ifndef NDEBUG
    442 String FontPlatformData::description() const
    443 {
    444     return String();
    445 }
    446 #endif
    447 
    448 } // namespace WebCore
    449