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