Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxDWriteFonts.cpp
blobb1619abe432e9a51e409ebaeea0131f5b497dac8
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/. */
6 #include "gfxDWriteFonts.h"
8 #include "mozilla/MemoryReporting.h"
10 #include <algorithm>
11 #include "gfxDWriteFontList.h"
12 #include "gfxContext.h"
13 #include <dwrite.h>
15 #include "harfbuzz/hb.h"
17 // Chosen this as to resemble DWrite's own oblique face style.
18 #define OBLIQUE_SKEW_FACTOR 0.3
20 using namespace mozilla;
21 using namespace mozilla::gfx;
23 // This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
24 // but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
25 // because those are exported, and the cairo headers aren't.
26 static inline cairo_antialias_t
27 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
29 switch (anAntialiasOption) {
30 default:
31 case gfxFont::kAntialiasDefault:
32 return CAIRO_ANTIALIAS_DEFAULT;
33 case gfxFont::kAntialiasNone:
34 return CAIRO_ANTIALIAS_NONE;
35 case gfxFont::kAntialiasGrayscale:
36 return CAIRO_ANTIALIAS_GRAY;
37 case gfxFont::kAntialiasSubpixel:
38 return CAIRO_ANTIALIAS_SUBPIXEL;
42 // Code to determine whether Windows is set to use ClearType font smoothing;
43 // based on private functions in cairo-win32-font.c
45 #ifndef SPI_GETFONTSMOOTHINGTYPE
46 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
47 #endif
48 #ifndef FE_FONTSMOOTHINGCLEARTYPE
49 #define FE_FONTSMOOTHINGCLEARTYPE 2
50 #endif
52 static bool
53 UsingClearType()
55 BOOL fontSmoothing;
56 if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0) ||
57 !fontSmoothing)
59 return false;
62 UINT type;
63 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0) &&
64 type == FE_FONTSMOOTHINGCLEARTYPE)
66 return true;
68 return false;
71 ////////////////////////////////////////////////////////////////////////////////
72 // gfxDWriteFont
73 gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
74 const gfxFontStyle *aFontStyle,
75 bool aNeedsBold,
76 AntialiasOption anAAOption)
77 : gfxFont(aFontEntry, aFontStyle, anAAOption)
78 , mCairoFontFace(nullptr)
79 , mMetrics(nullptr)
80 , mNeedsOblique(false)
81 , mNeedsBold(aNeedsBold)
82 , mUseSubpixelPositions(false)
83 , mAllowManualShowGlyphs(true)
85 gfxDWriteFontEntry *fe =
86 static_cast<gfxDWriteFontEntry*>(aFontEntry);
87 nsresult rv;
88 DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
89 if ((GetStyle()->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) &&
90 !fe->IsItalic() && GetStyle()->allowSyntheticStyle) {
91 // For this we always use the font_matrix for uniformity. Not the
92 // DWrite simulation.
93 mNeedsOblique = true;
95 if (aNeedsBold) {
96 sims |= DWRITE_FONT_SIMULATIONS_BOLD;
99 rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
101 if (NS_FAILED(rv)) {
102 mIsValid = false;
103 return;
106 ComputeMetrics(anAAOption);
109 gfxDWriteFont::~gfxDWriteFont()
111 if (mCairoFontFace) {
112 cairo_font_face_destroy(mCairoFontFace);
114 if (mScaledFont) {
115 cairo_scaled_font_destroy(mScaledFont);
117 delete mMetrics;
120 gfxFont*
121 gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
123 return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
124 &mStyle, mNeedsBold, anAAOption);
127 const gfxFont::Metrics&
128 gfxDWriteFont::GetMetrics()
130 return *mMetrics;
133 bool
134 gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
136 gfxFontStyle style(mStyle);
137 style.weight = 700;
138 bool needsBold;
140 gfxFontEntry* fe =
141 gfxPlatformFontList::PlatformFontList()->
142 FindFontForFamily(NS_LITERAL_STRING("Arial"), &style, needsBold);
143 if (!fe || fe == mFontEntry) {
144 return false;
147 nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&style, needsBold);
148 gfxDWriteFont *dwFont = static_cast<gfxDWriteFont*>(font.get());
149 dwFont->mFontFace->GetMetrics(aFontMetrics);
151 return true;
154 void
155 gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
157 DWRITE_FONT_METRICS fontMetrics;
158 if (!(mFontEntry->Weight() == 900 &&
159 !mFontEntry->IsUserFont() &&
160 mFontEntry->Name().EqualsLiteral("Arial Black") &&
161 GetFakeMetricsForArialBlack(&fontMetrics)))
163 mFontFace->GetMetrics(&fontMetrics);
166 if (mStyle.sizeAdjust != 0.0) {
167 gfxFloat aspect = (gfxFloat)fontMetrics.xHeight /
168 fontMetrics.designUnitsPerEm;
169 mAdjustedSize = mStyle.GetAdjustedSize(aspect);
170 } else {
171 mAdjustedSize = mStyle.size;
174 // Note that GetMeasuringMode depends on mAdjustedSize
175 if ((anAAOption == gfxFont::kAntialiasDefault &&
176 UsingClearType() &&
177 GetMeasuringMode() == DWRITE_MEASURING_MODE_NATURAL) ||
178 anAAOption == gfxFont::kAntialiasSubpixel)
180 mUseSubpixelPositions = true;
181 // note that this may be reset to FALSE if we determine that a bitmap
182 // strike is going to be used
185 gfxDWriteFontEntry *fe =
186 static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
187 if (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) {
188 mAdjustedSize = NS_lround(mAdjustedSize);
189 mUseSubpixelPositions = false;
190 // if we have bitmaps, we need to tell Cairo NOT to use subpixel AA,
191 // to avoid the manual-subpixel codepath in cairo-d2d-surface.cpp
192 // which fails to render bitmap glyphs (see bug 626299).
193 // This option will be passed to the cairo_dwrite_scaled_font_t
194 // after creation.
195 mAllowManualShowGlyphs = false;
198 mMetrics = new gfxFont::Metrics;
199 ::memset(mMetrics, 0, sizeof(*mMetrics));
201 mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
203 mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
205 mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor);
206 mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor);
207 mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
209 mMetrics->emHeight = mAdjustedSize;
210 mMetrics->emAscent = mMetrics->emHeight *
211 mMetrics->maxAscent / mMetrics->maxHeight;
212 mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
214 mMetrics->maxAdvance = mAdjustedSize;
216 // try to get the true maxAdvance value from 'hhea'
217 gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
218 TRUETYPE_TAG('h','h','e','a'));
219 if (hheaTable) {
220 uint32_t len;
221 const HheaTable* hhea =
222 reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
223 if (len >= sizeof(HheaTable)) {
224 mMetrics->maxAdvance =
225 uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
229 mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
230 mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
232 UINT16 glyph = (uint16_t)GetSpaceGlyph();
233 mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
235 // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
236 // if the table is not available or if using hinted/pixel-snapped widths
237 if (mUseSubpixelPositions) {
238 mMetrics->aveCharWidth = 0;
239 gfxFontEntry::AutoTable os2Table(GetFontEntry(),
240 TRUETYPE_TAG('O','S','/','2'));
241 if (os2Table) {
242 uint32_t len;
243 const OS2Table* os2 =
244 reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
245 if (len >= 4) {
246 // Not checking against sizeof(mozilla::OS2Table) here because older
247 // versions of the table have different sizes; we only need the first
248 // two 16-bit fields here.
249 mMetrics->aveCharWidth =
250 int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
255 UINT32 ucs;
256 if (mMetrics->aveCharWidth < 1) {
257 ucs = L'x';
258 if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
259 mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
261 if (mMetrics->aveCharWidth < 1) {
262 // Let's just assume the X is square.
263 mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
267 ucs = L'0';
268 if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
269 mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph);
271 if (mMetrics->zeroOrAveCharWidth < 1) {
272 mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
275 mMetrics->underlineOffset =
276 fontMetrics.underlinePosition * mFUnitsConvFactor;
277 mMetrics->underlineSize =
278 fontMetrics.underlineThickness * mFUnitsConvFactor;
279 mMetrics->strikeoutOffset =
280 fontMetrics.strikethroughPosition * mFUnitsConvFactor;
281 mMetrics->strikeoutSize =
282 fontMetrics.strikethroughThickness * mFUnitsConvFactor;
284 SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
286 #if 0
287 printf("Font: %p (%s) size: %f\n", this,
288 NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
289 printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
290 printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
291 printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
292 printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n",
293 mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight);
294 printf(" uOff: %f uSize: %f stOff: %f stSize: %f\n",
295 mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize);
296 #endif
299 using namespace mozilla; // for AutoSwap_* types
301 struct EBLCHeader {
302 AutoSwap_PRUint32 version;
303 AutoSwap_PRUint32 numSizes;
306 struct SbitLineMetrics {
307 int8_t ascender;
308 int8_t descender;
309 uint8_t widthMax;
310 int8_t caretSlopeNumerator;
311 int8_t caretSlopeDenominator;
312 int8_t caretOffset;
313 int8_t minOriginSB;
314 int8_t minAdvanceSB;
315 int8_t maxBeforeBL;
316 int8_t minAfterBL;
317 int8_t pad1;
318 int8_t pad2;
321 struct BitmapSizeTable {
322 AutoSwap_PRUint32 indexSubTableArrayOffset;
323 AutoSwap_PRUint32 indexTablesSize;
324 AutoSwap_PRUint32 numberOfIndexSubTables;
325 AutoSwap_PRUint32 colorRef;
326 SbitLineMetrics hori;
327 SbitLineMetrics vert;
328 AutoSwap_PRUint16 startGlyphIndex;
329 AutoSwap_PRUint16 endGlyphIndex;
330 uint8_t ppemX;
331 uint8_t ppemY;
332 uint8_t bitDepth;
333 uint8_t flags;
336 typedef EBLCHeader EBSCHeader;
338 struct BitmapScaleTable {
339 SbitLineMetrics hori;
340 SbitLineMetrics vert;
341 uint8_t ppemX;
342 uint8_t ppemY;
343 uint8_t substitutePpemX;
344 uint8_t substitutePpemY;
347 bool
348 gfxDWriteFont::HasBitmapStrikeForSize(uint32_t aSize)
350 uint8_t *tableData;
351 uint32_t len;
352 void *tableContext;
353 BOOL exists;
354 HRESULT hr =
355 mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'L', 'C'),
356 (const void**)&tableData, &len,
357 &tableContext, &exists);
358 if (FAILED(hr)) {
359 return false;
362 bool hasStrike = false;
363 // not really a loop, but this lets us use 'break' to skip out of the block
364 // as soon as we know the answer, and skips it altogether if the table is
365 // not present
366 while (exists) {
367 if (len < sizeof(EBLCHeader)) {
368 break;
370 const EBLCHeader *hdr = reinterpret_cast<const EBLCHeader*>(tableData);
371 if (hdr->version != 0x00020000) {
372 break;
374 uint32_t numSizes = hdr->numSizes;
375 if (numSizes > 0xffff) { // sanity-check, prevent overflow below
376 break;
378 if (len < sizeof(EBLCHeader) + numSizes * sizeof(BitmapSizeTable)) {
379 break;
381 const BitmapSizeTable *sizeTable =
382 reinterpret_cast<const BitmapSizeTable*>(hdr + 1);
383 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
384 if (sizeTable->ppemX == aSize && sizeTable->ppemY == aSize) {
385 // we ignore a strike that contains fewer than 4 glyphs,
386 // as that probably indicates a font such as Courier New
387 // that provides bitmaps ONLY for the "shading" characters
388 // U+2591..2593
389 hasStrike = (uint16_t(sizeTable->endGlyphIndex) >=
390 uint16_t(sizeTable->startGlyphIndex) + 3);
391 break;
394 // if we reach here, we didn't find a strike; unconditionally break
395 // out of the while-loop block
396 break;
398 mFontFace->ReleaseFontTable(tableContext);
400 if (hasStrike) {
401 return true;
404 // if we didn't find a real strike, check if the font calls for scaling
405 // another bitmap to this size
406 hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'S', 'C'),
407 (const void**)&tableData, &len,
408 &tableContext, &exists);
409 if (FAILED(hr)) {
410 return false;
413 while (exists) {
414 if (len < sizeof(EBSCHeader)) {
415 break;
417 const EBSCHeader *hdr = reinterpret_cast<const EBSCHeader*>(tableData);
418 if (hdr->version != 0x00020000) {
419 break;
421 uint32_t numSizes = hdr->numSizes;
422 if (numSizes > 0xffff) {
423 break;
425 if (len < sizeof(EBSCHeader) + numSizes * sizeof(BitmapScaleTable)) {
426 break;
428 const BitmapScaleTable *scaleTable =
429 reinterpret_cast<const BitmapScaleTable*>(hdr + 1);
430 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
431 if (scaleTable->ppemX == aSize && scaleTable->ppemY == aSize) {
432 hasStrike = true;
433 break;
436 break;
438 mFontFace->ReleaseFontTable(tableContext);
440 return hasStrike;
443 uint32_t
444 gfxDWriteFont::GetSpaceGlyph()
446 UINT32 ucs = L' ';
447 UINT16 glyph;
448 HRESULT hr;
449 hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph);
450 if (FAILED(hr)) {
451 return 0;
453 return glyph;
456 bool
457 gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
459 cairo_scaled_font_t *scaledFont = GetCairoScaledFont();
460 if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
461 // Don't cairo_set_scaled_font as that would propagate the error to
462 // the cairo_t, precluding any further drawing.
463 return false;
465 cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
466 return true;
469 bool
470 gfxDWriteFont::IsValid()
472 return mFontFace != nullptr;
475 IDWriteFontFace*
476 gfxDWriteFont::GetFontFace()
478 return mFontFace.get();
481 cairo_font_face_t *
482 gfxDWriteFont::CairoFontFace()
484 if (!mCairoFontFace) {
485 #ifdef CAIRO_HAS_DWRITE_FONT
486 mCairoFontFace =
487 cairo_dwrite_font_face_create_for_dwrite_fontface(
488 ((gfxDWriteFontEntry*)mFontEntry.get())->mFont, mFontFace);
489 #endif
491 return mCairoFontFace;
495 cairo_scaled_font_t *
496 gfxDWriteFont::GetCairoScaledFont()
498 if (!mScaledFont) {
499 cairo_matrix_t sizeMatrix;
500 cairo_matrix_t identityMatrix;
502 cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
503 cairo_matrix_init_identity(&identityMatrix);
505 cairo_font_options_t *fontOptions = cairo_font_options_create();
506 if (mNeedsOblique) {
507 double skewfactor = OBLIQUE_SKEW_FACTOR;
509 cairo_matrix_t style;
510 cairo_matrix_init(&style,
511 1, //xx
512 0, //yx
513 -1 * skewfactor, //xy
514 1, //yy
515 0, //x0
516 0); //y0
517 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
520 if (mAntialiasOption != kAntialiasDefault) {
521 cairo_font_options_set_antialias(fontOptions,
522 GetCairoAntialiasOption(mAntialiasOption));
525 mScaledFont = cairo_scaled_font_create(CairoFontFace(),
526 &sizeMatrix,
527 &identityMatrix,
528 fontOptions);
529 cairo_font_options_destroy(fontOptions);
531 cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont,
532 mAllowManualShowGlyphs);
534 gfxDWriteFontEntry *fe =
535 static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
536 cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont,
537 GetForceGDIClassic());
540 NS_ASSERTION(mAdjustedSize == 0.0 ||
541 cairo_scaled_font_status(mScaledFont)
542 == CAIRO_STATUS_SUCCESS,
543 "Failed to make scaled font");
545 return mScaledFont;
548 gfxFont::RunMetrics
549 gfxDWriteFont::Measure(gfxTextRun *aTextRun,
550 uint32_t aStart, uint32_t aEnd,
551 BoundingBoxType aBoundingBoxType,
552 gfxContext *aRefContext,
553 Spacing *aSpacing)
555 gfxFont::RunMetrics metrics =
556 gfxFont::Measure(aTextRun, aStart, aEnd,
557 aBoundingBoxType, aRefContext, aSpacing);
559 // if aBoundingBoxType is LOOSE_INK_EXTENTS
560 // and the underlying cairo font may be antialiased,
561 // we can't trust Windows to have considered all the pixels
562 // so we need to add "padding" to the bounds.
563 // (see bugs 475968, 439831, compare also bug 445087)
564 if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
565 mAntialiasOption != kAntialiasNone &&
566 GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_CLASSIC &&
567 metrics.mBoundingBox.width > 0) {
568 metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
569 metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
572 return metrics;
575 bool
576 gfxDWriteFont::ProvidesGlyphWidths() const
578 return !mUseSubpixelPositions ||
579 (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
582 int32_t
583 gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
585 if (!mGlyphWidths) {
586 mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(128);
589 int32_t width = -1;
590 if (mGlyphWidths->Get(aGID, &width)) {
591 return width;
594 width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0);
595 mGlyphWidths->Put(aGID, width);
596 return width;
599 TemporaryRef<GlyphRenderingOptions>
600 gfxDWriteFont::GetGlyphRenderingOptions()
602 if (UsingClearType()) {
603 return Factory::CreateDWriteGlyphRenderingOptions(
604 gfxWindowsPlatform::GetPlatform()->GetRenderingParams(GetForceGDIClassic() ?
605 gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : gfxWindowsPlatform::TEXT_RENDERING_NORMAL));
606 } else {
607 return Factory::CreateDWriteGlyphRenderingOptions(gfxWindowsPlatform::GetPlatform()->
608 GetRenderingParams(gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE));
612 bool
613 gfxDWriteFont::GetForceGDIClassic()
615 return static_cast<gfxDWriteFontEntry*>(mFontEntry.get())->GetForceGDIClassic() &&
616 cairo_dwrite_get_cleartype_rendering_mode() < 0 &&
617 GetAdjustedSize() <=
618 gfxDWriteFontList::PlatformFontList()->GetForceGDIClassicMaxFontSize();
621 DWRITE_MEASURING_MODE
622 gfxDWriteFont::GetMeasuringMode()
624 return GetForceGDIClassic()
625 ? DWRITE_MEASURING_MODE_GDI_CLASSIC
626 : gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode();
629 gfxFloat
630 gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph)
632 DWRITE_GLYPH_METRICS metrics;
633 HRESULT hr;
634 if (mUseSubpixelPositions) {
635 hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE);
636 if (SUCCEEDED(hr)) {
637 return metrics.advanceWidth * mFUnitsConvFactor;
639 } else {
640 hr = mFontFace->GetGdiCompatibleGlyphMetrics(
641 FLOAT(mAdjustedSize), 1.0f, nullptr,
642 GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL,
643 &aGlyph, 1, &metrics, FALSE);
644 if (SUCCEEDED(hr)) {
645 return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
648 return 0;
651 void
652 gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
653 FontCacheSizes* aSizes) const
655 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
656 aSizes->mFontInstances += aMallocSizeOf(mMetrics);
657 if (mGlyphWidths) {
658 aSizes->mFontInstances +=
659 mGlyphWidths->SizeOfIncludingThis(nullptr, aMallocSizeOf);
663 void
664 gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
665 FontCacheSizes* aSizes) const
667 aSizes->mFontInstances += aMallocSizeOf(this);
668 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
671 TemporaryRef<ScaledFont>
672 gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
674 bool wantCairo = aTarget->GetBackendType() == BackendType::CAIRO;
675 if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) {
676 return mAzureScaledFont;
679 NativeFont nativeFont;
680 nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
681 nativeFont.mFont = GetFontFace();
683 if (wantCairo) {
684 mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont,
685 GetAdjustedSize(),
686 GetCairoScaledFont());
687 } else {
688 mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont,
689 GetAdjustedSize());
692 mAzureScaledFontIsCairo = wantCairo;
694 return mAzureScaledFont;