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