1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxDWriteFonts.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,717 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "gfxDWriteFonts.h" 1.10 + 1.11 +#include "mozilla/MemoryReporting.h" 1.12 + 1.13 +#include "gfxDWriteShaper.h" 1.14 +#include "gfxHarfBuzzShaper.h" 1.15 +#include <algorithm> 1.16 +#include "gfxGraphiteShaper.h" 1.17 +#include "gfxDWriteFontList.h" 1.18 +#include "gfxContext.h" 1.19 +#include <dwrite.h> 1.20 + 1.21 +#include "gfxDWriteTextAnalysis.h" 1.22 + 1.23 +#include "harfbuzz/hb.h" 1.24 + 1.25 +// Chosen this as to resemble DWrite's own oblique face style. 1.26 +#define OBLIQUE_SKEW_FACTOR 0.3 1.27 + 1.28 +using namespace mozilla; 1.29 +using namespace mozilla::gfx; 1.30 + 1.31 +// This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common, 1.32 +// but we can't declare it in the gfxFont.h or gfxFontUtils.h headers 1.33 +// because those are exported, and the cairo headers aren't. 1.34 +static inline cairo_antialias_t 1.35 +GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption) 1.36 +{ 1.37 + switch (anAntialiasOption) { 1.38 + default: 1.39 + case gfxFont::kAntialiasDefault: 1.40 + return CAIRO_ANTIALIAS_DEFAULT; 1.41 + case gfxFont::kAntialiasNone: 1.42 + return CAIRO_ANTIALIAS_NONE; 1.43 + case gfxFont::kAntialiasGrayscale: 1.44 + return CAIRO_ANTIALIAS_GRAY; 1.45 + case gfxFont::kAntialiasSubpixel: 1.46 + return CAIRO_ANTIALIAS_SUBPIXEL; 1.47 + } 1.48 +} 1.49 + 1.50 +// Code to determine whether Windows is set to use ClearType font smoothing; 1.51 +// based on private functions in cairo-win32-font.c 1.52 + 1.53 +#ifndef SPI_GETFONTSMOOTHINGTYPE 1.54 +#define SPI_GETFONTSMOOTHINGTYPE 0x200a 1.55 +#endif 1.56 +#ifndef FE_FONTSMOOTHINGCLEARTYPE 1.57 +#define FE_FONTSMOOTHINGCLEARTYPE 2 1.58 +#endif 1.59 + 1.60 +static bool 1.61 +UsingClearType() 1.62 +{ 1.63 + BOOL fontSmoothing; 1.64 + if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0) || 1.65 + !fontSmoothing) 1.66 + { 1.67 + return false; 1.68 + } 1.69 + 1.70 + UINT type; 1.71 + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0) && 1.72 + type == FE_FONTSMOOTHINGCLEARTYPE) 1.73 + { 1.74 + return true; 1.75 + } 1.76 + return false; 1.77 +} 1.78 + 1.79 +//////////////////////////////////////////////////////////////////////////////// 1.80 +// gfxDWriteFont 1.81 +gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry, 1.82 + const gfxFontStyle *aFontStyle, 1.83 + bool aNeedsBold, 1.84 + AntialiasOption anAAOption) 1.85 + : gfxFont(aFontEntry, aFontStyle, anAAOption) 1.86 + , mCairoFontFace(nullptr) 1.87 + , mMetrics(nullptr) 1.88 + , mNeedsOblique(false) 1.89 + , mNeedsBold(aNeedsBold) 1.90 + , mUseSubpixelPositions(false) 1.91 + , mAllowManualShowGlyphs(true) 1.92 +{ 1.93 + gfxDWriteFontEntry *fe = 1.94 + static_cast<gfxDWriteFontEntry*>(aFontEntry); 1.95 + nsresult rv; 1.96 + DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE; 1.97 + if ((GetStyle()->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && 1.98 + !fe->IsItalic()) { 1.99 + // For this we always use the font_matrix for uniformity. Not the 1.100 + // DWrite simulation. 1.101 + mNeedsOblique = true; 1.102 + } 1.103 + if (aNeedsBold) { 1.104 + sims |= DWRITE_FONT_SIMULATIONS_BOLD; 1.105 + } 1.106 + 1.107 + rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims); 1.108 + 1.109 + if (NS_FAILED(rv)) { 1.110 + mIsValid = false; 1.111 + return; 1.112 + } 1.113 + 1.114 + ComputeMetrics(anAAOption); 1.115 + 1.116 + if (FontCanSupportGraphite()) { 1.117 + mGraphiteShaper = new gfxGraphiteShaper(this); 1.118 + } 1.119 + 1.120 + if (FontCanSupportHarfBuzz()) { 1.121 + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); 1.122 + } 1.123 +} 1.124 + 1.125 +gfxDWriteFont::~gfxDWriteFont() 1.126 +{ 1.127 + if (mCairoFontFace) { 1.128 + cairo_font_face_destroy(mCairoFontFace); 1.129 + } 1.130 + if (mScaledFont) { 1.131 + cairo_scaled_font_destroy(mScaledFont); 1.132 + } 1.133 + delete mMetrics; 1.134 +} 1.135 + 1.136 +gfxFont* 1.137 +gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption) 1.138 +{ 1.139 + return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()), 1.140 + &mStyle, mNeedsBold, anAAOption); 1.141 +} 1.142 + 1.143 +void 1.144 +gfxDWriteFont::CreatePlatformShaper() 1.145 +{ 1.146 + mPlatformShaper = new gfxDWriteShaper(this); 1.147 +} 1.148 + 1.149 +const gfxFont::Metrics& 1.150 +gfxDWriteFont::GetMetrics() 1.151 +{ 1.152 + return *mMetrics; 1.153 +} 1.154 + 1.155 +bool 1.156 +gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics) 1.157 +{ 1.158 + gfxFontStyle style(mStyle); 1.159 + style.weight = 700; 1.160 + bool needsBold; 1.161 + 1.162 + gfxFontEntry* fe = 1.163 + gfxPlatformFontList::PlatformFontList()-> 1.164 + FindFontForFamily(NS_LITERAL_STRING("Arial"), &style, needsBold); 1.165 + if (!fe || fe == mFontEntry) { 1.166 + return false; 1.167 + } 1.168 + 1.169 + nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&style, needsBold); 1.170 + gfxDWriteFont *dwFont = static_cast<gfxDWriteFont*>(font.get()); 1.171 + dwFont->mFontFace->GetMetrics(aFontMetrics); 1.172 + 1.173 + return true; 1.174 +} 1.175 + 1.176 +void 1.177 +gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) 1.178 +{ 1.179 + DWRITE_FONT_METRICS fontMetrics; 1.180 + if (!(mFontEntry->Weight() == 900 && 1.181 + !mFontEntry->IsUserFont() && 1.182 + mFontEntry->Name().EqualsLiteral("Arial Black") && 1.183 + GetFakeMetricsForArialBlack(&fontMetrics))) 1.184 + { 1.185 + mFontFace->GetMetrics(&fontMetrics); 1.186 + } 1.187 + 1.188 + if (mStyle.sizeAdjust != 0.0) { 1.189 + gfxFloat aspect = (gfxFloat)fontMetrics.xHeight / 1.190 + fontMetrics.designUnitsPerEm; 1.191 + mAdjustedSize = mStyle.GetAdjustedSize(aspect); 1.192 + } else { 1.193 + mAdjustedSize = mStyle.size; 1.194 + } 1.195 + 1.196 + // Note that GetMeasuringMode depends on mAdjustedSize 1.197 + if ((anAAOption == gfxFont::kAntialiasDefault && 1.198 + UsingClearType() && 1.199 + GetMeasuringMode() == DWRITE_MEASURING_MODE_NATURAL) || 1.200 + anAAOption == gfxFont::kAntialiasSubpixel) 1.201 + { 1.202 + mUseSubpixelPositions = true; 1.203 + // note that this may be reset to FALSE if we determine that a bitmap 1.204 + // strike is going to be used 1.205 + } 1.206 + 1.207 + gfxDWriteFontEntry *fe = 1.208 + static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); 1.209 + if (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) { 1.210 + mAdjustedSize = NS_lround(mAdjustedSize); 1.211 + mUseSubpixelPositions = false; 1.212 + // if we have bitmaps, we need to tell Cairo NOT to use subpixel AA, 1.213 + // to avoid the manual-subpixel codepath in cairo-d2d-surface.cpp 1.214 + // which fails to render bitmap glyphs (see bug 626299). 1.215 + // This option will be passed to the cairo_dwrite_scaled_font_t 1.216 + // after creation. 1.217 + mAllowManualShowGlyphs = false; 1.218 + } 1.219 + 1.220 + mMetrics = new gfxFont::Metrics; 1.221 + ::memset(mMetrics, 0, sizeof(*mMetrics)); 1.222 + 1.223 + mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm); 1.224 + 1.225 + mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor; 1.226 + 1.227 + mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor); 1.228 + mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor); 1.229 + mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent; 1.230 + 1.231 + mMetrics->emHeight = mAdjustedSize; 1.232 + mMetrics->emAscent = mMetrics->emHeight * 1.233 + mMetrics->maxAscent / mMetrics->maxHeight; 1.234 + mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; 1.235 + 1.236 + mMetrics->maxAdvance = mAdjustedSize; 1.237 + 1.238 + // try to get the true maxAdvance value from 'hhea' 1.239 + gfxFontEntry::AutoTable hheaTable(GetFontEntry(), 1.240 + TRUETYPE_TAG('h','h','e','a')); 1.241 + if (hheaTable) { 1.242 + uint32_t len; 1.243 + const HheaTable* hhea = 1.244 + reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len)); 1.245 + if (len >= sizeof(HheaTable)) { 1.246 + mMetrics->maxAdvance = 1.247 + uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor; 1.248 + } 1.249 + } 1.250 + 1.251 + mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0); 1.252 + mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor); 1.253 + 1.254 + UINT16 glyph = (uint16_t)GetSpaceGlyph(); 1.255 + mMetrics->spaceWidth = MeasureGlyphWidth(glyph); 1.256 + 1.257 + // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x' 1.258 + // if the table is not available or if using hinted/pixel-snapped widths 1.259 + if (mUseSubpixelPositions) { 1.260 + mMetrics->aveCharWidth = 0; 1.261 + gfxFontEntry::AutoTable os2Table(GetFontEntry(), 1.262 + TRUETYPE_TAG('O','S','/','2')); 1.263 + if (os2Table) { 1.264 + uint32_t len; 1.265 + const OS2Table* os2 = 1.266 + reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len)); 1.267 + if (len >= 4) { 1.268 + // Not checking against sizeof(mozilla::OS2Table) here because older 1.269 + // versions of the table have different sizes; we only need the first 1.270 + // two 16-bit fields here. 1.271 + mMetrics->aveCharWidth = 1.272 + int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor; 1.273 + } 1.274 + } 1.275 + } 1.276 + 1.277 + UINT32 ucs; 1.278 + if (mMetrics->aveCharWidth < 1) { 1.279 + ucs = L'x'; 1.280 + if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) { 1.281 + mMetrics->aveCharWidth = MeasureGlyphWidth(glyph); 1.282 + } 1.283 + if (mMetrics->aveCharWidth < 1) { 1.284 + // Let's just assume the X is square. 1.285 + mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor; 1.286 + } 1.287 + } 1.288 + 1.289 + ucs = L'0'; 1.290 + if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) { 1.291 + mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph); 1.292 + } 1.293 + if (mMetrics->zeroOrAveCharWidth < 1) { 1.294 + mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; 1.295 + } 1.296 + 1.297 + mMetrics->underlineOffset = 1.298 + fontMetrics.underlinePosition * mFUnitsConvFactor; 1.299 + mMetrics->underlineSize = 1.300 + fontMetrics.underlineThickness * mFUnitsConvFactor; 1.301 + mMetrics->strikeoutOffset = 1.302 + fontMetrics.strikethroughPosition * mFUnitsConvFactor; 1.303 + mMetrics->strikeoutSize = 1.304 + fontMetrics.strikethroughThickness * mFUnitsConvFactor; 1.305 + mMetrics->superscriptOffset = 0; 1.306 + mMetrics->subscriptOffset = 0; 1.307 + 1.308 + SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); 1.309 + 1.310 +#if 0 1.311 + printf("Font: %p (%s) size: %f\n", this, 1.312 + NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); 1.313 + printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); 1.314 + printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); 1.315 + printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); 1.316 + printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n", 1.317 + mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight); 1.318 + printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", 1.319 + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, 1.320 + mMetrics->superscriptOffset, mMetrics->subscriptOffset); 1.321 +#endif 1.322 +} 1.323 + 1.324 +using namespace mozilla; // for AutoSwap_* types 1.325 + 1.326 +struct EBLCHeader { 1.327 + AutoSwap_PRUint32 version; 1.328 + AutoSwap_PRUint32 numSizes; 1.329 +}; 1.330 + 1.331 +struct SbitLineMetrics { 1.332 + int8_t ascender; 1.333 + int8_t descender; 1.334 + uint8_t widthMax; 1.335 + int8_t caretSlopeNumerator; 1.336 + int8_t caretSlopeDenominator; 1.337 + int8_t caretOffset; 1.338 + int8_t minOriginSB; 1.339 + int8_t minAdvanceSB; 1.340 + int8_t maxBeforeBL; 1.341 + int8_t minAfterBL; 1.342 + int8_t pad1; 1.343 + int8_t pad2; 1.344 +}; 1.345 + 1.346 +struct BitmapSizeTable { 1.347 + AutoSwap_PRUint32 indexSubTableArrayOffset; 1.348 + AutoSwap_PRUint32 indexTablesSize; 1.349 + AutoSwap_PRUint32 numberOfIndexSubTables; 1.350 + AutoSwap_PRUint32 colorRef; 1.351 + SbitLineMetrics hori; 1.352 + SbitLineMetrics vert; 1.353 + AutoSwap_PRUint16 startGlyphIndex; 1.354 + AutoSwap_PRUint16 endGlyphIndex; 1.355 + uint8_t ppemX; 1.356 + uint8_t ppemY; 1.357 + uint8_t bitDepth; 1.358 + uint8_t flags; 1.359 +}; 1.360 + 1.361 +typedef EBLCHeader EBSCHeader; 1.362 + 1.363 +struct BitmapScaleTable { 1.364 + SbitLineMetrics hori; 1.365 + SbitLineMetrics vert; 1.366 + uint8_t ppemX; 1.367 + uint8_t ppemY; 1.368 + uint8_t substitutePpemX; 1.369 + uint8_t substitutePpemY; 1.370 +}; 1.371 + 1.372 +bool 1.373 +gfxDWriteFont::HasBitmapStrikeForSize(uint32_t aSize) 1.374 +{ 1.375 + uint8_t *tableData; 1.376 + uint32_t len; 1.377 + void *tableContext; 1.378 + BOOL exists; 1.379 + HRESULT hr = 1.380 + mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'L', 'C'), 1.381 + (const void**)&tableData, &len, 1.382 + &tableContext, &exists); 1.383 + if (FAILED(hr)) { 1.384 + return false; 1.385 + } 1.386 + 1.387 + bool hasStrike = false; 1.388 + // not really a loop, but this lets us use 'break' to skip out of the block 1.389 + // as soon as we know the answer, and skips it altogether if the table is 1.390 + // not present 1.391 + while (exists) { 1.392 + if (len < sizeof(EBLCHeader)) { 1.393 + break; 1.394 + } 1.395 + const EBLCHeader *hdr = reinterpret_cast<const EBLCHeader*>(tableData); 1.396 + if (hdr->version != 0x00020000) { 1.397 + break; 1.398 + } 1.399 + uint32_t numSizes = hdr->numSizes; 1.400 + if (numSizes > 0xffff) { // sanity-check, prevent overflow below 1.401 + break; 1.402 + } 1.403 + if (len < sizeof(EBLCHeader) + numSizes * sizeof(BitmapSizeTable)) { 1.404 + break; 1.405 + } 1.406 + const BitmapSizeTable *sizeTable = 1.407 + reinterpret_cast<const BitmapSizeTable*>(hdr + 1); 1.408 + for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { 1.409 + if (sizeTable->ppemX == aSize && sizeTable->ppemY == aSize) { 1.410 + // we ignore a strike that contains fewer than 4 glyphs, 1.411 + // as that probably indicates a font such as Courier New 1.412 + // that provides bitmaps ONLY for the "shading" characters 1.413 + // U+2591..2593 1.414 + hasStrike = (uint16_t(sizeTable->endGlyphIndex) >= 1.415 + uint16_t(sizeTable->startGlyphIndex) + 3); 1.416 + break; 1.417 + } 1.418 + } 1.419 + // if we reach here, we didn't find a strike; unconditionally break 1.420 + // out of the while-loop block 1.421 + break; 1.422 + } 1.423 + mFontFace->ReleaseFontTable(tableContext); 1.424 + 1.425 + if (hasStrike) { 1.426 + return true; 1.427 + } 1.428 + 1.429 + // if we didn't find a real strike, check if the font calls for scaling 1.430 + // another bitmap to this size 1.431 + hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'S', 'C'), 1.432 + (const void**)&tableData, &len, 1.433 + &tableContext, &exists); 1.434 + if (FAILED(hr)) { 1.435 + return false; 1.436 + } 1.437 + 1.438 + while (exists) { 1.439 + if (len < sizeof(EBSCHeader)) { 1.440 + break; 1.441 + } 1.442 + const EBSCHeader *hdr = reinterpret_cast<const EBSCHeader*>(tableData); 1.443 + if (hdr->version != 0x00020000) { 1.444 + break; 1.445 + } 1.446 + uint32_t numSizes = hdr->numSizes; 1.447 + if (numSizes > 0xffff) { 1.448 + break; 1.449 + } 1.450 + if (len < sizeof(EBSCHeader) + numSizes * sizeof(BitmapScaleTable)) { 1.451 + break; 1.452 + } 1.453 + const BitmapScaleTable *scaleTable = 1.454 + reinterpret_cast<const BitmapScaleTable*>(hdr + 1); 1.455 + for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { 1.456 + if (scaleTable->ppemX == aSize && scaleTable->ppemY == aSize) { 1.457 + hasStrike = true; 1.458 + break; 1.459 + } 1.460 + } 1.461 + break; 1.462 + } 1.463 + mFontFace->ReleaseFontTable(tableContext); 1.464 + 1.465 + return hasStrike; 1.466 +} 1.467 + 1.468 +uint32_t 1.469 +gfxDWriteFont::GetSpaceGlyph() 1.470 +{ 1.471 + UINT32 ucs = L' '; 1.472 + UINT16 glyph; 1.473 + HRESULT hr; 1.474 + hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph); 1.475 + if (FAILED(hr)) { 1.476 + return 0; 1.477 + } 1.478 + return glyph; 1.479 +} 1.480 + 1.481 +bool 1.482 +gfxDWriteFont::SetupCairoFont(gfxContext *aContext) 1.483 +{ 1.484 + cairo_scaled_font_t *scaledFont = GetCairoScaledFont(); 1.485 + if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) { 1.486 + // Don't cairo_set_scaled_font as that would propagate the error to 1.487 + // the cairo_t, precluding any further drawing. 1.488 + return false; 1.489 + } 1.490 + cairo_set_scaled_font(aContext->GetCairo(), scaledFont); 1.491 + return true; 1.492 +} 1.493 + 1.494 +bool 1.495 +gfxDWriteFont::IsValid() 1.496 +{ 1.497 + return mFontFace != nullptr; 1.498 +} 1.499 + 1.500 +IDWriteFontFace* 1.501 +gfxDWriteFont::GetFontFace() 1.502 +{ 1.503 + return mFontFace.get(); 1.504 +} 1.505 + 1.506 +cairo_font_face_t * 1.507 +gfxDWriteFont::CairoFontFace() 1.508 +{ 1.509 + if (!mCairoFontFace) { 1.510 +#ifdef CAIRO_HAS_DWRITE_FONT 1.511 + mCairoFontFace = 1.512 + cairo_dwrite_font_face_create_for_dwrite_fontface( 1.513 + ((gfxDWriteFontEntry*)mFontEntry.get())->mFont, mFontFace); 1.514 +#endif 1.515 + } 1.516 + return mCairoFontFace; 1.517 +} 1.518 + 1.519 + 1.520 +cairo_scaled_font_t * 1.521 +gfxDWriteFont::GetCairoScaledFont() 1.522 +{ 1.523 + if (!mScaledFont) { 1.524 + cairo_matrix_t sizeMatrix; 1.525 + cairo_matrix_t identityMatrix; 1.526 + 1.527 + cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); 1.528 + cairo_matrix_init_identity(&identityMatrix); 1.529 + 1.530 + cairo_font_options_t *fontOptions = cairo_font_options_create(); 1.531 + if (mNeedsOblique) { 1.532 + double skewfactor = OBLIQUE_SKEW_FACTOR; 1.533 + 1.534 + cairo_matrix_t style; 1.535 + cairo_matrix_init(&style, 1.536 + 1, //xx 1.537 + 0, //yx 1.538 + -1 * skewfactor, //xy 1.539 + 1, //yy 1.540 + 0, //x0 1.541 + 0); //y0 1.542 + cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); 1.543 + } 1.544 + 1.545 + if (mAntialiasOption != kAntialiasDefault) { 1.546 + cairo_font_options_set_antialias(fontOptions, 1.547 + GetCairoAntialiasOption(mAntialiasOption)); 1.548 + } 1.549 + 1.550 + mScaledFont = cairo_scaled_font_create(CairoFontFace(), 1.551 + &sizeMatrix, 1.552 + &identityMatrix, 1.553 + fontOptions); 1.554 + cairo_font_options_destroy(fontOptions); 1.555 + 1.556 + cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont, 1.557 + mAllowManualShowGlyphs); 1.558 + 1.559 + gfxDWriteFontEntry *fe = 1.560 + static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); 1.561 + cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont, 1.562 + GetForceGDIClassic()); 1.563 + } 1.564 + 1.565 + NS_ASSERTION(mAdjustedSize == 0.0 || 1.566 + cairo_scaled_font_status(mScaledFont) 1.567 + == CAIRO_STATUS_SUCCESS, 1.568 + "Failed to make scaled font"); 1.569 + 1.570 + return mScaledFont; 1.571 +} 1.572 + 1.573 +gfxFont::RunMetrics 1.574 +gfxDWriteFont::Measure(gfxTextRun *aTextRun, 1.575 + uint32_t aStart, uint32_t aEnd, 1.576 + BoundingBoxType aBoundingBoxType, 1.577 + gfxContext *aRefContext, 1.578 + Spacing *aSpacing) 1.579 +{ 1.580 + gfxFont::RunMetrics metrics = 1.581 + gfxFont::Measure(aTextRun, aStart, aEnd, 1.582 + aBoundingBoxType, aRefContext, aSpacing); 1.583 + 1.584 + // if aBoundingBoxType is LOOSE_INK_EXTENTS 1.585 + // and the underlying cairo font may be antialiased, 1.586 + // we can't trust Windows to have considered all the pixels 1.587 + // so we need to add "padding" to the bounds. 1.588 + // (see bugs 475968, 439831, compare also bug 445087) 1.589 + if (aBoundingBoxType == LOOSE_INK_EXTENTS && 1.590 + mAntialiasOption != kAntialiasNone && 1.591 + GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_CLASSIC && 1.592 + metrics.mBoundingBox.width > 0) { 1.593 + metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); 1.594 + metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3; 1.595 + } 1.596 + 1.597 + return metrics; 1.598 +} 1.599 + 1.600 +bool 1.601 +gfxDWriteFont::ProvidesGlyphWidths() 1.602 +{ 1.603 + return !mUseSubpixelPositions || 1.604 + (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD); 1.605 +} 1.606 + 1.607 +int32_t 1.608 +gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) 1.609 +{ 1.610 + if (!mGlyphWidths) { 1.611 + mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200); 1.612 + } 1.613 + 1.614 + int32_t width = -1; 1.615 + if (mGlyphWidths->Get(aGID, &width)) { 1.616 + return width; 1.617 + } 1.618 + 1.619 + width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0); 1.620 + mGlyphWidths->Put(aGID, width); 1.621 + return width; 1.622 +} 1.623 + 1.624 +TemporaryRef<GlyphRenderingOptions> 1.625 +gfxDWriteFont::GetGlyphRenderingOptions() 1.626 +{ 1.627 + if (UsingClearType()) { 1.628 + return Factory::CreateDWriteGlyphRenderingOptions( 1.629 + gfxWindowsPlatform::GetPlatform()->GetRenderingParams(GetForceGDIClassic() ? 1.630 + gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : gfxWindowsPlatform::TEXT_RENDERING_NORMAL)); 1.631 + } else { 1.632 + return Factory::CreateDWriteGlyphRenderingOptions(gfxWindowsPlatform::GetPlatform()-> 1.633 + GetRenderingParams(gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE)); 1.634 + } 1.635 +} 1.636 + 1.637 +bool 1.638 +gfxDWriteFont::GetForceGDIClassic() 1.639 +{ 1.640 + return static_cast<gfxDWriteFontEntry*>(mFontEntry.get())->GetForceGDIClassic() && 1.641 + cairo_dwrite_get_cleartype_rendering_mode() < 0 && 1.642 + GetAdjustedSize() <= 1.643 + gfxDWriteFontList::PlatformFontList()->GetForceGDIClassicMaxFontSize(); 1.644 +} 1.645 + 1.646 +DWRITE_MEASURING_MODE 1.647 +gfxDWriteFont::GetMeasuringMode() 1.648 +{ 1.649 + return GetForceGDIClassic() 1.650 + ? DWRITE_MEASURING_MODE_GDI_CLASSIC 1.651 + : gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode(); 1.652 +} 1.653 + 1.654 +gfxFloat 1.655 +gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph) 1.656 +{ 1.657 + DWRITE_GLYPH_METRICS metrics; 1.658 + HRESULT hr; 1.659 + if (mUseSubpixelPositions) { 1.660 + hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE); 1.661 + if (SUCCEEDED(hr)) { 1.662 + return metrics.advanceWidth * mFUnitsConvFactor; 1.663 + } 1.664 + } else { 1.665 + hr = mFontFace->GetGdiCompatibleGlyphMetrics( 1.666 + FLOAT(mAdjustedSize), 1.0f, nullptr, 1.667 + GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL, 1.668 + &aGlyph, 1, &metrics, FALSE); 1.669 + if (SUCCEEDED(hr)) { 1.670 + return NS_lround(metrics.advanceWidth * mFUnitsConvFactor); 1.671 + } 1.672 + } 1.673 + return 0; 1.674 +} 1.675 + 1.676 +void 1.677 +gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, 1.678 + FontCacheSizes* aSizes) const 1.679 +{ 1.680 + gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.681 + aSizes->mFontInstances += aMallocSizeOf(mMetrics); 1.682 + if (mGlyphWidths) { 1.683 + aSizes->mFontInstances += 1.684 + mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf); 1.685 + } 1.686 +} 1.687 + 1.688 +void 1.689 +gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, 1.690 + FontCacheSizes* aSizes) const 1.691 +{ 1.692 + aSizes->mFontInstances += aMallocSizeOf(this); 1.693 + AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.694 +} 1.695 + 1.696 +TemporaryRef<ScaledFont> 1.697 +gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget) 1.698 +{ 1.699 + bool wantCairo = aTarget->GetType() == BackendType::CAIRO; 1.700 + if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) { 1.701 + return mAzureScaledFont; 1.702 + } 1.703 + 1.704 + NativeFont nativeFont; 1.705 + nativeFont.mType = NativeFontType::DWRITE_FONT_FACE; 1.706 + nativeFont.mFont = GetFontFace(); 1.707 + 1.708 + if (wantCairo) { 1.709 + mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont, 1.710 + GetAdjustedSize(), 1.711 + GetCairoScaledFont()); 1.712 + } else { 1.713 + mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont, 1.714 + GetAdjustedSize()); 1.715 + } 1.716 + 1.717 + mAzureScaledFontIsCairo = wantCairo; 1.718 + 1.719 + return mAzureScaledFont; 1.720 +}