Bug 1407767 - reimplement text bullets to use TextDrawTarget. r?jrmuizel draft
authorAlexis Beingessner <a.beingessner@gmail.com>
Tue, 17 Oct 2017 16:05:29 -0400
changeset 683323 51b7e31fe23d0049fe7fc08e8b574929ba6933fb
parent 683249 31af3ee0436093bfd3300e9002f1118df0420309
child 683324 5fdce7f73923f5c34f85c6b886c8209d55facfe0
child 683434 59c3bdcedc90af06018f0d4c9f345816a6a3daaa
push id85333
push userbmo:a.beingessner@gmail.com
push dateThu, 19 Oct 2017 14:58:21 +0000
reviewersjrmuizel
bugs1407767
milestone58.0a1
Bug 1407767 - reimplement text bullets to use TextDrawTarget. r?jrmuizel This makes the implementation more robust and unifies all our text handling under one implementation. Also includes some refatoring of our CreateWebRenderCommands impl to divest us from the layerful/stateful GetLayerState(). Future work should be done here, but that's low priority for the moment. MozReview-Commit-ID: Hypb02aDStm
layout/generic/nsBulletFrame.cpp
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -219,17 +219,17 @@ public:
     , mText(text)
     , mFontMetrics(fm)
     , mPoint(point)
     , mListStyleType(listStyleType)
   {
     MOZ_ASSERT(IsTextType());
   }
 
-  void
+  bool
   CreateWebRenderCommands(nsDisplayItem* aItem,
                           wr::DisplayListBuilder& aBuilder,
                           wr::IpcResourceUpdateQueue& aResources,
                           const layers::StackingContextHelper& aSc,
                           mozilla::layers::WebRenderLayerManager* aManager,
                           nsDisplayListBuilder* aDisplayListBuilder);
 
   DrawResult
@@ -264,37 +264,42 @@ public:
            mListStyleType != NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN &&
            mListStyleType != NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED &&
            !mText.IsEmpty();
   }
 
   bool
   BuildGlyphForText(nsDisplayItem* aItem, bool disableSubpixelAA);
 
+  void
+  PaintTextToContext(nsIFrame* aFrame,
+                     gfxContext* aCtx,
+                     bool aDisableSubpixelAA);
+
   bool
   IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
 
 private:
-  void
+  bool
   CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                   wr::DisplayListBuilder& aBuilder,
                                   wr::IpcResourceUpdateQueue& aResources,
                                   const layers::StackingContextHelper& aSc,
                                   mozilla::layers::WebRenderLayerManager* aManager,
                                   nsDisplayListBuilder* aDisplayListBuilder);
 
-  void
+  bool
   CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                  wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const layers::StackingContextHelper& aSc,
                                  mozilla::layers::WebRenderLayerManager* aManager,
                                  nsDisplayListBuilder* aDisplayListBuilder);
 
-  void
+  bool
   CreateWebRenderCommandsForText(nsDisplayItem* aItem,
                                  wr::DisplayListBuilder& aBuilder,
                                  wr::IpcResourceUpdateQueue& aResources,
                                  const layers::StackingContextHelper& aSc,
                                  mozilla::layers::WebRenderLayerManager* aManager,
                                  nsDisplayListBuilder* aDisplayListBuilder);
 
 private:
@@ -317,34 +322,34 @@ private:
   nsPoint mPoint;
   RefPtr<ScaledFont> mFont;
   nsTArray<layers::GlyphArray> mGlyphs;
 
   // Store the type of list-style-type.
   int32_t mListStyleType;
 };
 
-void
+bool
 BulletRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
                                         wr::DisplayListBuilder& aBuilder,
                                         wr::IpcResourceUpdateQueue& aResources,
                                         const layers::StackingContextHelper& aSc,
                                         mozilla::layers::WebRenderLayerManager* aManager,
                                         nsDisplayListBuilder* aDisplayListBuilder)
 {
   if (IsImageType()) {
-    CreateWebRenderCommandsForImage(aItem, aBuilder, aResources,
+    return CreateWebRenderCommandsForImage(aItem, aBuilder, aResources,
                                     aSc, aManager, aDisplayListBuilder);
   } else if (IsPathType()) {
-    CreateWebRenderCommandsForPath(aItem, aBuilder, aResources,
+    return CreateWebRenderCommandsForPath(aItem, aBuilder, aResources,
                                    aSc, aManager, aDisplayListBuilder);
   } else {
     MOZ_ASSERT(IsTextType());
-    CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
-                                   aManager, aDisplayListBuilder);
+    return CreateWebRenderCommandsForText(aItem, aBuilder, aResources, aSc,
+                                          aManager, aDisplayListBuilder);
   }
 }
 
 DrawResult
 BulletRenderer::Paint(gfxContext& aRenderingContext, nsPoint aPt,
                       const nsRect& aDirtyRect, uint32_t aFlags,
                       bool aDisableSubpixelAA, nsIFrame* aFrame)
 {
@@ -372,28 +377,17 @@ BulletRenderer::Paint(gfxContext& aRende
       drawTarget->Fill(mPath, ColorPattern(ToDeviceColor(mColor)));
       break;
     default:
       MOZ_CRASH("unreachable");
     }
   }
 
   if (IsTextType()) {
-    DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
-    DrawTargetAutoDisableSubpixelAntialiasing
-      disable(drawTarget, aDisableSubpixelAA);
-
-    aRenderingContext.SetColor(Color::FromABGR(mColor));
-
-    nsPresContext* presContext = aFrame->PresContext();
-    if (!presContext->BidiEnabled() && HasRTLChars(mText)) {
-      presContext->SetBidiEnabled();
-    }
-    nsLayoutUtils::DrawString(aFrame, *mFontMetrics, &aRenderingContext,
-                              mText.get(), mText.Length(), mPoint);
+    PaintTextToContext(aFrame, &aRenderingContext, aDisableSubpixelAA);
   }
 
   return DrawResult::SUCCESS;
 }
 
 bool
 BulletRenderer::BuildGlyphForText(nsDisplayItem* aItem, bool disableSubpixelAA)
 {
@@ -402,31 +396,17 @@ BulletRenderer::BuildGlyphForText(nsDisp
   RefPtr<DrawTarget> screenTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
   RefPtr<DrawTargetCapture> capture =
     Factory::CreateCaptureDrawTarget(screenTarget->GetBackendType(),
                                      IntSize(),
                                      screenTarget->GetFormat());
 
   RefPtr<gfxContext> captureCtx = gfxContext::CreateOrNull(capture);
 
-  {
-    DrawTargetAutoDisableSubpixelAntialiasing
-      disable(capture, disableSubpixelAA);
-
-    captureCtx->SetColor(
-      Color::FromABGR(mColor));
-
-    nsPresContext* presContext = aItem->Frame()->PresContext();
-    if (!presContext->BidiEnabled() && HasRTLChars(mText)) {
-      presContext->SetBidiEnabled();
-    }
-
-    nsLayoutUtils::DrawString(aItem->Frame(), *mFontMetrics, captureCtx,
-                              mText.get(), mText.Length(), mPoint);
-  }
+  PaintTextToContext(aItem->Frame(), captureCtx, disableSubpixelAA);
 
   layers::GlyphArray* g = mGlyphs.AppendElement();
   std::vector<Glyph> glyphs;
   Color color;
   if (!capture->ContainsOnlyColoredGlyphs(mFont, color, glyphs)) {
     mFont = nullptr;
     mGlyphs.Clear();
     return false;
@@ -434,115 +414,131 @@ BulletRenderer::BuildGlyphForText(nsDisp
 
   g->glyphs().SetLength(glyphs.size());
   PodCopy(g->glyphs().Elements(), glyphs.data(), glyphs.size());
   g->color() = color;
 
   return true;
 }
 
+void
+BulletRenderer::PaintTextToContext(nsIFrame* aFrame,
+                                   gfxContext* aCtx,
+                                   bool aDisableSubpixelAA)
+{
+  MOZ_ASSERT(IsTextType());
+
+  DrawTarget* drawTarget = aCtx->GetDrawTarget();
+  DrawTargetAutoDisableSubpixelAntialiasing
+    disable(drawTarget, aDisableSubpixelAA);
+
+  aCtx->SetColor(Color::FromABGR(mColor));
+
+  nsPresContext* presContext = aFrame->PresContext();
+  if (!presContext->BidiEnabled() && HasRTLChars(mText)) {
+    presContext->SetBidiEnabled();
+  }
+  nsLayoutUtils::DrawString(aFrame, *mFontMetrics, aCtx,
+                            mText.get(), mText.Length(), mPoint);
+}
+
 bool
 BulletRenderer::IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags)
 {
   MOZ_ASSERT(IsImageType());
 
   return mImage->IsImageContainerAvailable(aManager, aFlags);
 }
 
-void
+bool
 BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
                                                 wr::DisplayListBuilder& aBuilder,
                                                 wr::IpcResourceUpdateQueue& aResources,
                                                 const layers::StackingContextHelper& aSc,
                                                 mozilla::layers::WebRenderLayerManager* aManager,
                                                 nsDisplayListBuilder* aDisplayListBuilder)
 {
-  MOZ_ASSERT(IsImageType());
-
-  if (!mImage) {
-     return;
-  }
+  MOZ_RELEASE_ASSERT(IsImageType());
+  MOZ_RELEASE_ASSERT(mImage);
 
   uint32_t flags = aDisplayListBuilder->ShouldSyncDecodeImages() ?
                    imgIContainer::FLAG_SYNC_DECODE :
                    imgIContainer::FLAG_NONE;
 
+  // FIXME: is this check always redundant with the next one?
+  if (IsImageContainerAvailable(aManager, flags)) {
+    return false;
+  }
+
   RefPtr<layers::ImageContainer> container =
     mImage->GetImageContainer(aManager, flags);
   if (!container) {
-    return;
+    return false;
   }
 
   gfx::IntSize size;
   Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container, aBuilder, aResources, aSc, size);
   if (key.isNothing()) {
-    return;
+    return true;  // Nothing to do
   }
 
   const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(mDest, appUnitsPerDevPixel);
   wr::LayoutRect dest = aSc.ToRelativeLayoutRect(destRect);
 
   aBuilder.PushImage(dest,
                      dest,
                      !aItem->BackfaceIsHidden(),
                      wr::ImageRendering::Auto,
                      key.value());
+
+  return true;
 }
 
-void
+bool
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
                                                const layers::StackingContextHelper& aSc,
                                                mozilla::layers::WebRenderLayerManager* aManager,
                                                nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(IsPathType());
 
   if (!aManager->CommandBuilder().PushItemAsImage(aItem, aBuilder, aResources, aSc, aDisplayListBuilder)) {
     NS_WARNING("Fail to create WebRender commands for Bullet path.");
+    return false;
   }
+
+  return true;
 }
 
-void
+bool
 BulletRenderer::CreateWebRenderCommandsForText(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
                                                const layers::StackingContextHelper& aSc,
                                                mozilla::layers::WebRenderLayerManager* aManager,
                                                nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(IsTextType());
-  MOZ_ASSERT(mFont);
-  MOZ_ASSERT(!mGlyphs.IsEmpty());
 
-  const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   bool dummy;
-  LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
-          aItem->GetBounds(aDisplayListBuilder, &dummy), appUnitsPerDevPixel);
-  wr::LayoutRect wrDestRect = aSc.ToRelativeLayoutRect(destRect);
-
-  nsTArray<wr::GlyphInstance> wrGlyphs;
+  nsRect bounds = aItem->GetBounds(aDisplayListBuilder, &dummy);
 
-  for (layers::GlyphArray& glyphArray : mGlyphs) {
-    const auto& glyphs = glyphArray.glyphs();
-    wrGlyphs.SetLength(glyphs.Length());
+  if (bounds.IsEmpty()) {
+    return true;
+  }
 
-    for (size_t j = 0; j < glyphs.Length(); j++) {
-      wrGlyphs[j].index = glyphs[j].mIndex;
-      wrGlyphs[j].point = aSc.ToRelativeLayoutPoint(
-              LayoutDevicePoint::FromUnknownPoint(glyphs[j].mPosition));
-    }
+  RefPtr<TextDrawTarget> textDrawer = new TextDrawTarget(aBuilder, aSc, aManager, aItem, bounds);
+  RefPtr<gfxContext> captureCtx = gfxContext::CreateOrNull(textDrawer);
+  PaintTextToContext(aItem->Frame(), captureCtx, aItem);
+  textDrawer->TerminateShadows();
 
-    aManager->WrBridge()->PushGlyphs(aBuilder, wrGlyphs, mFont,
-                                     wr::ToColorF(glyphArray.color().value()),
-                                     aSc, wrDestRect, wrDestRect,
-                                     !aItem->BackfaceIsHidden());
-  }
+  return !textDrawer->HasUnsupportedFeatures();
 }
 
 class nsDisplayBullet final : public nsDisplayItem {
 public:
   nsDisplayBullet(nsDisplayListBuilder* aBuilder, nsBulletFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame)
   {
     MOZ_COUNT_CTOR(nsDisplayBullet);
@@ -673,27 +669,29 @@ nsDisplayBullet::BuildLayer(nsDisplayLis
 
 bool
 nsDisplayBullet::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                          wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
-  ContainerLayerParameters parameter;
-  if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
+  // FIXME: avoid needing to make this target if we're drawing text
+  // (non-trivial refactor of all this code)
+  RefPtr<gfxContext> screenRefCtx = gfxContext::CreateOrNull(
+    gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget().get());
+  Maybe<BulletRenderer> br = static_cast<nsBulletFrame*>(mFrame)->
+    CreateBulletRenderer(*screenRefCtx, ToReferenceFrame());
+
+  if (!br) {
     return false;
   }
 
-  if (!mBulletRenderer)
-    return false;
-
-  mBulletRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
-                                           aManager, aDisplayListBuilder);
-  return true;
+  return br->CreateWebRenderCommands(this, aBuilder, aResources, aSc,
+                                     aManager, aDisplayListBuilder);
 }
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             gfxContext* aCtx)
 {
   uint32_t flags = imgIContainer::FLAG_NONE;
   if (aBuilder->ShouldSyncDecodeImages()) {
     flags |= imgIContainer::FLAG_SYNC_DECODE;