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.

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

mercurial