Bug 1341101 part 5 - Support building WR DisplayItems for BackgroundImageLayers that are gradients r=mattwoodrow
MozReview-Commit-ID: BNLT8Wbp672
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1933,16 +1933,75 @@ nsCSSRendering::PaintStyleImageLayer(con
}
sc = aParams.frame->StyleContext();
}
return PaintStyleImageLayerWithSC(aParams, aRenderingCtx, sc, *aParams.frame->StyleBorder());
}
+bool
+nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(nsPresContext& aPresCtx,
+ nsIFrame *aFrame,
+ const nsStyleBackground* aBackgroundStyle,
+ int32_t aLayer)
+{
+ if (!aBackgroundStyle) {
+ return false;
+ }
+
+ MOZ_ASSERT(aFrame &&
+ aLayer >= 0 &&
+ (uint32_t)aLayer < aBackgroundStyle->mImage.mLayers.Length());
+
+ // We cannot draw native themed backgrounds
+ const nsStyleDisplay* displayData = aFrame->StyleDisplay();
+ if (displayData->UsedAppearance()) {
+ nsITheme *theme = aPresCtx.GetTheme();
+ if (theme && theme->ThemeSupportsWidget(&aPresCtx,
+ aFrame,
+ displayData->UsedAppearance())) {
+ return false;
+ }
+ }
+
+ // We only support painting gradients for a single style image layer
+ return aBackgroundStyle->mImage.mLayers[aLayer].mImage.GetType() == eStyleImageType_Gradient;
+}
+
+void
+nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer)
+{
+ NS_PRECONDITION(aParams.frame,
+ "Frame is expected to be provided to BuildWebRenderDisplayItemsForStyleImageLayer");
+
+ nsStyleContext *sc;
+ if (!FindBackground(aParams.frame, &sc)) {
+ // We don't want to bail out if moz-appearance is set on a root
+ // node. If it has a parent content node, bail because it's not
+ // a root, otherwise keep going in order to let the theme stuff
+ // draw the background. The canvas really should be drawing the
+ // bg, but there's no way to hook that up via css.
+ if (!aParams.frame->StyleDisplay()->UsedAppearance()) {
+ return;
+ }
+
+ nsIContent* content = aParams.frame->GetContent();
+ if (!content || content->GetParent()) {
+ return;
+ }
+
+ sc = aParams.frame->StyleContext();
+ }
+
+ return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aLayer, sc, *aParams.frame->StyleBorder());
+}
+
static bool
IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
{
if (aBorder.GetComputedBorder().Side(aSide) == 0)
return true;
switch (aBorder.GetBorderStyle(aSide)) {
case NS_STYLE_BORDER_STYLE_SOLID:
case NS_STYLE_BORDER_STYLE_GROOVE:
@@ -2642,16 +2701,71 @@ nsCSSRendering::PaintStyleImageLayerWith
ctx->SetOp(CompositionOp::OP_OVER);
}
}
}
return result;
}
+void
+nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+ nsStyleContext *aBackgroundSC,
+ const nsStyleBorder& aBorder)
+{
+ MOZ_ASSERT(CanBuildWebRenderDisplayItemsForStyleImageLayer(aParams.presCtx,
+ aParams.frame,
+ aBackgroundSC->StyleBackground(),
+ aParams.layer));
+
+ MOZ_ASSERT(!(aParams.paintFlags & PAINTBG_MASK_IMAGE));
+
+ nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
+ ImageLayerClipState clipState;
+
+ clipState.mBGClipArea = *aParams.bgClipRect;
+ clipState.mCustomClip = true;
+ clipState.mHasRoundedCorners = false;
+ SetupDirtyRects(clipState.mBGClipArea, aParams.dirtyRect, appUnitsPerPixel,
+ &clipState.mDirtyRectInAppUnits,
+ &clipState.mDirtyRectInDevPx);
+
+ // Compute the outermost boundary of the area that might be painted.
+ // Same coordinate space as aParams.borderArea & aParams.bgClipRect.
+ Sides skipSides = aParams.frame->GetSkipSides();
+ nsRect paintBorderArea =
+ ::BoxDecorationRectForBackground(aParams.frame, aParams.borderArea,
+ skipSides, &aBorder);
+
+ const nsStyleImageLayers& layers = aBackgroundSC->StyleBackground()->mImage;
+ const nsStyleImageLayers::Layer& layer = layers.mLayers[aParams.layer];
+
+ // Skip the following layer painting code if we found the dirty region is
+ // empty or the current layer is not selected for drawing.
+ if (clipState.mDirtyRectInDevPx.IsEmpty()) {
+ return;
+ }
+
+ nsBackgroundLayerState state =
+ PrepareImageLayer(&aParams.presCtx, aParams.frame,
+ aParams.paintFlags, paintBorderArea,
+ clipState.mBGClipArea, layer, nullptr);
+
+ if (!state.mFillArea.IsEmpty()) {
+ state.mImageRenderer.BuildWebRenderDisplayItemsForLayer(&aParams.presCtx,
+ aBuilder, aLayer,
+ state.mDestArea, state.mFillArea,
+ state.mAnchor + paintBorderArea.TopLeft(),
+ clipState.mDirtyRectInAppUnits,
+ state.mRepeatSize, aParams.opacity);
+ }
+}
+
nsRect
nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
const nsStyleImageLayers::Layer& aLayer,
nsIFrame** aAttachedToFrame,
bool* aOutIsTransformedFixed)
{
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -28,18 +28,23 @@ namespace mozilla {
namespace gfx {
struct Color;
class DrawTarget;
} // namespace gfx
namespace layers {
class ImageContainer;
+class WebRenderDisplayItemLayer;
} // namespace layers
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+
enum class PaintBorderFlags : uint8_t
{
SYNC_DECODE_IMAGES = 1 << 0
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintBorderFlags)
} // namespace mozilla
@@ -445,17 +450,16 @@ struct nsCSSRendering {
layer(aLayer),
compositionOp(aCompositionOp),
opacity(aOpacity) {}
};
static DrawResult PaintStyleImageLayer(const PaintBGParams& aParams,
nsRenderingContext& aRenderingCtx);
-
/**
* Same as |PaintStyleImageLayer|, except using the provided style structs.
* This short-circuits the code that ensures that the root element's
* {background|mask} is drawn on the canvas.
* The aLayer parameter allows you to paint a single layer of the
* {background|mask}.
* The default value for aLayer, -1, means that all layers will be painted.
* The background color will only be painted if the back-most layer is also
@@ -464,16 +468,30 @@ struct nsCSSRendering {
* If all layers are painted, the image layer's blend mode (or the mask
* layer's composition mode) will be used.
*/
static DrawResult PaintStyleImageLayerWithSC(const PaintBGParams& aParams,
nsRenderingContext& aRenderingCtx,
nsStyleContext *mBackgroundSC,
const nsStyleBorder& aBorder);
+ static bool CanBuildWebRenderDisplayItemsForStyleImageLayer(nsPresContext& aPresCtx,
+ nsIFrame *aFrame,
+ const nsStyleBackground* aBackgroundStyle,
+ int32_t aLayer);
+ static void BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer);
+
+ static void BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+ nsStyleContext *mBackgroundSC,
+ const nsStyleBorder& aBorder);
+
/**
* Returns the rectangle covered by the given background layer image, taking
* into account background positioning, sizing, and repetition, but not
* clipping.
*/
static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
nsIFrame* aForFrame,
const nsRect& aBorderArea,
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* utility functions for drawing borders and backgrounds */
#include "nsImageRenderer.h"
#include "nsCSSRenderingGradients.h"
+#include "mozilla/webrender/WebRenderAPI.h"
nsSize
CSSSizeOrRatio::ComputeConcreteSize() const
{
NS_ASSERTION(CanComputeConcreteSize(), "Cannot compute");
if (mHasWidth && mHasHeight) {
return nsSize(mWidth, mHeight);
}
@@ -438,17 +439,16 @@ RGBALuminanceOperation(uint8_t *aData,
*pixel = (((((*pixel & 0x00FF0000) >> 16) * redFactor) +
(((*pixel & 0x0000FF00) >> 8) * greenFactor) +
((*pixel & 0x000000FF) * blueFactor)) >> 8) << 24;
pixel++;
}
}
}
-
DrawResult
nsImageRenderer::Draw(nsPresContext* aPresContext,
nsRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsSize& aRepeatSize,
@@ -559,16 +559,54 @@ nsImageRenderer::Draw(nsPresContext*
Rect(0, 0, tmpDTRect.width, tmpDTRect.height),
DrawSurfaceOptions(SamplingFilter::POINT),
DrawOptions(1.0f, aRenderingContext.ThebesContext()->CurrentOp()));
}
return result;
}
+void
+nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext* aPresContext,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+ const nsRect& aDirtyRect,
+ const nsRect& aDest,
+ const nsRect& aFill,
+ const nsPoint& aAnchor,
+ const nsSize& aRepeatSize,
+ const CSSIntRect& aSrc,
+ float aOpacity)
+{
+ if (!IsReady()) {
+ NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
+ return;
+ }
+ if (aDest.IsEmpty() || aFill.IsEmpty() ||
+ mSize.width <= 0 || mSize.height <= 0) {
+ return;
+ }
+
+ switch (mType) {
+ case eStyleImageType_Gradient:
+ {
+ Maybe<nsCSSGradientRenderer> renderer =
+ nsCSSGradientRenderer::Create(aPresContext, mGradientData,
+ aDest, aFill, aRepeatSize, aSrc, mSize);
+
+ if (renderer) {
+ renderer->BuildWebRenderDisplayItems(aBuilder, aLayer, aOpacity);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
already_AddRefed<gfxDrawable>
nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
gfxContext& aContext)
{
NS_ASSERTION(mType == eStyleImageType_Element,
"DrawableForElement only makes sense if backed by an element");
if (mPaintServerFrame) {
// XXX(seth): In order to not pass FLAG_SYNC_DECODE_IMAGES here,
@@ -619,16 +657,44 @@ nsImageRenderer::DrawLayer(nsPresContext
return Draw(aPresContext, aRenderingContext,
aDirty, aDest, aFill, aAnchor, aRepeatSize,
CSSIntRect(0, 0,
nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
aOpacity);
}
+void
+nsImageRenderer::BuildWebRenderDisplayItemsForLayer(nsPresContext* aPresContext,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ WebRenderDisplayItemLayer* aLayer,
+ const nsRect& aDest,
+ const nsRect& aFill,
+ const nsPoint& aAnchor,
+ const nsRect& aDirty,
+ const nsSize& aRepeatSize,
+ float aOpacity)
+{
+ if (!IsReady()) {
+ NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
+ return;
+ }
+ if (aDest.IsEmpty() || aFill.IsEmpty() ||
+ mSize.width <= 0 || mSize.height <= 0) {
+ return;
+ }
+
+ BuildWebRenderDisplayItems(aPresContext, aBuilder, aLayer,
+ aDirty, aDest, aFill, aAnchor, aRepeatSize,
+ CSSIntRect(0, 0,
+ nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
+ nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
+ aOpacity);
+}
+
/**
* Compute the size and position of the master copy of the image. I.e., a single
* tile used to fill the dest rect.
* aFill The destination rect to be filled
* aHFill and aVFill are the repeat patterns for the component -
* NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
* aUnitSize The size of the source rect in dest coords.
*/
--- a/layout/painting/nsImageRenderer.h
+++ b/layout/painting/nsImageRenderer.h
@@ -8,16 +8,24 @@
#include "nsLayoutUtils.h"
#include "nsStyleStruct.h"
#include "Units.h"
class gfxDrawable;
namespace mozilla {
+namespace layers {
+class WebRenderDisplayItemLayer;
+} // namespace layers
+
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+
// A CSSSizeOrRatio represents a (possibly partially specified) size for use
// in computing image sizes. Either or both of the width and height might be
// given. A ratio of width to height may also be given. If we at least two
// of these then we can compute a concrete size, that is a width and height.
struct CSSSizeOrRatio
{
CSSSizeOrRatio()
: mRatio(0, 0)
@@ -188,16 +196,31 @@ public:
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsRect& aDirty,
const nsSize& aRepeatSize,
float aOpacity);
/**
+ * Builds WebRender DisplayItems for an image using
+ * {background|mask}-specific arguments.
+ * @see nsLayoutUtils::DrawImage() for parameters.
+ */
+ void BuildWebRenderDisplayItemsForLayer(nsPresContext* aPresContext,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+ const nsRect& aDest,
+ const nsRect& aFill,
+ const nsPoint& aAnchor,
+ const nsRect& aDirty,
+ const nsSize& aRepeatSize,
+ float aOpacity);
+
+ /**
* Draw the image to a single component of a border-image style rendering.
* aFill The destination rect to be drawn into
* aSrc is the part of the image to be rendered into a tile (aUnitSize in
* aFill), if aSrc and the dest tile are different sizes, the image will be
* scaled to map aSrc onto the dest tile.
* aHFill and aVFill are the repeat patterns for the component -
* NS_STYLE_BORDER_IMAGE_REPEAT_*
* aUnitSize The scaled size of a single source rect (in destination coords)
@@ -252,16 +275,34 @@ private:
const nsRect& aDest,
const nsRect& aFill,
const nsPoint& aAnchor,
const nsSize& aRepeatSize,
const mozilla::CSSIntRect& aSrc,
float aOpacity = 1.0);
/**
+ * Builds WebRender DisplayItems for the image.
+ * aSrc is a rect on the source image which will be mapped to aDest; it's
+ * currently only used for gradients.
+ *
+ * @see nsLayoutUtils::DrawImage() for other parameters.
+ */
+ void BuildWebRenderDisplayItems(nsPresContext* aPresContext,
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+ const nsRect& aDirtyRect,
+ const nsRect& aDest,
+ const nsRect& aFill,
+ const nsPoint& aAnchor,
+ const nsSize& aRepeatSize,
+ const mozilla::CSSIntRect& aSrc,
+ float aOpacity = 1.0);
+
+ /**
* Helper method for creating a gfxDrawable from mPaintServerFrame or
* mImageElementSurface.
* Requires mType is eStyleImageType_Element.
* Returns null if we cannot create the drawable.
*/
already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
gfxContext& aContext);