Bug 1589888 - Handle glyph buffering for color or synthetic-bold fonts with partial opacity on a per-glyphrun basis. r=lsalzman
authorJonathan Kew <jkew@mozilla.com>
Wed, 13 Nov 2019 17:33:34 +0000
changeset 501832 7071b1bdd74110deca5dea19250a2d571223d698
parent 501831 16bc115ecd46ed37ff921ed4273532c16d3b0205
child 501833 536a4cac3ffe4b8752587bf0246953ceac77c0b3
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1589888
milestone72.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 1589888 - Handle glyph buffering for color or synthetic-bold fonts with partial opacity on a per-glyphrun basis. r=lsalzman Differential Revision: https://phabricator.services.mozilla.com/D52877
gfx/thebes/gfxTextRun.cpp
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -483,40 +483,33 @@ void gfxTextRun::DrawPartialLigature(gfx
 
   if (aParams.isVerticalRun) {
     aPt->y += aParams.direction * data.mPartWidth;
   } else {
     aPt->x += aParams.direction * data.mPartWidth;
   }
 }
 
-// Returns true if a glyph run is using a font with synthetic bolding enabled,
-// or a color font (COLR/SVG/sbix/CBDT), false otherwise. This is used to
+// Returns true if the font has synthetic bolding enabled,
+// or is a color font (COLR/SVG/sbix/CBDT), false otherwise. This is used to
 // check whether the text run needs to be explicitly composited in order to
 // support opacity.
-static bool HasSyntheticBoldOrColor(const gfxTextRun* aRun,
-                                    gfxTextRun::Range aRange) {
-  gfxTextRun::GlyphRunIterator iter(aRun, aRange);
-  while (iter.NextRun()) {
-    gfxFont* font = iter.GetGlyphRun()->mFont;
-    if (font) {
-      if (font->IsSyntheticBold()) {
-        return true;
-      }
-      gfxFontEntry* fe = font->GetFontEntry();
-      if (fe->TryGetSVGData(font) || fe->TryGetColorGlyphs()) {
-        return true;
-      }
+static bool HasSyntheticBoldOrColor(gfxFont* aFont) {
+  if (aFont->IsSyntheticBold()) {
+    return true;
+  }
+  gfxFontEntry* fe = aFont->GetFontEntry();
+  if (fe->TryGetSVGData(aFont) || fe->TryGetColorGlyphs()) {
+    return true;
+  }
 #if defined(XP_MACOSX)  // sbix fonts only supported via Core Text
-      if (fe->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'))) {
-        return true;
-      }
+  if (fe->HasFontTable(TRUETYPE_TAG('s', 'b', 'i', 'x'))) {
+    return true;
+  }
 #endif
-    }
-  }
   return false;
 }
 
 // helper class for double-buffering drawing with non-opaque color
 struct MOZ_STACK_CLASS BufferAlphaColor {
   explicit BufferAlphaColor(gfxContext* aContext) : mContext(aContext) {}
 
   ~BufferAlphaColor() {}
@@ -574,37 +567,20 @@ void gfxTextRun::Draw(Range aRange, gfx:
     // return without drawing
     return;
   }
 
   // synthetic bolding draws glyphs twice ==> colors with opacity won't draw
   // correctly unless first drawn without alpha
   BufferAlphaColor syntheticBoldBuffer(aParams.context);
   Color currentColor;
-  bool needToRestore = false;
-
-  if (aParams.drawMode & DrawMode::GLYPH_FILL &&
+  bool mayNeedBuffering =
+      aParams.drawMode & DrawMode::GLYPH_FILL &&
       aParams.context->HasNonOpaqueNonTransparentColor(currentColor) &&
-      HasSyntheticBoldOrColor(this, aRange) &&
-      !aParams.context->GetTextDrawer()) {
-    needToRestore = true;
-    // Measure text; use the bounding box to determine the area we need
-    // to buffer.
-    gfxTextRun::Metrics metrics =
-        MeasureText(aRange, gfxFont::LOOSE_INK_EXTENTS,
-                    aParams.context->GetDrawTarget(), aParams.provider);
-    if (IsRightToLeft()) {
-      metrics.mBoundingBox.MoveBy(
-          gfxPoint(aPt.x - metrics.mAdvanceWidth, aPt.y));
-    } else {
-      metrics.mBoundingBox.MoveBy(gfxPoint(aPt.x, aPt.y));
-    }
-    syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
-                                       GetAppUnitsPerDevUnit());
-  }
+      !aParams.context->GetTextDrawer();
 
   // Set up parameters that will be constant across all glyph runs we need
   // to draw, regardless of the font used.
   TextRunDrawParams params;
   params.context = aParams.context;
   params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit());
   params.isVerticalRun = IsVertical();
   params.isRTL = IsRightToLeft();
@@ -620,51 +596,69 @@ void gfxTextRun::Draw(Range aRange, gfx:
       !aParams.callbacks || aParams.callbacks->mShouldPaintSVGGlyphs;
   params.dt = aParams.context->GetDrawTarget();
 
   GlyphRunIterator iter(this, aRange);
   gfxFloat advance = 0.0;
 
   while (iter.NextRun()) {
     gfxFont* font = iter.GetGlyphRun()->mFont;
-    uint32_t start = iter.GetStringStart();
-    uint32_t end = iter.GetStringEnd();
-    Range ligatureRange(start, end);
+    Range runRange(iter.GetStringStart(), iter.GetStringEnd());
+
+    bool needToRestore = false;
+    if (mayNeedBuffering && HasSyntheticBoldOrColor(font)) {
+      needToRestore = true;
+      // Measure text; use the bounding box to determine the area we need
+      // to buffer.
+      gfxTextRun::Metrics metrics =
+          MeasureText(runRange, gfxFont::LOOSE_INK_EXTENTS,
+                      aParams.context->GetDrawTarget(), aParams.provider);
+      if (IsRightToLeft()) {
+        metrics.mBoundingBox.MoveBy(
+            gfxPoint(aPt.x - metrics.mAdvanceWidth, aPt.y));
+      } else {
+        metrics.mBoundingBox.MoveBy(gfxPoint(aPt.x, aPt.y));
+      }
+      syntheticBoldBuffer.PushSolidColor(metrics.mBoundingBox, currentColor,
+                                         GetAppUnitsPerDevUnit());
+    }
+
+    Range ligatureRange(runRange);
     ShrinkToLigatureBoundaries(&ligatureRange);
 
     bool drawPartial =
         (aParams.drawMode & (DrawMode::GLYPH_FILL | DrawMode::GLYPH_STROKE)) ||
         (aParams.drawMode == DrawMode::GLYPH_PATH && aParams.callbacks);
     gfx::Point origPt = aPt;
 
     if (drawPartial) {
-      DrawPartialLigature(font, Range(start, ligatureRange.start), &aPt,
-                          aParams.provider, params,
+      DrawPartialLigature(font, Range(runRange.start, ligatureRange.start),
+                          &aPt, aParams.provider, params,
                           iter.GetGlyphRun()->mOrientation);
     }
 
     DrawGlyphs(font, ligatureRange, &aPt, aParams.provider, ligatureRange,
                params, iter.GetGlyphRun()->mOrientation);
 
     if (drawPartial) {
-      DrawPartialLigature(font, Range(ligatureRange.end, end), &aPt,
+      DrawPartialLigature(font, Range(ligatureRange.end, runRange.end), &aPt,
                           aParams.provider, params,
                           iter.GetGlyphRun()->mOrientation);
     }
 
     if (params.isVerticalRun) {
       advance += (aPt.y - origPt.y) * params.direction;
     } else {
       advance += (aPt.x - origPt.x) * params.direction;
     }
-  }
-
-  // composite result when synthetic bolding used
-  if (needToRestore) {
-    syntheticBoldBuffer.PopAlpha();
+
+    // composite result when synthetic bolding used
+    if (needToRestore) {
+      syntheticBoldBuffer.PopAlpha();
+    }
   }
 
   if (aParams.advanceWidth) {
     *aParams.advanceWidth = advance;
   }
 }
 
 // This method is mostly parallel to Draw().