gfx/thebes/gfxGDIFont.cpp

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "gfxGDIFont.h"
michael@0 7
michael@0 8 #include "mozilla/MemoryReporting.h"
michael@0 9 #include "mozilla/WindowsVersion.h"
michael@0 10
michael@0 11 #include "gfxGDIShaper.h"
michael@0 12 #include "gfxUniscribeShaper.h"
michael@0 13 #include "gfxHarfBuzzShaper.h"
michael@0 14 #include <algorithm>
michael@0 15 #include "gfxGraphiteShaper.h"
michael@0 16 #include "gfxWindowsPlatform.h"
michael@0 17 #include "gfxContext.h"
michael@0 18 #include "mozilla/Preferences.h"
michael@0 19 #include "nsUnicodeProperties.h"
michael@0 20 #include "gfxFontConstants.h"
michael@0 21
michael@0 22 #include "cairo-win32.h"
michael@0 23
michael@0 24 #define ROUND(x) floor((x) + 0.5)
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27 using namespace mozilla::unicode;
michael@0 28
michael@0 29 static inline cairo_antialias_t
michael@0 30 GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
michael@0 31 {
michael@0 32 switch (anAntialiasOption) {
michael@0 33 default:
michael@0 34 case gfxFont::kAntialiasDefault:
michael@0 35 return CAIRO_ANTIALIAS_DEFAULT;
michael@0 36 case gfxFont::kAntialiasNone:
michael@0 37 return CAIRO_ANTIALIAS_NONE;
michael@0 38 case gfxFont::kAntialiasGrayscale:
michael@0 39 return CAIRO_ANTIALIAS_GRAY;
michael@0 40 case gfxFont::kAntialiasSubpixel:
michael@0 41 return CAIRO_ANTIALIAS_SUBPIXEL;
michael@0 42 }
michael@0 43 }
michael@0 44
michael@0 45 gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
michael@0 46 const gfxFontStyle *aFontStyle,
michael@0 47 bool aNeedsBold,
michael@0 48 AntialiasOption anAAOption)
michael@0 49 : gfxFont(aFontEntry, aFontStyle, anAAOption),
michael@0 50 mFont(nullptr),
michael@0 51 mFontFace(nullptr),
michael@0 52 mMetrics(nullptr),
michael@0 53 mSpaceGlyph(0),
michael@0 54 mNeedsBold(aNeedsBold)
michael@0 55 {
michael@0 56 if (FontCanSupportGraphite()) {
michael@0 57 mGraphiteShaper = new gfxGraphiteShaper(this);
michael@0 58 }
michael@0 59 if (FontCanSupportHarfBuzz()) {
michael@0 60 mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
michael@0 61 }
michael@0 62 }
michael@0 63
michael@0 64 gfxGDIFont::~gfxGDIFont()
michael@0 65 {
michael@0 66 if (mScaledFont) {
michael@0 67 cairo_scaled_font_destroy(mScaledFont);
michael@0 68 }
michael@0 69 if (mFontFace) {
michael@0 70 cairo_font_face_destroy(mFontFace);
michael@0 71 }
michael@0 72 if (mFont) {
michael@0 73 ::DeleteObject(mFont);
michael@0 74 }
michael@0 75 delete mMetrics;
michael@0 76 }
michael@0 77
michael@0 78 void
michael@0 79 gfxGDIFont::CreatePlatformShaper()
michael@0 80 {
michael@0 81 mPlatformShaper = new gfxGDIShaper(this);
michael@0 82 }
michael@0 83
michael@0 84 gfxFont*
michael@0 85 gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
michael@0 86 {
michael@0 87 return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()),
michael@0 88 &mStyle, mNeedsBold, anAAOption);
michael@0 89 }
michael@0 90
michael@0 91 static bool
michael@0 92 UseUniscribe(gfxShapedText *aShapedText,
michael@0 93 char16ptr_t aText,
michael@0 94 uint32_t aLength)
michael@0 95 {
michael@0 96 uint32_t flags = aShapedText->Flags();
michael@0 97 bool useGDI;
michael@0 98
michael@0 99 bool isXP = !IsVistaOrLater();
michael@0 100
michael@0 101 // bug 561304 - Uniscribe bug produces bad positioning at certain
michael@0 102 // font sizes on XP, so default to GDI on XP using logic of 3.6
michael@0 103
michael@0 104 useGDI = isXP &&
michael@0 105 (flags &
michael@0 106 (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED |
michael@0 107 gfxTextRunFactory::TEXT_IS_RTL)
michael@0 108 ) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
michael@0 109
michael@0 110 return !useGDI ||
michael@0 111 ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK;
michael@0 112 }
michael@0 113
michael@0 114 bool
michael@0 115 gfxGDIFont::ShapeText(gfxContext *aContext,
michael@0 116 const char16_t *aText,
michael@0 117 uint32_t aOffset,
michael@0 118 uint32_t aLength,
michael@0 119 int32_t aScript,
michael@0 120 gfxShapedText *aShapedText,
michael@0 121 bool aPreferPlatformShaping)
michael@0 122 {
michael@0 123 if (!mMetrics) {
michael@0 124 Initialize();
michael@0 125 }
michael@0 126 if (!mIsValid) {
michael@0 127 NS_WARNING("invalid font! expect incorrect text rendering");
michael@0 128 return false;
michael@0 129 }
michael@0 130
michael@0 131 bool ok = false;
michael@0 132
michael@0 133 // Ensure the cairo font is set up, so there's no risk it'll fall back to
michael@0 134 // creating a "toy" font internally (see bug 544617).
michael@0 135 // We must check that this succeeded, otherwise we risk cairo creating the
michael@0 136 // wrong kind of font internally as a fallback (bug 744480).
michael@0 137 if (!SetupCairoFont(aContext)) {
michael@0 138 return false;
michael@0 139 }
michael@0 140
michael@0 141 if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
michael@0 142 ok = mGraphiteShaper->ShapeText(aContext, aText,
michael@0 143 aOffset, aLength,
michael@0 144 aScript, aShapedText);
michael@0 145 }
michael@0 146
michael@0 147 if (!ok && mHarfBuzzShaper) {
michael@0 148 if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) ||
michael@0 149 (!IsVistaOrLater() &&
michael@0 150 ScriptShapingType(aScript) == SHAPING_INDIC &&
michael@0 151 !Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe",
michael@0 152 false))) {
michael@0 153 ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
michael@0 154 aScript, aShapedText);
michael@0 155 }
michael@0 156 }
michael@0 157
michael@0 158 if (!ok) {
michael@0 159 GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
michael@0 160 bool preferUniscribe =
michael@0 161 (!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI;
michael@0 162
michael@0 163 if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) {
michael@0 164 // first try Uniscribe
michael@0 165 if (!mUniscribeShaper) {
michael@0 166 mUniscribeShaper = new gfxUniscribeShaper(this);
michael@0 167 }
michael@0 168
michael@0 169 ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength,
michael@0 170 aScript, aShapedText);
michael@0 171 if (!ok) {
michael@0 172 // fallback to GDI shaping
michael@0 173 if (!mPlatformShaper) {
michael@0 174 CreatePlatformShaper();
michael@0 175 }
michael@0 176
michael@0 177 ok = mPlatformShaper->ShapeText(aContext, aText, aOffset,
michael@0 178 aLength, aScript, aShapedText);
michael@0 179 }
michael@0 180 } else {
michael@0 181 // first use GDI
michael@0 182 if (!mPlatformShaper) {
michael@0 183 CreatePlatformShaper();
michael@0 184 }
michael@0 185
michael@0 186 ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
michael@0 187 aScript, aShapedText);
michael@0 188 if (!ok) {
michael@0 189 // try Uniscribe if GDI failed
michael@0 190 if (!mUniscribeShaper) {
michael@0 191 mUniscribeShaper = new gfxUniscribeShaper(this);
michael@0 192 }
michael@0 193
michael@0 194 // use Uniscribe shaping
michael@0 195 ok = mUniscribeShaper->ShapeText(aContext, aText,
michael@0 196 aOffset, aLength,
michael@0 197 aScript, aShapedText);
michael@0 198 }
michael@0 199 }
michael@0 200
michael@0 201 #if DEBUG
michael@0 202 if (!ok) {
michael@0 203 NS_ConvertUTF16toUTF8 name(GetName());
michael@0 204 char msg[256];
michael@0 205
michael@0 206 sprintf(msg,
michael@0 207 "text shaping with both uniscribe and GDI failed for"
michael@0 208 " font: %s",
michael@0 209 name.get());
michael@0 210 NS_WARNING(msg);
michael@0 211 }
michael@0 212 #endif
michael@0 213 }
michael@0 214
michael@0 215 PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
michael@0 216
michael@0 217 return ok;
michael@0 218 }
michael@0 219
michael@0 220 const gfxFont::Metrics&
michael@0 221 gfxGDIFont::GetMetrics()
michael@0 222 {
michael@0 223 if (!mMetrics) {
michael@0 224 Initialize();
michael@0 225 }
michael@0 226 return *mMetrics;
michael@0 227 }
michael@0 228
michael@0 229 uint32_t
michael@0 230 gfxGDIFont::GetSpaceGlyph()
michael@0 231 {
michael@0 232 if (!mMetrics) {
michael@0 233 Initialize();
michael@0 234 }
michael@0 235 return mSpaceGlyph;
michael@0 236 }
michael@0 237
michael@0 238 bool
michael@0 239 gfxGDIFont::SetupCairoFont(gfxContext *aContext)
michael@0 240 {
michael@0 241 if (!mMetrics) {
michael@0 242 Initialize();
michael@0 243 }
michael@0 244 if (!mScaledFont ||
michael@0 245 cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
michael@0 246 // Don't cairo_set_scaled_font as that would propagate the error to
michael@0 247 // the cairo_t, precluding any further drawing.
michael@0 248 return false;
michael@0 249 }
michael@0 250 cairo_set_scaled_font(aContext->GetCairo(), mScaledFont);
michael@0 251 return true;
michael@0 252 }
michael@0 253
michael@0 254 gfxFont::RunMetrics
michael@0 255 gfxGDIFont::Measure(gfxTextRun *aTextRun,
michael@0 256 uint32_t aStart, uint32_t aEnd,
michael@0 257 BoundingBoxType aBoundingBoxType,
michael@0 258 gfxContext *aRefContext,
michael@0 259 Spacing *aSpacing)
michael@0 260 {
michael@0 261 gfxFont::RunMetrics metrics =
michael@0 262 gfxFont::Measure(aTextRun, aStart, aEnd,
michael@0 263 aBoundingBoxType, aRefContext, aSpacing);
michael@0 264
michael@0 265 // if aBoundingBoxType is LOOSE_INK_EXTENTS
michael@0 266 // and the underlying cairo font may be antialiased,
michael@0 267 // we can't trust Windows to have considered all the pixels
michael@0 268 // so we need to add "padding" to the bounds.
michael@0 269 // (see bugs 475968, 439831, compare also bug 445087)
michael@0 270 if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
michael@0 271 mAntialiasOption != kAntialiasNone &&
michael@0 272 metrics.mBoundingBox.width > 0) {
michael@0 273 metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
michael@0 274 metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
michael@0 275 }
michael@0 276
michael@0 277 return metrics;
michael@0 278 }
michael@0 279
michael@0 280 #define OBLIQUE_SKEW_FACTOR 0.3
michael@0 281
michael@0 282 void
michael@0 283 gfxGDIFont::Initialize()
michael@0 284 {
michael@0 285 NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak");
michael@0 286
michael@0 287 LOGFONTW logFont;
michael@0 288
michael@0 289 // Figure out if we want to do synthetic oblique styling.
michael@0 290 GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry());
michael@0 291 bool wantFakeItalic =
michael@0 292 (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) &&
michael@0 293 !fe->IsItalic();
michael@0 294
michael@0 295 // If the font's family has an actual italic face (but font matching
michael@0 296 // didn't choose it), we have to use a cairo transform instead of asking
michael@0 297 // GDI to italicize, because that would use a different face and result
michael@0 298 // in a possible glyph ID mismatch between shaping and rendering.
michael@0 299 //
michael@0 300 // We use the mFamilyHasItalicFace flag in the entry in case of user fonts,
michael@0 301 // where the *CSS* family may not know about italic faces that are present
michael@0 302 // in the *GDI* family, and which GDI would use if we asked it to perform
michael@0 303 // the "italicization".
michael@0 304 bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace;
michael@0 305
michael@0 306 if (mAdjustedSize == 0.0) {
michael@0 307 mAdjustedSize = mStyle.size;
michael@0 308 if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) {
michael@0 309 // to implement font-size-adjust, we first create the "unadjusted" font
michael@0 310 FillLogFont(logFont, mAdjustedSize,
michael@0 311 wantFakeItalic && !useCairoFakeItalic);
michael@0 312 mFont = ::CreateFontIndirectW(&logFont);
michael@0 313
michael@0 314 // initialize its metrics so we can calculate size adjustment
michael@0 315 Initialize();
michael@0 316
michael@0 317 // calculate the properly adjusted size, and then proceed
michael@0 318 // to recreate mFont and recalculate metrics
michael@0 319 gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight;
michael@0 320 mAdjustedSize = mStyle.GetAdjustedSize(aspect);
michael@0 321
michael@0 322 // delete the temporary font and metrics
michael@0 323 ::DeleteObject(mFont);
michael@0 324 mFont = nullptr;
michael@0 325 delete mMetrics;
michael@0 326 mMetrics = nullptr;
michael@0 327 }
michael@0 328 }
michael@0 329
michael@0 330 // (bug 724231) for local user fonts, we don't use GDI's synthetic bold,
michael@0 331 // as it could lead to a different, incompatible face being used
michael@0 332 // but instead do our own multi-striking
michael@0 333 if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) {
michael@0 334 mApplySyntheticBold = true;
michael@0 335 }
michael@0 336
michael@0 337 // this may end up being zero
michael@0 338 mAdjustedSize = ROUND(mAdjustedSize);
michael@0 339 FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic);
michael@0 340 mFont = ::CreateFontIndirectW(&logFont);
michael@0 341
michael@0 342 mMetrics = new gfxFont::Metrics;
michael@0 343 ::memset(mMetrics, 0, sizeof(*mMetrics));
michael@0 344
michael@0 345 AutoDC dc;
michael@0 346 SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
michael@0 347 AutoSelectFont selectFont(dc.GetDC(), mFont);
michael@0 348
michael@0 349 // Get font metrics if size > 0
michael@0 350 if (mAdjustedSize > 0.0) {
michael@0 351
michael@0 352 OUTLINETEXTMETRIC oMetrics;
michael@0 353 TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
michael@0 354
michael@0 355 if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
michael@0 356 mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y;
michael@0 357 // Some fonts have wrong sign on their subscript offset, bug 410917.
michael@0 358 mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y);
michael@0 359 mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
michael@0 360 mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
michael@0 361 mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
michael@0 362 mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition;
michael@0 363
michael@0 364 const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
michael@0 365 GLYPHMETRICS gm;
michael@0 366 DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix);
michael@0 367 if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
michael@0 368 // 56% of ascent, best guess for true type
michael@0 369 mMetrics->xHeight =
michael@0 370 ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
michael@0 371 } else {
michael@0 372 mMetrics->xHeight = gm.gmptGlyphOrigin.y;
michael@0 373 }
michael@0 374 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
michael@0 375 gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent;
michael@0 376 mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight);
michael@0 377 mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
michael@0 378 if (oMetrics.otmEMSquare > 0) {
michael@0 379 mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare);
michael@0 380 }
michael@0 381 } else {
michael@0 382 // Make a best-effort guess at extended metrics
michael@0 383 // this is based on general typographic guidelines
michael@0 384
michael@0 385 // GetTextMetrics can fail if the font file has been removed
michael@0 386 // or corrupted recently.
michael@0 387 BOOL result = GetTextMetrics(dc.GetDC(), &metrics);
michael@0 388 if (!result) {
michael@0 389 NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
michael@0 390 mIsValid = false;
michael@0 391 memset(mMetrics, 0, sizeof(*mMetrics));
michael@0 392 return;
michael@0 393 }
michael@0 394
michael@0 395 mMetrics->xHeight =
michael@0 396 ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
michael@0 397 mMetrics->superscriptOffset = mMetrics->xHeight;
michael@0 398 mMetrics->subscriptOffset = mMetrics->xHeight;
michael@0 399 mMetrics->strikeoutSize = 1;
michael@0 400 mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
michael@0 401 mMetrics->underlineSize = 1;
michael@0 402 mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent
michael@0 403 mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
michael@0 404 mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading;
michael@0 405 mMetrics->emDescent = metrics.tmDescent;
michael@0 406 }
michael@0 407
michael@0 408 mMetrics->internalLeading = metrics.tmInternalLeading;
michael@0 409 mMetrics->externalLeading = metrics.tmExternalLeading;
michael@0 410 mMetrics->maxHeight = metrics.tmHeight;
michael@0 411 mMetrics->maxAscent = metrics.tmAscent;
michael@0 412 mMetrics->maxDescent = metrics.tmDescent;
michael@0 413 mMetrics->maxAdvance = metrics.tmMaxCharWidth;
michael@0 414 mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth);
michael@0 415 // The font is monospace when TMPF_FIXED_PITCH is *not* set!
michael@0 416 // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx
michael@0 417 if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
michael@0 418 mMetrics->maxAdvance = mMetrics->aveCharWidth;
michael@0 419 }
michael@0 420
michael@0 421 // Cache the width of a single space.
michael@0 422 SIZE size;
michael@0 423 GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size);
michael@0 424 mMetrics->spaceWidth = ROUND(size.cx);
michael@0 425
michael@0 426 // Cache the width of digit zero.
michael@0 427 // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx)
michael@0 428 // does not say what the failure modes for GetTextExtentPoint32 are -
michael@0 429 // is it safe to assume it will fail iff the font has no '0'?
michael@0 430 if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) {
michael@0 431 mMetrics->zeroOrAveCharWidth = ROUND(size.cx);
michael@0 432 } else {
michael@0 433 mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
michael@0 434 }
michael@0 435
michael@0 436 WORD glyph;
michael@0 437 DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
michael@0 438 GGI_MARK_NONEXISTING_GLYPHS);
michael@0 439 if (ret != GDI_ERROR && glyph != 0xFFFF) {
michael@0 440 mSpaceGlyph = glyph;
michael@0 441 }
michael@0 442
michael@0 443 SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
michael@0 444 }
michael@0 445
michael@0 446 if (IsSyntheticBold()) {
michael@0 447 mMetrics->aveCharWidth += GetSyntheticBoldOffset();
michael@0 448 mMetrics->maxAdvance += GetSyntheticBoldOffset();
michael@0 449 }
michael@0 450
michael@0 451 mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont,
michael@0 452 mFont);
michael@0 453
michael@0 454 cairo_matrix_t sizeMatrix, ctm;
michael@0 455 cairo_matrix_init_identity(&ctm);
michael@0 456 cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
michael@0 457
michael@0 458 if (useCairoFakeItalic) {
michael@0 459 // Skew the matrix to do fake italic if it wasn't already applied
michael@0 460 // via the LOGFONT
michael@0 461 double skewfactor = OBLIQUE_SKEW_FACTOR;
michael@0 462 cairo_matrix_t style;
michael@0 463 cairo_matrix_init(&style,
michael@0 464 1, //xx
michael@0 465 0, //yx
michael@0 466 -1 * skewfactor, //xy
michael@0 467 1, //yy
michael@0 468 0, //x0
michael@0 469 0); //y0
michael@0 470 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
michael@0 471 }
michael@0 472
michael@0 473 cairo_font_options_t *fontOptions = cairo_font_options_create();
michael@0 474 if (mAntialiasOption != kAntialiasDefault) {
michael@0 475 cairo_font_options_set_antialias(fontOptions,
michael@0 476 GetCairoAntialiasOption(mAntialiasOption));
michael@0 477 }
michael@0 478 mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix,
michael@0 479 &ctm, fontOptions);
michael@0 480 cairo_font_options_destroy(fontOptions);
michael@0 481
michael@0 482 if (!mScaledFont ||
michael@0 483 cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
michael@0 484 #ifdef DEBUG
michael@0 485 char warnBuf[1024];
michael@0 486 sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
michael@0 487 NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(),
michael@0 488 mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0);
michael@0 489 NS_WARNING(warnBuf);
michael@0 490 #endif
michael@0 491 mIsValid = false;
michael@0 492 } else {
michael@0 493 mIsValid = true;
michael@0 494 }
michael@0 495
michael@0 496 #if 0
michael@0 497 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this,
michael@0 498 NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no"));
michael@0 499 printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
michael@0 500 printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
michael@0 501 printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
michael@0 502 printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight);
michael@0 503 printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
michael@0 504 mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
michael@0 505 mMetrics->superscriptOffset, mMetrics->subscriptOffset);
michael@0 506 #endif
michael@0 507 }
michael@0 508
michael@0 509 void
michael@0 510 gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize,
michael@0 511 bool aUseGDIFakeItalic)
michael@0 512 {
michael@0 513 GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
michael@0 514
michael@0 515 uint16_t weight;
michael@0 516 if (fe->IsUserFont()) {
michael@0 517 if (fe->IsLocalUserFont()) {
michael@0 518 // for local user fonts, don't change the original weight
michael@0 519 // in the entry's logfont, because that could alter the
michael@0 520 // choice of actual face used (bug 724231)
michael@0 521 weight = 0;
michael@0 522 } else {
michael@0 523 // avoid GDI synthetic bold which occurs when weight
michael@0 524 // specified is >= font data weight + 200
michael@0 525 weight = mNeedsBold ? 700 : 200;
michael@0 526 }
michael@0 527 } else {
michael@0 528 weight = mNeedsBold ? 700 : fe->Weight();
michael@0 529 }
michael@0 530
michael@0 531 fe->FillLogFont(&aLogFont, weight, aSize,
michael@0 532 (mAntialiasOption == kAntialiasSubpixel) ? true : false);
michael@0 533
michael@0 534 // If GDI synthetic italic is wanted, force the lfItalic field to true
michael@0 535 if (aUseGDIFakeItalic) {
michael@0 536 aLogFont.lfItalic = 1;
michael@0 537 }
michael@0 538 }
michael@0 539
michael@0 540 int32_t
michael@0 541 gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
michael@0 542 {
michael@0 543 if (!mGlyphWidths) {
michael@0 544 mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200);
michael@0 545 }
michael@0 546
michael@0 547 int32_t width;
michael@0 548 if (mGlyphWidths->Get(aGID, &width)) {
michael@0 549 return width;
michael@0 550 }
michael@0 551
michael@0 552 DCFromContext dc(aCtx);
michael@0 553 AutoSelectFont fs(dc, GetHFONT());
michael@0 554
michael@0 555 int devWidth;
michael@0 556 if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
michael@0 557 // ensure width is positive, 16.16 fixed-point value
michael@0 558 width = (devWidth & 0x7fff) << 16;
michael@0 559 mGlyphWidths->Put(aGID, width);
michael@0 560 return width;
michael@0 561 }
michael@0 562
michael@0 563 return -1;
michael@0 564 }
michael@0 565
michael@0 566 void
michael@0 567 gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
michael@0 568 FontCacheSizes* aSizes) const
michael@0 569 {
michael@0 570 gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 571 aSizes->mFontInstances += aMallocSizeOf(mMetrics);
michael@0 572 if (mGlyphWidths) {
michael@0 573 aSizes->mFontInstances +=
michael@0 574 mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf);
michael@0 575 }
michael@0 576 }
michael@0 577
michael@0 578 void
michael@0 579 gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
michael@0 580 FontCacheSizes* aSizes) const
michael@0 581 {
michael@0 582 aSizes->mFontInstances += aMallocSizeOf(this);
michael@0 583 AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
michael@0 584 }

mercurial