gfx/thebes/gfxGDIFont.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxGDIFont.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,584 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "gfxGDIFont.h"
    1.10 +
    1.11 +#include "mozilla/MemoryReporting.h"
    1.12 +#include "mozilla/WindowsVersion.h"
    1.13 +
    1.14 +#include "gfxGDIShaper.h"
    1.15 +#include "gfxUniscribeShaper.h"
    1.16 +#include "gfxHarfBuzzShaper.h"
    1.17 +#include <algorithm>
    1.18 +#include "gfxGraphiteShaper.h"
    1.19 +#include "gfxWindowsPlatform.h"
    1.20 +#include "gfxContext.h"
    1.21 +#include "mozilla/Preferences.h"
    1.22 +#include "nsUnicodeProperties.h"
    1.23 +#include "gfxFontConstants.h"
    1.24 +
    1.25 +#include "cairo-win32.h"
    1.26 +
    1.27 +#define ROUND(x) floor((x) + 0.5)
    1.28 +
    1.29 +using namespace mozilla;
    1.30 +using namespace mozilla::unicode;
    1.31 +
    1.32 +static inline cairo_antialias_t
    1.33 +GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption)
    1.34 +{
    1.35 +    switch (anAntialiasOption) {
    1.36 +    default:
    1.37 +    case gfxFont::kAntialiasDefault:
    1.38 +        return CAIRO_ANTIALIAS_DEFAULT;
    1.39 +    case gfxFont::kAntialiasNone:
    1.40 +        return CAIRO_ANTIALIAS_NONE;
    1.41 +    case gfxFont::kAntialiasGrayscale:
    1.42 +        return CAIRO_ANTIALIAS_GRAY;
    1.43 +    case gfxFont::kAntialiasSubpixel:
    1.44 +        return CAIRO_ANTIALIAS_SUBPIXEL;
    1.45 +    }
    1.46 +}
    1.47 +
    1.48 +gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
    1.49 +                       const gfxFontStyle *aFontStyle,
    1.50 +                       bool aNeedsBold,
    1.51 +                       AntialiasOption anAAOption)
    1.52 +    : gfxFont(aFontEntry, aFontStyle, anAAOption),
    1.53 +      mFont(nullptr),
    1.54 +      mFontFace(nullptr),
    1.55 +      mMetrics(nullptr),
    1.56 +      mSpaceGlyph(0),
    1.57 +      mNeedsBold(aNeedsBold)
    1.58 +{
    1.59 +    if (FontCanSupportGraphite()) {
    1.60 +        mGraphiteShaper = new gfxGraphiteShaper(this);
    1.61 +    }
    1.62 +    if (FontCanSupportHarfBuzz()) {
    1.63 +        mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
    1.64 +    }
    1.65 +}
    1.66 +
    1.67 +gfxGDIFont::~gfxGDIFont()
    1.68 +{
    1.69 +    if (mScaledFont) {
    1.70 +        cairo_scaled_font_destroy(mScaledFont);
    1.71 +    }
    1.72 +    if (mFontFace) {
    1.73 +        cairo_font_face_destroy(mFontFace);
    1.74 +    }
    1.75 +    if (mFont) {
    1.76 +        ::DeleteObject(mFont);
    1.77 +    }
    1.78 +    delete mMetrics;
    1.79 +}
    1.80 +
    1.81 +void
    1.82 +gfxGDIFont::CreatePlatformShaper()
    1.83 +{
    1.84 +    mPlatformShaper = new gfxGDIShaper(this);
    1.85 +}
    1.86 +
    1.87 +gfxFont*
    1.88 +gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
    1.89 +{
    1.90 +    return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()),
    1.91 +                          &mStyle, mNeedsBold, anAAOption);
    1.92 +}
    1.93 +
    1.94 +static bool
    1.95 +UseUniscribe(gfxShapedText *aShapedText,
    1.96 +             char16ptr_t aText,
    1.97 +             uint32_t aLength)
    1.98 +{
    1.99 +    uint32_t flags = aShapedText->Flags();
   1.100 +    bool useGDI;
   1.101 +
   1.102 +    bool isXP = !IsVistaOrLater();
   1.103 +
   1.104 +    // bug 561304 - Uniscribe bug produces bad positioning at certain
   1.105 +    // font sizes on XP, so default to GDI on XP using logic of 3.6
   1.106 +
   1.107 +    useGDI = isXP &&
   1.108 +             (flags &
   1.109 +               (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | 
   1.110 +                gfxTextRunFactory::TEXT_IS_RTL)
   1.111 +             ) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
   1.112 +
   1.113 +    return !useGDI ||
   1.114 +        ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK;
   1.115 +}
   1.116 +
   1.117 +bool
   1.118 +gfxGDIFont::ShapeText(gfxContext      *aContext,
   1.119 +                      const char16_t *aText,
   1.120 +                      uint32_t         aOffset,
   1.121 +                      uint32_t         aLength,
   1.122 +                      int32_t          aScript,
   1.123 +                      gfxShapedText   *aShapedText,
   1.124 +                      bool             aPreferPlatformShaping)
   1.125 +{
   1.126 +    if (!mMetrics) {
   1.127 +        Initialize();
   1.128 +    }
   1.129 +    if (!mIsValid) {
   1.130 +        NS_WARNING("invalid font! expect incorrect text rendering");
   1.131 +        return false;
   1.132 +    }
   1.133 +
   1.134 +    bool ok = false;
   1.135 +
   1.136 +    // Ensure the cairo font is set up, so there's no risk it'll fall back to
   1.137 +    // creating a "toy" font internally (see bug 544617).
   1.138 +    // We must check that this succeeded, otherwise we risk cairo creating the
   1.139 +    // wrong kind of font internally as a fallback (bug 744480).
   1.140 +    if (!SetupCairoFont(aContext)) {
   1.141 +        return false;
   1.142 +    }
   1.143 +
   1.144 +    if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
   1.145 +        ok = mGraphiteShaper->ShapeText(aContext, aText,
   1.146 +                                        aOffset, aLength,
   1.147 +                                        aScript, aShapedText);
   1.148 +    }
   1.149 +
   1.150 +    if (!ok && mHarfBuzzShaper) {
   1.151 +        if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) ||
   1.152 +            (!IsVistaOrLater() &&
   1.153 +             ScriptShapingType(aScript) == SHAPING_INDIC &&
   1.154 +             !Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe",
   1.155 +                                   false))) {
   1.156 +            ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
   1.157 +                                            aScript, aShapedText);
   1.158 +        }
   1.159 +    }
   1.160 +
   1.161 +    if (!ok) {
   1.162 +        GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
   1.163 +        bool preferUniscribe =
   1.164 +            (!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI;
   1.165 +
   1.166 +        if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) {
   1.167 +            // first try Uniscribe
   1.168 +            if (!mUniscribeShaper) {
   1.169 +                mUniscribeShaper = new gfxUniscribeShaper(this);
   1.170 +            }
   1.171 +
   1.172 +            ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength,
   1.173 +                                             aScript, aShapedText);
   1.174 +            if (!ok) {
   1.175 +                // fallback to GDI shaping
   1.176 +                if (!mPlatformShaper) {
   1.177 +                    CreatePlatformShaper();
   1.178 +                }
   1.179 +
   1.180 +                ok = mPlatformShaper->ShapeText(aContext, aText, aOffset,
   1.181 +                                                aLength, aScript, aShapedText);
   1.182 +            }
   1.183 +        } else {
   1.184 +            // first use GDI
   1.185 +            if (!mPlatformShaper) {
   1.186 +                CreatePlatformShaper();
   1.187 +            }
   1.188 +
   1.189 +            ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
   1.190 +                                            aScript, aShapedText);
   1.191 +            if (!ok) {
   1.192 +                // try Uniscribe if GDI failed
   1.193 +                if (!mUniscribeShaper) {
   1.194 +                    mUniscribeShaper = new gfxUniscribeShaper(this);
   1.195 +                }
   1.196 +
   1.197 +                // use Uniscribe shaping
   1.198 +                ok = mUniscribeShaper->ShapeText(aContext, aText,
   1.199 +                                                 aOffset, aLength,
   1.200 +                                                 aScript, aShapedText);
   1.201 +            }
   1.202 +        }
   1.203 +
   1.204 +#if DEBUG
   1.205 +        if (!ok) {
   1.206 +            NS_ConvertUTF16toUTF8 name(GetName());
   1.207 +            char msg[256];
   1.208 +
   1.209 +            sprintf(msg, 
   1.210 +                    "text shaping with both uniscribe and GDI failed for"
   1.211 +                    " font: %s",
   1.212 +                    name.get());
   1.213 +            NS_WARNING(msg);
   1.214 +        }
   1.215 +#endif
   1.216 +    }
   1.217 +
   1.218 +    PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
   1.219 +
   1.220 +    return ok;
   1.221 +}
   1.222 +
   1.223 +const gfxFont::Metrics&
   1.224 +gfxGDIFont::GetMetrics()
   1.225 +{
   1.226 +    if (!mMetrics) {
   1.227 +        Initialize();
   1.228 +    }
   1.229 +    return *mMetrics;
   1.230 +}
   1.231 +
   1.232 +uint32_t
   1.233 +gfxGDIFont::GetSpaceGlyph()
   1.234 +{
   1.235 +    if (!mMetrics) {
   1.236 +        Initialize();
   1.237 +    }
   1.238 +    return mSpaceGlyph;
   1.239 +}
   1.240 +
   1.241 +bool
   1.242 +gfxGDIFont::SetupCairoFont(gfxContext *aContext)
   1.243 +{
   1.244 +    if (!mMetrics) {
   1.245 +        Initialize();
   1.246 +    }
   1.247 +    if (!mScaledFont ||
   1.248 +        cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
   1.249 +        // Don't cairo_set_scaled_font as that would propagate the error to
   1.250 +        // the cairo_t, precluding any further drawing.
   1.251 +        return false;
   1.252 +    }
   1.253 +    cairo_set_scaled_font(aContext->GetCairo(), mScaledFont);
   1.254 +    return true;
   1.255 +}
   1.256 +
   1.257 +gfxFont::RunMetrics
   1.258 +gfxGDIFont::Measure(gfxTextRun *aTextRun,
   1.259 +                    uint32_t aStart, uint32_t aEnd,
   1.260 +                    BoundingBoxType aBoundingBoxType,
   1.261 +                    gfxContext *aRefContext,
   1.262 +                    Spacing *aSpacing)
   1.263 +{
   1.264 +    gfxFont::RunMetrics metrics =
   1.265 +        gfxFont::Measure(aTextRun, aStart, aEnd,
   1.266 +                         aBoundingBoxType, aRefContext, aSpacing);
   1.267 +
   1.268 +    // if aBoundingBoxType is LOOSE_INK_EXTENTS
   1.269 +    // and the underlying cairo font may be antialiased,
   1.270 +    // we can't trust Windows to have considered all the pixels
   1.271 +    // so we need to add "padding" to the bounds.
   1.272 +    // (see bugs 475968, 439831, compare also bug 445087)
   1.273 +    if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
   1.274 +        mAntialiasOption != kAntialiasNone &&
   1.275 +        metrics.mBoundingBox.width > 0) {
   1.276 +        metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit();
   1.277 +        metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3;
   1.278 +    }
   1.279 +
   1.280 +    return metrics;
   1.281 +}
   1.282 +
   1.283 +#define OBLIQUE_SKEW_FACTOR 0.3
   1.284 +
   1.285 +void
   1.286 +gfxGDIFont::Initialize()
   1.287 +{
   1.288 +    NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak");
   1.289 +
   1.290 +    LOGFONTW logFont;
   1.291 +
   1.292 +    // Figure out if we want to do synthetic oblique styling.
   1.293 +    GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry());
   1.294 +    bool wantFakeItalic =
   1.295 +        (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) &&
   1.296 +        !fe->IsItalic();
   1.297 +
   1.298 +    // If the font's family has an actual italic face (but font matching
   1.299 +    // didn't choose it), we have to use a cairo transform instead of asking
   1.300 +    // GDI to italicize, because that would use a different face and result
   1.301 +    // in a possible glyph ID mismatch between shaping and rendering.
   1.302 +    //
   1.303 +    // We use the mFamilyHasItalicFace flag in the entry in case of user fonts,
   1.304 +    // where the *CSS* family may not know about italic faces that are present
   1.305 +    // in the *GDI* family, and which GDI would use if we asked it to perform
   1.306 +    // the "italicization".
   1.307 +    bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace;
   1.308 +
   1.309 +    if (mAdjustedSize == 0.0) {
   1.310 +        mAdjustedSize = mStyle.size;
   1.311 +        if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) {
   1.312 +            // to implement font-size-adjust, we first create the "unadjusted" font
   1.313 +            FillLogFont(logFont, mAdjustedSize,
   1.314 +                        wantFakeItalic && !useCairoFakeItalic);
   1.315 +            mFont = ::CreateFontIndirectW(&logFont);
   1.316 +
   1.317 +            // initialize its metrics so we can calculate size adjustment
   1.318 +            Initialize();
   1.319 +
   1.320 +            // calculate the properly adjusted size, and then proceed
   1.321 +            // to recreate mFont and recalculate metrics
   1.322 +            gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight;
   1.323 +            mAdjustedSize = mStyle.GetAdjustedSize(aspect);
   1.324 +
   1.325 +            // delete the temporary font and metrics
   1.326 +            ::DeleteObject(mFont);
   1.327 +            mFont = nullptr;
   1.328 +            delete mMetrics;
   1.329 +            mMetrics = nullptr;
   1.330 +        }
   1.331 +    }
   1.332 +
   1.333 +    // (bug 724231) for local user fonts, we don't use GDI's synthetic bold,
   1.334 +    // as it could lead to a different, incompatible face being used
   1.335 +    // but instead do our own multi-striking
   1.336 +    if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) {
   1.337 +        mApplySyntheticBold = true;
   1.338 +    }
   1.339 +
   1.340 +    // this may end up being zero
   1.341 +    mAdjustedSize = ROUND(mAdjustedSize);
   1.342 +    FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic);
   1.343 +    mFont = ::CreateFontIndirectW(&logFont);
   1.344 +
   1.345 +    mMetrics = new gfxFont::Metrics;
   1.346 +    ::memset(mMetrics, 0, sizeof(*mMetrics));
   1.347 +
   1.348 +    AutoDC dc;
   1.349 +    SetGraphicsMode(dc.GetDC(), GM_ADVANCED);
   1.350 +    AutoSelectFont selectFont(dc.GetDC(), mFont);
   1.351 +
   1.352 +    // Get font metrics if size > 0
   1.353 +    if (mAdjustedSize > 0.0) {
   1.354 +
   1.355 +        OUTLINETEXTMETRIC oMetrics;
   1.356 +        TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
   1.357 +
   1.358 +        if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) {
   1.359 +            mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y;
   1.360 +            // Some fonts have wrong sign on their subscript offset, bug 410917.
   1.361 +            mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y);
   1.362 +            mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize;
   1.363 +            mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition;
   1.364 +            mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize;
   1.365 +            mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition;
   1.366 +
   1.367 +            const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
   1.368 +            GLYPHMETRICS gm;
   1.369 +            DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix);
   1.370 +            if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
   1.371 +                // 56% of ascent, best guess for true type
   1.372 +                mMetrics->xHeight =
   1.373 +                    ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
   1.374 +            } else {
   1.375 +                mMetrics->xHeight = gm.gmptGlyphOrigin.y;
   1.376 +            }
   1.377 +            mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
   1.378 +            gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent;
   1.379 +            mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight);
   1.380 +            mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent;
   1.381 +            if (oMetrics.otmEMSquare > 0) {
   1.382 +                mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare);
   1.383 +            }
   1.384 +        } else {
   1.385 +            // Make a best-effort guess at extended metrics
   1.386 +            // this is based on general typographic guidelines
   1.387 +
   1.388 +            // GetTextMetrics can fail if the font file has been removed
   1.389 +            // or corrupted recently.
   1.390 +            BOOL result = GetTextMetrics(dc.GetDC(), &metrics);
   1.391 +            if (!result) {
   1.392 +                NS_WARNING("Missing or corrupt font data, fasten your seatbelt");
   1.393 +                mIsValid = false;
   1.394 +                memset(mMetrics, 0, sizeof(*mMetrics));
   1.395 +                return;
   1.396 +            }
   1.397 +
   1.398 +            mMetrics->xHeight =
   1.399 +                ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR);
   1.400 +            mMetrics->superscriptOffset = mMetrics->xHeight;
   1.401 +            mMetrics->subscriptOffset = mMetrics->xHeight;
   1.402 +            mMetrics->strikeoutSize = 1;
   1.403 +            mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight
   1.404 +            mMetrics->underlineSize = 1;
   1.405 +            mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent
   1.406 +            mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading;
   1.407 +            mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading;
   1.408 +            mMetrics->emDescent = metrics.tmDescent;
   1.409 +        }
   1.410 +
   1.411 +        mMetrics->internalLeading = metrics.tmInternalLeading;
   1.412 +        mMetrics->externalLeading = metrics.tmExternalLeading;
   1.413 +        mMetrics->maxHeight = metrics.tmHeight;
   1.414 +        mMetrics->maxAscent = metrics.tmAscent;
   1.415 +        mMetrics->maxDescent = metrics.tmDescent;
   1.416 +        mMetrics->maxAdvance = metrics.tmMaxCharWidth;
   1.417 +        mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth);
   1.418 +        // The font is monospace when TMPF_FIXED_PITCH is *not* set!
   1.419 +        // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx
   1.420 +        if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
   1.421 +            mMetrics->maxAdvance = mMetrics->aveCharWidth;
   1.422 +        }
   1.423 +
   1.424 +        // Cache the width of a single space.
   1.425 +        SIZE size;
   1.426 +        GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size);
   1.427 +        mMetrics->spaceWidth = ROUND(size.cx);
   1.428 +
   1.429 +        // Cache the width of digit zero.
   1.430 +        // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx)
   1.431 +        // does not say what the failure modes for GetTextExtentPoint32 are -
   1.432 +        // is it safe to assume it will fail iff the font has no '0'?
   1.433 +        if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) {
   1.434 +            mMetrics->zeroOrAveCharWidth = ROUND(size.cx);
   1.435 +        } else {
   1.436 +            mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
   1.437 +        }
   1.438 +
   1.439 +        WORD glyph;
   1.440 +        DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph,
   1.441 +                                     GGI_MARK_NONEXISTING_GLYPHS);
   1.442 +        if (ret != GDI_ERROR && glyph != 0xFFFF) {
   1.443 +            mSpaceGlyph = glyph;
   1.444 +        }
   1.445 +
   1.446 +        SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
   1.447 +    }
   1.448 +
   1.449 +    if (IsSyntheticBold()) {
   1.450 +        mMetrics->aveCharWidth += GetSyntheticBoldOffset();
   1.451 +        mMetrics->maxAdvance += GetSyntheticBoldOffset();
   1.452 +    }
   1.453 +
   1.454 +    mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont,
   1.455 +                                                                mFont);
   1.456 +
   1.457 +    cairo_matrix_t sizeMatrix, ctm;
   1.458 +    cairo_matrix_init_identity(&ctm);
   1.459 +    cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize);
   1.460 +
   1.461 +    if (useCairoFakeItalic) {
   1.462 +        // Skew the matrix to do fake italic if it wasn't already applied
   1.463 +        // via the LOGFONT
   1.464 +        double skewfactor = OBLIQUE_SKEW_FACTOR;
   1.465 +        cairo_matrix_t style;
   1.466 +        cairo_matrix_init(&style,
   1.467 +                          1,                //xx
   1.468 +                          0,                //yx
   1.469 +                          -1 * skewfactor,  //xy
   1.470 +                          1,                //yy
   1.471 +                          0,                //x0
   1.472 +                          0);               //y0
   1.473 +        cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style);
   1.474 +    }
   1.475 +
   1.476 +    cairo_font_options_t *fontOptions = cairo_font_options_create();
   1.477 +    if (mAntialiasOption != kAntialiasDefault) {
   1.478 +        cairo_font_options_set_antialias(fontOptions,
   1.479 +            GetCairoAntialiasOption(mAntialiasOption));
   1.480 +    }
   1.481 +    mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix,
   1.482 +                                           &ctm, fontOptions);
   1.483 +    cairo_font_options_destroy(fontOptions);
   1.484 +
   1.485 +    if (!mScaledFont ||
   1.486 +        cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) {
   1.487 +#ifdef DEBUG
   1.488 +        char warnBuf[1024];
   1.489 +        sprintf(warnBuf, "Failed to create scaled font: %s status: %d",
   1.490 +                NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(),
   1.491 +                mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0);
   1.492 +        NS_WARNING(warnBuf);
   1.493 +#endif
   1.494 +        mIsValid = false;
   1.495 +    } else {
   1.496 +        mIsValid = true;
   1.497 +    }
   1.498 +
   1.499 +#if 0
   1.500 +    printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this,
   1.501 +           NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no"));
   1.502 +    printf("    emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent);
   1.503 +    printf("    maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance);
   1.504 +    printf("    internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading);
   1.505 +    printf("    spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight);
   1.506 +    printf("    uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n",
   1.507 +           mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize,
   1.508 +           mMetrics->superscriptOffset, mMetrics->subscriptOffset);
   1.509 +#endif
   1.510 +}
   1.511 +
   1.512 +void
   1.513 +gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize,
   1.514 +                        bool aUseGDIFakeItalic)
   1.515 +{
   1.516 +    GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
   1.517 +
   1.518 +    uint16_t weight;
   1.519 +    if (fe->IsUserFont()) {
   1.520 +        if (fe->IsLocalUserFont()) {
   1.521 +            // for local user fonts, don't change the original weight
   1.522 +            // in the entry's logfont, because that could alter the
   1.523 +            // choice of actual face used (bug 724231)
   1.524 +            weight = 0;
   1.525 +        } else {
   1.526 +            // avoid GDI synthetic bold which occurs when weight
   1.527 +            // specified is >= font data weight + 200
   1.528 +            weight = mNeedsBold ? 700 : 200;
   1.529 +        }
   1.530 +    } else {
   1.531 +        weight = mNeedsBold ? 700 : fe->Weight();
   1.532 +    }
   1.533 +
   1.534 +    fe->FillLogFont(&aLogFont, weight, aSize, 
   1.535 +                    (mAntialiasOption == kAntialiasSubpixel) ? true : false);
   1.536 +
   1.537 +    // If GDI synthetic italic is wanted, force the lfItalic field to true
   1.538 +    if (aUseGDIFakeItalic) {
   1.539 +        aLogFont.lfItalic = 1;
   1.540 +    }
   1.541 +}
   1.542 +
   1.543 +int32_t
   1.544 +gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
   1.545 +{
   1.546 +    if (!mGlyphWidths) {
   1.547 +        mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200);
   1.548 +    }
   1.549 +
   1.550 +    int32_t width;
   1.551 +    if (mGlyphWidths->Get(aGID, &width)) {
   1.552 +        return width;
   1.553 +    }
   1.554 +
   1.555 +    DCFromContext dc(aCtx);
   1.556 +    AutoSelectFont fs(dc, GetHFONT());
   1.557 +
   1.558 +    int devWidth;
   1.559 +    if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) {
   1.560 +        // ensure width is positive, 16.16 fixed-point value
   1.561 +        width = (devWidth & 0x7fff) << 16;
   1.562 +        mGlyphWidths->Put(aGID, width);
   1.563 +        return width;
   1.564 +    }
   1.565 +
   1.566 +    return -1;
   1.567 +}
   1.568 +
   1.569 +void
   1.570 +gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
   1.571 +                                   FontCacheSizes* aSizes) const
   1.572 +{
   1.573 +    gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.574 +    aSizes->mFontInstances += aMallocSizeOf(mMetrics);
   1.575 +    if (mGlyphWidths) {
   1.576 +        aSizes->mFontInstances +=
   1.577 +            mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf);
   1.578 +    }
   1.579 +}
   1.580 +
   1.581 +void
   1.582 +gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
   1.583 +                                   FontCacheSizes* aSizes) const
   1.584 +{
   1.585 +    aSizes->mFontInstances += aMallocSizeOf(this);
   1.586 +    AddSizeOfExcludingThis(aMallocSizeOf, aSizes);
   1.587 +}

mercurial