Bug 1449634. Handle foreignobject better with blob invalidation. r=mstange draft
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Wed, 02 May 2018 18:40:33 -0400
changeset 791222 858a4ce9b5fcb1568403ce038a59bde3b5d202d3
parent 786949 781457239e63258ea069ccdd16ebaadb6c5fa33b
push id108742
push userbmo:jmuizelaar@mozilla.com
push dateThu, 03 May 2018 19:37:08 +0000
reviewersmstange
bugs1449634
milestone61.0a1
Bug 1449634. Handle foreignobject better with blob invalidation. r=mstange Turn off grouping and switch to regular WebRender building when we encounter a foreignobject. MozReview-Commit-ID: 6fHc4Ioi22N
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
layout/painting/nsDisplayItemTypesList.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/svg/nsSVGForeignObjectFrame.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -834,16 +834,18 @@ IsItemProbablyActive(nsDisplayItem* aIte
     bool is2D = t.Is2D(&t2d);
     GP("active: %d\n", transformItem->MayBeAnimated(aDisplayListBuilder));
     return transformItem->MayBeAnimated(aDisplayListBuilder) || !is2D || HasActiveChildren(*transformItem->GetChildren(), aDisplayListBuilder);
   } else if (aItem->GetType() == DisplayItemType::TYPE_OPACITY) {
     nsDisplayOpacity* opacityItem = static_cast<nsDisplayOpacity*>(aItem);
     bool active = opacityItem->NeedsActiveLayer(aDisplayListBuilder, opacityItem->Frame());
     GP("active: %d\n", active);
     return active || HasActiveChildren(*opacityItem->GetChildren(), aDisplayListBuilder);
+  } else if (aItem->GetType() == DisplayItemType::TYPE_FOREIGN_OBJECT) {
+    return true;
   }
   // TODO: handle other items?
   return false;
 }
 
 // If we have an item we need to make sure it matches the current group
 // otherwise it means the item switched groups and we need to invalidate
 // it and recreate the data.
@@ -1270,21 +1272,17 @@ WebRenderCommandBuilder::CreateWebRender
       AutoRestore<bool> restoreDoGrouping(mDoGrouping);
       if (itemType == DisplayItemType::TYPE_SVG_WRAPPER) {
         // Inside an <svg>, all display items that are not LAYER_ACTIVE wrapper
         // display items (like animated transforms / opacity) share the same
         // animated geometry root, so we can combine subsequent items of that
         // type into the same image.
         mDoGrouping = true;
         GP("attempting to enter the grouping code\n");
-      }/* else if (itemType == DisplayItemType::TYPE_FOREIGN_OBJECT) {
-        // We do not want to apply grouping inside <foreignObject>.
-        // TODO: TYPE_FOREIGN_OBJECT does not exist yet, make it exist
-        mDoGrouping = false;
-      }*/
+      }
 
       // Note: this call to CreateWebRenderCommands can recurse back into
       // this function if the |item| is a wrapper for a sublist.
       bool createdWRCommands =
         item->CreateWebRenderCommands(aBuilder, aResources, aSc, mManager,
                                       aDisplayListBuilder);
       if (!createdWRCommands) {
         PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -175,17 +175,17 @@ private:
   // tree don't duplicate scroll metadata that their ancestors already have.
   std::vector<const ActiveScrolledRoot*> mAsrStack;
   const ActiveScrolledRoot* mLastAsr;
 
   WebRenderUserDataRefTable mWebRenderUserDatas;
 
   // Store of WebRenderCanvasData objects for use in empty transactions
   CanvasDataSet mLastCanvasDatas;
-
+public:
   // Whether consecutive inactive display items should be grouped into one
   // blob image.
   bool mDoGrouping;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/layout/painting/nsDisplayItemTypesList.h
+++ b/layout/painting/nsDisplayItemTypesList.h
@@ -58,16 +58,17 @@ DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR_RE
 DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(MASK, 0)
 DECLARE_DISPLAY_ITEM_TYPE(FILTER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, 0)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT, 0)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_CHAR_CLIP, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, 0)
+DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_IMAGE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_THEMED_BACKGROUND_IMAGE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_FIXED_POSITION, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(TEXT, TYPE_RENDERS_NO_IMAGES)
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -52,16 +52,17 @@
 #include "GeckoProfiler.h"
 #include "nsViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
 #include "nsCanvasFrame.h"
 #include "StickyScrollContainer.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationUtils.h"
+#include "mozilla/AutoRestore.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/OperatorNewExtensions.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StyleAnimationValue.h"
@@ -10092,16 +10093,87 @@ nsDisplaySVGWrapper::CreateWebRenderComm
                                              aSc,
                                              aManager,
                                              aDisplayListBuilder);
   } else {
     return false;
   }
 }
 
+
+nsDisplayForeignObject::nsDisplayForeignObject(nsDisplayListBuilder* aBuilder,
+                                               nsIFrame* aFrame, nsDisplayList* aList)
+    : nsDisplayWrapList(aBuilder, aFrame, aList)
+{
+  MOZ_COUNT_CTOR(nsDisplayForeignObject);
+}
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+nsDisplayForeignObject::~nsDisplayForeignObject() {
+  MOZ_COUNT_DTOR(nsDisplayForeignObject);
+}
+#endif
+
+LayerState
+nsDisplayForeignObject::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                      LayerManager* aManager,
+                                      const ContainerLayerParameters& aParameters)
+{
+  RefPtr<LayerManager> layerManager = aBuilder->GetWidgetLayerManager();
+  if (layerManager && layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+    return LAYER_ACTIVE_FORCE;
+  }
+  return LAYER_NONE;
+}
+
+bool
+nsDisplayForeignObject::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
+{
+  RefPtr<LayerManager> layerManager = aBuilder->GetWidgetLayerManager();
+  if (layerManager && layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+    return false;
+  }
+  return true;
+}
+
+already_AddRefed<Layer>
+nsDisplayForeignObject::BuildLayer(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
+                                   const ContainerLayerParameters& aContainerParameters)
+{
+  ContainerLayerParameters newContainerParameters = aContainerParameters;
+  newContainerParameters.mDisableSubpixelAntialiasingInDescendants = true;
+
+  RefPtr<ContainerLayer> container = aManager->GetLayerBuilder()->
+    BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
+                           newContainerParameters, nullptr);
+
+  return container.forget();
+}
+
+bool
+nsDisplayForeignObject::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                             mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                             const StackingContextHelper& aSc,
+                                             mozilla::layers::WebRenderLayerManager* aManager,
+                                             nsDisplayListBuilder* aDisplayListBuilder)
+{
+  if (gfxPrefs::WebRenderBlobInvalidation()) {
+    AutoRestore<bool> restoreDoGrouping(aManager->CommandBuilder().mDoGrouping);
+    aManager->CommandBuilder().mDoGrouping = false;
+    return nsDisplayWrapList::CreateWebRenderCommands(aBuilder,
+                                             aResources,
+                                             aSc,
+                                             aManager,
+                                             aDisplayListBuilder);
+  } else {
+    return false;
+  }
+}
+
 namespace mozilla {
 
 uint32_t PaintTelemetry::sPaintLevel = 0;
 uint32_t PaintTelemetry::sMetricLevel = 0;
 EnumeratedArray<PaintTelemetry::Metric,
                 PaintTelemetry::Metric::COUNT,
                 double> PaintTelemetry::sMetrics;
 
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -6905,16 +6905,43 @@ public:
 
   bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                mozilla::wr::IpcResourceUpdateQueue& aResources,
                                const StackingContextHelper& aSc,
                                mozilla::layers::WebRenderLayerManager* aManager,
                                nsDisplayListBuilder* aDisplayListBuilder) override;
 };
 
+/**
+ * A display item for webrender to handle SVG foreign object
+ */
+class nsDisplayForeignObject : public nsDisplayWrapList {
+public:
+  NS_DISPLAY_DECL_NAME("ForeignObject", TYPE_FOREIGN_OBJECT)
+
+  nsDisplayForeignObject(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                         nsDisplayList* aList);
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayForeignObject();
+#endif
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager,
+                                             const ContainerLayerParameters& aContainerParameters) override;
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
+                                   const ContainerLayerParameters& aParameters) override;
+  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;
+
+  bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                               mozilla::wr::IpcResourceUpdateQueue& aResources,
+                               const StackingContextHelper& aSc,
+                               mozilla::layers::WebRenderLayerManager* aManager,
+                               nsDisplayListBuilder* aDisplayListBuilder) override;
+};
+
 namespace mozilla {
 
 class PaintTelemetry
 {
  public:
   enum class Metric {
     DisplayList,
     Layerization,
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -156,19 +156,22 @@ nsSVGForeignObjectFrame::Reflow(nsPresCo
 
 void
 nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                           const nsDisplayListSet& aLists)
 {
   if (!static_cast<const nsSVGElement*>(GetContent())->HasValidDimensions()) {
     return;
   }
-  // TODO: wrap items into an nsDisplayForeignObject
-  DisplayOutline(aBuilder, aLists);
-  BuildDisplayListForNonBlockChildren(aBuilder, aLists);
+  nsDisplayList newList;
+  nsDisplayListSet set(&newList, &newList, &newList,
+                       &newList, &newList, &newList);
+  DisplayOutline(aBuilder, set);
+  BuildDisplayListForNonBlockChildren(aBuilder, set);
+  aLists.Content()->AppendToTop(MakeDisplayItem<nsDisplayForeignObject>(aBuilder, this, &newList));
 }
 
 bool
 nsSVGForeignObjectFrame::IsSVGTransformed(Matrix *aOwnTransform,
                                           Matrix *aFromParentTransform) const
 {
   bool foundTransform = false;