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 "core/platform/graphics/FontCache.h" | |
36 #include "core/platform/graphics/GraphicsContext.h" | |
37 #if USE(HARFBUZZ) | |
38 #include "core/platform/graphics/harfbuzz/HarfBuzzFace.h" | |
39 #endif | |
40 #include "core/platform/graphics/skia/SkiaFontWin.h" | |
41 #include "platform/LayoutTestSupport.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) cons
t | |
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) && enable
d) { | |
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.lf
FaceName[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 lf
Quality | |
140 * setting (computing the corresponding SkPaint flags for AA and LCD). Howe
ver, 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 an
tialiasing. | |
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 B
W. | |
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* pain
tTextFlags) | |
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 orien
tation) | |
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 b
e 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 attem
pt"); | |
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_scriptFontP
roperties.get()); | |
403 if (result == E_PENDING) { | |
404 HWndDC dc(0); | |
405 HGDIOBJ oldFont = SelectObject(dc, hfont()); | |
406 HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFont
Properties.get()); | |
407 if (S_OK != hr) { | |
408 if (FontPlatformData::ensureFontLoaded(hfont())) { | |
409 // FIXME: Handle gracefully the error if this call also fail
s. | |
410 hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFont
Properties.get()); | |
411 if (S_OK != hr) { | |
412 WTF_LOG_ERROR("Unable to get the font properties after s
econd 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()->sandb
oxSupport(); | |
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 #ifndef NDEBUG | |
433 String FontPlatformData::description() const | |
434 { | |
435 return String(); | |
436 } | |
437 #endif | |
438 | |
439 } | |
OLD | NEW |