tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gfxMacFont.cpp (22014B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "gfxMacFont.h"
      7 
      8 #include "mozilla/MemoryReporting.h"
      9 #include "mozilla/Sprintf.h"
     10 #include "mozilla/StaticPrefs_gfx.h"
     11 #include "mozilla/gfx/ScaledFontMac.h"
     12 
     13 #include <algorithm>
     14 
     15 #include "CoreTextFontList.h"
     16 #include "gfxCoreTextShaper.h"
     17 #include "gfxPlatformMac.h"
     18 #include "gfxContext.h"
     19 #include "gfxFontUtils.h"
     20 #include "gfxHarfBuzzShaper.h"
     21 #include "gfxFontConstants.h"
     22 #include "gfxTextRun.h"
     23 #include "gfxUtils.h"
     24 #include "AppleUtils.h"
     25 #include "cairo-quartz.h"
     26 
     27 using namespace mozilla;
     28 using namespace mozilla::gfx;
     29 
     30 template <class T>
     31 struct TagEquals {
     32  bool Equals(const T& aIter, uint32_t aTag) const {
     33    return aIter.mTag == aTag;
     34  }
     35 };
     36 
     37 gfxMacFont::gfxMacFont(const RefPtr<UnscaledFontMac>& aUnscaledFont,
     38                       CTFontEntry* aFontEntry, const gfxFontStyle* aFontStyle)
     39    : gfxFont(aUnscaledFont, aFontEntry, aFontStyle),
     40      mCGFont(nullptr),
     41      mCTFont(nullptr),
     42      mVariationFont(aFontEntry->HasVariations()) {
     43  mApplySyntheticBold = aFontStyle->NeedsSyntheticBold(aFontEntry);
     44 
     45  if (mVariationFont) {
     46    CGFontRef baseFont = aUnscaledFont->GetFont();
     47    if (!baseFont) {
     48      mIsValid = false;
     49      return;
     50    }
     51 
     52    // Get the variation settings needed to instantiate the fontEntry
     53    // for a particular fontStyle.
     54    AutoTArray<gfxFontVariation, 4> vars;
     55    aFontEntry->GetVariationsForStyle(vars, *aFontStyle);
     56 
     57    if (aFontEntry->HasOpticalSize()) {
     58      // Because of a Core Text bug, we need to ensure that if the font has
     59      // an 'opsz' axis, it is always explicitly set, and NOT to the font's
     60      // default value. (See bug 1457417, bug 1478720.)
     61      // We record the result of searching the font's axes in the font entry,
     62      // so that this only has to be done by the first instance created for
     63      // a given font resource.
     64      const uint32_t kOpszTag = HB_TAG('o', 'p', 's', 'z');
     65      const float kOpszFudgeAmount = 0.01f;
     66 
     67      // Record the opsz axis details in the font entry, if not already done.
     68      if (!aFontEntry->mOpszAxis.mTag) {
     69        AutoTArray<gfxFontVariationAxis, 4> axes;
     70        aFontEntry->GetVariationAxes(axes);
     71        auto index =
     72            axes.IndexOf(kOpszTag, 0, TagEquals<gfxFontVariationAxis>());
     73        MOZ_ASSERT(index != axes.NoIndex);
     74        if (index != axes.NoIndex) {
     75          const auto& axis = axes[index];
     76          aFontEntry->mOpszAxis = axis;
     77          // Pick a slightly-adjusted version of the default that we'll
     78          // use to work around Core Text's habit of ignoring any attempt
     79          // to explicitly set the default value.
     80          aFontEntry->mAdjustedDefaultOpsz =
     81              axis.mDefaultValue == axis.mMinValue
     82                  ? axis.mDefaultValue + kOpszFudgeAmount
     83                  : axis.mDefaultValue - kOpszFudgeAmount;
     84        }
     85      }
     86 
     87      // Add 'opsz' if not present, or tweak its value if it looks too close
     88      // to the default (after clamping to the font's available range).
     89      auto index = vars.IndexOf(kOpszTag, 0, TagEquals<gfxFontVariation>());
     90      if (index == vars.NoIndex) {
     91        // No explicit opsz; set to the font's default.
     92        vars.AppendElement(
     93            gfxFontVariation{kOpszTag, aFontEntry->mAdjustedDefaultOpsz});
     94      } else {
     95        // An 'opsz' value was already present; use it, but adjust if necessary
     96        // to a "safe" value that Core Text won't ignore.
     97        auto& value = vars[index].mValue;
     98        auto& axis = aFontEntry->mOpszAxis;
     99        value = fmin(fmax(value, axis.mMinValue), axis.mMaxValue);
    100        if (std::abs(value - axis.mDefaultValue) < kOpszFudgeAmount) {
    101          value = aFontEntry->mAdjustedDefaultOpsz;
    102        }
    103      }
    104    }
    105 
    106    mCGFont = UnscaledFontMac::CreateCGFontWithVariations(
    107        baseFont, aUnscaledFont->CGAxesCache(), aUnscaledFont->CTAxesCache(),
    108        vars.Length(), vars.Elements());
    109    if (!mCGFont) {
    110      ::CFRetain(baseFont);
    111      mCGFont = baseFont;
    112    }
    113  } else {
    114    mCGFont = aUnscaledFont->GetFont();
    115    if (!mCGFont) {
    116      mIsValid = false;
    117      return;
    118    }
    119    ::CFRetain(mCGFont);
    120  }
    121 
    122  // InitMetrics will handle the sizeAdjust factor and set mAdjustedSize
    123  InitMetrics();
    124  if (!mIsValid) {
    125    return;
    126  }
    127 
    128  // turn off font anti-aliasing based on user pref setting
    129  if (mAdjustedSize <=
    130      (gfxFloat)gfxPlatformMac::GetPlatform()->GetAntiAliasingThreshold()) {
    131    mAntialiasOption = kAntialiasNone;
    132  } else if (mStyle.useGrayscaleAntialiasing) {
    133    mAntialiasOption = kAntialiasGrayscale;
    134  }
    135 }
    136 
    137 gfxMacFont::~gfxMacFont() {
    138  if (mCGFont) {
    139    ::CFRelease(mCGFont);
    140  }
    141  if (mCTFont) {
    142    ::CFRelease(mCTFont);
    143  }
    144 }
    145 
    146 bool gfxMacFont::ShapeText(DrawTarget* aDrawTarget, const char16_t* aText,
    147                           uint32_t aOffset, uint32_t aLength, Script aScript,
    148                           nsAtom* aLanguage, bool aVertical,
    149                           RoundingFlags aRounding,
    150                           gfxShapedText* aShapedText) {
    151  if (!mIsValid) {
    152    NS_WARNING("invalid font! expect incorrect text rendering");
    153    return false;
    154  }
    155 
    156  // Currently, we don't support vertical shaping via CoreText,
    157  // so we ignore RequiresAATLayout if vertical is requested.
    158  auto ctFontEntry = static_cast<CTFontEntry*>(GetFontEntry());
    159  if (ctFontEntry->RequiresAATLayout() && !aVertical &&
    160      StaticPrefs::gfx_font_rendering_coretext_enabled()) {
    161    if (!mCoreTextShaper) {
    162      mCoreTextShaper = MakeUnique<gfxCoreTextShaper>(this);
    163    }
    164    if (mCoreTextShaper->ShapeText(aDrawTarget, aText, aOffset, aLength,
    165                                   aScript, aLanguage, aVertical, aRounding,
    166                                   aShapedText)) {
    167      PostShapingFixup(aDrawTarget, aText, aOffset, aLength, aVertical,
    168                       aShapedText);
    169      if (ctFontEntry->HasTrackingTable()) {
    170        // Convert font size from device pixels back to CSS px
    171        // to use in selecting tracking value
    172        float trackSize = GetAdjustedSize() *
    173                          aShapedText->GetAppUnitsPerDevUnit() /
    174                          AppUnitsPerCSSPixel();
    175        float tracking =
    176            ctFontEntry->TrackingForCSSPx(trackSize) * mFUnitsConvFactor;
    177        // Applying tracking is a lot like the adjustment we do for
    178        // synthetic bold: we want to apply between clusters, not to
    179        // non-spacing glyphs within a cluster. So we can reuse that
    180        // helper here.
    181        aShapedText->ApplyTrackingToClusters(tracking, aOffset, aLength);
    182      }
    183      return true;
    184    }
    185  }
    186 
    187  return gfxFont::ShapeText(aDrawTarget, aText, aOffset, aLength, aScript,
    188                            aLanguage, aVertical, aRounding, aShapedText);
    189 }
    190 
    191 gfxFont::RunMetrics gfxMacFont::Measure(const gfxTextRun* aTextRun,
    192                                        uint32_t aStart, uint32_t aEnd,
    193                                        BoundingBoxType aBoundingBoxType,
    194                                        DrawTarget* aRefDrawTarget,
    195                                        Spacing* aSpacing,
    196                                        gfx::ShapedTextFlags aOrientation) {
    197  gfxFont::RunMetrics metrics =
    198      gfxFont::Measure(aTextRun, aStart, aEnd, aBoundingBoxType, aRefDrawTarget,
    199                       aSpacing, aOrientation);
    200 
    201  // if aBoundingBoxType is not TIGHT_HINTED_OUTLINE_EXTENTS then we need to add
    202  // a pixel column each side of the bounding box in case of antialiasing
    203  // "bleed"
    204  if (aBoundingBoxType != TIGHT_HINTED_OUTLINE_EXTENTS &&
    205      metrics.mBoundingBox.width > 0) {
    206    metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
    207    metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 2;
    208  }
    209 
    210  return metrics;
    211 }
    212 
    213 void gfxMacFont::InitMetrics() {
    214  mIsValid = false;
    215  ::memset(&mMetrics, 0, sizeof(mMetrics));
    216 
    217  uint32_t upem = 0;
    218 
    219  // try to get unitsPerEm from sfnt head table, to avoid calling CGFont
    220  // if possible (bug 574368) and because CGFontGetUnitsPerEm does not
    221  // return the true value for OpenType/CFF fonts (it normalizes to 1000,
    222  // which then leads to metrics errors when we read the 'hmtx' table to
    223  // get glyph advances for HarfBuzz, see bug 580863)
    224  AutoCFTypeRef<CFDataRef> headData(
    225      ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('h', 'e', 'a', 'd')));
    226  if (headData) {
    227    if (size_t(::CFDataGetLength(headData)) >= sizeof(HeadTable)) {
    228      const HeadTable* head =
    229          reinterpret_cast<const HeadTable*>(::CFDataGetBytePtr(headData));
    230      upem = head->unitsPerEm;
    231    }
    232  }
    233  if (!upem) {
    234    upem = ::CGFontGetUnitsPerEm(mCGFont);
    235  }
    236 
    237  if (upem < 16 || upem > 16384) {
    238    // See http://www.microsoft.com/typography/otspec/head.htm
    239 #ifdef DEBUG
    240    char warnBuf[1024];
    241    SprintfLiteral(warnBuf,
    242                   "Bad font metrics for: %s (invalid unitsPerEm value)",
    243                   mFontEntry->Name().get());
    244    NS_WARNING(warnBuf);
    245 #endif
    246    return;
    247  }
    248 
    249  // Apply any size-adjust from the font enty to the given size; this may be
    250  // re-adjusted below if font-size-adjust is in effect.
    251  mAdjustedSize = GetAdjustedSize();
    252  mFUnitsConvFactor = mAdjustedSize / upem;
    253 
    254  // For CFF fonts, when scaling values read from CGFont* APIs, we need to
    255  // use CG's idea of unitsPerEm, which may differ from the "true" value in
    256  // the head table of the font (see bug 580863)
    257  gfxFloat cgConvFactor;
    258  if (static_cast<CTFontEntry*>(mFontEntry.get())->IsCFF()) {
    259    cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont);
    260  } else {
    261    cgConvFactor = mFUnitsConvFactor;
    262  }
    263 
    264  // Try to read 'sfnt' metrics; for local, non-sfnt fonts ONLY, fall back to
    265  // platform APIs. The InitMetrics...() functions will set mIsValid on success.
    266  if (!InitMetricsFromSfntTables(mMetrics) &&
    267      (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) {
    268    InitMetricsFromPlatform();
    269  }
    270  if (!mIsValid) {
    271    return;
    272  }
    273 
    274  if (mMetrics.xHeight == 0.0) {
    275    mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor;
    276  }
    277  if (mMetrics.capHeight == 0.0) {
    278    mMetrics.capHeight = ::CGFontGetCapHeight(mCGFont) * cgConvFactor;
    279  }
    280 
    281  AutoCFTypeRef<CFDataRef> cmap(
    282      ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('c', 'm', 'a', 'p')));
    283 
    284  uint32_t glyphID;
    285  mMetrics.zeroWidth = GetCharWidth(cmap, '0', &glyphID, cgConvFactor);
    286  if (glyphID == 0) {
    287    mMetrics.zeroWidth = -1.0;  // indicates not found
    288  }
    289 
    290  if (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) !=
    291          FontSizeAdjust::Tag::None &&
    292      mStyle.sizeAdjust >= 0.0 && GetAdjustedSize() > 0.0) {
    293    // apply font-size-adjust, and recalculate metrics
    294    gfxFloat aspect;
    295    switch (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis)) {
    296      default:
    297        MOZ_ASSERT_UNREACHABLE("unhandled sizeAdjustBasis?");
    298        aspect = 0.0;
    299        break;
    300      case FontSizeAdjust::Tag::ExHeight:
    301        aspect = mMetrics.xHeight / mAdjustedSize;
    302        break;
    303      case FontSizeAdjust::Tag::CapHeight:
    304        aspect = mMetrics.capHeight / mAdjustedSize;
    305        break;
    306      case FontSizeAdjust::Tag::ChWidth:
    307        aspect =
    308            mMetrics.zeroWidth < 0.0 ? 0.5 : mMetrics.zeroWidth / mAdjustedSize;
    309        break;
    310      case FontSizeAdjust::Tag::IcWidth:
    311      case FontSizeAdjust::Tag::IcHeight: {
    312        bool vertical = FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) ==
    313                        FontSizeAdjust::Tag::IcHeight;
    314        gfxFloat advance = GetCharAdvance(kWaterIdeograph, vertical);
    315        aspect = advance > 0.0 ? advance / mAdjustedSize : 1.0;
    316        break;
    317      }
    318    }
    319    if (aspect > 0.0) {
    320      // If we created a shaper above (to measure glyphs), discard it so we
    321      // get a new one for the adjusted scaling.
    322      delete mHarfBuzzShaper.exchange(nullptr);
    323      mAdjustedSize = mStyle.GetAdjustedSize(aspect);
    324      mFUnitsConvFactor = mAdjustedSize / upem;
    325      if (static_cast<CTFontEntry*>(mFontEntry.get())->IsCFF()) {
    326        cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont);
    327      } else {
    328        cgConvFactor = mFUnitsConvFactor;
    329      }
    330      mMetrics.xHeight = 0.0;
    331      if (!InitMetricsFromSfntTables(mMetrics) &&
    332          (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) {
    333        InitMetricsFromPlatform();
    334      }
    335      if (!mIsValid) {
    336        // this shouldn't happen, as we succeeded earlier before applying
    337        // the size-adjust factor! But check anyway, for paranoia's sake.
    338        return;
    339      }
    340      // Update metrics from the re-scaled font.
    341      if (mMetrics.xHeight == 0.0) {
    342        mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor;
    343      }
    344      if (mMetrics.capHeight == 0.0) {
    345        mMetrics.capHeight = ::CGFontGetCapHeight(mCGFont) * cgConvFactor;
    346      }
    347      mMetrics.zeroWidth = GetCharWidth(cmap, '0', &glyphID, cgConvFactor);
    348      if (glyphID == 0) {
    349        mMetrics.zeroWidth = -1.0;  // indicates not found
    350      }
    351    }
    352  }
    353 
    354  // Once we reach here, we've got basic metrics and set mIsValid = TRUE;
    355  // there should be no further points of actual failure in InitMetrics().
    356  // (If one is introduced, be sure to reset mIsValid to FALSE!)
    357 
    358  mMetrics.emHeight = mAdjustedSize;
    359 
    360  // Measure/calculate additional metrics, independent of whether we used
    361  // the tables directly or ATS metrics APIs
    362 
    363  if (mMetrics.aveCharWidth <= 0) {
    364    mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID, cgConvFactor);
    365    if (glyphID == 0) {
    366      // we didn't find 'x', so use maxAdvance rather than zero
    367      mMetrics.aveCharWidth = mMetrics.maxAdvance;
    368    }
    369  }
    370 
    371  mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor);
    372  if (glyphID == 0) {
    373    // no space glyph?!
    374    mMetrics.spaceWidth = mMetrics.aveCharWidth;
    375  }
    376  mSpaceGlyph = glyphID;
    377 
    378  mMetrics.ideographicWidth =
    379      GetCharWidth(cmap, kWaterIdeograph, &glyphID, cgConvFactor);
    380  if (glyphID == 0) {
    381    // Indicate "not found".
    382    mMetrics.ideographicWidth = -1.0;
    383  }
    384 
    385  CalculateDerivedMetrics(mMetrics);
    386 
    387  SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont);
    388 
    389  if (ApplySyntheticBold()) {
    390    auto delta = GetSyntheticBoldOffset();
    391    mMetrics.spaceWidth += delta;
    392    mMetrics.aveCharWidth += delta;
    393    mMetrics.maxAdvance += delta;
    394    if (mMetrics.zeroWidth > 0) {
    395      mMetrics.zeroWidth += delta;
    396    }
    397    if (mMetrics.ideographicWidth > 0) {
    398      mMetrics.ideographicWidth += delta;
    399    }
    400  }
    401 
    402 #if 0
    403    fprintf (stderr, "Font: %p (%s) size: %f\n", this,
    404             NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
    405 //    fprintf (stderr, "    fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
    406    fprintf (stderr, "    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
    407    fprintf (stderr, "    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
    408    fprintf (stderr, "    internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
    409    fprintf (stderr, "    spaceWidth: %f aveCharWidth: %f xHeight: %f capHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight, mMetrics.capHeight);
    410    fprintf (stderr, "    uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
    411 #endif
    412 }
    413 
    414 gfxFloat gfxMacFont::GetCharWidth(CFDataRef aCmap, char16_t aUniChar,
    415                                  uint32_t* aGlyphID, gfxFloat aConvFactor) {
    416  CGGlyph glyph = 0;
    417 
    418  if (aCmap) {
    419    glyph = gfxFontUtils::MapCharToGlyph(::CFDataGetBytePtr(aCmap),
    420                                         ::CFDataGetLength(aCmap), aUniChar);
    421  }
    422 
    423  if (aGlyphID) {
    424    *aGlyphID = glyph;
    425  }
    426 
    427  if (glyph) {
    428    int advance;
    429    if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) {
    430      return advance * aConvFactor;
    431    }
    432  }
    433 
    434  return 0;
    435 }
    436 
    437 int32_t gfxMacFont::GetGlyphWidth(uint16_t aGID) {
    438  if (mVariationFont) {
    439    // Avoid a potential Core Text crash (bug 1450209) by using
    440    // CoreGraphics glyph advance API. This is inferior for 'sbix'
    441    // fonts, but those won't have variations, so it's OK.
    442    int cgAdvance;
    443    if (::CGFontGetGlyphAdvances(mCGFont, &aGID, 1, &cgAdvance)) {
    444      return cgAdvance * mFUnitsConvFactor * 0x10000;
    445    }
    446  }
    447 
    448  if (!mCTFont) {
    449    bool isInstalledFont =
    450        !mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont();
    451    mCTFont = CreateCTFontFromCGFontWithVariations(mCGFont, mAdjustedSize,
    452                                                   isInstalledFont);
    453    if (!mCTFont) {  // shouldn't happen, but let's be safe
    454      NS_WARNING("failed to create CTFontRef to measure glyph width");
    455      return 0;
    456    }
    457  }
    458 
    459  CGSize advance;
    460  ::CTFontGetAdvancesForGlyphs(mCTFont, kCTFontOrientationDefault, &aGID,
    461                               &advance, 1);
    462  return advance.width * 0x10000;
    463 }
    464 
    465 bool gfxMacFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
    466  CGRect bb;
    467  if (!::CGFontGetGlyphBBoxes(mCGFont, &aGID, 1, &bb)) {
    468    return false;
    469  }
    470 
    471  // broken fonts can return incorrect bounds for some null characters,
    472  // see https://bugzilla.mozilla.org/show_bug.cgi?id=534260
    473  if (bb.origin.x == -32767 && bb.origin.y == -32767 &&
    474      bb.size.width == 65534 && bb.size.height == 65534) {
    475    *aBounds = gfxRect(0, 0, 0, 0);
    476    return true;
    477  }
    478 
    479  gfxRect bounds(bb.origin.x, -(bb.origin.y + bb.size.height), bb.size.width,
    480                 bb.size.height);
    481  bounds.Scale(mFUnitsConvFactor);
    482 
    483  // For bitmap fonts (like Apple Color Emoji), CoreGraphics does not return
    484  // accurate bounds, so to try and avoid clipping when the bounds are used
    485  // to determine the area to render (e.g. when implementing canvas2d filters),
    486  // we inflate the bounds based on global metrics from the font.
    487  if (GetFontEntry()->HasColorBitmapTable()) {
    488    aBounds->x = std::min(bounds.x, 0.0);
    489    aBounds->width = std::max(bounds.width, mMetrics.maxAdvance);
    490    // Note that y-coordinates are downwards here, and bounds.y is MINUS the
    491    // glyph ascent as it measures from the baseline.
    492    aBounds->y = std::min(bounds.y, -mMetrics.maxAscent);
    493    aBounds->height =
    494        std::max(bounds.YMost(), mMetrics.maxDescent) - aBounds->y;
    495  } else {
    496    *aBounds = bounds;
    497  }
    498 
    499  return true;
    500 }
    501 
    502 // Try to initialize font metrics via platform APIs (CG/CT),
    503 // and set mIsValid = TRUE on success.
    504 // We ONLY call this for local (platform) fonts that are not sfnt format;
    505 // for sfnts, including ALL downloadable fonts, we prefer to use
    506 // InitMetricsFromSfntTables and avoid platform APIs.
    507 void gfxMacFont::InitMetricsFromPlatform() {
    508  AutoCFTypeRef<CTFontRef> ctFont(
    509      ::CTFontCreateWithGraphicsFont(mCGFont, mAdjustedSize, nullptr, nullptr));
    510  if (!ctFont) {
    511    return;
    512  }
    513 
    514  mMetrics.underlineOffset = ::CTFontGetUnderlinePosition(ctFont);
    515  mMetrics.underlineSize = ::CTFontGetUnderlineThickness(ctFont);
    516 
    517  mMetrics.externalLeading = ::CTFontGetLeading(ctFont);
    518 
    519  mMetrics.maxAscent = ::CTFontGetAscent(ctFont);
    520  mMetrics.maxDescent = ::CTFontGetDescent(ctFont);
    521 
    522  // this is not strictly correct, but neither CTFont nor CGFont seems to
    523  // provide maxAdvance, unless we were to iterate over all the glyphs
    524  // (which isn't worth the cost here)
    525  CGRect r = ::CTFontGetBoundingBox(ctFont);
    526  mMetrics.maxAdvance = r.size.width;
    527 
    528  // aveCharWidth is also not provided, so leave it at zero
    529  // (fallback code in gfxMacFont::InitMetrics will then try measuring 'x');
    530  // this could lead to less-than-"perfect" text field sizing when width is
    531  // specified as a number of characters, and the font in use is a non-sfnt
    532  // legacy font, but that's a sufficiently obscure edge case that we can
    533  // ignore the potential discrepancy.
    534  mMetrics.aveCharWidth = 0;
    535 
    536  mMetrics.xHeight = ::CTFontGetXHeight(ctFont);
    537  mMetrics.capHeight = ::CTFontGetCapHeight(ctFont);
    538 
    539  mIsValid = true;
    540 }
    541 
    542 already_AddRefed<ScaledFont> gfxMacFont::GetScaledFont(
    543    const TextRunDrawParams& aRunParams) {
    544  if (ScaledFont* scaledFont = mAzureScaledFont) {
    545    return do_AddRef(scaledFont);
    546  }
    547 
    548  gfxFontEntry* fe = GetFontEntry();
    549  bool hasColorGlyphs = fe->HasColorBitmapTable() || fe->TryGetColorGlyphs();
    550  RefPtr<ScaledFont> newScaledFont = Factory::CreateScaledFontForMacFont(
    551      GetCGFontRef(), GetUnscaledFont(), GetAdjustedSize(),
    552      !mStyle.useGrayscaleAntialiasing, ApplySyntheticBold(), hasColorGlyphs);
    553  if (!newScaledFont) {
    554    return nullptr;
    555  }
    556 
    557  InitializeScaledFont(newScaledFont);
    558 
    559  if (mAzureScaledFont.compareExchange(nullptr, newScaledFont.get())) {
    560    newScaledFont.forget().leak();
    561  }
    562  ScaledFont* scaledFont = mAzureScaledFont;
    563  return do_AddRef(scaledFont);
    564 }
    565 
    566 bool gfxMacFont::ShouldRoundXOffset(cairo_t* aCairo) const {
    567  // Quartz surfaces implement show_glyphs for Quartz fonts
    568  return aCairo && cairo_surface_get_type(cairo_get_target(aCairo)) !=
    569                       CAIRO_SURFACE_TYPE_QUARTZ;
    570 }
    571 
    572 bool gfxMacFont::UseNativeColrFontSupport() const {
    573  /*
    574    auto* colr = GetFontEntry()->GetCOLR();
    575    if (colr && COLRFonts::GetColrTableVersion(colr) == 0) {
    576      return true;
    577    }
    578  */
    579  return false;
    580 }
    581 
    582 void gfxMacFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
    583                                        FontCacheSizes* aSizes) const {
    584  gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    585  // mCGFont is shared with the font entry, so not counted here;
    586 }
    587 
    588 void gfxMacFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
    589                                        FontCacheSizes* aSizes) const {
    590  aSizes->mFontInstances += aMallocSizeOf(this);
    591  AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
    592 }