Bug 1341156 - Add border image support. r=mattwoodrow
MozReview-Commit-ID: 146FCaqEoi1
* * *
commit 363ddb5f00aa7d71c5a2916a645bd069d2658ab5
Author: Morris Tseng <mtseng@mozilla.com>
p4
MozReview-Commit-ID: Ax2WjDC0V5q
--- 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
@@ -77,16 +77,17 @@
#include "mozilla/GeckoRestyleManager.h"
#include "nsCaret.h"
#include "nsISelection.h"
#include "nsDOMTokenList.h"
#include "mozilla/RuleNodeCacheConditions.h"
#include "nsCSSProps.h"
#include "nsPluginFrame.h"
#include "nsSVGMaskFrame.h"
+#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderDisplayItemLayer.h"
#include "mozilla/layers/WebRenderMessages.h"
#include "mozilla/layers/WebRenderDisplayItemLayer.h"
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
// GetTickCount().
#ifdef GetCurrentTime
@@ -2745,18 +2746,19 @@ nsDisplayItem::GetClippedBounds(nsDispla
return GetClip().ApplyNonRoundedIntersection(r);
}
already_AddRefed<Layer>
nsDisplayItem::BuildDisplayItemLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters)
{
- RefPtr<DisplayItemLayer> layer = static_cast<DisplayItemLayer*>
- (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
+ RefPtr<Layer> oldLayer = aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
+ RefPtr<DisplayItemLayer> layer = oldLayer ? oldLayer->AsDisplayItemLayer() : nullptr;
+
if (!layer) {
layer = aManager->CreateDisplayItemLayer();
if (!layer) {
return nullptr;
}
}
@@ -4564,42 +4566,83 @@ 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;
+ mBorderImageRenderer = Nothing();
+ 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()),
+ mVisibleRect,
+ mFrame->GetSkipSides(),
+ flags,
+ &result);
+
+ if (!renderer) {
+ return LAYER_NONE;
+ }
+
+ mBorderImageRenderer = renderer;
+ }
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) {
@@ -4630,34 +4673,99 @@ nsDisplayBorder::GetLayerState(nsDisplay
return LAYER_ACTIVE;
}
already_AddRefed<Layer>
nsDisplayBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters)
{
- RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
- (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
+ if (mBorderImageRenderer) {
+ return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+ }
+
+ RefPtr<Layer> oldLayer = aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
+ RefPtr<BorderLayer> layer = oldLayer ? oldLayer->AsBorderLayer() : nullptr;
+
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));
return layer.forget();
}
void
+nsDisplayBorder::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ WebRenderDisplayItemLayer* aLayer)
+{
+ // Only support border-image currently
+ MOZ_ASSERT(mBorderImageRenderer);
+
+ nsDisplayListBuilder* builder = aLayer->GetDisplayListBuilder();
+ uint32_t flags = builder->ShouldSyncDecodeImages() ?
+ imgIContainer::FLAG_SYNC_DECODE :
+ imgIContainer::FLAG_NONE;
+
+ RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
+ RefPtr<layers::ImageContainer> container = img->GetImageContainer(aLayer->WrManager(), flags);
+ if (!container) {
+ return;
+ }
+
+ uint64_t externalImageId = aLayer->SendImageContainer(container);
+
+ const int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+ Rect destRect =
+ NSRectToRect(mBorderImageRenderer->mArea, appUnitsPerDevPixel);
+ Rect destRectTransformed = aLayer->RelativeToParent(destRect);
+ IntRect dest = RoundedToInt(destRectTransformed);
+
+ IntRect clip = dest;
+ if (!mBorderImageRenderer->mClip.IsEmpty()) {
+ Rect clipRect =
+ NSRectToRect(mBorderImageRenderer->mClip, appUnitsPerDevPixel);
+ Rect clipRectTransformed = aLayer->RelativeToParent(clipRect);
+ clip = RoundedToInt(clipRectTransformed);
+ }
+
+ float widths[4];
+ float slice[4];
+ float outset[4];
+ NS_FOR_CSS_SIDES(i) {
+ slice[i] = (float)(mBorderImageRenderer->mSlice.Side(i)) / appUnitsPerDevPixel;
+ widths[i] = (float)(mBorderImageRenderer->mWidths.Side(i)) / appUnitsPerDevPixel;
+ outset[i] = (float)(mBorderImageRenderer->mImageOutset.Side(i)) / appUnitsPerDevPixel;
+ }
+
+ WrImageKey key;
+ key.mNamespace = aLayer->WrBridge()->GetNamespace();
+ key.mHandle = aLayer->WrBridge()->GetNextResourceId();
+ aParentCommands.AppendElement(OpAddExternalImage(externalImageId, key));
+ aBuilder.PushBorderImage(wr::ToWrRect(dest), wr::ToWrRect(clip),
+ wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
+ key,
+ wr::ToWrNinePatchDescriptor(
+ (float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
+ (float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
+ wr::ToWrSideOffsets2Du32(slice[0], slice[1], slice[2], slice[3])),
+ wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]),
+ wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
+ wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeVertical));
+}
+
+void
nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
nsRenderingContext* aCtx) {
nsPoint offset = ToReferenceFrame();
PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
? PaintBorderFlags::SYNC_DECODE_IMAGES
: PaintBorderFlags();
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2853,19 +2853,22 @@ public:
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override;
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters) override;
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aContainerParameters) override;
+ virtual void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ WebRenderDisplayItemLayer* aLayer) override;
virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override;
NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER)
-
+
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) override;
virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
{
@@ -2877,16 +2880,19 @@ 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
+ mozilla::Maybe<nsCSSBorderImageRenderer> mBorderImageRenderer;
+
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