Tue, 06 Jan 2015 21:39:09 +0100
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 "gfxMacFont.h" |
michael@0 | 7 | |
michael@0 | 8 | #include "mozilla/MemoryReporting.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "gfxCoreTextShaper.h" |
michael@0 | 11 | #include "gfxHarfBuzzShaper.h" |
michael@0 | 12 | #include <algorithm> |
michael@0 | 13 | #include "gfxGraphiteShaper.h" |
michael@0 | 14 | #include "gfxPlatformMac.h" |
michael@0 | 15 | #include "gfxContext.h" |
michael@0 | 16 | #include "gfxFontUtils.h" |
michael@0 | 17 | #include "gfxMacPlatformFontList.h" |
michael@0 | 18 | #include "gfxFontConstants.h" |
michael@0 | 19 | |
michael@0 | 20 | #include "cairo-quartz.h" |
michael@0 | 21 | |
michael@0 | 22 | using namespace mozilla; |
michael@0 | 23 | using namespace mozilla::gfx; |
michael@0 | 24 | |
michael@0 | 25 | gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, |
michael@0 | 26 | bool aNeedsBold) |
michael@0 | 27 | : gfxFont(aFontEntry, aFontStyle), |
michael@0 | 28 | mCGFont(nullptr), |
michael@0 | 29 | mFontFace(nullptr) |
michael@0 | 30 | { |
michael@0 | 31 | mApplySyntheticBold = aNeedsBold; |
michael@0 | 32 | |
michael@0 | 33 | mCGFont = aFontEntry->GetFontRef(); |
michael@0 | 34 | if (!mCGFont) { |
michael@0 | 35 | mIsValid = false; |
michael@0 | 36 | return; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | // InitMetrics will handle the sizeAdjust factor and set mAdjustedSize |
michael@0 | 40 | InitMetrics(); |
michael@0 | 41 | if (!mIsValid) { |
michael@0 | 42 | return; |
michael@0 | 43 | } |
michael@0 | 44 | |
michael@0 | 45 | mFontFace = cairo_quartz_font_face_create_for_cgfont(mCGFont); |
michael@0 | 46 | |
michael@0 | 47 | cairo_status_t cairoerr = cairo_font_face_status(mFontFace); |
michael@0 | 48 | if (cairoerr != CAIRO_STATUS_SUCCESS) { |
michael@0 | 49 | mIsValid = false; |
michael@0 | 50 | #ifdef DEBUG |
michael@0 | 51 | char warnBuf[1024]; |
michael@0 | 52 | sprintf(warnBuf, "Failed to create Cairo font face: %s status: %d", |
michael@0 | 53 | NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr); |
michael@0 | 54 | NS_WARNING(warnBuf); |
michael@0 | 55 | #endif |
michael@0 | 56 | return; |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | cairo_matrix_t sizeMatrix, ctm; |
michael@0 | 60 | cairo_matrix_init_identity(&ctm); |
michael@0 | 61 | cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); |
michael@0 | 62 | |
michael@0 | 63 | // synthetic oblique by skewing via the font matrix |
michael@0 | 64 | bool needsOblique = |
michael@0 | 65 | (mFontEntry != nullptr) && |
michael@0 | 66 | (!mFontEntry->IsItalic() && |
michael@0 | 67 | (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE))); |
michael@0 | 68 | |
michael@0 | 69 | if (needsOblique) { |
michael@0 | 70 | double skewfactor = (needsOblique ? Fix2X(kATSItalicQDSkew) : 0); |
michael@0 | 71 | |
michael@0 | 72 | cairo_matrix_t style; |
michael@0 | 73 | cairo_matrix_init(&style, |
michael@0 | 74 | 1, //xx |
michael@0 | 75 | 0, //yx |
michael@0 | 76 | -1 * skewfactor, //xy |
michael@0 | 77 | 1, //yy |
michael@0 | 78 | 0, //x0 |
michael@0 | 79 | 0); //y0 |
michael@0 | 80 | cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | cairo_font_options_t *fontOptions = cairo_font_options_create(); |
michael@0 | 84 | |
michael@0 | 85 | // turn off font anti-aliasing based on user pref setting |
michael@0 | 86 | if (mAdjustedSize <= |
michael@0 | 87 | (gfxFloat)gfxPlatformMac::GetPlatform()->GetAntiAliasingThreshold()) { |
michael@0 | 88 | cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_NONE); |
michael@0 | 89 | mAntialiasOption = kAntialiasNone; |
michael@0 | 90 | } else if (mStyle.useGrayscaleAntialiasing) { |
michael@0 | 91 | cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_GRAY); |
michael@0 | 92 | mAntialiasOption = kAntialiasGrayscale; |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, |
michael@0 | 96 | fontOptions); |
michael@0 | 97 | cairo_font_options_destroy(fontOptions); |
michael@0 | 98 | |
michael@0 | 99 | cairoerr = cairo_scaled_font_status(mScaledFont); |
michael@0 | 100 | if (cairoerr != CAIRO_STATUS_SUCCESS) { |
michael@0 | 101 | mIsValid = false; |
michael@0 | 102 | #ifdef DEBUG |
michael@0 | 103 | char warnBuf[1024]; |
michael@0 | 104 | sprintf(warnBuf, "Failed to create scaled font: %s status: %d", |
michael@0 | 105 | NS_ConvertUTF16toUTF8(GetName()).get(), cairoerr); |
michael@0 | 106 | NS_WARNING(warnBuf); |
michael@0 | 107 | #endif |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | if (FontCanSupportGraphite()) { |
michael@0 | 111 | mGraphiteShaper = new gfxGraphiteShaper(this); |
michael@0 | 112 | } |
michael@0 | 113 | if (FontCanSupportHarfBuzz()) { |
michael@0 | 114 | mHarfBuzzShaper = new gfxHarfBuzzShaper(this); |
michael@0 | 115 | } |
michael@0 | 116 | } |
michael@0 | 117 | |
michael@0 | 118 | gfxMacFont::~gfxMacFont() |
michael@0 | 119 | { |
michael@0 | 120 | if (mScaledFont) { |
michael@0 | 121 | cairo_scaled_font_destroy(mScaledFont); |
michael@0 | 122 | } |
michael@0 | 123 | if (mFontFace) { |
michael@0 | 124 | cairo_font_face_destroy(mFontFace); |
michael@0 | 125 | } |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | bool |
michael@0 | 129 | gfxMacFont::ShapeText(gfxContext *aContext, |
michael@0 | 130 | const char16_t *aText, |
michael@0 | 131 | uint32_t aOffset, |
michael@0 | 132 | uint32_t aLength, |
michael@0 | 133 | int32_t aScript, |
michael@0 | 134 | gfxShapedText *aShapedText, |
michael@0 | 135 | bool aPreferPlatformShaping) |
michael@0 | 136 | { |
michael@0 | 137 | if (!mIsValid) { |
michael@0 | 138 | NS_WARNING("invalid font! expect incorrect text rendering"); |
michael@0 | 139 | return false; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | bool requiresAAT = |
michael@0 | 143 | static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout(); |
michael@0 | 144 | return gfxFont::ShapeText(aContext, aText, aOffset, aLength, |
michael@0 | 145 | aScript, aShapedText, requiresAAT); |
michael@0 | 146 | } |
michael@0 | 147 | |
michael@0 | 148 | void |
michael@0 | 149 | gfxMacFont::CreatePlatformShaper() |
michael@0 | 150 | { |
michael@0 | 151 | mPlatformShaper = new gfxCoreTextShaper(this); |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | bool |
michael@0 | 155 | gfxMacFont::SetupCairoFont(gfxContext *aContext) |
michael@0 | 156 | { |
michael@0 | 157 | if (cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { |
michael@0 | 158 | // Don't cairo_set_scaled_font as that would propagate the error to |
michael@0 | 159 | // the cairo_t, precluding any further drawing. |
michael@0 | 160 | return false; |
michael@0 | 161 | } |
michael@0 | 162 | cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); |
michael@0 | 163 | return true; |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | gfxFont::RunMetrics |
michael@0 | 167 | gfxMacFont::Measure(gfxTextRun *aTextRun, |
michael@0 | 168 | uint32_t aStart, uint32_t aEnd, |
michael@0 | 169 | BoundingBoxType aBoundingBoxType, |
michael@0 | 170 | gfxContext *aRefContext, |
michael@0 | 171 | Spacing *aSpacing) |
michael@0 | 172 | { |
michael@0 | 173 | gfxFont::RunMetrics metrics = |
michael@0 | 174 | gfxFont::Measure(aTextRun, aStart, aEnd, |
michael@0 | 175 | aBoundingBoxType, aRefContext, aSpacing); |
michael@0 | 176 | |
michael@0 | 177 | // if aBoundingBoxType is not TIGHT_HINTED_OUTLINE_EXTENTS then we need to add |
michael@0 | 178 | // a pixel column each side of the bounding box in case of antialiasing "bleed" |
michael@0 | 179 | if (aBoundingBoxType != TIGHT_HINTED_OUTLINE_EXTENTS && |
michael@0 | 180 | metrics.mBoundingBox.width > 0) { |
michael@0 | 181 | metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); |
michael@0 | 182 | metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 2; |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | return metrics; |
michael@0 | 186 | } |
michael@0 | 187 | |
michael@0 | 188 | void |
michael@0 | 189 | gfxMacFont::InitMetrics() |
michael@0 | 190 | { |
michael@0 | 191 | mIsValid = false; |
michael@0 | 192 | ::memset(&mMetrics, 0, sizeof(mMetrics)); |
michael@0 | 193 | |
michael@0 | 194 | uint32_t upem = 0; |
michael@0 | 195 | |
michael@0 | 196 | // try to get unitsPerEm from sfnt head table, to avoid calling CGFont |
michael@0 | 197 | // if possible (bug 574368) and because CGFontGetUnitsPerEm does not |
michael@0 | 198 | // return the true value for OpenType/CFF fonts (it normalizes to 1000, |
michael@0 | 199 | // which then leads to metrics errors when we read the 'hmtx' table to |
michael@0 | 200 | // get glyph advances for HarfBuzz, see bug 580863) |
michael@0 | 201 | CFDataRef headData = |
michael@0 | 202 | ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('h','e','a','d')); |
michael@0 | 203 | if (headData) { |
michael@0 | 204 | if (size_t(::CFDataGetLength(headData)) >= sizeof(HeadTable)) { |
michael@0 | 205 | const HeadTable *head = |
michael@0 | 206 | reinterpret_cast<const HeadTable*>(::CFDataGetBytePtr(headData)); |
michael@0 | 207 | upem = head->unitsPerEm; |
michael@0 | 208 | } |
michael@0 | 209 | ::CFRelease(headData); |
michael@0 | 210 | } |
michael@0 | 211 | if (!upem) { |
michael@0 | 212 | upem = ::CGFontGetUnitsPerEm(mCGFont); |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | if (upem < 16 || upem > 16384) { |
michael@0 | 216 | // See http://www.microsoft.com/typography/otspec/head.htm |
michael@0 | 217 | #ifdef DEBUG |
michael@0 | 218 | char warnBuf[1024]; |
michael@0 | 219 | sprintf(warnBuf, "Bad font metrics for: %s (invalid unitsPerEm value)", |
michael@0 | 220 | NS_ConvertUTF16toUTF8(mFontEntry->Name()).get()); |
michael@0 | 221 | NS_WARNING(warnBuf); |
michael@0 | 222 | #endif |
michael@0 | 223 | return; |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | mAdjustedSize = std::max(mStyle.size, 1.0); |
michael@0 | 227 | mFUnitsConvFactor = mAdjustedSize / upem; |
michael@0 | 228 | |
michael@0 | 229 | // For CFF fonts, when scaling values read from CGFont* APIs, we need to |
michael@0 | 230 | // use CG's idea of unitsPerEm, which may differ from the "true" value in |
michael@0 | 231 | // the head table of the font (see bug 580863) |
michael@0 | 232 | gfxFloat cgConvFactor; |
michael@0 | 233 | if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) { |
michael@0 | 234 | cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); |
michael@0 | 235 | } else { |
michael@0 | 236 | cgConvFactor = mFUnitsConvFactor; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | // Try to read 'sfnt' metrics; for local, non-sfnt fonts ONLY, fall back to |
michael@0 | 240 | // platform APIs. The InitMetrics...() functions will set mIsValid on success. |
michael@0 | 241 | if (!InitMetricsFromSfntTables(mMetrics) && |
michael@0 | 242 | (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { |
michael@0 | 243 | InitMetricsFromPlatform(); |
michael@0 | 244 | } |
michael@0 | 245 | if (!mIsValid) { |
michael@0 | 246 | return; |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | if (mMetrics.xHeight == 0.0) { |
michael@0 | 250 | mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; |
michael@0 | 251 | } |
michael@0 | 252 | |
michael@0 | 253 | if (mStyle.sizeAdjust != 0.0 && mStyle.size > 0.0 && |
michael@0 | 254 | mMetrics.xHeight > 0.0) { |
michael@0 | 255 | // apply font-size-adjust, and recalculate metrics |
michael@0 | 256 | gfxFloat aspect = mMetrics.xHeight / mStyle.size; |
michael@0 | 257 | mAdjustedSize = mStyle.GetAdjustedSize(aspect); |
michael@0 | 258 | mFUnitsConvFactor = mAdjustedSize / upem; |
michael@0 | 259 | if (static_cast<MacOSFontEntry*>(mFontEntry.get())->IsCFF()) { |
michael@0 | 260 | cgConvFactor = mAdjustedSize / ::CGFontGetUnitsPerEm(mCGFont); |
michael@0 | 261 | } else { |
michael@0 | 262 | cgConvFactor = mFUnitsConvFactor; |
michael@0 | 263 | } |
michael@0 | 264 | mMetrics.xHeight = 0.0; |
michael@0 | 265 | if (!InitMetricsFromSfntTables(mMetrics) && |
michael@0 | 266 | (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { |
michael@0 | 267 | InitMetricsFromPlatform(); |
michael@0 | 268 | } |
michael@0 | 269 | if (!mIsValid) { |
michael@0 | 270 | // this shouldn't happen, as we succeeded earlier before applying |
michael@0 | 271 | // the size-adjust factor! But check anyway, for paranoia's sake. |
michael@0 | 272 | return; |
michael@0 | 273 | } |
michael@0 | 274 | if (mMetrics.xHeight == 0.0) { |
michael@0 | 275 | mMetrics.xHeight = ::CGFontGetXHeight(mCGFont) * cgConvFactor; |
michael@0 | 276 | } |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | // Once we reach here, we've got basic metrics and set mIsValid = TRUE; |
michael@0 | 280 | // there should be no further points of actual failure in InitMetrics(). |
michael@0 | 281 | // (If one is introduced, be sure to reset mIsValid to FALSE!) |
michael@0 | 282 | |
michael@0 | 283 | mMetrics.emHeight = mAdjustedSize; |
michael@0 | 284 | |
michael@0 | 285 | // Measure/calculate additional metrics, independent of whether we used |
michael@0 | 286 | // the tables directly or ATS metrics APIs |
michael@0 | 287 | |
michael@0 | 288 | CFDataRef cmap = |
michael@0 | 289 | ::CGFontCopyTableForTag(mCGFont, TRUETYPE_TAG('c','m','a','p')); |
michael@0 | 290 | |
michael@0 | 291 | uint32_t glyphID; |
michael@0 | 292 | if (mMetrics.aveCharWidth <= 0) { |
michael@0 | 293 | mMetrics.aveCharWidth = GetCharWidth(cmap, 'x', &glyphID, |
michael@0 | 294 | cgConvFactor); |
michael@0 | 295 | if (glyphID == 0) { |
michael@0 | 296 | // we didn't find 'x', so use maxAdvance rather than zero |
michael@0 | 297 | mMetrics.aveCharWidth = mMetrics.maxAdvance; |
michael@0 | 298 | } |
michael@0 | 299 | } |
michael@0 | 300 | if (IsSyntheticBold()) { |
michael@0 | 301 | mMetrics.aveCharWidth += GetSyntheticBoldOffset(); |
michael@0 | 302 | mMetrics.maxAdvance += GetSyntheticBoldOffset(); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor); |
michael@0 | 306 | if (glyphID == 0) { |
michael@0 | 307 | // no space glyph?! |
michael@0 | 308 | mMetrics.spaceWidth = mMetrics.aveCharWidth; |
michael@0 | 309 | } |
michael@0 | 310 | mSpaceGlyph = glyphID; |
michael@0 | 311 | |
michael@0 | 312 | mMetrics.zeroOrAveCharWidth = GetCharWidth(cmap, '0', &glyphID, |
michael@0 | 313 | cgConvFactor); |
michael@0 | 314 | if (glyphID == 0) { |
michael@0 | 315 | mMetrics.zeroOrAveCharWidth = mMetrics.aveCharWidth; |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | if (cmap) { |
michael@0 | 319 | ::CFRelease(cmap); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | CalculateDerivedMetrics(mMetrics); |
michael@0 | 323 | |
michael@0 | 324 | SanitizeMetrics(&mMetrics, mFontEntry->mIsBadUnderlineFont); |
michael@0 | 325 | |
michael@0 | 326 | #if 0 |
michael@0 | 327 | fprintf (stderr, "Font: %p (%s) size: %f\n", this, |
michael@0 | 328 | NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); |
michael@0 | 329 | // 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); |
michael@0 | 330 | fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); |
michael@0 | 331 | fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); |
michael@0 | 332 | fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); |
michael@0 | 333 | fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); |
michael@0 | 334 | fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); |
michael@0 | 335 | #endif |
michael@0 | 336 | } |
michael@0 | 337 | |
michael@0 | 338 | gfxFloat |
michael@0 | 339 | gfxMacFont::GetCharWidth(CFDataRef aCmap, char16_t aUniChar, |
michael@0 | 340 | uint32_t *aGlyphID, gfxFloat aConvFactor) |
michael@0 | 341 | { |
michael@0 | 342 | CGGlyph glyph = 0; |
michael@0 | 343 | |
michael@0 | 344 | if (aCmap) { |
michael@0 | 345 | glyph = gfxFontUtils::MapCharToGlyph(::CFDataGetBytePtr(aCmap), |
michael@0 | 346 | ::CFDataGetLength(aCmap), |
michael@0 | 347 | aUniChar); |
michael@0 | 348 | } |
michael@0 | 349 | |
michael@0 | 350 | if (aGlyphID) { |
michael@0 | 351 | *aGlyphID = glyph; |
michael@0 | 352 | } |
michael@0 | 353 | |
michael@0 | 354 | if (glyph) { |
michael@0 | 355 | int advance; |
michael@0 | 356 | if (::CGFontGetGlyphAdvances(mCGFont, &glyph, 1, &advance)) { |
michael@0 | 357 | return advance * aConvFactor; |
michael@0 | 358 | } |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | return 0; |
michael@0 | 362 | } |
michael@0 | 363 | |
michael@0 | 364 | // Try to initialize font metrics via platform APIs (CG/CT), |
michael@0 | 365 | // and set mIsValid = TRUE on success. |
michael@0 | 366 | // We ONLY call this for local (platform) fonts that are not sfnt format; |
michael@0 | 367 | // for sfnts, including ALL downloadable fonts, we prefer to use |
michael@0 | 368 | // InitMetricsFromSfntTables and avoid platform APIs. |
michael@0 | 369 | void |
michael@0 | 370 | gfxMacFont::InitMetricsFromPlatform() |
michael@0 | 371 | { |
michael@0 | 372 | CTFontRef ctFont = ::CTFontCreateWithGraphicsFont(mCGFont, |
michael@0 | 373 | mAdjustedSize, |
michael@0 | 374 | nullptr, nullptr); |
michael@0 | 375 | if (!ctFont) { |
michael@0 | 376 | return; |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | mMetrics.underlineOffset = ::CTFontGetUnderlinePosition(ctFont); |
michael@0 | 380 | mMetrics.underlineSize = ::CTFontGetUnderlineThickness(ctFont); |
michael@0 | 381 | |
michael@0 | 382 | mMetrics.externalLeading = ::CTFontGetLeading(ctFont); |
michael@0 | 383 | |
michael@0 | 384 | mMetrics.maxAscent = ::CTFontGetAscent(ctFont); |
michael@0 | 385 | mMetrics.maxDescent = ::CTFontGetDescent(ctFont); |
michael@0 | 386 | |
michael@0 | 387 | // this is not strictly correct, but neither CTFont nor CGFont seems to |
michael@0 | 388 | // provide maxAdvance, unless we were to iterate over all the glyphs |
michael@0 | 389 | // (which isn't worth the cost here) |
michael@0 | 390 | CGRect r = ::CTFontGetBoundingBox(ctFont); |
michael@0 | 391 | mMetrics.maxAdvance = r.size.width; |
michael@0 | 392 | |
michael@0 | 393 | // aveCharWidth is also not provided, so leave it at zero |
michael@0 | 394 | // (fallback code in gfxMacFont::InitMetrics will then try measuring 'x'); |
michael@0 | 395 | // this could lead to less-than-"perfect" text field sizing when width is |
michael@0 | 396 | // specified as a number of characters, and the font in use is a non-sfnt |
michael@0 | 397 | // legacy font, but that's a sufficiently obscure edge case that we can |
michael@0 | 398 | // ignore the potential discrepancy. |
michael@0 | 399 | mMetrics.aveCharWidth = 0; |
michael@0 | 400 | |
michael@0 | 401 | mMetrics.xHeight = ::CTFontGetXHeight(ctFont); |
michael@0 | 402 | |
michael@0 | 403 | ::CFRelease(ctFont); |
michael@0 | 404 | |
michael@0 | 405 | mIsValid = true; |
michael@0 | 406 | } |
michael@0 | 407 | |
michael@0 | 408 | TemporaryRef<ScaledFont> |
michael@0 | 409 | gfxMacFont::GetScaledFont(DrawTarget *aTarget) |
michael@0 | 410 | { |
michael@0 | 411 | if (!mAzureScaledFont) { |
michael@0 | 412 | NativeFont nativeFont; |
michael@0 | 413 | nativeFont.mType = NativeFontType::MAC_FONT_FACE; |
michael@0 | 414 | nativeFont.mFont = GetCGFontRef(); |
michael@0 | 415 | mAzureScaledFont = mozilla::gfx::Factory::CreateScaledFontWithCairo(nativeFont, GetAdjustedSize(), mScaledFont); |
michael@0 | 416 | } |
michael@0 | 417 | |
michael@0 | 418 | return mAzureScaledFont; |
michael@0 | 419 | } |
michael@0 | 420 | |
michael@0 | 421 | void |
michael@0 | 422 | gfxMacFont::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, |
michael@0 | 423 | FontCacheSizes* aSizes) const |
michael@0 | 424 | { |
michael@0 | 425 | gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
michael@0 | 426 | // mCGFont is shared with the font entry, so not counted here; |
michael@0 | 427 | // and we don't have APIs to measure the cairo mFontFace object |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | void |
michael@0 | 431 | gfxMacFont::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
michael@0 | 432 | FontCacheSizes* aSizes) const |
michael@0 | 433 | { |
michael@0 | 434 | aSizes->mFontInstances += aMallocSizeOf(this); |
michael@0 | 435 | AddSizeOfExcludingThis(aMallocSizeOf, aSizes); |
michael@0 | 436 | } |