Bug 1302551 - Add nsDisplaySolidColorRegion and create it for elements that have the cutoutregion property set on them. r=mattwoodrow
authorMarkus Stange <mstange@themasta.com>
Wed, 14 Sep 2016 23:18:30 -0400
changeset 342837 eb2ab5bb69304f6081e1e33b20a7e1cf6abe23e2
parent 342836 11f62de653a855b1e96c4e9460e5045917221cb5
child 342838 4e8e39b7c8ed539688c6b7bf4b3e8ebff013e936
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-esr52@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1302551
milestone51.0a1
Bug 1302551 - Add nsDisplaySolidColorRegion and create it for elements that have the cutoutregion property set on them. r=mattwoodrow MozReview-Commit-ID: LtXrks9Su73
layout/base/nsDisplayItemTypesList.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsDisplayListInvalidation.cpp
layout/base/nsDisplayListInvalidation.h
--- a/layout/base/nsDisplayItemTypesList.h
+++ b/layout/base/nsDisplayItemTypesList.h
@@ -45,16 +45,17 @@ DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_VIDEO)
 DECLARE_DISPLAY_ITEM_TYPE(PRINT_PLUGIN)
 DECLARE_DISPLAY_ITEM_TYPE(RANGE_FOCUS_RING)
 DECLARE_DISPLAY_ITEM_TYPE(REMOTE)
 DECLARE_DISPLAY_ITEM_TYPE(REMOTE_SHADOW)
 DECLARE_DISPLAY_ITEM_TYPE(RESOLUTION)
 DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER)
 DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY)
 DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR)
+DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR_REGION)
 DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT)
 DECLARE_DISPLAY_ITEM_TYPE(MASK)
 DECLARE_DISPLAY_ITEM_TYPE(FILTER)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_GLYPHS)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_PATH_GEOMETRY)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND)
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2383,16 +2383,47 @@ nsDisplaySolidColor::WriteDebugInfo(std:
 {
   aStream << " (rgba "
           << (int)NS_GET_R(mColor) << ","
           << (int)NS_GET_G(mColor) << ","
           << (int)NS_GET_B(mColor) << ","
           << (int)NS_GET_A(mColor) << ")";
 }
 
+nsRect
+nsDisplaySolidColorRegion::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
+{
+  *aSnap = true;
+  return mRegion.GetBounds();
+}
+
+void
+nsDisplaySolidColorRegion::Paint(nsDisplayListBuilder* aBuilder,
+                                 nsRenderingContext* aCtx)
+{
+  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+  DrawTarget* drawTarget = aCtx->GetDrawTarget();
+  ColorPattern color(mColor);
+  for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
+    Rect rect =
+      NSRectToSnappedRect(iter.Get(), appUnitsPerDevPixel, *drawTarget);
+    drawTarget->FillRect(rect, color);
+  }
+}
+
+void
+nsDisplaySolidColorRegion::WriteDebugInfo(std::stringstream& aStream)
+{
+  aStream << " (rgba "
+          << int(mColor.r * 255) << ","
+          << int(mColor.g * 255) << ","
+          << int(mColor.b * 255) << ","
+          << mColor.a << ")";
+}
+
 static void
 RegisterThemeGeometry(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       nsITheme::ThemeGeometryType aType)
 {
   if (aBuilder->IsInRootChromeDocumentOrPopup() && !aBuilder->IsInTransform()) {
     nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
     nsRect borderBox(aFrame->GetOffsetTo(displayRoot), aFrame->GetSize());
     aBuilder->RegisterThemeGeometry(aType,
@@ -2509,16 +2540,50 @@ SetBackgroundClipRegion(DisplayListClipS
   if (clip.mHasAdditionalBGClipArea) {
     aClipState.ClipContentDescendants(clip.mAdditionalBGClipArea, clip.mBGClipArea,
                                       clip.mHasRoundedCorners ? clip.mRadii : nullptr);
   } else {
     aClipState.ClipContentDescendants(clip.mBGClipArea, clip.mHasRoundedCorners ? clip.mRadii : nullptr);
   }
 }
 
+/**
+ * This is used for the find bar highlighter overlay. It's only accessible
+ * through the AnonymousContent API, so it's not exposed to general web pages.
+ */
+static bool
+SpecialCutoutRegionCase(nsDisplayListBuilder* aBuilder,
+                        nsIFrame* aFrame,
+                        const nsRect& aBackgroundRect,
+                        nsDisplayList* aList,
+                        nscolor aColor)
+{
+  nsIContent* content = aFrame->GetContent();
+  if (!content) {
+    return false;
+  }
+
+  void* cutoutRegion = content->GetProperty(nsGkAtoms::cutoutregion);
+  if (!cutoutRegion) {
+    return false;
+  }
+
+  if (NS_GET_A(aColor) == 0) {
+    return true;
+  }
+
+  nsRegion region;
+  region.Sub(aBackgroundRect, *static_cast<nsRegion*>(cutoutRegion));
+  region.MoveBy(aBuilder->ToReferenceFrame(aFrame));
+  aList->AppendNewToTop(
+    new (aBuilder) nsDisplaySolidColorRegion(aBuilder, aFrame, region, aColor));
+
+  return true;
+}
+
 
 /*static*/ bool
 nsDisplayBackgroundImage::AppendBackgroundItemsToTop(nsDisplayListBuilder* aBuilder,
                                                      nsIFrame* aFrame,
                                                      const nsRect& aBackgroundRect,
                                                      nsDisplayList* aList,
                                                      bool aAllowWillPaintBorderOptimization)
 {
@@ -2540,16 +2605,20 @@ nsDisplayBackgroundImage::AppendBackgrou
   nscolor color = NS_RGBA(0,0,0,0);
   if (!nsCSSRendering::IsCanvasFrame(aFrame) && bg) {
     bool drawBackgroundImage;
     color =
       nsCSSRendering::DetermineBackgroundColor(presContext, bgSC, aFrame,
                                                drawBackgroundImage, drawBackgroundColor);
   }
 
+  if (SpecialCutoutRegionCase(aBuilder, aFrame, aBackgroundRect, aList, color)) {
+    return false;
+  }
+
   const nsStyleBorder* borderStyle = aFrame->StyleBorder();
   const nsStyleEffects* effectsStyle = aFrame->StyleEffects();
   bool hasInsetShadow = effectsStyle->mBoxShadow &&
                         effectsStyle->mBoxShadow->HasShadowWithInset(true);
   bool willPaintBorder = aAllowWillPaintBorderOptimization &&
                          !isThemed && !hasInsetShadow &&
                          borderStyle->HasBorder();
 
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2650,16 +2650,69 @@ public:
 
   NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
 
 private:
   nsRect  mBounds;
 };
 
 /**
+ * A display item that renders a solid color over a region. This is not
+ * exposed through CSS, its only purpose is efficient invalidation of
+ * the find bar highlighter dimmer.
+ */
+class nsDisplaySolidColorRegion : public nsDisplayItem {
+  typedef mozilla::gfx::Color Color;
+
+public:
+  nsDisplaySolidColorRegion(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                            const nsRegion& aRegion, nscolor aColor)
+    : nsDisplayItem(aBuilder, aFrame), mRegion(aRegion), mColor(Color::FromABGR(aColor))
+  {
+    NS_ASSERTION(NS_GET_A(aColor) > 0, "Don't create invisible nsDisplaySolidColorRegions!");
+    MOZ_COUNT_CTOR(nsDisplaySolidColorRegion);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplaySolidColorRegion() {
+    MOZ_COUNT_DTOR(nsDisplaySolidColorRegion);
+  }
+#endif
+
+  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
+  {
+    return new nsDisplaySolidColorRegionGeometry(this, aBuilder, mRegion, mColor);
+  }
+
+  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
+                                         const nsDisplayItemGeometry* aGeometry,
+                                         nsRegion* aInvalidRegion) override
+  {
+    const nsDisplaySolidColorRegionGeometry* geometry =
+      static_cast<const nsDisplaySolidColorRegionGeometry*>(aGeometry);
+    if (mColor == geometry->mColor) {
+      aInvalidRegion->Xor(geometry->mRegion, mRegion);
+    } else {
+      aInvalidRegion->Or(geometry->mRegion.GetBounds(), mRegion.GetBounds());
+    }
+  }
+
+protected:
+
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
+  virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
+  virtual void WriteDebugInfo(std::stringstream& aStream) override;
+
+  NS_DISPLAY_DECL_NAME("SolidColorRegion", TYPE_SOLID_COLOR_REGION)
+
+private:
+  nsRegion mRegion;
+  Color mColor;
+};
+
+/**
  * A display item to paint one background-image for a frame. Each background
  * image layer gets its own nsDisplayBackgroundImage.
  */
 class nsDisplayBackgroundImage : public nsDisplayImageContainer {
 public:
   /**
    * aLayer signifies which background layer this item represents.
    * aIsThemed should be the value of aFrame->IsThemed.
--- a/layout/base/nsDisplayListInvalidation.cpp
+++ b/layout/base/nsDisplayListInvalidation.cpp
@@ -101,16 +101,23 @@ nsDisplayBoxShadowInnerGeometry::MoveBy(
 }
 
 nsDisplayBoxShadowOuterGeometry::nsDisplayBoxShadowOuterGeometry(nsDisplayItem* aItem,
     nsDisplayListBuilder* aBuilder, float aOpacity)
   : nsDisplayItemGenericGeometry(aItem, aBuilder)
   , mOpacity(aOpacity)
 {}
 
+void
+nsDisplaySolidColorRegionGeometry::MoveBy(const nsPoint& aOffset)
+{
+  nsDisplayItemGeometry::MoveBy(aOffset);
+  mRegion.MoveBy(aOffset);
+}
+
 nsDisplaySVGEffectsGeometry::nsDisplaySVGEffectsGeometry(nsDisplaySVGEffects* aItem, nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGeometry(aItem, aBuilder)
   , nsImageGeometryMixin(aItem, aBuilder)
   , mBBox(aItem->BBoxInUserSpace())
   , mUserSpaceOffset(aItem->UserSpaceOffset())
   , mFrameOffsetToReferenceFrame(aItem->ToReferenceFrame())
 {}
 
--- a/layout/base/nsDisplayListInvalidation.h
+++ b/layout/base/nsDisplayListInvalidation.h
@@ -16,16 +16,22 @@
 class nsDisplayBackgroundImage;
 class nsCharClipDisplayItem;
 class nsDisplayItem;
 class nsDisplayListBuilder;
 class nsDisplaySVGEffects;
 class nsDisplayTableItem;
 class nsDisplayThemedBackground;
 
+namespace mozilla {
+namespace gfx {
+struct Color;
+}
+}
+
 /**
  * This stores the geometry of an nsDisplayItem, and the area
  * that will be affected when painting the item.
  *
  * It is used to retain information about display items so they
  * can be compared against new display items in the next paint.
  */
 class nsDisplayItemGeometry
@@ -236,16 +242,34 @@ public:
                               nscolor aColor)
     : nsDisplayItemBoundsGeometry(aItem, aBuilder)
     , mColor(aColor)
   { }
 
   nscolor mColor;
 };
 
+class nsDisplaySolidColorRegionGeometry : public nsDisplayItemBoundsGeometry
+{
+public:
+  nsDisplaySolidColorRegionGeometry(nsDisplayItem* aItem,
+                                    nsDisplayListBuilder* aBuilder,
+                                    const nsRegion& aRegion,
+                                    mozilla::gfx::Color aColor)
+    : nsDisplayItemBoundsGeometry(aItem, aBuilder)
+    , mRegion(aRegion)
+    , mColor(aColor)
+  { }
+
+  virtual void MoveBy(const nsPoint& aOffset) override;
+
+  nsRegion mRegion;
+  mozilla::gfx::Color mColor;
+};
+
 class nsDisplaySVGEffectsGeometry : public nsDisplayItemGeometry
   , public nsImageGeometryMixin<nsDisplaySVGEffectsGeometry>
 {
 public:
   nsDisplaySVGEffectsGeometry(nsDisplaySVGEffects* aItem, nsDisplayListBuilder* aBuilder);
 
   virtual void MoveBy(const nsPoint& aOffset) override;