Bug 1341156 - Add border image support. r=mattwoodrow
MozReview-Commit-ID: 146FCaqEoi1
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -12,16 +12,17 @@
#include <sys/types.h> // for int32_t, int64_t
#include "FrameMetrics.h" // for FrameMetrics
#include "Units.h" // for LayerMargin, LayerPoint, ParentLayerIntRect
#include "gfxContext.h"
#include "gfxTypes.h"
#include "gfxPoint.h" // for gfxPoint
#include "gfxRect.h" // for gfxRect
#include "gfx2DGlue.h"
+#include "imgIContainer.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2, etc
#include "mozilla/Array.h"
#include "mozilla/DebugOnly.h" // for DebugOnly
#include "mozilla/EventForwards.h" // for nsPaintEvent
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/Poison.h"
#include "mozilla/RefPtr.h" // for already_AddRefed
#include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
@@ -2541,16 +2542,58 @@ public:
virtual void SetStyles(const BorderStyles& aBorderStyles)
{
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Widths", this));
PodCopy(&mBorderStyles[0], &aBorderStyles[0], 4);
Mutated();
}
+ virtual void SetImage(imgIContainer* aImage)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Image", this));
+ mImage = aImage;
+ Mutated();
+ }
+
+ virtual void SetImageSize(const mozilla::LayerSize& aSize)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ImageSize", this));
+ mImageSize = aSize;
+ Mutated();
+ }
+
+ virtual void SetSlice(const mozilla::Array<mozilla::LayerCoord, 4>& aSlice)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Slice", this));
+ PodCopy(&mSlice[0], &aSlice[0], 4);
+ Mutated();
+ }
+
+ virtual void SetOutset(const mozilla::Array<mozilla::LayerCoord, 4>& aOutset)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) Outset", this));
+ PodCopy(&mOutset[0], &aOutset[0], 4);
+ Mutated();
+ }
+
+ virtual void SetRepeatModeHorizontal(uint8_t aRepeatMode)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) RepeatModeHorizontal", this));
+ mRepeatModeHorizontal = aRepeatMode;
+ Mutated();
+ }
+
+ virtual void SetRepeatModeVertical(uint8_t aRepeatMode)
+ {
+ MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) RepeatModeVertical", this));
+ mRepeatModeVertical = aRepeatMode;
+ Mutated();
+ }
+
MOZ_LAYER_DECL_NAME("BorderLayer", TYPE_BORDER)
virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
{
gfx::Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
mEffectiveTransform = SnapTransformTranslation(idealTransform, nullptr);
ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
}
@@ -2569,16 +2612,24 @@ protected:
virtual void DumpPacket(layerscope::LayersPacket* aPacket, const void* aParent) override;
BorderColors mColors;
LayerRect mRect;
BorderCorners mCorners;
BorderWidths mWidths;
BorderStyles mBorderStyles;
+
+ // For border image
+ RefPtr<imgIContainer> mImage;
+ mozilla::LayerSize mImageSize;
+ mozilla::Array<mozilla::LayerCoord, 4> mSlice;
+ mozilla::Array<mozilla::LayerCoord, 4> mOutset;
+ uint8_t mRepeatModeHorizontal;
+ uint8_t mRepeatModeVertical;
};
/**
* A Layer for HTML Canvas elements. It's backed by either a
* gfxASurface or a GLContext (for WebGL layers), and has some control
* for intelligent updating from the source if necessary (for example,
* if hardware compositing is not available, for reading from the GL
* buffer into an image surface that we can layer composite.)
--- a/gfx/layers/wr/WebRenderBorderLayer.cpp
+++ b/gfx/layers/wr/WebRenderBorderLayer.cpp
@@ -59,25 +59,53 @@ WebRenderBorderLayer::RenderLayer()
OpDPPushStackingContext(wr::ToWrRect(relBounds),
wr::ToWrRect(overflow),
Nothing(),
1.0f,
GetAnimations(),
transform,
WrMixBlendMode::Normal,
FrameMetrics::NULL_SCROLL_ID));
- WrBridge()->AddWebRenderCommand(
- OpDPPushBorder(wr::ToWrRect(rect), wr::ToWrRect(clip),
- wr::ToWrBorderWidth(mWidths[0], mWidths[1], mWidths[2], mWidths[3]),
- wr::ToWrNormalBorder(
- wr::ToWrBorderSide(mColors[0], mBorderStyles[0]),
- wr::ToWrBorderSide(mColors[1], mBorderStyles[1]),
- wr::ToWrBorderSide(mColors[2], mBorderStyles[2]),
- wr::ToWrBorderSide(mColors[3], mBorderStyles[3]),
- wr::ToWrBorderRadius(mCorners[0], mCorners[1], mCorners[3], mCorners[2]))));
+
+ if (!mImage) {
+ WrBridge()->AddWebRenderCommand(
+ OpDPPushBorder(wr::ToWrRect(rect), wr::ToWrRect(clip),
+ wr::ToWrBorderWidth(mWidths[0], mWidths[1], mWidths[2], mWidths[3]),
+ wr::ToWrNormalBorder(
+ wr::ToWrBorderSide(mColors[0], mBorderStyles[0]),
+ wr::ToWrBorderSide(mColors[1], mBorderStyles[1]),
+ wr::ToWrBorderSide(mColors[2], mBorderStyles[2]),
+ wr::ToWrBorderSide(mColors[3], mBorderStyles[3]),
+ wr::ToWrBorderRadius(mCorners[0], mCorners[1], mCorners[3], mCorners[2]))));
+ } else {
+ uint32_t flags = imgIContainer::FLAG_NONE;
+
+ RefPtr<layers::ImageContainer> container =
+ mImage->GetImageContainer(WrManager(), flags);
+ if (!container) {
+ return;
+ }
+
+ uint64_t externalImageId = SendImageContainer(container);
+
+ WrImageKey key;
+ key.mNamespace = WrBridge()->GetNamespace();
+ key.mHandle = WrBridge()->GetNextResourceId();
+ WrBridge()->AddWebRenderCommand(OpAddExternalImage(LayerIntRegion(), externalImageId, key));
+ WrBridge()->AddWebRenderCommand(
+ OpDPPushBorderImage(wr::ToWrRect(rect), wr::ToWrRect(clip),
+ wr::ToWrBorderWidth(mWidths[0], mWidths[1], mWidths[2], mWidths[3]),
+ key,
+ wr::ToWrNinePatchDescriptor(
+ mImageSize.width, mImageSize.height,
+ wr::ToWrSideOffsets2Du32(mSlice[0], mSlice[1], mSlice[2], mSlice[3])),
+ wr::ToWrSideOffsets2Df32(mOutset[0], mOutset[1], mOutset[2], mOutset[3]),
+ wr::ToWrRepeatMode(mRepeatModeHorizontal),
+ wr::ToWrRepeatMode(mRepeatModeVertical)));
+ }
WrBridge()->AddWebRenderCommand(OpDPPopStackingContext());
}
uint64_t
WebRenderBorderLayer::SendImageContainer(ImageContainer* aContainer)
{
if (mImageContainer != aContainer) {
AutoLockImage autoLock(aContainer);
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -299,16 +299,18 @@ private:
nsMargin mSlice;
nsMargin mWidths;
nsMargin mImageOutset;
nsRect mArea;
nsRect mClip;
uint8_t mRepeatModeHorizontal;
uint8_t mRepeatModeVertical;
uint8_t mFill;
+
+ friend class nsDisplayBorder;
};
namespace mozilla {
#ifdef DEBUG_NEW_BORDERS
#include <stdarg.h>
static inline void PrintAsString(const mozilla::gfx::Point& p) {
fprintf (stderr, "[%f,%f]", p.x, p.y);
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4558,42 +4558,95 @@ nsDisplayBorder::GetLayerState(nsDisplay
Maybe<nsCSSBorderRenderer> br =
nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
nullptr,
mFrame,
nsRect(),
nsRect(offset, mFrame->GetSize()),
mFrame->StyleContext(),
mFrame->GetSkipSides());
- if (!br) {
+
+ const nsStyleBorder *styleBorder = mFrame->StyleContext()->StyleBorder();
+ const nsStyleImage* image = &styleBorder->mBorderImageSource;
+ if ((!image || image->GetType() != eStyleImageType_Image) && !br) {
return LAYER_NONE;
}
LayersBackend backend = aManager->GetBackendType();
if (backend == layers::LayersBackend::LAYERS_WR) {
- bool hasCompositeColors;
- br->AllBordersSolid(&hasCompositeColors);
- if (hasCompositeColors) {
- return LAYER_NONE;
- }
-
- NS_FOR_CSS_SIDES(i) {
- mColors[i] = ToDeviceColor(br->mBorderColors[i]);
- mWidths[i] = br->mBorderWidths[i];
- mBorderStyles[i] = br->mBorderStyles[i];
- }
- NS_FOR_CSS_FULL_CORNERS(corner) {
- mCorners[corner] = LayerSize(br->mBorderRadii[corner].width, br->mBorderRadii[corner].height);
- }
-
- mRect = ViewAs<LayerPixel>(br->mOuterRect);
+ if (br) {
+ bool hasCompositeColors;
+ br->AllBordersSolid(&hasCompositeColors);
+ if (hasCompositeColors) {
+ return LAYER_NONE;
+ }
+
+ NS_FOR_CSS_SIDES(i) {
+ mColors[i] = ToDeviceColor(br->mBorderColors[i]);
+ mWidths[i] = br->mBorderWidths[i];
+ mBorderStyles[i] = br->mBorderStyles[i];
+ }
+
+ NS_FOR_CSS_FULL_CORNERS(corner) {
+ mCorners[corner] = LayerSize(br->mBorderRadii[corner].width, br->mBorderRadii[corner].height);
+ }
+
+ mRect = ViewAs<LayerPixel>(br->mOuterRect);
+ } else {
+ if (styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
+ styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE ||
+ styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
+ styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE) {
+ // WebRender not supports this currently
+ return LAYER_NONE;
+ }
+
+ uint32_t flags = 0;
+ if (aBuilder->ShouldSyncDecodeImages()) {
+ flags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
+ }
+
+ image::DrawResult result;
+ Maybe<nsCSSBorderImageRenderer> renderer =
+ nsCSSBorderImageRenderer::CreateBorderImageRenderer(mFrame->PresContext(),
+ mFrame,
+ nsRect(offset, mFrame->GetSize()),
+ *(mFrame->StyleContext()->StyleBorder()),
+ nsRect(),
+ mFrame->GetSkipSides(),
+ flags,
+ &result);
+
+ if (!renderer) {
+ return LAYER_NONE;
+ }
+
+ nscoord twipsPerPixel = mFrame->PresContext()->DevPixelsToAppUnits(1);
+
+ mImage = renderer->mImageRenderer.GetImage();
+ mRepeatModeHorizontal = renderer->mRepeatModeHorizontal;
+ mRepeatModeVertical = renderer->mRepeatModeVertical;
+ mImageSize.width = (float)(renderer->mImageSize.width) / twipsPerPixel;
+ mImageSize.height = (float)(renderer->mImageSize.height) / twipsPerPixel;
+ NS_FOR_CSS_SIDES(i) {
+ mSlice[i] = (float)(renderer->mSlice.Side(i)) / twipsPerPixel;
+ mWidths[i] = (float)(renderer->mWidths.Side(i)) / twipsPerPixel;
+ mOutset[i] = (float)(renderer->mImageOutset.Side(i)) / twipsPerPixel;
+ }
+
+ mRect = ViewAs<LayerPixel>(NSRectToRect(renderer->mArea, twipsPerPixel));
+ }
return LAYER_ACTIVE;
}
+ if (!br) {
+ return LAYER_NONE;
+ }
+
bool hasCompositeColors;
if (!br->AllBordersSolid(&hasCompositeColors) || hasCompositeColors) {
return LAYER_NONE;
}
// We don't support this yet as we don't copy the values to
// the layer, and BasicBorderLayer doesn't support it yet.
if (!br->mNoBorderRadius) {
@@ -4631,23 +4684,33 @@ nsDisplayBorder::BuildLayer(nsDisplayLis
{
RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
(aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
if (!layer) {
layer = aManager->CreateBorderLayer();
if (!layer)
return nullptr;
}
+
layer->SetRect(mRect);
- layer->SetCornerRadii(mCorners);
- layer->SetColors(mColors);
layer->SetWidths(mWidths);
- layer->SetStyles(mBorderStyles);
layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
aContainerParameters.mOffset.y, 0));
+ if (!mImage) {
+ layer->SetCornerRadii(mCorners);
+ layer->SetColors(mColors);
+ layer->SetStyles(mBorderStyles);
+ } else {
+ layer->SetImage(mImage);
+ layer->SetImageSize(mImageSize);
+ layer->SetSlice(mSlice);
+ layer->SetOutset(mOutset);
+ layer->SetRepeatModeVertical(mRepeatModeVertical);
+ layer->SetRepeatModeHorizontal(mRepeatModeHorizontal);
+ }
return layer.forget();
}
void
nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) {
nsPoint offset = ToReferenceFrame();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2870,16 +2870,24 @@ protected:
nsRegion CalculateBounds(const nsStyleBorder& aStyleBorder);
mozilla::Array<mozilla::gfx::Color, 4> mColors;
mozilla::Array<mozilla::LayerCoord, 4> mWidths;
mozilla::Array<mozilla::LayerSize, 4> mCorners;
mozilla::Array<uint8_t, 4> mBorderStyles;
mozilla::LayerRect mRect;
+ // For border image
+ RefPtr<imgIContainer> mImage;
+ mozilla::LayerSize mImageSize;
+ mozilla::Array<mozilla::LayerCoord, 4> mSlice;
+ mozilla::Array<mozilla::LayerCoord, 4> mOutset;
+ uint8_t mRepeatModeHorizontal;
+ uint8_t mRepeatModeVertical;
+
nsRect mBounds;
};
/**
* A simple display item that just renders a solid color across the
* specified bounds. For canvas frames (in the CSS sense) we split off the
* drawing of the background color into this class (from nsDisplayBackground
* via nsDisplayCanvasBackground). This is done so that we can always draw a