--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -5,16 +5,17 @@
#include "nsButtonFrameRenderer.h"
#include "nsCSSRendering.h"
#include "nsPresContext.h"
#include "nsGkAtoms.h"
#include "nsCSSPseudoElements.h"
#include "nsNameSpaceManager.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
+#include "mozilla/Unused.h"
#include "nsDisplayList.h"
#include "nsITheme.h"
#include "nsFrame.h"
#include "mozilla/EventStates.h"
#include "mozilla/dom/Element.h"
#include "Layers.h"
#include "gfxPrefs.h"
#include "gfxUtils.h"
@@ -82,16 +83,35 @@ public:
MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayButtonBoxShadowOuter() {
MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
}
#endif
+ virtual bool CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder) 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;
+
+ bool CanBuildWebRenderDisplayItems();
+
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) override;
NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
};
nsRect
@@ -104,16 +124,147 @@ void
nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) {
nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
frameRect, mVisibleRect);
}
+bool
+nsDisplayButtonBoxShadowOuter::CanBuildWebRenderDisplayItems()
+{
+ nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+ if (!shadows) {
+ return false;
+ }
+
+ bool hasBorderRadius;
+ bool nativeTheme =
+ nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
+
+ // We don't support native themed things yet like box shadows around
+ // input buttons.
+ if (nativeTheme) {
+ return false;
+ }
+
+ nsPoint offset = ToReferenceFrame();
+ nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
+ nsRect frameRect =
+ nsCSSRendering::GetShadowRect(borderRect, nativeTheme, mFrame);
+
+ if (hasBorderRadius) {
+ nscoord twipsRadii[8];
+ nsSize sz = frameRect.Size();
+ hasBorderRadius = mFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
+ }
+
+ if (hasBorderRadius) {
+ nsCSSRendering::RectCornerRadii borderRadii;
+ nsCSSRendering::GetBorderRadii(frameRect, borderRect, mFrame, borderRadii);
+ if (!borderRadii.AreRadiiSame()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+LayerState
+nsDisplayButtonBoxShadowOuter::GetLayerState(
+ nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ const ContainerLayerParameters& aParameters)
+{
+ if (ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowOuterBoxShadow) &&
+ CanBuildWebRenderDisplayItems()) {
+ return LAYER_ACTIVE;
+ }
+ return LAYER_NONE;
+}
+
+already_AddRefed<Layer>
+nsDisplayButtonBoxShadowOuter::BuildLayer(
+ nsDisplayListBuilder* aBuilder,
+ LayerManager* aManager,
+ const ContainerLayerParameters& aContainerParameters)
+{
+ return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+}
+
+bool
+nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
+ mozilla::wr::DisplayListBuilder& aBuilder,
+ const StackingContextHelper& aSc,
+ nsTArray<WebRenderParentCommand>& aParentCommands,
+ mozilla::layers::WebRenderLayerManager* aManager,
+ nsDisplayListBuilder* aDisplayListBuilder)
+{
+ if (aManager->IsLayersFreeTransaction()) {
+ ContainerLayerParameters parameter;
+ if (GetLayerState(aDisplayListBuilder, aManager, parameter) !=
+ LAYER_ACTIVE) {
+ return false;
+ }
+ }
+ int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+ nsRect shadowRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
+ LayoutDeviceRect deviceBox =
+ LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
+ wr::LayoutRect deviceBoxRect = aSc.ToRelativeLayoutRectRounded(deviceBox);
+
+ LayoutDeviceRect clipRect =
+ LayoutDeviceRect::FromAppUnits(mVisibleRect, appUnitsPerDevPixel);
+ wr::LayoutRect deviceClipRect = aSc.ToRelativeLayoutRect(clipRect);
+
+ bool hasBorderRadius;
+ Unused << nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
+
+ float borderRadius = 0.0;
+ if (hasBorderRadius) {
+ mozilla::gfx::RectCornerRadii borderRadii;
+ hasBorderRadius = nsCSSRendering::GetBorderRadii(
+ shadowRect, shadowRect, mFrame, borderRadii);
+ // TODO: support non-uniform border radius.
+ MOZ_ASSERT(borderRadii.AreRadiiSame());
+ borderRadius = hasBorderRadius ? borderRadii.TopLeft().width : 0.0;
+ }
+
+ nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+ MOZ_ASSERT(shadows);
+
+ for (uint32_t i = shadows->Length(); i > 0; i--) {
+ nsCSSShadowItem* shadow = shadows->ShadowAt(i - 1);
+ if (shadow->mInset) {
+ continue;
+ }
+ float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
+ gfx::Color shadowColor =
+ nsCSSRendering::GetShadowColor(shadow, mFrame, 1.0);
+
+ mozilla::gfx::Point shadowOffset;
+ shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel);
+ shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel);
+
+ float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
+
+ aBuilder.PushBoxShadow(deviceBoxRect,
+ deviceClipRect,
+ deviceBoxRect,
+ wr::ToLayoutVector2D(shadowOffset),
+ wr::ToColorF(shadowColor),
+ blurRadius,
+ spreadRadius,
+ borderRadius,
+ wr::BoxShadowClipMode::Outset);
+ }
+ return true;
+}
+
class nsDisplayButtonBorder : public nsDisplayItem {
public:
nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder,
nsButtonFrameRenderer* aRenderer)
: nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
MOZ_COUNT_CTOR(nsDisplayButtonBorder);
}
#ifdef NS_BUILD_REFCNT_LOGGING