Bug 1355570 - Update bindings and WebRender display list building for gradient tiling r?mattwoodrow draft
authorRyan Hunt <rhunt@eqrion.net>
Mon, 10 Apr 2017 07:52:27 -0400
changeset 560651 2691ef16e7c776441c176b69cf700eee670eabfe
parent 560650 a0dd5dc6fe2846e64de9feb1035b7618ca5adb6a
child 560652 0fa17b46b0d1e7cf7342bdc78e52171d9a69d41e
push id53497
push userbmo:rhunt@eqrion.net
push dateTue, 11 Apr 2017 18:52:32 +0000
reviewersmattwoodrow
bugs1355570
milestone55.0a1
Bug 1355570 - Update bindings and WebRender display list building for gradient tiling r?mattwoodrow MozReview-Commit-ID: KwhCBc8XxCN
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
layout/base/Units.h
layout/painting/nsCSSRenderingGradients.cpp
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -575,38 +575,44 @@ DisplayListBuilder::PushRect(const WrRec
 }
 
 void
 DisplayListBuilder::PushLinearGradient(const WrRect& aBounds,
                                        const WrClipRegion& aClip,
                                        const WrPoint& aStartPoint,
                                        const WrPoint& aEndPoint,
                                        const nsTArray<WrGradientStop>& aStops,
-                                       wr::GradientExtendMode aExtendMode)
+                                       wr::GradientExtendMode aExtendMode,
+                                       const WrSize aTileSize,
+                                       const WrSize aTileSpacing)
 {
   wr_dp_push_linear_gradient(mWrState,
                              aBounds, aClip,
                              aStartPoint, aEndPoint,
                              aStops.Elements(), aStops.Length(),
-                             aExtendMode);
+                             aExtendMode,
+                             aTileSize, aTileSpacing);
 }
 
 void
 DisplayListBuilder::PushRadialGradient(const WrRect& aBounds,
                                        const WrClipRegion& aClip,
                                        const WrPoint& aCenter,
                                        const WrSize& aRadius,
                                        const nsTArray<WrGradientStop>& aStops,
-                                       wr::GradientExtendMode aExtendMode)
+                                       wr::GradientExtendMode aExtendMode,
+                                       const WrSize aTileSize,
+                                       const WrSize aTileSpacing)
 {
   wr_dp_push_radial_gradient(mWrState,
                              aBounds, aClip,
                              aCenter, aRadius,
                              aStops.Elements(), aStops.Length(),
-                             aExtendMode);
+                             aExtendMode,
+                             aTileSize, aTileSpacing);
 }
 
 void
 DisplayListBuilder::PushImage(const WrRect& aBounds,
                               const WrClipRegion& aClip,
                               wr::ImageRendering aFilter,
                               wr::ImageKey aImage)
 {
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -159,24 +159,28 @@ public:
                 const WrClipRegion& aClip,
                 const WrColor& aColor);
 
   void PushLinearGradient(const WrRect& aBounds,
                           const WrClipRegion& aClip,
                           const WrPoint& aStartPoint,
                           const WrPoint& aEndPoint,
                           const nsTArray<WrGradientStop>& aStops,
-                          wr::GradientExtendMode aExtendMode);
+                          wr::GradientExtendMode aExtendMode,
+                          const WrSize aTileSize,
+                          const WrSize aTileSpacing);
 
   void PushRadialGradient(const WrRect& aBounds,
                           const WrClipRegion& aClip,
                           const WrPoint& aCenter,
                           const WrSize& aRadius,
                           const nsTArray<WrGradientStop>& aStops,
-                          wr::GradientExtendMode aExtendMode);
+                          wr::GradientExtendMode aExtendMode,
+                          const WrSize aTileSize,
+                          const WrSize aTileSpacing);
 
   void PushImage(const WrRect& aBounds,
                  const WrClipRegion& aClip,
                  wr::ImageRendering aFilter,
                  wr::ImageKey aImage);
 
   void PushImage(const WrRect& aBounds,
                  const WrClipRegion& aClip,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1345,60 +1345,66 @@ pub extern "C" fn wr_dp_push_border_radi
 #[no_mangle]
 pub extern "C" fn wr_dp_push_linear_gradient(state: &mut WrState,
                                              rect: WrRect,
                                              clip: WrClipRegion,
                                              start_point: WrPoint,
                                              end_point: WrPoint,
                                              stops: *const WrGradientStop,
                                              stops_count: usize,
-                                             extend_mode: WrGradientExtendMode) {
+                                             extend_mode: WrGradientExtendMode,
+                                             tile_size: WrSize,
+                                             tile_spacing: WrSize) {
     assert!(unsafe { is_in_main_thread() });
 
     let stops =
         WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
 
     let gradient = state.frame_builder.dl_builder.create_gradient(start_point.to_point(),
                                                                   end_point.to_point(),
                                                                   stops,
                                                                   extend_mode.to_gradient_extend_mode());
     let rect = rect.to_rect();
-    let tile_size = rect.size.clone();
+    let tile_size = tile_size.to_size();
+    let tile_spacing = tile_spacing.to_size();
     state.frame_builder.dl_builder.push_gradient(rect,
                                                  clip.to_clip_region(),
                                                  gradient,
                                                  tile_size,
-                                                 LayoutSize::new(0.0, 0.0));
+                                                 tile_spacing);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_radial_gradient(state: &mut WrState,
                                              rect: WrRect,
                                              clip: WrClipRegion,
                                              center: WrPoint,
                                              radius: WrSize,
                                              stops: *const WrGradientStop,
                                              stops_count: usize,
-                                             extend_mode: WrGradientExtendMode) {
+                                             extend_mode: WrGradientExtendMode,
+                                             tile_size: WrSize,
+                                             tile_spacing: WrSize) {
     assert!(unsafe { is_in_main_thread() });
 
     let stops =
         WrGradientStop::to_gradient_stops(unsafe { slice::from_raw_parts(stops, stops_count) });
 
     let gradient = state.frame_builder.dl_builder.create_radial_gradient(center.to_point(),
                                                                          radius.to_size(),
                                                                          stops,
                                                                          extend_mode.to_gradient_extend_mode());
     let rect = rect.to_rect();
-    let tile_size = rect.size.clone();
+    let tile_size = tile_size.to_size();
+    let tile_spacing = tile_spacing.to_size();
     state.frame_builder.dl_builder.push_radial_gradient(rect,
                                                         clip.to_clip_region(),
                                                         gradient,
                                                         tile_size,
-                                                        LayoutSize::new(0.0, 0.0));
+                                                        tile_spacing);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_push_box_shadow(state: &mut WrState,
                                         rect: WrRect,
                                         clip: WrClipRegion,
                                         box_bounds: WrRect,
                                         offset: WrPoint,
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -706,24 +706,26 @@ wr_dp_push_border_radial_gradient(WrStat
                                   WrGradientExtendMode extendMode,
                                   WrSideOffsets2Df32 outset)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_linear_gradient(WrState* wrState, WrRect bounds, WrClipRegion clip,
                            WrPoint startPoint, WrPoint endPoint,
                            const WrGradientStop* stops, size_t stopsCount,
-                           WrGradientExtendMode extendMode)
+                           WrGradientExtendMode extendMode,
+                           WrSize tileSize, WrSize tileSpacing)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_radial_gradient(WrState* wrState, WrRect bounds, WrClipRegion clip,
                            WrPoint center, WrSize radius,
                            const WrGradientStop* stops, size_t stopsCount,
-                           WrGradientExtendMode extendMode)
+                           WrGradientExtendMode extendMode,
+                           WrSize tileSize, WrSize tileSpacing)
 WR_FUNC;
 
 WR_INLINE void
 wr_dp_push_box_shadow(WrState* wrState, WrRect rect, WrClipRegion clip,
                       WrRect box_bounds, WrPoint offset, WrColor color,
                       float blur_radius, float spread_radius, float border_radius,
                       WrBoxShadowClipMode clip_mode)
 WR_FUNC;
--- a/layout/base/Units.h
+++ b/layout/base/Units.h
@@ -292,16 +292,22 @@ struct CSSPixel {
 struct LayoutDevicePixel {
   static LayoutDeviceRect FromAppUnits(const nsRect& aRect, nscoord aAppUnitsPerDevPixel) {
     return LayoutDeviceRect(NSAppUnitsToFloatPixels(aRect.x, float(aAppUnitsPerDevPixel)),
                             NSAppUnitsToFloatPixels(aRect.y, float(aAppUnitsPerDevPixel)),
                             NSAppUnitsToFloatPixels(aRect.width, float(aAppUnitsPerDevPixel)),
                             NSAppUnitsToFloatPixels(aRect.height, float(aAppUnitsPerDevPixel)));
   }
 
+  static LayoutDeviceSize FromAppUnits(const nsSize& aSize, nscoord aAppUnitsPerDevPixel) {
+    return LayoutDeviceSize(
+      NSAppUnitsToFloatPixels(aSize.width, aAppUnitsPerDevPixel),
+      NSAppUnitsToFloatPixels(aSize.height, aAppUnitsPerDevPixel));
+  }
+
   static LayoutDevicePoint FromAppUnits(const nsPoint& aPoint, nscoord aAppUnitsPerDevPixel) {
     return LayoutDevicePoint(NSAppUnitsToFloatPixels(aPoint.x, aAppUnitsPerDevPixel),
                              NSAppUnitsToFloatPixels(aPoint.y, aAppUnitsPerDevPixel));
   }
 
   static LayoutDeviceMargin FromAppUnits(const nsMargin& aMargin, nscoord aAppUnitsPerDevPixel) {
     return LayoutDeviceMargin(NSAppUnitsToFloatPixels(aMargin.top, aAppUnitsPerDevPixel),
                               NSAppUnitsToFloatPixels(aMargin.right, aAppUnitsPerDevPixel),
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -1043,59 +1043,53 @@ nsCSSGradientRenderer::BuildWebRenderDis
 {
   WrGradientExtendMode extendMode;
   nsTArray<WrGradientStop> stops;
   LayoutDevicePoint lineStart;
   LayoutDevicePoint lineEnd;
   LayoutDeviceSize gradientRadius;
   BuildWebRenderParameters(aOpacity, extendMode, stops, lineStart, lineEnd, gradientRadius);
 
-  // Do a naive tiling of the gradient by making multiple display items
-  // TODO: this should be done on the WebRender side eventually
+  nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel();
 
-  nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel();
+  // Translate the parameters into device coordinates
+  LayoutDeviceRect clipBounds = LayoutDevicePixel::FromAppUnits(mFillArea, appUnitsPerDevPixel);
   LayoutDeviceRect firstTileBounds = LayoutDevicePixel::FromAppUnits(mDest, appUnitsPerDevPixel);
-  LayoutDeviceRect clipBounds = LayoutDevicePixel::FromAppUnits(mFillArea, appUnitsPerDevPixel);
-
-  // Make the units relative to the parent stacking context
-  firstTileBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(firstTileBounds.ToUnknownRect()));
-  clipBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(clipBounds.ToUnknownRect()));
+  LayoutDeviceSize tileRepeat = LayoutDevicePixel::FromAppUnits(mRepeatSize, appUnitsPerDevPixel);
 
-  float xStart = 0;
-  float yStart = 0;
-  float xEnd = (mFillArea.XMost() - mDest.X()) / appUnitsPerDevPixel;
-  float yEnd = (mFillArea.YMost() - mDest.Y()) / appUnitsPerDevPixel;
+  // Calculate the bounds of the gradient display item, which starts at the first
+  // tile and extends to the end of clip bounds
+  LayoutDevicePoint tileToClip = clipBounds.BottomRight() - firstTileBounds.TopLeft();
+  LayoutDeviceRect gradientBounds = LayoutDeviceRect(firstTileBounds.TopLeft(),
+                                                     LayoutDeviceSize(tileToClip.x, tileToClip.y));
 
-  float stepX = mRepeatSize.width / appUnitsPerDevPixel;
-  float stepY = mRepeatSize.height / appUnitsPerDevPixel;
+  // Calculate the tile spacing, which is the repeat size minus the tile size
+  LayoutDeviceSize tileSpacing = tileRepeat - firstTileBounds.Size();
 
-  for (float y = yStart; y < yEnd; y += stepY) {
-    for (float x = xStart; x < xEnd; x += stepX) {
-      LayoutDevicePoint tileOffset = firstTileBounds.TopLeft() + LayoutDevicePoint(x, y);
-      LayoutDeviceRect tileRect = LayoutDeviceRect(tileOffset, firstTileBounds.Size());
+  // Make the rects relative to the parent stacking context
+  clipBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(clipBounds.ToUnknownRect()));
+  firstTileBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(firstTileBounds.ToUnknownRect()));
+  gradientBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(gradientBounds.ToUnknownRect()));
 
-      if (mGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
-        LayoutDevicePoint relativeGradientStart = lineStart + tileOffset;
-        LayoutDevicePoint relativeGradientEnd = lineEnd + tileOffset;
-
-        aBuilder.PushLinearGradient(
-          mozilla::wr::ToWrRect(tileRect),
-          aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
-          mozilla::wr::ToWrPoint(relativeGradientStart),
-          mozilla::wr::ToWrPoint(relativeGradientEnd),
-          stops,
-          extendMode);
-      } else {
-        LayoutDevicePoint relativeGradientCenter = lineStart + tileOffset;
-
-        aBuilder.PushRadialGradient(
-          mozilla::wr::ToWrRect(tileRect),
-          aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
-          mozilla::wr::ToWrPoint(relativeGradientCenter),
-          mozilla::wr::ToWrSize(gradientRadius),
-          stops,
-          extendMode);
-      }
-    }
+  if (mGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
+    aBuilder.PushLinearGradient(
+      mozilla::wr::ToWrRect(gradientBounds),
+      aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
+      mozilla::wr::ToWrPoint(lineStart),
+      mozilla::wr::ToWrPoint(lineEnd),
+      stops,
+      extendMode,
+      mozilla::wr::ToWrSize(firstTileBounds.Size()),
+      mozilla::wr::ToWrSize(tileSpacing));
+  } else {
+    aBuilder.PushRadialGradient(
+      mozilla::wr::ToWrRect(gradientBounds),
+      aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
+      mozilla::wr::ToWrPoint(lineStart),
+      mozilla::wr::ToWrSize(gradientRadius),
+      stops,
+      extendMode,
+      mozilla::wr::ToWrSize(firstTileBounds.Size()),
+      mozilla::wr::ToWrSize(tileSpacing));
   }
 }
 
 } // namespace mozilla