gfx/thebes/gfxDWriteFonts.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "gfxDWriteFonts.h"
michael@0 7
michael@0 8 #include "mozilla/MemoryReporting.h"
michael@0 9
michael@0 10 #include "gfxDWriteShaper.h"
michael@0 11 #include "gfxHarfBuzzShaper.h"
michael@0 12 #include <algorithm>
michael@0 13 #include "gfxGraphiteShaper.h"
michael@0 14 #include "gfxDWriteFontList.h"
michael@0 15 #include "gfxContext.h"
michael@0 16 #include <dwrite.h>
michael@0 17
michael@0 18 #include "gfxDWriteTextAnalysis.h"
michael@0 19
michael@0 20 #include "harfbuzz/hb.h"
michael@0 21
michael@0 22 // Chosen this as to resemble DWrite's own oblique face style.
michael@0 23 #define OBLIQUE_SKEW_FACTOR 0.3
michael@0 24
michael@0 25 using namespace mozilla;
michael@0 26 using namespace mozilla::gfx;
michael@0 27
michael@0 28 // This is also in gfxGDIFont.cpp. Would be nice to put it somewhere common,
michael@0 29 // but we can't declare it in the gfxFont.h or gfxFontUtils.h headers
michael@0 30 // because those are exported, and the cairo headers aren't.
michael@0 31 static inline cairo_antialias_t
michael@0 32 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
michael@0 33 {
michael@0 34 switch (anAntialiasOption) {
michael@0 35 default:
michael@0 36 case gfxFont::kAntialiasDefault:
michael@0 37 return CAIRO_ANTIALIAS_DEFAULT;
michael@0 38 case gfxFont::kAntialiasNone:
michael@0 39 return CAIRO_ANTIALIAS_NONE;
michael@0 40 case gfxFont::kAntialiasGrayscale:
michael@0 41 return CAIRO_ANTIALIAS_GRAY;
michael@0 42 case gfxFont::kAntialiasSubpixel:
michael@0 43 return CAIRO_ANTIALIAS_SUBPIXEL;
michael@0 44 }
michael@0 45 }
michael@0 46
michael@0 47 // Code to determine whether Windows is set to use ClearType font smoothing;
michael@0 48 // based on private functions in cairo-win32-font.c
michael@0 49
michael@0 50 #ifndef SPI_GETFONTSMOOTHINGTYPE
michael@0 51 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
michael@0 52 #endif
michael@0 53 #ifndef FE_FONTSMOOTHINGCLEARTYPE
michael@0 54 #define FE_FONTSMOOTHINGCLEARTYPE 2
michael@0 55 #endif
michael@0 56
michael@0 57 static bool
michael@0 58 UsingClearType()
michael@0 59 {
michael@0 60 BOOL fontSmoothing;
michael@0 61 if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0) ||
michael@0 62 !fontSmoothing)
michael@0 63 {
michael@0 64 return false;
michael@0 65 }
michael@0 66
michael@0 67 UINT type;
michael@0 68 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &type, 0) &&
michael@0 69 type == FE_FONTSMOOTHINGCLEARTYPE)
michael@0 70 {
michael@0 71 return true;
michael@0 72 }
michael@0 73 return false;
michael@0 74 }
michael@0 75
michael@0 76 ////////////////////////////////////////////////////////////////////////////////
michael@0 77 // gfxDWriteFont
michael@0 78 gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
michael@0 79 const gfxFontStyle *aFontStyle,
michael@0 80 bool aNeedsBold,
michael@0 81 AntialiasOption anAAOption)
michael@0 82 : gfxFont(aFontEntry, aFontStyle, anAAOption)
michael@0 83 , mCairoFontFace(nullptr)
michael@0 84 , mMetrics(nullptr)
michael@0 85 , mNeedsOblique(false)
michael@0 86 , mNeedsBold(aNeedsBold)
michael@0 87 , mUseSubpixelPositions(false)
michael@0 88 , mAllowManualShowGlyphs(true)
michael@0 89 {
michael@0 90 gfxDWriteFontEntry *fe =
michael@0 91 static_cast<gfxDWriteFontEntry*>(aFontEntry);
michael@0 92 nsresult rv;
michael@0 93 DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE;
michael@0 94 if ((GetStyle()->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) &&
michael@0 95 !fe->IsItalic()) {
michael@0 96 // For this we always use the font_matrix for uniformity. Not the
michael@0 97 // DWrite simulation.
michael@0 98 mNeedsOblique = true;
michael@0 99 }
michael@0 100 if (aNeedsBold) {
michael@0 101 sims |= DWRITE_FONT_SIMULATIONS_BOLD;
michael@0 102 }
michael@0 103
michael@0 104 rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
michael@0 105
michael@0 106 if (NS_FAILED(rv)) {
michael@0 107 mIsValid = false;
michael@0 108 return;
michael@0 109 }
michael@0 110
michael@0 111 ComputeMetrics(anAAOption);
michael@0 112
michael@0 113 if (FontCanSupportGraphite()) {
michael@0 114 mGraphiteShaper = new gfxGraphiteShaper(this);
michael@0 115 }
michael@0 116
michael@0 117 if (FontCanSupportHarfBuzz()) {
michael@0 118 mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
michael@0 119 }
michael@0 120 }
michael@0 121
michael@0 122 gfxDWriteFont::~gfxDWriteFont()
michael@0 123 {
michael@0 124 if (mCairoFontFace) {
michael@0 125 cairo_font_face_destroy(mCairoFontFace);
michael@0 126 }
michael@0 127 if (mScaledFont) {
michael@0 128 cairo_scaled_font_destroy(mScaledFont);
michael@0 129 }
michael@0 130 delete mMetrics;
michael@0 131 }
michael@0 132
michael@0 133 gfxFont*
michael@0 134 gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
michael@0 135 {
michael@0 136 return new gfxDWriteFont(static_cast<gfxDWriteFontEntry*>(mFontEntry.get()),
michael@0 137 &mStyle, mNeedsBold, anAAOption);
michael@0 138 }
michael@0 139
michael@0 140 void
michael@0 141 gfxDWriteFont::CreatePlatformShaper()
michael@0 142 {
michael@0 143 mPlatformShaper = new gfxDWriteShaper(this);
michael@0 144 }
michael@0 145
michael@0 146 const gfxFont::Metrics&
michael@0 147 gfxDWriteFont::GetMetrics()
michael@0 148 {
michael@0 149 return *mMetrics;
michael@0 150 }
michael@0 151
michael@0 152 bool
michael@0 153 gfxDWriteFont::GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics)
michael@0 154 {
michael@0 155 gfxFontStyle style(mStyle);
michael@0 156 style.weight = 700;
michael@0 157 bool needsBold;
michael@0 158
michael@0 159 gfxFontEntry* fe =
michael@0 160 gfxPlatformFontList::PlatformFontList()->
michael@0 161 FindFontForFamily(NS_LITERAL_STRING("Arial"), &style, needsBold);
michael@0 162 if (!fe || fe == mFontEntry) {
michael@0 163 return false;
michael@0 164 }
michael@0 165
michael@0 166 nsRefPtr<gfxFont> font = fe->FindOrMakeFont(&style, needsBold);
michael@0 167 gfxDWriteFont *dwFont = static_cast<gfxDWriteFont*>(font.get());
michael@0 168 dwFont->mFontFace->GetMetrics(aFontMetrics);
michael@0 169
michael@0 170 return true;
michael@0 171 }
michael@0 172
michael@0 173 void
michael@0 174 gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
michael@0 175 {
michael@0 176 DWRITE_FONT_METRICS fontMetrics;
michael@0 177 if (!(mFontEntry->Weight() == 900 &&
michael@0 178 !mFontEntry->IsUserFont() &&
michael@0 179 mFontEntry->Name().EqualsLiteral("Arial Black") &&
michael@0 180 GetFakeMetricsForArialBlack(&fontMetrics)))
michael@0 181 {
michael@0 182 mFontFace->GetMetrics(&fontMetrics);
michael@0 183 }
michael@0 184
michael@0 185 if (mStyle.sizeAdjust != 0.0) {
michael@0 186 gfxFloat aspect = (gfxFloat)fontMetrics.xHeight /
michael@0 187 fontMetrics.designUnitsPerEm;
michael@0 188 mAdjustedSize = mStyle.GetAdjustedSize(aspect);
michael@0 189 } else {
michael@0 190 mAdjustedSize = mStyle.size;
michael@0 191 }
michael@0 192
michael@0 193 // Note that GetMeasuringMode depends on mAdjustedSize
michael@0 194 if ((anAAOption == gfxFont::kAntialiasDefault &&
michael@0 195 UsingClearType() &&
michael@0 196 GetMeasuringMode() == DWRITE_MEASURING_MODE_NATURAL) ||
michael@0 197 anAAOption == gfxFont::kAntialiasSubpixel)
michael@0 198 {
michael@0 199 mUseSubpixelPositions = true;
michael@0 200 // note that this may be reset to FALSE if we determine that a bitmap
michael@0 201 // strike is going to be used
michael@0 202 }
michael@0 203
michael@0 204 gfxDWriteFontEntry *fe =
michael@0 205 static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
michael@0 206 if (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) {
michael@0 207 mAdjustedSize = NS_lround(mAdjustedSize);
michael@0 208 mUseSubpixelPositions = false;
michael@0 209 // if we have bitmaps, we need to tell Cairo NOT to use subpixel AA,
michael@0 210 // to avoid the manual-subpixel codepath in cairo-d2d-surface.cpp
michael@0 211 // which fails to render bitmap glyphs (see bug 626299).
michael@0 212 // This option will be passed to the cairo_dwrite_scaled_font_t
michael@0 213 // after creation.
michael@0 214 mAllowManualShowGlyphs = false;
michael@0 215 }
michael@0 216
michael@0 217 mMetrics = new gfxFont::Metrics;
michael@0 218 ::memset(mMetrics, 0, sizeof(*mMetrics));
michael@0 219
michael@0 220 mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
michael@0 221
michael@0 222 mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
michael@0 223
michael@0 224 mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor);
michael@0 225 mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor);
michael@0 226 mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
michael@0 227
michael@0 228 mMetrics->emHeight = mAdjustedSize;
michael@0 229 mMetrics->emAscent = mMetrics->emHeight *
michael@0 230 mMetrics->maxAscent / mMetrics->maxHeight;
michael@0 231 mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
michael@0 232
michael@0 233 mMetrics->maxAdvance = mAdjustedSize;
michael@0 234
michael@0 235 // try to get the true maxAdvance value from 'hhea'
michael@0 236 gfxFontEntry::AutoTable hheaTable(GetFontEntry(),
michael@0 237 TRUETYPE_TAG('h','h','e','a'));
michael@0 238 if (hheaTable) {
michael@0 239 uint32_t len;
michael@0 240 const HheaTable* hhea =
michael@0 241 reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
michael@0 242 if (len >= sizeof(HheaTable)) {
michael@0 243 mMetrics->maxAdvance =
michael@0 244 uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
michael@0 245 }
michael@0 246 }
michael@0 247
michael@0 248 mMetrics->internalLeading = std::max(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
michael@0 249 mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
michael@0 250
michael@0 251 UINT16 glyph = (uint16_t)GetSpaceGlyph();
michael@0 252 mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
michael@0 253
michael@0 254 // try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
michael@0 255 // if the table is not available or if using hinted/pixel-snapped widths
michael@0 256 if (mUseSubpixelPositions) {
michael@0 257 mMetrics->aveCharWidth = 0;
michael@0 258 gfxFontEntry::AutoTable os2Table(GetFontEntry(),
michael@0 259 TRUETYPE_TAG('O','S','/','2'));
michael@0 260 if (os2Table) {
michael@0 261 uint32_t len;
michael@0 262 const OS2Table* os2 =
michael@0 263 reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len));
michael@0 264 if (len >= 4) {
michael@0 265 // Not checking against sizeof(mozilla::OS2Table) here because older
michael@0 266 // versions of the table have different sizes; we only need the first
michael@0 267 // two 16-bit fields here.
michael@0 268 mMetrics->aveCharWidth =
michael@0 269 int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
michael@0 270 }
michael@0 271 }
michael@0 272 }
michael@0 273
michael@0 274 UINT32 ucs;
michael@0 275 if (mMetrics->aveCharWidth < 1) {
michael@0 276 ucs = L'x';
michael@0 277 if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
michael@0 278 mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
michael@0 279 }
michael@0 280 if (mMetrics->aveCharWidth < 1) {
michael@0 281 // Let's just assume the X is square.
michael@0 282 mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
michael@0 283 }
michael@0 284 }
michael@0 285
michael@0 286 ucs = L'0';
michael@0 287 if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
michael@0 288 mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph);
michael@0 289 }
michael@0 290 if (mMetrics->zeroOrAveCharWidth < 1) {
michael@0 291 mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
michael@0 292 }
michael@0 293
michael@0 294 mMetrics->underlineOffset =
michael@0 295 fontMetrics.underlinePosition * mFUnitsConvFactor;
michael@0 296 mMetrics->underlineSize =
michael@0 297 fontMetrics.underlineThickness * mFUnitsConvFactor;
michael@0 298 mMetrics->strikeoutOffset =
michael@0 299 fontMetrics.strikethroughPosition * mFUnitsConvFactor;
michael@0 300 mMetrics->strikeoutSize =
michael@0 301 fontMetrics.strikethroughThickness * mFUnitsConvFactor;
michael@0 302 mMetrics->superscriptOffset = 0;
michael@0 303 mMetrics->subscriptOffset = 0;
michael@0 304
michael@0 305 SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
michael@0 306
michael@0 307 #if 0
michael@0 308 printf("Font: %p (%s) size: %f\n", this,
michael@0 309 NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
michael@0 310 printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
michael@0 311 printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
michael@0 312 printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
michael@0 313 printf(" spaceWidth: %f aveCharWidth: %f zeroOrAve: %f xHeight: %f\n",
michael@0 314 mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->zeroOrAveCharWidth, mMetrics->xHeight);
michael@0 315 printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
michael@0 316 mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
michael@0 317 mMetrics->superscriptOffset, mMetrics->subscriptOffset);
michael@0 318 #endif
michael@0 319 }
michael@0 320
michael@0 321 using namespace mozilla; // for AutoSwap_* types
michael@0 322
michael@0 323 struct EBLCHeader {
michael@0 324 AutoSwap_PRUint32 version;
michael@0 325 AutoSwap_PRUint32 numSizes;
michael@0 326 };
michael@0 327
michael@0 328 struct SbitLineMetrics {
michael@0 329 int8_t ascender;
michael@0 330 int8_t descender;
michael@0 331 uint8_t widthMax;
michael@0 332 int8_t caretSlopeNumerator;
michael@0 333 int8_t caretSlopeDenominator;
michael@0 334 int8_t caretOffset;
michael@0 335 int8_t minOriginSB;
michael@0 336 int8_t minAdvanceSB;
michael@0 337 int8_t maxBeforeBL;
michael@0 338 int8_t minAfterBL;
michael@0 339 int8_t pad1;
michael@0 340 int8_t pad2;
michael@0 341 };
michael@0 342
michael@0 343 struct BitmapSizeTable {
michael@0 344 AutoSwap_PRUint32 indexSubTableArrayOffset;
michael@0 345 AutoSwap_PRUint32 indexTablesSize;
michael@0 346 AutoSwap_PRUint32 numberOfIndexSubTables;
michael@0 347 AutoSwap_PRUint32 colorRef;
michael@0 348 SbitLineMetrics hori;
michael@0 349 SbitLineMetrics vert;
michael@0 350 AutoSwap_PRUint16 startGlyphIndex;
michael@0 351 AutoSwap_PRUint16 endGlyphIndex;
michael@0 352 uint8_t ppemX;
michael@0 353 uint8_t ppemY;
michael@0 354 uint8_t bitDepth;
michael@0 355 uint8_t flags;
michael@0 356 };
michael@0 357
michael@0 358 typedef EBLCHeader EBSCHeader;
michael@0 359
michael@0 360 struct BitmapScaleTable {
michael@0 361 SbitLineMetrics hori;
michael@0 362 SbitLineMetrics vert;
michael@0 363 uint8_t ppemX;
michael@0 364 uint8_t ppemY;
michael@0 365 uint8_t substitutePpemX;
michael@0 366 uint8_t substitutePpemY;
michael@0 367 };
michael@0 368
michael@0 369 bool
michael@0 370 gfxDWriteFont::HasBitmapStrikeForSize(uint32_t aSize)
michael@0 371 {
michael@0 372 uint8_t *tableData;
michael@0 373 uint32_t len;
michael@0 374 void *tableContext;
michael@0 375 BOOL exists;
michael@0 376 HRESULT hr =
michael@0 377 mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'L', 'C'),
michael@0 378 (const void**)&tableData, &len,
michael@0 379 &tableContext, &exists);
michael@0 380 if (FAILED(hr)) {
michael@0 381 return false;
michael@0 382 }
michael@0 383
michael@0 384 bool hasStrike = false;
michael@0 385 // not really a loop, but this lets us use 'break' to skip out of the block
michael@0 386 // as soon as we know the answer, and skips it altogether if the table is
michael@0 387 // not present
michael@0 388 while (exists) {
michael@0 389 if (len < sizeof(EBLCHeader)) {
michael@0 390 break;
michael@0 391 }
michael@0 392 const EBLCHeader *hdr = reinterpret_cast<const EBLCHeader*>(tableData);
michael@0 393 if (hdr->version != 0x00020000) {
michael@0 394 break;
michael@0 395 }
michael@0 396 uint32_t numSizes = hdr->numSizes;
michael@0 397 if (numSizes > 0xffff) { // sanity-check, prevent overflow below
michael@0 398 break;
michael@0 399 }
michael@0 400 if (len < sizeof(EBLCHeader) + numSizes * sizeof(BitmapSizeTable)) {
michael@0 401 break;
michael@0 402 }
michael@0 403 const BitmapSizeTable *sizeTable =
michael@0 404 reinterpret_cast<const BitmapSizeTable*>(hdr + 1);
michael@0 405 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) {
michael@0 406 if (sizeTable->ppemX == aSize && sizeTable->ppemY == aSize) {
michael@0 407 // we ignore a strike that contains fewer than 4 glyphs,
michael@0 408 // as that probably indicates a font such as Courier New
michael@0 409 // that provides bitmaps ONLY for the "shading" characters
michael@0 410 // U+2591..2593
michael@0 411 hasStrike = (uint16_t(sizeTable->endGlyphIndex) >=
michael@0 412 uint16_t(sizeTable->startGlyphIndex) + 3);
michael@0 413 break;
michael@0 414 }
michael@0 415 }
michael@0 416 // if we reach here, we didn't find a strike; unconditionally break
michael@0 417 // out of the while-loop block
michael@0 418 break;
michael@0 419 }
michael@0 420 mFontFace->ReleaseFontTable(tableContext);
michael@0 421
michael@0 422 if (hasStrike) {
michael@0 423 return true;
michael@0 424 }
michael@0 425
michael@0 426 // if we didn't find a real strike, check if the font calls for scaling
michael@0 427 // another bitmap to this size
michael@0 428 hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'S', 'C'),
michael@0 429 (const void**)&tableData, &len,
michael@0 430 &tableContext, &exists);
michael@0 431 if (FAILED(hr)) {
michael@0 432 return false;
michael@0 433 }
michael@0 434
michael@0 435 while (exists) {
michael@0 436 if (len < sizeof(EBSCHeader)) {
michael@0 437 break;
michael@0 438 }
michael@0 439 const EBSCHeader *hdr = reinterpret_cast<const EBSCHeader*>(tableData);
michael@0 440 if (hdr->version != 0x00020000) {
michael@0 441 break;
michael@0 442 }
michael@0 443 uint32_t numSizes = hdr->numSizes;
michael@0 444 if (numSizes > 0xffff) {
michael@0 445 break;
michael@0 446 }
michael@0 447 if (len < sizeof(EBSCHeader) + numSizes * sizeof(BitmapScaleTable)) {
michael@0 448 break;
michael@0 449 }
michael@0 450 const BitmapScaleTable *scaleTable =
michael@0 451 reinterpret_cast<const BitmapScaleTable*>(hdr + 1);
michael@0 452 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) {
michael@0 453 if (scaleTable->ppemX == aSize && scaleTable->ppemY == aSize) {
michael@0 454 hasStrike = true;
michael@0 455 break;
michael@0 456 }
michael@0 457 }
michael@0 458 break;
michael@0 459 }
michael@0 460 mFontFace->ReleaseFontTable(tableContext);
michael@0 461
michael@0 462 return hasStrike;
michael@0 463 }
michael@0 464
michael@0 465 uint32_t
michael@0 466 gfxDWriteFont::GetSpaceGlyph()
michael@0 467 {
michael@0 468 UINT32 ucs = L' ';
michael@0 469 UINT16 glyph;
michael@0 470 HRESULT hr;
michael@0 471 hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph);
michael@0 472 if (FAILED(hr)) {
michael@0 473 return 0;
michael@0 474 }
michael@0 475 return glyph;
michael@0 476 }
michael@0 477
michael@0 478 bool
michael@0 479 gfxDWriteFont::SetupCairoFont(gfxContext *aContext)
michael@0 480 {
michael@0 481 cairo_scaled_font_t *scaledFont = GetCairoScaledFont();
michael@0 482 if (cairo_scaled_font_status(scaledFont) != CAIRO_STATUS_SUCCESS) {
michael@0 483 // Don't cairo_set_scaled_font as that would propagate the error to
michael@0 484 // the cairo_t, precluding any further drawing.
michael@0 485 return false;
michael@0 486 }
michael@0 487 cairo_set_scaled_font(aContext->GetCairo(), scaledFont);
michael@0 488 return true;
michael@0 489 }
michael@0 490
michael@0 491 bool
michael@0 492 gfxDWriteFont::IsValid()
michael@0 493 {
michael@0 494 return mFontFace != nullptr;
michael@0 495 }
michael@0 496
michael@0 497 IDWriteFontFace*
michael@0 498 gfxDWriteFont::GetFontFace()
michael@0 499 {
michael@0 500 return mFontFace.get();
michael@0 501 }
michael@0 502
michael@0 503 cairo_font_face_t *
michael@0 504 gfxDWriteFont::CairoFontFace()
michael@0 505 {
michael@0 506 if (!mCairoFontFace) {
michael@0 507 #ifdef CAIRO_HAS_DWRITE_FONT
michael@0 508 mCairoFontFace =
michael@0 509 cairo_dwrite_font_face_create_for_dwrite_fontface(
michael@0 510 ((gfxDWriteFontEntry*)mFontEntry.get())->mFont, mFontFace);
michael@0 511 #endif
michael@0 512 }
michael@0 513 return mCairoFontFace;
michael@0 514 }
michael@0 515
michael@0 516
michael@0 517 cairo_scaled_font_t *
michael@0 518 gfxDWriteFont::GetCairoScaledFont()
michael@0 519 {
michael@0 520 if (!mScaledFont) {
michael@0 521 cairo_matrix_t sizeMatrix;
michael@0 522 cairo_matrix_t identityMatrix;
michael@0 523
michael@0 524 cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
michael@0 525 cairo_matrix_init_identity(&identityMatrix);
michael@0 526
michael@0 527 cairo_font_options_t *fontOptions = cairo_font_options_create();
michael@0 528 if (mNeedsOblique) {
michael@0 529 double skewfactor = OBLIQUE_SKEW_FACTOR;
michael@0 530
michael@0 531 cairo_matrix_t style;
michael@0 532 cairo_matrix_init(&style,
michael@0 533 1, //xx
michael@0 534 0, //yx
michael@0 535 -1 * skewfactor, //xy
michael@0 536 1, //yy
michael@0 537 0, //x0
michael@0 538 0); //y0
michael@0 539 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
michael@0 540 }
michael@0 541
michael@0 542 if (mAntialiasOption != kAntialiasDefault) {
michael@0 543 cairo_font_options_set_antialias(fontOptions,
michael@0 544 GetCairoAntialiasOption(mAntialiasOption));
michael@0 545 }
michael@0 546
michael@0 547 mScaledFont = cairo_scaled_font_create(CairoFontFace(),
michael@0 548 &sizeMatrix,
michael@0 549 &identityMatrix,
michael@0 550 fontOptions);
michael@0 551 cairo_font_options_destroy(fontOptions);
michael@0 552
michael@0 553 cairo_dwrite_scaled_font_allow_manual_show_glyphs(mScaledFont,
michael@0 554 mAllowManualShowGlyphs);
michael@0 555
michael@0 556 gfxDWriteFontEntry *fe =
michael@0 557 static_cast<gfxDWriteFontEntry*>(mFontEntry.get());
michael@0 558 cairo_dwrite_scaled_font_set_force_GDI_classic(mScaledFont,
michael@0 559 GetForceGDIClassic());
michael@0 560 }
michael@0 561
michael@0 562 NS_ASSERTION(mAdjustedSize == 0.0 ||
michael@0 563 cairo_scaled_font_status(mScaledFont)
michael@0 564 == CAIRO_STATUS_SUCCESS,
michael@0 565 "Failed to make scaled font");
michael@0 566
michael@0 567 return mScaledFont;
michael@0 568 }
michael@0 569
michael@0 570 gfxFont::RunMetrics
michael@0 571 gfxDWriteFont::Measure(gfxTextRun *aTextRun,
michael@0 572 uint32_t aStart, uint32_t aEnd,
michael@0 573 BoundingBoxType aBoundingBoxType,
michael@0 574 gfxContext *aRefContext,
michael@0 575 Spacing *aSpacing)
michael@0 576 {
michael@0 577 gfxFont::RunMetrics metrics =
michael@0 578 gfxFont::Measure(aTextRun, aStart, aEnd,
michael@0 579 aBoundingBoxType, aRefContext, aSpacing);
michael@0 580
michael@0 581 // if aBoundingBoxType is LOOSE_INK_EXTENTS
michael@0 582 // and the underlying cairo font may be antialiased,
michael@0 583 // we can't trust Windows to have considered all the pixels
michael@0 584 // so we need to add "padding" to the bounds.
michael@0 585 // (see bugs 475968, 439831, compare also bug 445087)
michael@0 586 if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
michael@0 587 mAntialiasOption != kAntialiasNone &&
michael@0 588 GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_CLASSIC &&
michael@0 589 metrics.mBoundingBox.width > 0) {
michael@0 590 metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
michael@0 591 metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
michael@0 592 }
michael@0 593
michael@0 594 return metrics;
michael@0 595 }
michael@0 596
michael@0 597 bool
michael@0 598 gfxDWriteFont::ProvidesGlyphWidths()
michael@0 599 {
michael@0 600 return !mUseSubpixelPositions ||
michael@0 601 (mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
michael@0 602 }
michael@0 603
michael@0 604 int32_t
michael@0 605 gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
michael@0 606 {
michael@0 607 if (!mGlyphWidths) {
michael@0 608 mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200);
michael@0 609 }
michael@0 610
michael@0 611 int32_t width = -1;
michael@0 612 if (mGlyphWidths->Get(aGID, &width)) {
michael@0 613 return width;
michael@0 614 }
michael@0 615
michael@0 616 width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0);
michael@0 617 mGlyphWidths->Put(aGID, width);
michael@0 618 return width;
michael@0 619 }
michael@0 620
michael@0 621 TemporaryRef<GlyphRenderingOptions>
michael@0 622 gfxDWriteFont::GetGlyphRenderingOptions()
michael@0 623 {
michael@0 624 if (UsingClearType()) {
michael@0 625 return Factory::CreateDWriteGlyphRenderingOptions(
michael@0 626 gfxWindowsPlatform::GetPlatform()->GetRenderingParams(GetForceGDIClassic() ?
michael@0 627 gfxWindowsPlatform::TEXT_RENDERING_GDI_CLASSIC : gfxWindowsPlatform::TEXT_RENDERING_NORMAL));
michael@0 628 } else {
michael@0 629 return Factory::CreateDWriteGlyphRenderingOptions(gfxWindowsPlatform::GetPlatform()->
michael@0 630 GetRenderingParams(gfxWindowsPlatform::TEXT_RENDERING_NO_CLEARTYPE));
michael@0 631 }
michael@0 632 }
michael@0 633
michael@0 634 bool
michael@0 635 gfxDWriteFont::GetForceGDIClassic()
michael@0 636 {
michael@0 637 return static_cast<gfxDWriteFontEntry*>(mFontEntry.get())->GetForceGDIClassic() &&
michael@0 638 cairo_dwrite_get_cleartype_rendering_mode() < 0 &&
michael@0 639 GetAdjustedSize() <=
michael@0 640 gfxDWriteFontList::PlatformFontList()->GetForceGDIClassicMaxFontSize();
michael@0 641 }
michael@0 642
michael@0 643 DWRITE_MEASURING_MODE
michael@0 644 gfxDWriteFont::GetMeasuringMode()
michael@0 645 {
michael@0 646 return GetForceGDIClassic()
michael@0 647 ? DWRITE_MEASURING_MODE_GDI_CLASSIC
michael@0 648 : gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode();
michael@0 649 }
michael@0 650
michael@0 651 gfxFloat
michael@0 652 gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph)
michael@0 653 {
michael@0 654 DWRITE_GLYPH_METRICS metrics;
michael@0 655 HRESULT hr;
michael@0 656 if (mUseSubpixelPositions) {
michael@0 657 hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE);
michael@0 658 if (SUCCEEDED(hr)) {
michael@0 659 return metrics.advanceWidth * mFUnitsConvFactor;
michael@0 660 }
michael@0 661 } else {
michael@0 662 hr = mFontFace->GetGdiCompatibleGlyphMetrics(
michael@0 663 FLOAT(mAdjustedSize), 1.0f, nullptr,
michael@0 664 GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL,
michael@0 665 &aGlyph, 1, &metrics, FALSE);
michael@0 666 if (SUCCEEDED(hr)) {
michael@0 667 return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
michael@0 668 }
michael@0 669 }
michael@0 670 return 0;
michael@0 671 }
michael@0 672
michael@0 673 void
michael@0 674 gfxDWriteFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
michael@0 675 FontCacheSizes* aSizes) const
michael@0 676 {
michael@0 677 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 678 aSizes->mFontInstances += aMallocSizeOf(mMetrics);
michael@0 679 if (mGlyphWidths) {
michael@0 680 aSizes->mFontInstances +=
michael@0 681 mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf);
michael@0 682 }
michael@0 683 }
michael@0 684
michael@0 685 void
michael@0 686 gfxDWriteFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
michael@0 687 FontCacheSizes* aSizes) const
michael@0 688 {
michael@0 689 aSizes->mFontInstances += aMallocSizeOf(this);
michael@0 690 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 691 }
michael@0 692
michael@0 693 TemporaryRef<ScaledFont>
michael@0 694 gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget)
michael@0 695 {
michael@0 696 bool wantCairo = aTarget->GetType() == BackendType::CAIRO;
michael@0 697 if (mAzureScaledFont && mAzureScaledFontIsCairo == wantCairo) {
michael@0 698 return mAzureScaledFont;
michael@0 699 }
michael@0 700
michael@0 701 NativeFont nativeFont;
michael@0 702 nativeFont.mType = NativeFontType::DWRITE_FONT_FACE;
michael@0 703 nativeFont.mFont = GetFontFace();
michael@0 704
michael@0 705 if (wantCairo) {
michael@0 706 mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont,
michael@0 707 GetAdjustedSize(),
michael@0 708 GetCairoScaledFont());
michael@0 709 } else {
michael@0 710 mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont,
michael@0 711 GetAdjustedSize());
michael@0 712 }
michael@0 713
michael@0 714 mAzureScaledFontIsCairo = wantCairo;
michael@0 715
michael@0 716 return mAzureScaledFont;
michael@0 717 }

mercurial