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 }