|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "gfxGDIFont.h" |
|
7 |
|
8 #include "mozilla/MemoryReporting.h" |
|
9 #include "mozilla/WindowsVersion.h" |
|
10 |
|
11 #include "gfxGDIShaper.h" |
|
12 #include "gfxUniscribeShaper.h" |
|
13 #include "gfxHarfBuzzShaper.h" |
|
14 #include <algorithm> |
|
15 #include "gfxGraphiteShaper.h" |
|
16 #include "gfxWindowsPlatform.h" |
|
17 #include "gfxContext.h" |
|
18 #include "mozilla/Preferences.h" |
|
19 #include "nsUnicodeProperties.h" |
|
20 #include "gfxFontConstants.h" |
|
21 |
|
22 #include "cairo-win32.h" |
|
23 |
|
24 #define ROUND(x) floor((x) + 0.5) |
|
25 |
|
26 using namespace mozilla; |
|
27 using namespace mozilla::unicode; |
|
28 |
|
29 static inline cairo_antialias_t |
|
30 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption) |
|
31 { |
|
32 switch (anAntialiasOption) { |
|
33 default: |
|
34 case gfxFont::kAntialiasDefault: |
|
35 return CAIRO_ANTIALIAS_DEFAULT; |
|
36 case gfxFont::kAntialiasNone: |
|
37 return CAIRO_ANTIALIAS_NONE; |
|
38 case gfxFont::kAntialiasGrayscale: |
|
39 return CAIRO_ANTIALIAS_GRAY; |
|
40 case gfxFont::kAntialiasSubpixel: |
|
41 return CAIRO_ANTIALIAS_SUBPIXEL; |
|
42 } |
|
43 } |
|
44 |
|
45 gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry, |
|
46 const gfxFontStyle *aFontStyle, |
|
47 bool aNeedsBold, |
|
48 AntialiasOption anAAOption) |
|
49 : gfxFont(aFontEntry, aFontStyle, anAAOption), |
|
50 mFont(nullptr), |
|
51 mFontFace(nullptr), |
|
52 mMetrics(nullptr), |
|
53 mSpaceGlyph(0), |
|
54 mNeedsBold(aNeedsBold) |
|
55 { |
|
56 if (FontCanSupportGraphite()) { |
|
57 mGraphiteShaper = new gfxGraphiteShaper(this); |
|
58 } |
|
59 if (FontCanSupportHarfBuzz()) { |
|
60 mHarfBuzzShaper = new gfxHarfBuzzShaper(this); |
|
61 } |
|
62 } |
|
63 |
|
64 gfxGDIFont::~gfxGDIFont() |
|
65 { |
|
66 if (mScaledFont) { |
|
67 cairo_scaled_font_destroy(mScaledFont); |
|
68 } |
|
69 if (mFontFace) { |
|
70 cairo_font_face_destroy(mFontFace); |
|
71 } |
|
72 if (mFont) { |
|
73 ::DeleteObject(mFont); |
|
74 } |
|
75 delete mMetrics; |
|
76 } |
|
77 |
|
78 void |
|
79 gfxGDIFont::CreatePlatformShaper() |
|
80 { |
|
81 mPlatformShaper = new gfxGDIShaper(this); |
|
82 } |
|
83 |
|
84 gfxFont* |
|
85 gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) |
|
86 { |
|
87 return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()), |
|
88 &mStyle, mNeedsBold, anAAOption); |
|
89 } |
|
90 |
|
91 static bool |
|
92 UseUniscribe(gfxShapedText *aShapedText, |
|
93 char16ptr_t aText, |
|
94 uint32_t aLength) |
|
95 { |
|
96 uint32_t flags = aShapedText->Flags(); |
|
97 bool useGDI; |
|
98 |
|
99 bool isXP = !IsVistaOrLater(); |
|
100 |
|
101 // bug 561304 - Uniscribe bug produces bad positioning at certain |
|
102 // font sizes on XP, so default to GDI on XP using logic of 3.6 |
|
103 |
|
104 useGDI = isXP && |
|
105 (flags & |
|
106 (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | |
|
107 gfxTextRunFactory::TEXT_IS_RTL) |
|
108 ) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED; |
|
109 |
|
110 return !useGDI || |
|
111 ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK; |
|
112 } |
|
113 |
|
114 bool |
|
115 gfxGDIFont::ShapeText(gfxContext *aContext, |
|
116 const char16_t *aText, |
|
117 uint32_t aOffset, |
|
118 uint32_t aLength, |
|
119 int32_t aScript, |
|
120 gfxShapedText *aShapedText, |
|
121 bool aPreferPlatformShaping) |
|
122 { |
|
123 if (!mMetrics) { |
|
124 Initialize(); |
|
125 } |
|
126 if (!mIsValid) { |
|
127 NS_WARNING("invalid font! expect incorrect text rendering"); |
|
128 return false; |
|
129 } |
|
130 |
|
131 bool ok = false; |
|
132 |
|
133 // Ensure the cairo font is set up, so there's no risk it'll fall back to |
|
134 // creating a "toy" font internally (see bug 544617). |
|
135 // We must check that this succeeded, otherwise we risk cairo creating the |
|
136 // wrong kind of font internally as a fallback (bug 744480). |
|
137 if (!SetupCairoFont(aContext)) { |
|
138 return false; |
|
139 } |
|
140 |
|
141 if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) { |
|
142 ok = mGraphiteShaper->ShapeText(aContext, aText, |
|
143 aOffset, aLength, |
|
144 aScript, aShapedText); |
|
145 } |
|
146 |
|
147 if (!ok && mHarfBuzzShaper) { |
|
148 if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) || |
|
149 (!IsVistaOrLater() && |
|
150 ScriptShapingType(aScript) == SHAPING_INDIC && |
|
151 !Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe", |
|
152 false))) { |
|
153 ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, |
|
154 aScript, aShapedText); |
|
155 } |
|
156 } |
|
157 |
|
158 if (!ok) { |
|
159 GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry()); |
|
160 bool preferUniscribe = |
|
161 (!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI; |
|
162 |
|
163 if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) { |
|
164 // first try Uniscribe |
|
165 if (!mUniscribeShaper) { |
|
166 mUniscribeShaper = new gfxUniscribeShaper(this); |
|
167 } |
|
168 |
|
169 ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength, |
|
170 aScript, aShapedText); |
|
171 if (!ok) { |
|
172 // fallback to GDI shaping |
|
173 if (!mPlatformShaper) { |
|
174 CreatePlatformShaper(); |
|
175 } |
|
176 |
|
177 ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, |
|
178 aLength, aScript, aShapedText); |
|
179 } |
|
180 } else { |
|
181 // first use GDI |
|
182 if (!mPlatformShaper) { |
|
183 CreatePlatformShaper(); |
|
184 } |
|
185 |
|
186 ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength, |
|
187 aScript, aShapedText); |
|
188 if (!ok) { |
|
189 // try Uniscribe if GDI failed |
|
190 if (!mUniscribeShaper) { |
|
191 mUniscribeShaper = new gfxUniscribeShaper(this); |
|
192 } |
|
193 |
|
194 // use Uniscribe shaping |
|
195 ok = mUniscribeShaper->ShapeText(aContext, aText, |
|
196 aOffset, aLength, |
|
197 aScript, aShapedText); |
|
198 } |
|
199 } |
|
200 |
|
201 #if DEBUG |
|
202 if (!ok) { |
|
203 NS_ConvertUTF16toUTF8 name(GetName()); |
|
204 char msg[256]; |
|
205 |
|
206 sprintf(msg, |
|
207 "text shaping with both uniscribe and GDI failed for" |
|
208 " font: %s", |
|
209 name.get()); |
|
210 NS_WARNING(msg); |
|
211 } |
|
212 #endif |
|
213 } |
|
214 |
|
215 PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); |
|
216 |
|
217 return ok; |
|
218 } |
|
219 |
|
220 const gfxFont::Metrics& |
|
221 gfxGDIFont::GetMetrics() |
|
222 { |
|
223 if (!mMetrics) { |
|
224 Initialize(); |
|
225 } |
|
226 return *mMetrics; |
|
227 } |
|
228 |
|
229 uint32_t |
|
230 gfxGDIFont::GetSpaceGlyph() |
|
231 { |
|
232 if (!mMetrics) { |
|
233 Initialize(); |
|
234 } |
|
235 return mSpaceGlyph; |
|
236 } |
|
237 |
|
238 bool |
|
239 gfxGDIFont::SetupCairoFont(gfxContext *aContext) |
|
240 { |
|
241 if (!mMetrics) { |
|
242 Initialize(); |
|
243 } |
|
244 if (!mScaledFont || |
|
245 cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { |
|
246 // Don't cairo_set_scaled_font as that would propagate the error to |
|
247 // the cairo_t, precluding any further drawing. |
|
248 return false; |
|
249 } |
|
250 cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); |
|
251 return true; |
|
252 } |
|
253 |
|
254 gfxFont::RunMetrics |
|
255 gfxGDIFont::Measure(gfxTextRun *aTextRun, |
|
256 uint32_t aStart, uint32_t aEnd, |
|
257 BoundingBoxType aBoundingBoxType, |
|
258 gfxContext *aRefContext, |
|
259 Spacing *aSpacing) |
|
260 { |
|
261 gfxFont::RunMetrics metrics = |
|
262 gfxFont::Measure(aTextRun, aStart, aEnd, |
|
263 aBoundingBoxType, aRefContext, aSpacing); |
|
264 |
|
265 // if aBoundingBoxType is LOOSE_INK_EXTENTS |
|
266 // and the underlying cairo font may be antialiased, |
|
267 // we can't trust Windows to have considered all the pixels |
|
268 // so we need to add "padding" to the bounds. |
|
269 // (see bugs 475968, 439831, compare also bug 445087) |
|
270 if (aBoundingBoxType == LOOSE_INK_EXTENTS && |
|
271 mAntialiasOption != kAntialiasNone && |
|
272 metrics.mBoundingBox.width > 0) { |
|
273 metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); |
|
274 metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3; |
|
275 } |
|
276 |
|
277 return metrics; |
|
278 } |
|
279 |
|
280 #define OBLIQUE_SKEW_FACTOR 0.3 |
|
281 |
|
282 void |
|
283 gfxGDIFont::Initialize() |
|
284 { |
|
285 NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); |
|
286 |
|
287 LOGFONTW logFont; |
|
288 |
|
289 // Figure out if we want to do synthetic oblique styling. |
|
290 GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry()); |
|
291 bool wantFakeItalic = |
|
292 (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && |
|
293 !fe->IsItalic(); |
|
294 |
|
295 // If the font's family has an actual italic face (but font matching |
|
296 // didn't choose it), we have to use a cairo transform instead of asking |
|
297 // GDI to italicize, because that would use a different face and result |
|
298 // in a possible glyph ID mismatch between shaping and rendering. |
|
299 // |
|
300 // We use the mFamilyHasItalicFace flag in the entry in case of user fonts, |
|
301 // where the *CSS* family may not know about italic faces that are present |
|
302 // in the *GDI* family, and which GDI would use if we asked it to perform |
|
303 // the "italicization". |
|
304 bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace; |
|
305 |
|
306 if (mAdjustedSize == 0.0) { |
|
307 mAdjustedSize = mStyle.size; |
|
308 if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { |
|
309 // to implement font-size-adjust, we first create the "unadjusted" font |
|
310 FillLogFont(logFont, mAdjustedSize, |
|
311 wantFakeItalic && !useCairoFakeItalic); |
|
312 mFont = ::CreateFontIndirectW(&logFont); |
|
313 |
|
314 // initialize its metrics so we can calculate size adjustment |
|
315 Initialize(); |
|
316 |
|
317 // calculate the properly adjusted size, and then proceed |
|
318 // to recreate mFont and recalculate metrics |
|
319 gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; |
|
320 mAdjustedSize = mStyle.GetAdjustedSize(aspect); |
|
321 |
|
322 // delete the temporary font and metrics |
|
323 ::DeleteObject(mFont); |
|
324 mFont = nullptr; |
|
325 delete mMetrics; |
|
326 mMetrics = nullptr; |
|
327 } |
|
328 } |
|
329 |
|
330 // (bug 724231) for local user fonts, we don't use GDI's synthetic bold, |
|
331 // as it could lead to a different, incompatible face being used |
|
332 // but instead do our own multi-striking |
|
333 if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) { |
|
334 mApplySyntheticBold = true; |
|
335 } |
|
336 |
|
337 // this may end up being zero |
|
338 mAdjustedSize = ROUND(mAdjustedSize); |
|
339 FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); |
|
340 mFont = ::CreateFontIndirectW(&logFont); |
|
341 |
|
342 mMetrics = new gfxFont::Metrics; |
|
343 ::memset(mMetrics, 0, sizeof(*mMetrics)); |
|
344 |
|
345 AutoDC dc; |
|
346 SetGraphicsMode(dc.GetDC(), GM_ADVANCED); |
|
347 AutoSelectFont selectFont(dc.GetDC(), mFont); |
|
348 |
|
349 // Get font metrics if size > 0 |
|
350 if (mAdjustedSize > 0.0) { |
|
351 |
|
352 OUTLINETEXTMETRIC oMetrics; |
|
353 TEXTMETRIC& metrics = oMetrics.otmTextMetrics; |
|
354 |
|
355 if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { |
|
356 mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; |
|
357 // Some fonts have wrong sign on their subscript offset, bug 410917. |
|
358 mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); |
|
359 mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; |
|
360 mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; |
|
361 mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; |
|
362 mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; |
|
363 |
|
364 const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; |
|
365 GLYPHMETRICS gm; |
|
366 DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); |
|
367 if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { |
|
368 // 56% of ascent, best guess for true type |
|
369 mMetrics->xHeight = |
|
370 ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); |
|
371 } else { |
|
372 mMetrics->xHeight = gm.gmptGlyphOrigin.y; |
|
373 } |
|
374 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; |
|
375 gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; |
|
376 mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); |
|
377 mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; |
|
378 if (oMetrics.otmEMSquare > 0) { |
|
379 mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); |
|
380 } |
|
381 } else { |
|
382 // Make a best-effort guess at extended metrics |
|
383 // this is based on general typographic guidelines |
|
384 |
|
385 // GetTextMetrics can fail if the font file has been removed |
|
386 // or corrupted recently. |
|
387 BOOL result = GetTextMetrics(dc.GetDC(), &metrics); |
|
388 if (!result) { |
|
389 NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); |
|
390 mIsValid = false; |
|
391 memset(mMetrics, 0, sizeof(*mMetrics)); |
|
392 return; |
|
393 } |
|
394 |
|
395 mMetrics->xHeight = |
|
396 ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); |
|
397 mMetrics->superscriptOffset = mMetrics->xHeight; |
|
398 mMetrics->subscriptOffset = mMetrics->xHeight; |
|
399 mMetrics->strikeoutSize = 1; |
|
400 mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight |
|
401 mMetrics->underlineSize = 1; |
|
402 mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent |
|
403 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; |
|
404 mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; |
|
405 mMetrics->emDescent = metrics.tmDescent; |
|
406 } |
|
407 |
|
408 mMetrics->internalLeading = metrics.tmInternalLeading; |
|
409 mMetrics->externalLeading = metrics.tmExternalLeading; |
|
410 mMetrics->maxHeight = metrics.tmHeight; |
|
411 mMetrics->maxAscent = metrics.tmAscent; |
|
412 mMetrics->maxDescent = metrics.tmDescent; |
|
413 mMetrics->maxAdvance = metrics.tmMaxCharWidth; |
|
414 mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth); |
|
415 // The font is monospace when TMPF_FIXED_PITCH is *not* set! |
|
416 // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx |
|
417 if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { |
|
418 mMetrics->maxAdvance = mMetrics->aveCharWidth; |
|
419 } |
|
420 |
|
421 // Cache the width of a single space. |
|
422 SIZE size; |
|
423 GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); |
|
424 mMetrics->spaceWidth = ROUND(size.cx); |
|
425 |
|
426 // Cache the width of digit zero. |
|
427 // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) |
|
428 // does not say what the failure modes for GetTextExtentPoint32 are - |
|
429 // is it safe to assume it will fail iff the font has no '0'? |
|
430 if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { |
|
431 mMetrics->zeroOrAveCharWidth = ROUND(size.cx); |
|
432 } else { |
|
433 mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; |
|
434 } |
|
435 |
|
436 WORD glyph; |
|
437 DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, |
|
438 GGI_MARK_NONEXISTING_GLYPHS); |
|
439 if (ret != GDI_ERROR && glyph != 0xFFFF) { |
|
440 mSpaceGlyph = glyph; |
|
441 } |
|
442 |
|
443 SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); |
|
444 } |
|
445 |
|
446 if (IsSyntheticBold()) { |
|
447 mMetrics->aveCharWidth += GetSyntheticBoldOffset(); |
|
448 mMetrics->maxAdvance += GetSyntheticBoldOffset(); |
|
449 } |
|
450 |
|
451 mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, |
|
452 mFont); |
|
453 |
|
454 cairo_matrix_t sizeMatrix, ctm; |
|
455 cairo_matrix_init_identity(&ctm); |
|
456 cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); |
|
457 |
|
458 if (useCairoFakeItalic) { |
|
459 // Skew the matrix to do fake italic if it wasn't already applied |
|
460 // via the LOGFONT |
|
461 double skewfactor = OBLIQUE_SKEW_FACTOR; |
|
462 cairo_matrix_t style; |
|
463 cairo_matrix_init(&style, |
|
464 1, //xx |
|
465 0, //yx |
|
466 -1 * skewfactor, //xy |
|
467 1, //yy |
|
468 0, //x0 |
|
469 0); //y0 |
|
470 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); |
|
471 } |
|
472 |
|
473 cairo_font_options_t *fontOptions = cairo_font_options_create(); |
|
474 if (mAntialiasOption != kAntialiasDefault) { |
|
475 cairo_font_options_set_antialias(fontOptions, |
|
476 GetCairoAntialiasOption(mAntialiasOption)); |
|
477 } |
|
478 mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, |
|
479 &ctm, fontOptions); |
|
480 cairo_font_options_destroy(fontOptions); |
|
481 |
|
482 if (!mScaledFont || |
|
483 cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { |
|
484 #ifdef DEBUG |
|
485 char warnBuf[1024]; |
|
486 sprintf(warnBuf, "Failed to create scaled font: %s status: %d", |
|
487 NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), |
|
488 mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); |
|
489 NS_WARNING(warnBuf); |
|
490 #endif |
|
491 mIsValid = false; |
|
492 } else { |
|
493 mIsValid = true; |
|
494 } |
|
495 |
|
496 #if 0 |
|
497 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, |
|
498 NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); |
|
499 printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); |
|
500 printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); |
|
501 printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); |
|
502 printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); |
|
503 printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", |
|
504 mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, |
|
505 mMetrics->superscriptOffset, mMetrics->subscriptOffset); |
|
506 #endif |
|
507 } |
|
508 |
|
509 void |
|
510 gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, |
|
511 bool aUseGDIFakeItalic) |
|
512 { |
|
513 GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry()); |
|
514 |
|
515 uint16_t weight; |
|
516 if (fe->IsUserFont()) { |
|
517 if (fe->IsLocalUserFont()) { |
|
518 // for local user fonts, don't change the original weight |
|
519 // in the entry's logfont, because that could alter the |
|
520 // choice of actual face used (bug 724231) |
|
521 weight = 0; |
|
522 } else { |
|
523 // avoid GDI synthetic bold which occurs when weight |
|
524 // specified is >= font data weight + 200 |
|
525 weight = mNeedsBold ? 700 : 200; |
|
526 } |
|
527 } else { |
|
528 weight = mNeedsBold ? 700 : fe->Weight(); |
|
529 } |
|
530 |
|
531 fe->FillLogFont(&aLogFont, weight, aSize, |
|
532 (mAntialiasOption == kAntialiasSubpixel) ? true : false); |
|
533 |
|
534 // If GDI synthetic italic is wanted, force the lfItalic field to true |
|
535 if (aUseGDIFakeItalic) { |
|
536 aLogFont.lfItalic = 1; |
|
537 } |
|
538 } |
|
539 |
|
540 int32_t |
|
541 gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) |
|
542 { |
|
543 if (!mGlyphWidths) { |
|
544 mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200); |
|
545 } |
|
546 |
|
547 int32_t width; |
|
548 if (mGlyphWidths->Get(aGID, &width)) { |
|
549 return width; |
|
550 } |
|
551 |
|
552 DCFromContext dc(aCtx); |
|
553 AutoSelectFont fs(dc, GetHFONT()); |
|
554 |
|
555 int devWidth; |
|
556 if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) { |
|
557 // ensure width is positive, 16.16 fixed-point value |
|
558 width = (devWidth & 0x7fff) << 16; |
|
559 mGlyphWidths->Put(aGID, width); |
|
560 return width; |
|
561 } |
|
562 |
|
563 return -1; |
|
564 } |
|
565 |
|
566 void |
|
567 gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
568 FontCacheSizes* aSizes) const |
|
569 { |
|
570 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
571 aSizes->mFontInstances += aMallocSizeOf(mMetrics); |
|
572 if (mGlyphWidths) { |
|
573 aSizes->mFontInstances += |
|
574 mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf); |
|
575 } |
|
576 } |
|
577 |
|
578 void |
|
579 gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
|
580 FontCacheSizes* aSizes) const |
|
581 { |
|
582 aSizes->mFontInstances += aMallocSizeOf(this); |
|
583 AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
|
584 } |