Bug 1458004 - Link font-style values italic / oblique to the appropriate variation-font axes or synthetic styling. r=jwatt
authorJonathan Kew <jkew@mozilla.com>
Wed, 09 May 2018 13:49:24 +0100
changeset 417568 18cf597d218bce788f581545819a3907e16d5884
parent 417567 7e3488313a539b11ad1c684490c68b52f6a89349
child 417569 1ee5b2531836bbdb799a4dd1846430455e74ad51
push id33971
push usercsabou@mozilla.com
push dateWed, 09 May 2018 17:28:02 +0000
treeherdermozilla-central@76aad17f5b50 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1458004
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1458004 - Link font-style values italic / oblique to the appropriate variation-font axes or synthetic styling. r=jwatt
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
layout/reftests/mathml/reftest.list
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -746,16 +746,42 @@ gfxShapedText::AdjustAdvancesForSyntheti
                  } else {
                      details[detailedLength - 1].mAdvance += synAppUnitOffset;
                  }
              }
          }
     }
 }
 
+float
+gfxFont::SkewForSyntheticOblique() const
+{
+    // Precomputed value of tan(14deg), the default italic/oblique slant;
+    // avoids calling tan() at runtime except for custom oblique values.
+    const float kTan14deg = 0.249328f;
+
+    // If the style doesn't call for italic/oblique, or if the face already
+    // provides it, no synthetic style should be added.
+    if (mStyle.style == FontSlantStyle::Normal() ||
+        !mStyle.allowSyntheticStyle ||
+        !mFontEntry->IsUpright()) {
+        return 0.0f;
+    }
+
+    // If style calls for italic, and face doesn't support it, use default
+    // oblique angle as a simulation.
+    if (mStyle.style.IsItalic()) {
+        return mFontEntry->SupportsItalic() ? 0.0f : kTan14deg;
+    }
+
+    // Default oblique angle
+    return mStyle.style == FontSlantStyle::Oblique()
+           ? kTan14deg : tan(mStyle.style.ObliqueAngle() * (M_PI / 180.0));
+}
+
 void
 gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, bool aOtherIsOnLeft)
 {
     mAscent = std::max(mAscent, aOther.mAscent);
     mDescent = std::max(mDescent, aOther.mDescent);
     if (aOtherIsOnLeft) {
         mBoundingBox =
             (mBoundingBox + gfxPoint(aOther.mAdvanceWidth, 0)).Union(aOther.mBoundingBox);
@@ -1976,27 +2002,28 @@ gfxFont::DrawOneGlyph(uint32_t aGlyphID,
 
     if (FC == FontComplexityT::ComplexFont) {
         const FontDrawParams& fontParams(aBuffer.mFontParams);
 
         auto* textDrawer = runParams.context->GetTextDrawer();
 
         gfxContextMatrixAutoSaveRestore matrixRestore;
 
-        if (fontParams.needsOblique && fontParams.isVerticalFont && !textDrawer) {
+        if (fontParams.obliqueSkew != 0.0f &&
+            fontParams.isVerticalFont && !textDrawer) {
             // We have to flush each glyph individually when doing
             // synthetic-oblique for vertical-upright text, because
             // the skew transform needs to be applied to a separate
             // origin for each glyph, not once for the whole run.
             aBuffer.Flush();
             matrixRestore.SetContext(runParams.context);
             gfx::Matrix mat =
                 runParams.context->CurrentMatrix().
                 PreTranslate(devPt).
-                PreMultiply(gfx::Matrix(1, 0, -OBLIQUE_SKEW_FACTOR, 1, 0, 0)).
+                PreMultiply(gfx::Matrix(1, 0, -fontParams.obliqueSkew, 1, 0, 0)).
                 PreTranslate(-devPt);
             runParams.context->SetMatrix(mat);
         }
 
         if (fontParams.haveSVGGlyphs) {
             if (!runParams.paintSVGGlyphs) {
                 return;
             }
@@ -2026,17 +2053,18 @@ gfxFont::DrawOneGlyph(uint32_t aGlyphID,
             if (fontParams.isVerticalFont) {
                 devPt.y += fontParams.synBoldOnePixelOffset;
             } else {
                 devPt.x += fontParams.synBoldOnePixelOffset;
             }
             aBuffer.OutputGlyph(aGlyphID, devPt);
         }
 
-        if (fontParams.needsOblique && fontParams.isVerticalFont && !textDrawer) {
+        if (fontParams.obliqueSkew != 0.0f &&
+            fontParams.isVerticalFont && !textDrawer) {
             aBuffer.Flush();
         }
     } else {
         aBuffer.OutputGlyph(aGlyphID, devPt);
     }
 
     *aEmittedGlyphs = true;
 }
@@ -2077,22 +2105,23 @@ gfxFont::DrawMissingGlyph(const TextRunD
                  height, advanceDevUnits) :
             Rect(pt.x, pt.y - height,
                  advanceDevUnits, height);
 
         // If there's a fake-italic skew in effect as part
         // of the drawTarget's transform, we need to undo
         // this before drawing the hexbox. (Bug 983985)
         gfxContextMatrixAutoSaveRestore matrixRestore;
-        if (aFontParams.needsOblique && !aFontParams.isVerticalFont && !textDrawer) {
+        if (aFontParams.obliqueSkew != 0.0f &&
+            !aFontParams.isVerticalFont && !textDrawer) {
             matrixRestore.SetContext(aRunParams.context);
             gfx::Matrix mat =
                 aRunParams.context->CurrentMatrix().
                 PreTranslate(pt).
-                PreMultiply(gfx::Matrix(1, 0, OBLIQUE_SKEW_FACTOR, 1, 0, 0)).
+                PreMultiply(gfx::Matrix(1, 0, aFontParams.obliqueSkew, 1, 0, 0)).
                 PreTranslate(-pt);
             aRunParams.context->SetMatrix(mat);
         }
 
         gfxFontMissingGlyphs::DrawMissingGlyph(
             aDetails->mGlyphID, glyphRect, *aRunParams.dt,
             PatternFromState(aRunParams.context),
             1.0 / aRunParams.devPerApp, matPtr);
@@ -2161,17 +2190,17 @@ gfxFont::Draw(const gfxTextRun *aTextRun
 
     fontParams.scaledFont = GetScaledFont(aRunParams.dt);
     if (!fontParams.scaledFont) {
         return;
     }
 
     auto* textDrawer = aRunParams.context->GetTextDrawer();
 
-    fontParams.needsOblique = IsSyntheticOblique();
+    fontParams.obliqueSkew = SkewForSyntheticOblique();
     fontParams.haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
     fontParams.haveColorGlyphs = GetFontEntry()->TryGetColorGlyphs();
     fontParams.contextPaint = aRunParams.runContextPaint;
 
     if (textDrawer) {
         Color color;
         if (fontParams.haveSVGGlyphs ||
             (fontParams.haveColorGlyphs &&
@@ -2269,34 +2298,34 @@ gfxFont::Draw(const gfxTextRun *aTextRun
         // [1] See http://www.microsoft.com/typography/otspec/base.htm
         if (aTextRun->UseCenterBaseline()) {
             const Metrics& metrics = GetMetrics(eHorizontal);
             float baseAdj = (metrics.emAscent - metrics.emDescent) / 2;
             baseline += baseAdj * aTextRun->GetAppUnitsPerDevUnit() * baselineDir;
         }
     }
 
-    if (fontParams.needsOblique) {
+    if (fontParams.obliqueSkew != 0.0f) {
         if (textDrawer) {
             glyphFlagsRestore.Save(textDrawer);
             textDrawer->SetWRGlyphFlags(textDrawer->GetWRGlyphFlags() |
                                         wr::FontInstanceFlags::SYNTHETIC_ITALICS);
         } else if (!fontParams.isVerticalFont) {
             // Adjust matrix for synthetic-oblique, except if we're doing vertical-
             // upright text, in which case this will be handled for each glyph
             // individually in DrawOneGlyph.
             if (!matrixRestore.HasMatrix()) {
                 matrixRestore.SetContext(aRunParams.context);
             }
             gfx::Point p(aPt->x * aRunParams.devPerApp,
                          aPt->y * aRunParams.devPerApp);
             gfx::Matrix mat =
                 aRunParams.context->CurrentMatrix().
                 PreTranslate(p).
-                PreMultiply(gfx::Matrix(1, 0, -OBLIQUE_SKEW_FACTOR, 1, 0, 0)).
+                PreMultiply(gfx::Matrix(1, 0, -fontParams.obliqueSkew, 1, 0, 0)).
                 PreTranslate(-p);
             aRunParams.context->SetMatrix(mat);
         }
     }
 
     RefPtr<SVGContextPaint> contextPaint;
     if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) {
         // If no pattern is specified for fill, use the current pattern
@@ -2345,17 +2374,18 @@ gfxFont::Draw(const gfxTextRun *aTextRun
     {
         // Select appropriate version of the templated DrawGlyphs method
         // to output glyphs to the buffer, depending on complexity needed
         // for the type of font, and whether added inter-glyph spacing
         // is specified.
         GlyphBufferAzure buffer(aRunParams, fontParams);
         if (fontParams.haveSVGGlyphs || fontParams.haveColorGlyphs ||
             fontParams.extraStrikes ||
-            (fontParams.needsOblique && fontParams.isVerticalFont && !textDrawer)) {
+            (fontParams.obliqueSkew != 0.0f &&
+             fontParams.isVerticalFont && !textDrawer)) {
             if (aRunParams.spacing) {
                 emittedGlyphs =
                     DrawGlyphs<FontComplexityT::ComplexFont,
                                SpacingT::HasSpacing>(aTextRun, aStart,
                                                      aEnd - aStart, aPt,
                                                      buffer);
             } else {
                 emittedGlyphs =
@@ -2673,24 +2703,28 @@ gfxFont::Measure(const gfxTextRun *aText
         if (isRTL) {
             metrics.mBoundingBox -= gfxPoint(x, 0);
         }
     }
 
     // If the font may be rendered with a fake-italic effect, we need to allow
     // for the top-right of the glyphs being skewed to the right, and the
     // bottom-left being skewed further left.
-    if (mStyle.style != FontSlantStyle::Normal() &&
-        mFontEntry->IsUpright() &&
-        mStyle.allowSyntheticStyle) {
+    gfx::Float obliqueSkew = SkewForSyntheticOblique();
+    if (obliqueSkew != 0.0f) {
         gfxFloat extendLeftEdge =
-            ceil(OBLIQUE_SKEW_FACTOR * metrics.mBoundingBox.YMost());
+            obliqueSkew < 0.0f
+                ? ceil(-obliqueSkew * -metrics.mBoundingBox.Y())
+                : ceil(obliqueSkew * metrics.mBoundingBox.YMost());
         gfxFloat extendRightEdge =
-            ceil(OBLIQUE_SKEW_FACTOR * -metrics.mBoundingBox.Y());
-        metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() + extendLeftEdge + extendRightEdge);
+            obliqueSkew < 0.0f
+                ? ceil(-obliqueSkew * metrics.mBoundingBox.YMost())
+                : ceil(obliqueSkew * -metrics.mBoundingBox.Y());
+        metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() +
+                                      extendLeftEdge + extendRightEdge);
         metrics.mBoundingBox.MoveByX(-extendLeftEdge);
     }
 
     if (baselineOffset != 0) {
         metrics.mAscent -= baselineOffset;
         metrics.mDescent += baselineOffset;
         metrics.mBoundingBox.MoveByY(baselineOffset);
     }
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1815,23 +1815,19 @@ public:
     void SetupGlyphExtents(DrawTarget* aDrawTarget, uint32_t aGlyphID,
                            bool aNeedTight, gfxGlyphExtents *aExtents);
 
     // This is called by the default Draw() implementation above.
     virtual bool SetupCairoFont(DrawTarget* aDrawTarget) = 0;
 
     virtual bool AllowSubpixelAA() { return true; }
 
-    bool IsSyntheticBold() { return mApplySyntheticBold; }
+    bool IsSyntheticBold() const { return mApplySyntheticBold; }
 
-    bool IsSyntheticOblique() {
-        return mFontEntry->IsUpright() &&
-               mStyle.style != FontSlantStyle::Normal() &&
-               mStyle.allowSyntheticStyle;
-    }
+    float SkewForSyntheticOblique() const;
 
     // Amount by which synthetic bold "fattens" the glyphs:
     // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
     // so that the result ranges from 0.25 to 1.0; thereafter,
     // simply use (S / T).
     gfxFloat GetSyntheticBoldOffset() {
         gfxFloat size = GetAdjustedSize();
         const gfxFloat threshold = 48.0;
@@ -2369,23 +2365,23 @@ struct MOZ_STACK_CLASS TextRunDrawParams
     bool                     isRTL;
     bool                     paintSVGGlyphs;
 };
 
 struct MOZ_STACK_CLASS FontDrawParams {
     RefPtr<mozilla::gfx::ScaledFont>            scaledFont;
     mozilla::SVGContextPaint *contextPaint;
     mozilla::gfx::Float       synBoldOnePixelOffset;
+    mozilla::gfx::Float       obliqueSkew;
     int32_t                   extraStrikes;
     mozilla::gfx::DrawOptions drawOptions;
     gfxFloat                  advanceDirection;
     bool                      isVerticalFont;
     bool                      haveSVGGlyphs;
     bool                      haveColorGlyphs;
-    bool                      needsOblique;
 };
 
 struct MOZ_STACK_CLASS EmphasisMarkDrawParams {
     gfxContext* context;
     gfxFont::Spacing* spacing;
     gfxTextRun* mark;
     gfxFloat advance;
     gfxFloat direction;
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -76,17 +76,17 @@ gfxFontEntry::gfxFontEntry() :
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mCheckedForVariableWeight(false)
+    mCheckedForVariationAxes(false)
 {
     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
 }
 
 gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
     mName(aName),
     mFixedPitch(false),
@@ -106,17 +106,17 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mCheckedForVariableWeight(false)
+    mCheckedForVariationAxes(false)
 {
     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
 }
 
 gfxFontEntry::~gfxFontEntry()
 {
     // Should not be dropped by stylo
@@ -1068,61 +1068,99 @@ gfxFontEntry::SetupVariationRanges()
                     mStandardFace = false;
                 }
                 mStyleRange =
                     SlantStyleRange(FontSlantStyle::Oblique(axis.mMinValue),
                                     FontSlantStyle::Oblique(axis.mMaxValue));
             }
             break;
 
-        // case HB_TAG('i','t','a','l'): // XXX how to handle?
+        case HB_TAG('i','t','a','l'):
+            if (axis.mMinValue <= 0.0f && axis.mMaxValue >= 1.0f) {
+                if (axis.mDefaultValue != 0.0f) {
+                    mStandardFace = false;
+                }
+                mStyleRange =
+                    SlantStyleRange(FontSlantStyle::Normal(),
+                                    FontSlantStyle::Italic());
+            }
+            break;
+
         default:
             continue;
         }
     }
 }
 
+void
+gfxFontEntry::CheckForVariationAxes()
+{
+    if (HasVariations()) {
+        AutoTArray<gfxFontVariationAxis,4> axes;
+        GetVariationAxes(axes);
+        for (const auto& axis : axes) {
+            if (axis.mTag == HB_TAG('w','g','h','t') &&
+                axis.mMaxValue >= 600.0f) {
+                mRangeFlags |= RangeFlags::eBoldVariableWeight;
+            } else if (axis.mTag == HB_TAG('i','t','a','l') &&
+                axis.mMaxValue >= 1.0f) {
+                mRangeFlags |= RangeFlags::eItalicVariation;
+            }
+        }
+    }
+    mCheckedForVariationAxes = true;
+}
+
 bool
 gfxFontEntry::HasBoldVariableWeight()
 {
     MOZ_ASSERT(!mIsUserFontContainer,
                "should not be called for user-font containers!");
 
     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
         return false;
     }
 
-    if (!mCheckedForVariableWeight) {
-        if (HasVariations()) {
-            AutoTArray<gfxFontVariationAxis,4> axes;
-            GetVariationAxes(axes);
-            for (const auto& axis : axes) {
-                if (axis.mTag == HB_TAG('w','g','h','t') &&
-                    axis.mMaxValue >= 600.0f) {
-                    mRangeFlags |= RangeFlags::eBoldVariableWeight;
-                    break;
-                }
-            }
-        }
-        mCheckedForVariableWeight = true;
+    if (!mCheckedForVariationAxes) {
+        CheckForVariationAxes();
     }
 
-    return (mRangeFlags & RangeFlags::eBoldVariableWeight) ==
-           RangeFlags::eBoldVariableWeight;
+    return bool(mRangeFlags & RangeFlags::eBoldVariableWeight);
+}
+
+bool
+gfxFontEntry::HasItalicVariation()
+{
+    MOZ_ASSERT(!mIsUserFontContainer,
+               "should not be called for user-font containers!");
+
+    if (!gfxPlatform::GetPlatform()->HasVariationFontSupport()) {
+        return false;
+    }
+
+    if (!mCheckedForVariationAxes) {
+        CheckForVariationAxes();
+    }
+
+    return bool(mRangeFlags & RangeFlags::eItalicVariation);
 }
 
 void
 gfxFontEntry::GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
                                     const gfxFontStyle& aStyle)
 {
     if (!gfxPlatform::GetPlatform()->HasVariationFontSupport() ||
         !StaticPrefs::layout_css_font_variations_enabled()) {
         return;
     }
 
+    if (!HasVariations()) {
+        return;
+    }
+
     // Resolve high-level CSS properties from the requested style
     // (font-{style,weight,stretch}) to the appropriate variations.
     // The value used is clamped to the range available in the font face,
     // unless the face is a user font where no explicit descriptor was
     // given, indicated by the corresponding 'auto' range-flag.
 
     // We don't do these mappings if the font entry has weight and/or stretch
     // ranges that do not appear to use the CSS property scale. Some older
@@ -1142,17 +1180,22 @@ gfxFontEntry::GetVariationsForStyle(nsTA
         float stretch =
             (IsUserFont() && (mRangeFlags & RangeFlags::eAutoStretch))
                 ? aStyle.stretch.Percentage()
                 : Stretch().Clamp(aStyle.stretch).Percentage();
         aResult.AppendElement(gfxFontVariation{HB_TAG('w','d','t','h'),
                                                stretch});
     }
 
-    if (SlantStyle().Min().IsOblique()) {
+    if (aStyle.style.IsItalic() && SupportsItalic()) {
+        // The 'ital' axis is normally a binary toggle; intermediate values
+        // can only be set using font-variation-settings.
+        aResult.AppendElement(gfxFontVariation{HB_TAG('i','t','a','l'),
+                                               1.0f});
+    } else if (SlantStyle().Min().IsOblique()) {
         // Figure out what slant angle we should try to match from the
         // requested style.
         float angle =
             aStyle.style.IsNormal()
                 ? 0.0f
                 : aStyle.style.IsItalic()
                     ? FontSlantStyle::Oblique().ObliqueAngle()
                     : aStyle.style.ObliqueAngle();
@@ -1161,21 +1204,16 @@ gfxFontEntry::GetVariationsForStyle(nsTA
         if (!(IsUserFont() && (mRangeFlags & RangeFlags::eAutoSlantStyle))) {
             angle = SlantStyle().Clamp(
                 FontSlantStyle::Oblique(angle)).ObliqueAngle();
         }
         aResult.AppendElement(gfxFontVariation{HB_TAG('s','l','n','t'),
                                                angle});
     }
 
-    // Although there is a registered tag 'ital', it is normally considered
-    // a binary toggle rather than a variable axis, so not set here.
-    // (For a non-standard font that implements 'ital' as an actual variation,
-    // authors can still use font-variation-settings to control it.)
-
     auto replaceOrAppend = [&aResult](const gfxFontVariation& aSetting) {
         struct TagEquals {
             bool Equals(const gfxFontVariation& aIter, uint32_t aTag) const {
                 return aIter.mTag == aTag;
             }
         };
         auto index = aResult.IndexOf(aSetting.mTag, 0, TagEquals());
         if (index == aResult.NoIndex) {
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -153,16 +153,17 @@ public:
     SlantStyleRange SlantStyle() const { return mStyleRange; }
 
     bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
     bool IsLocalUserFont() const { return mIsLocalUserFont; }
     bool IsFixedPitch() const { return mFixedPitch; }
     bool IsItalic() const { return SlantStyle().Min().IsItalic(); }
     bool IsOblique() const { return SlantStyle().Min().IsOblique(); }
     bool IsUpright() const { return SlantStyle().Min().IsNormal(); }
+    inline bool SupportsItalic();
     inline bool SupportsBold(); // defined below, because of RangeFlags use
     bool IgnoreGDEF() const { return mIgnoreGDEF; }
     bool IgnoreGSUB() const { return mIgnoreGSUB; }
 
     // Return whether the face corresponds to "normal" CSS style properties:
     //    font-style: normal;
     //    font-weight: normal;
     //    font-stretch: normal;
@@ -374,16 +375,18 @@ public:
 
     virtual void
     GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes) = 0;
 
     virtual void
     GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances) = 0;
 
     bool HasBoldVariableWeight();
+    bool HasItalicVariation();
+    void CheckForVariationAxes();
 
     // Set up the entry's weight/stretch/style ranges according to axes found
     // by GetVariationAxes (for installed fonts; do NOT call this for user
     // fonts, where the ranges are provided by @font-face descriptors).
     void SetupVariationRanges();
 
     // Get variation axis settings that should be used to implement a particular
     // font style using this resource.
@@ -431,26 +434,30 @@ public:
     // descriptors, it is treated as the initial value for font-matching (and
     // so that is what we record in the font entry), but when rendering the
     // range is NOT clamped.
     enum class RangeFlags : uint8_t {
         eNoFlags        = 0,
         eAutoWeight     = (1 << 0),
         eAutoStretch    = (1 << 1),
         eAutoSlantStyle = (1 << 2),
+
         // Flag to record whether the face has a variable "wght" axis
         // that supports "bold" values, used to disable the application
         // of synthetic-bold effects.
         eBoldVariableWeight = (1 << 3),
+        // Whether the face has an 'ital' axis.
+        eItalicVariation    = (1 << 4),
+
         // Flags to record if the face uses a non-CSS-compatible scale
         // for weight and/or stretch, in which case we won't map the
         // properties to the variation axes (though they can still be
         // explicitly set using font-variation-settings).
-        eNonCSSWeight   = (1 << 4),
-        eNonCSSStretch  = (1 << 5)
+        eNonCSSWeight   = (1 << 5),
+        eNonCSSStretch  = (1 << 6)
     };
     RangeFlags       mRangeFlags = RangeFlags::eNoFlags;
 
     // NOTE that there are currently exactly 24 one-bit flags defined here,
     // so together with the 8-bit RangeFlags above, this packs neatly to a
     // 32-bit boundary. Worth considering if further flags are wanted.
     bool             mFixedPitch  : 1;
     bool             mIsBadUnderlineFont : 1;
@@ -470,17 +477,17 @@ public:
     bool             mHasGraphiteSpaceContextuals : 1;
     bool             mSpaceGlyphIsInvisible : 1;
     bool             mSpaceGlyphIsInvisibleInitialized : 1;
     bool             mHasGraphiteTables : 1;
     bool             mCheckedForGraphiteTables : 1;
     bool             mHasCmapTable : 1;
     bool             mGrFaceInitialized : 1;
     bool             mCheckedForColorGlyph : 1;
-    bool             mCheckedForVariableWeight : 1;
+    bool             mCheckedForVariationAxes : 1;
 
 protected:
     friend class gfxPlatformFontList;
     friend class gfxMacPlatformFontList;
     friend class gfxUserFcFontEntry;
     friend class gfxFontFamily;
     friend class gfxSingleFaceMacFontFamily;
     friend class gfxUserFontEntry;
@@ -654,16 +661,25 @@ private:
 
     gfxFontEntry(const gfxFontEntry&);
     gfxFontEntry& operator=(const gfxFontEntry&);
 };
 
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxFontEntry::RangeFlags)
 
 inline bool
+gfxFontEntry::SupportsItalic()
+{
+    return SlantStyle().Max().IsItalic() ||
+           ((mRangeFlags & RangeFlags::eAutoSlantStyle) ==
+               RangeFlags::eAutoSlantStyle &&
+            HasItalicVariation());
+}
+
+inline bool
 gfxFontEntry::SupportsBold()
 {
     // bold == weights 600 and above
     // We return true if the face has a max weight descriptor >= 600,
     // OR if it's a user font with auto-weight (no descriptor) and has
     // a weight axis that supports values >= 600
     return Weight().Max().IsBold() ||
            ((mRangeFlags & RangeFlags::eAutoWeight) ==
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -84,17 +84,17 @@ fails-if(gtkWidget) == mfenced-12.html m
 fails == stretchy-mover-2a.html stretchy-mover-2-ref.html
 != stretchy-mover-2b.html stretchy-mover-2-ref.html
 == stretchy-mover-3.html stretchy-mover-3-ref.html
 == stretchy-largeop-1.html stretchy-largeop-1-ref.html
 == stretchy-largeop-2.html stretchy-largeop-2-ref.html
 == stretchy-largeop-3.html stretchy-largeop-3-ref.html
 == table-width-1.xhtml table-width-1-ref.xhtml
 == table-width-2.html table-width-2-ref.html
-== table-width-3.html table-width-3-ref.html
+fails-if(webrender&&winWidget) == table-width-3.html table-width-3-ref.html # bug 1460259
 == table-width-4.html table-width-4-ref.html
 == underbar-width-1.xhtml underbar-width-1-ref.xhtml
 == mathml-type-supported.xhtml mathml-type-supported-ref.xml
 == mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html
 == mtable-align-negative-rownumber-2.html mtable-align-negative-rownumber-2-ref.html
 != embellished-op-1-1.html embellished-op-1-1-ref.html
 != embellished-op-1-2.html embellished-op-1-2-ref.html
 != embellished-op-1-3.html embellished-op-1-3-ref.html