Bug 1405927 - Change PushGlyphs to take webrender formats. r?jrmuizel draft
authorAlexis Beingessner <a.beingessner@gmail.com>
Wed, 04 Oct 2017 13:49:51 -0400
changeset 675763 fe8ce94dc05a7b36891de3b70a304ddb6b8a18b0
parent 675762 6fa79b1e52055ff1a3d532e5ef4372581b772363
child 734703 f4013663abdf8bd3ffd31a523d645d2142615d59
push id83234
push userbmo:a.beingessner@gmail.com
push dateThu, 05 Oct 2017 21:00:46 +0000
reviewersjrmuizel
bugs1405927
milestone58.0a1
Bug 1405927 - Change PushGlyphs to take webrender formats. r?jrmuizel Also cleans up a bunch of TextDrawTarget code as fallout. This is a significant perf win for textFrames. MozReview-Commit-ID: J1BDkXZdvnc
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
layout/generic/TextDrawTarget.h
layout/generic/TextOverflow.cpp
layout/generic/nsBulletFrame.cpp
layout/generic/nsTextFrame.cpp
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -241,41 +241,32 @@ WriteFontFileData(const uint8_t* aData, 
     return;
   }
   memcpy(data->mFontBuffer.mData, aData, aLength);
 
   data->mFontIndex = aIndex;
 }
 
 void
-WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<gfx::Glyph>& aGlyphs,
-                                 gfx::ScaledFont* aFont, const gfx::Color& aColor, const StackingContextHelper& aSc,
-                                 const LayerRect& aBounds, const LayerRect& aClip, bool aBackfaceVisible)
+WebRenderBridgeChild::PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<wr::GlyphInstance>& aGlyphs,
+                                 gfx::ScaledFont* aFont, const wr::ColorF& aColor, const StackingContextHelper& aSc,
+                                 const wr::LayerRect& aBounds, const wr::LayerRect& aClip, bool aBackfaceVisible)
 {
   MOZ_ASSERT(aFont);
   MOZ_ASSERT(!aGlyphs.IsEmpty());
 
   wr::WrFontInstanceKey key = GetFontKeyForScaledFont(aFont);
   MOZ_ASSERT(key.mNamespace.mHandle && key.mHandle);
 
-  nsTArray<wr::GlyphInstance> wr_glyph_instances;
-  wr_glyph_instances.SetLength(aGlyphs.Length());
-
-  for (size_t j = 0; j < aGlyphs.Length(); j++) {
-    wr_glyph_instances[j].index = aGlyphs[j].mIndex;
-    wr_glyph_instances[j].point = aSc.ToRelativeLayoutPoint(
-            LayerPoint::FromUnknownPoint(aGlyphs[j].mPosition));
-  }
-
-  aBuilder.PushText(aSc.ToRelativeLayoutRect(aBounds),
-                    aSc.ToRelativeLayoutRect(aClip),
+  aBuilder.PushText(aBounds,
+                    aClip,
                     aBackfaceVisible,
                     aColor,
                     key,
-                    Range<const wr::GlyphInstance>(wr_glyph_instances.Elements(), wr_glyph_instances.Length()));
+                    Range<const wr::GlyphInstance>(aGlyphs.Elements(), aGlyphs.Length()));
 }
 
 wr::FontInstanceKey
 WebRenderBridgeChild::GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont)
 {
   MOZ_ASSERT(!mDestroyed);
   MOZ_ASSERT(aScaledFont);
   MOZ_ASSERT((aScaledFont->GetType() == gfx::FontType::DWRITE) ||
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -109,20 +109,20 @@ public:
     mIdNamespace = aIdNamespace;
   }
 
   wr::WrImageKey GetNextImageKey()
   {
     return wr::WrImageKey{ GetNamespace(), GetNextResourceId() };
   }
 
-  void PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<gfx::Glyph>& aGlyphs,
-                  gfx::ScaledFont* aFont, const gfx::Color& aColor,
+  void PushGlyphs(wr::DisplayListBuilder& aBuilder, const nsTArray<wr::GlyphInstance>& aGlyphs,
+                  gfx::ScaledFont* aFont, const wr::ColorF& aColor,
                   const StackingContextHelper& aSc,
-                  const LayerRect& aBounds, const LayerRect& aClip,
+                  const wr::LayerRect& aBounds, const wr::LayerRect& aClip,
                   bool aBackfaceVisible);
 
   wr::FontInstanceKey GetFontKeyForScaledFont(gfx::ScaledFont* aScaledFont);
 
   void RemoveExpiredFontKeys();
   void ClearReadLocks();
 
   void BeginClearCachedResources();
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1036,23 +1036,23 @@ DisplayListBuilder::PushBorderRadialGrad
     aRadius, aStops.Elements(), aStops.Length(),
     aExtendMode, aOutset);
 }
 
 void
 DisplayListBuilder::PushText(const wr::LayoutRect& aBounds,
                              const wr::LayoutRect& aClip,
                              bool aIsBackfaceVisible,
-                             const gfx::Color& aColor,
+                             const wr::ColorF& aColor,
                              wr::FontInstanceKey aFontKey,
                              Range<const wr::GlyphInstance> aGlyphBuffer,
                              const wr::GlyphOptions* aGlyphOptions)
 {
   wr_dp_push_text(mWrState, aBounds, aClip, aIsBackfaceVisible,
-                  ToColorF(aColor),
+                  aColor,
                   aFontKey,
                   &aGlyphBuffer[0], aGlyphBuffer.length(),
                   aGlyphOptions);
 }
 
 void
 DisplayListBuilder::PushLine(const wr::LayoutRect& aClip,
                              bool aIsBackfaceVisible,
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -353,17 +353,17 @@ public:
                                 const wr::LayoutSize& aRadius,
                                 const nsTArray<wr::GradientStop>& aStops,
                                 wr::ExtendMode aExtendMode,
                                 const wr::SideOffsets2D_f32& aOutset);
 
   void PushText(const wr::LayoutRect& aBounds,
                 const wr::LayoutRect& aClip,
                 bool aIsBackfaceVisible,
-                const gfx::Color& aColor,
+                const wr::ColorF& aColor,
                 wr::FontInstanceKey aFontKey,
                 Range<const wr::GlyphInstance> aGlyphBuffer,
                 const wr::GlyphOptions* aGlyphOptions = nullptr);
 
   void PushLine(const wr::LayoutRect& aClip,
                 bool aIsBackfaceVisible,
                 const wr::Line& aLine);
 
--- a/layout/generic/TextDrawTarget.h
+++ b/layout/generic/TextDrawTarget.h
@@ -15,18 +15,18 @@
 namespace mozilla {
 namespace layout {
 
 using namespace gfx;
 
 // This is used by all Advanced Layers users, so we use plain gfx types
 struct TextRunFragment {
   ScaledFont* font;
-  Color color;
-  nsTArray<gfx::Glyph> glyphs;
+  wr::ColorF color;
+  nsTArray<wr::GlyphInstance> glyphs;
 };
 
 // Only webrender handles this, so we use webrender types
 struct SelectionFragment {
   wr::ColorF color;
   wr::LayoutRect rect;
 };
 
@@ -44,22 +44,37 @@ struct SelectionFragment {
 //
 // Would be broken up into 5 SelectedTextRunFragments
 //
 // ["Hello ", "there", " my name ", "is Mega", "man"]
 //
 // For almost all nsTextFrames, there will be only one SelectedTextRunFragment.
 struct SelectedTextRunFragment {
   Maybe<SelectionFragment> selection;
-  nsTArray<wr::Shadow> shadows;
-  nsTArray<TextRunFragment> text;
-  nsTArray<wr::Line> beforeDecorations;
-  nsTArray<wr::Line> afterDecorations;
+  AutoTArray<wr::Shadow, 1> shadows;
+  AutoTArray<TextRunFragment, 1> text;
+  AutoTArray<wr::Line, 1> beforeDecorations;
+  AutoTArray<wr::Line, 1> afterDecorations;
 };
 
+}
+}
+
+// AutoTArray is bad
+template<>
+struct nsTArray_CopyChooser<mozilla::layout::SelectedTextRunFragment>
+{
+  typedef nsTArray_CopyWithConstructors<mozilla::layout::SelectedTextRunFragment> Type;
+};
+
+namespace mozilla {
+namespace layout {
+
+using namespace gfx;
+
 // This class is fake DrawTarget, used to intercept text draw calls, while
 // also collecting up the other aspects of text natively.
 //
 // When using advanced-layers in nsDisplayText's constructor, we construct this
 // and run the full painting algorithm with this as the DrawTarget. This is
 // done to avoid having to massively refactor gecko's text painting code (which
 // has lots of components shared between other rendering algorithms).
 //
@@ -86,18 +101,20 @@ class TextDrawTarget : public DrawTarget
 {
 public:
   // The different phases of drawing the text we're in
   // Each should only happen once, and in the given order.
   enum class Phase : uint8_t {
     eSelection, eUnderline, eOverline, eGlyphs, eEmphasisMarks, eLineThrough
   };
 
-  explicit TextDrawTarget()
-  : mCurrentlyDrawing(Phase::eSelection), mHasUnsupportedFeatures(false)
+  explicit TextDrawTarget(const layers::StackingContextHelper& aSc)
+  : mCurrentlyDrawing(Phase::eSelection),
+    mHasUnsupportedFeatures(false),
+    mSc(aSc)
   {
     SetSelectionIndex(0);
   }
 
   // Prevent this from being copied
   TextDrawTarget(const TextDrawTarget& src) = delete;
   TextDrawTarget& operator=(const TextDrawTarget&) = delete;
 
@@ -142,29 +159,36 @@ public:
       MOZ_CRASH("TextDrawTarget received glyphs in wrong phase");
     }
 
     // We need to push a new TextRunFragment whenever the font/color changes
     // (usually this implies some font fallback from mixing languages/emoji)
     TextRunFragment* fragment;
     if (mCurrentPart->text.IsEmpty() ||
         mCurrentPart->text.LastElement().font != aFont ||
-        mCurrentPart->text.LastElement().color != colorPat->mColor) {
+        !(mCurrentPart->text.LastElement().color ==  wr::ToColorF(colorPat->mColor))) {
       fragment = mCurrentPart->text.AppendElement();
       fragment->font = aFont;
-      fragment->color = colorPat->mColor;
+      fragment->color = wr::ToColorF(colorPat->mColor);
     } else {
       fragment = &mCurrentPart->text.LastElement();
     }
 
-    nsTArray<Glyph>& glyphs = fragment->glyphs;
+    nsTArray<wr::GlyphInstance>& glyphs = fragment->glyphs;
 
     size_t oldLength = glyphs.Length();
     glyphs.SetLength(oldLength + aBuffer.mNumGlyphs);
-    PodCopy(glyphs.Elements() + oldLength, aBuffer.mGlyphs, aBuffer.mNumGlyphs);
+
+    for (size_t i = 0; i < aBuffer.mNumGlyphs; i++) {
+      wr::GlyphInstance& targetGlyph = glyphs[oldLength + i];
+      const gfx::Glyph& sourceGlyph = aBuffer.mGlyphs[i];
+      targetGlyph.index = sourceGlyph.mIndex;
+      targetGlyph.point = mSc.ToRelativeLayoutPoint(
+              LayerPoint::FromUnknownPoint(sourceGlyph.mPosition));
+    }
   }
 
   void
   AppendShadow(const wr::Shadow& aShadow) {
     mCurrentPart->shadows.AppendElement(aShadow);
   }
 
   void
@@ -253,59 +277,27 @@ public:
         if (!frag.font->CanSerialize()) {
           return false;
         }
       }
     }
     return true;
   }
 
-  // TextLayers don't support very complicated text right now. This checks
-  // if any of the problem cases exist.
   bool
-  ContentsAreSimple()
-  {
-
-    ScaledFont* font = nullptr;
-
-    for (const SelectedTextRunFragment& part : GetParts()) {
-      // Can't handle shadows, selections, or decorations
-      if (part.shadows.Length() > 0 ||
-          part.beforeDecorations.Length() > 0 ||
-          part.afterDecorations.Length() > 0 ||
-          part.selection.isSome()) {
-        return false;
-      }
-
-      // Must only have one font (multiple colors is fine)
-      for (const mozilla::layout::TextRunFragment& text : part.text) {
-        if (!font) {
-          font = text.font;
-        }
-        if (font != text.font) {
-          return false;
-        }
-      }
-    }
-
-    // Must have an actual font (i.e. actual text)
-    if (!font) {
-      return false;
-    }
-
-    return true;
-  }
-
-  void
   CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                           const layers::StackingContextHelper& aSc,
                           layers::WebRenderLayerManager* aManager,
                           nsDisplayItem* aItem,
                           nsRect& aBounds) {
 
+  if (!CanSerializeFonts()) {
+    return false;
+  }
+
   // Drawing order: selections,
   //                shadows,
   //                underline, overline, [grouped in one array]
   //                text, emphasisText,  [grouped in one array]
   //                lineThrough
 
   // Compute clip/bounds
   auto appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
@@ -343,44 +335,50 @@ public:
     }
 
     for (const wr::Line& decoration : part.beforeDecorations) {
       aBuilder.PushLine(wrClipRect, backfaceVisible, decoration);
     }
 
     for (const mozilla::layout::TextRunFragment& text : part.text) {
       aManager->WrBridge()->PushGlyphs(aBuilder, text.glyphs, text.font,
-                                       text.color, aSc, boundsRect, clipRect,
+                                       text.color, aSc, wrBoundsRect, wrClipRect,
                                        backfaceVisible);
     }
 
     for (const wr::Line& decoration : part.afterDecorations) {
       aBuilder.PushLine(wrClipRect, backfaceVisible, decoration);
     }
 
     for (size_t i = 0; i < part.shadows.Length(); ++i) {
       aBuilder.PopShadow();
     }
   }
+
+  return true;
 }
 
-
 private:
   // The part of the text we're currently drawing (glyphs, underlines, etc.)
   Phase mCurrentlyDrawing;
 
   // Which chunk of mParts is actively being populated
   SelectedTextRunFragment* mCurrentPart;
 
   // Chunks of the text, grouped by selection
-  nsTArray<SelectedTextRunFragment> mParts;
+  AutoTArray<SelectedTextRunFragment, 1> mParts;
 
   // Whether Tofu or SVG fonts were encountered
   bool mHasUnsupportedFeatures;
 
+  // Needs to be saved so FillGlyphs can use this to offset glyphs to
+  // relative space. Shouldn't be used otherwise (may dangle if we move
+  // to retaining TextDrawTargets)
+  const layers::StackingContextHelper& mSc;
+
   // The rest of this is dummy implementations of DrawTarget's API
 public:
   DrawTargetType GetType() const override {
     return DrawTargetType::SOFTWARE_RASTER;
   }
 
   BackendType GetBackendType() const override {
     return BackendType::WEBRENDER_TEXT;
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -290,42 +290,34 @@ nsDisplayTextOverflowMarker::PaintTextTo
 
 bool
 nsDisplayTextOverflowMarker::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                      mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                      const StackingContextHelper& aSc,
                                                      layers::WebRenderLayerManager* aManager,
                                                      nsDisplayListBuilder* aDisplayListBuilder)
 {
-  if (!gfxPrefs::LayersAllowTextLayers() ||
-      !CanUseAdvancedLayer(aDisplayListBuilder->GetWidgetLayerManager())) {
+  if (!gfxPrefs::LayersAllowTextLayers()) {
       return false;
   }
 
   bool snap;
   nsRect bounds = GetBounds(aDisplayListBuilder, &snap);
   if (bounds.IsEmpty()) {
     return true;
   }
 
   // Run the rendering algorithm to capture the glyphs and shadows
-  RefPtr<TextDrawTarget> textDrawer = new TextDrawTarget();
+  RefPtr<TextDrawTarget> textDrawer = new TextDrawTarget(aSc);
   RefPtr<gfxContext> captureCtx = gfxContext::CreateOrNull(textDrawer);
   // TextOverflowMarker only draws glyphs
   textDrawer->StartDrawing(TextDrawTarget::Phase::eGlyphs);
   Paint(aDisplayListBuilder, captureCtx);
 
-  if (!textDrawer->CanSerializeFonts()) {
-    return false;
-  }
-
-  textDrawer->CreateWebRenderCommands(aBuilder, aSc, aManager, this, bounds);
-
-
-  return true;
+  return textDrawer->CreateWebRenderCommands(aBuilder, aSc, aManager, this, bounds);
 }
 
 
 TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
                            nsIFrame* aBlockFrame)
   : mContentArea(aBlockFrame->GetWritingMode(),
                  aBlockFrame->GetContentRectRelativeToSelf(),
                  aBlockFrame->GetSize())
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -516,21 +516,34 @@ BulletRenderer::CreateWebRenderCommandsF
   MOZ_ASSERT(!mGlyphs.IsEmpty());
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   bool dummy;
   LayerRect destRect = ViewAs<LayerPixel>(
       LayoutDeviceRect::FromAppUnits(
           aItem->GetBounds(aDisplayListBuilder, &dummy), appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
+  wr::LayoutRect wrDestRect = aSc.ToRelativeLayoutRect(destRect);
 
-  for (layers::GlyphArray& glyphs : mGlyphs) {
-    aManager->WrBridge()->PushGlyphs(aBuilder, glyphs.glyphs(), mFont,
-                                     glyphs.color().value(),
-                                     aSc, destRect, destRect, !aItem->BackfaceIsHidden());
+  nsTArray<wr::GlyphInstance> wrGlyphs;
+
+  for (layers::GlyphArray& glyphArray : mGlyphs) {
+    const auto& glyphs = glyphArray.glyphs();
+    wrGlyphs.SetLength(glyphs.Length());
+
+    for (size_t j = 0; j < glyphs.Length(); j++) {
+      wrGlyphs[j].index = glyphs[j].mIndex;
+      wrGlyphs[j].point = aSc.ToRelativeLayoutPoint(
+              LayerPoint::FromUnknownPoint(glyphs[j].mPosition));
+    }
+
+    aManager->WrBridge()->PushGlyphs(aBuilder, wrGlyphs, mFont,
+                                     wr::ToColorF(glyphArray.color().value()),
+                                     aSc, wrDestRect, wrDestRect,
+                                     !aItem->BackfaceIsHidden());
   }
 }
 
 class nsDisplayBullet final : public nsDisplayItem {
 public:
   nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -5044,17 +5044,16 @@ public:
     nsCString buf;
     int32_t totalContentLength;
     f->ToCString(buf, &totalContentLength);
 
     aStream << buf.get() << "\")";
 #endif
   }
 
-  RefPtr<TextDrawTarget> mTextDrawer;
   nsRect mBounds;
   float mOpacity;
 };
 
 class nsDisplayTextGeometry : public nsCharClipGeometry
 {
 public:
   nsDisplayTextGeometry(nsDisplayText* aItem, nsDisplayListBuilder* aBuilder)
@@ -5145,29 +5144,23 @@ nsDisplayText::CreateWebRenderCommands(m
   if (!gfxPrefs::LayersAllowTextLayers()) {
     return false;
   }
 
   if (mBounds.IsEmpty()) {
     return true;
   }
 
-  RefPtr<TextDrawTarget> textDrawer = new TextDrawTarget();
+  RefPtr<TextDrawTarget> textDrawer = new TextDrawTarget(aSc);
   RefPtr<gfxContext> captureCtx = gfxContext::CreateOrNull(textDrawer);
 
   // TODO: Paint() checks mDisableSubpixelAA, we should too.
   RenderToContext(captureCtx, aDisplayListBuilder, true);
 
-  if (!textDrawer->CanSerializeFonts()) {
-    return false;
-  }
-
-  textDrawer->CreateWebRenderCommands(aBuilder, aSc, aManager, this, mBounds);
-
-  return true;
+  return textDrawer->CreateWebRenderCommands(aBuilder, aSc, aManager, this, mBounds);
 }
 
 void
 nsDisplayText::RenderToContext(gfxContext* aCtx, nsDisplayListBuilder* aBuilder, bool aIsRecording)
 {
   nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
 
   // Add 1 pixel of dirty area around mVisibleRect to allow us to paint