author | Mason Chang <mchang@mozilla.com> |
Thu, 23 Feb 2017 20:01:58 -0800 | |
changeset 345868 | 991f5724e58f47884ebbdb5c438b53ee1226ab4e |
parent 345867 | fe0b89ed61f95b5eb239f79caa930392a08ea06e |
child 345869 | fb90c86d6503ae12d5a29465222e3df01a9a60d5 |
push id | 38337 |
push user | kwierso@gmail.com |
push date | Sat, 04 Mar 2017 01:30:14 +0000 |
treeherder | autoland@b691557cb7a3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | lsalzman |
bugs | 1342281 |
milestone | 54.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -456,16 +456,17 @@ private: DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram", FPSPrintHistogram, bool, false); DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false); DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabledDoNotUseDirectly, bool, false); DECL_GFX_PREF(Live, "layers.advanced.border-layers", LayersAllowBorderLayers, bool, false); DECL_GFX_PREF(Live, "layers.advanced.text-layers", LayersAllowTextLayers, bool, false); DECL_GFX_PREF(Live, "layers.advanced.bullet-layers", LayersAllowBulletLayers, bool, false); DECL_GFX_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, bool, false); DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false); + DECL_GFX_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false); DECL_GFX_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, bool, false); DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback", LayersAllowD3D9Fallback, bool, false); DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled", LayersAMDSwitchableGfxEnabled, bool, false); DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true); DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false); DECL_GFX_PREF(Live, "layers.bench.enabled", LayersBenchEnabled, bool, false); DECL_GFX_PREF(Once, "layers.bufferrotation.enabled", BufferRotationEnabled, bool, true); DECL_GFX_PREF(Live, "layers.child-process-shutdown", ChildProcessShutdown, bool, true);
--- a/layout/painting/nsCSSRendering.cpp +++ b/layout/painting/nsCSSRendering.cpp @@ -1436,16 +1436,35 @@ nsCSSRendering::GetShadowRect(const nsRe Sides skipSides = aForFrame->GetSkipSides(); frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides); // Explicitly do not need to account for the spread radius here // Webrender does it for us or PaintBoxShadow will for non-WR return frameRect; } +bool +nsCSSRendering::GetBorderRadii(const nsRect& aFrameRect, + const nsRect& aBorderRect, + nsIFrame* aFrame, + RectCornerRadii& aOutRadii) +{ + const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1); + nscoord twipsRadii[8]; + NS_ASSERTION(aBorderRect.Size() == aFrame->VisualBorderRectRelativeToSelf().Size(), + "unexpected size"); + nsSize sz = aFrameRect.Size(); + bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii); + if (hasBorderRadius) { + ComputePixelRadii(twipsRadii, twipsPerPixel, &aOutRadii); + } + + return hasBorderRadius; +} + void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aFrameArea, const nsRect& aDirtyRect, float aOpacity) { @@ -1654,83 +1673,121 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr aDirtyRect, skipGfxRect); renderContext->Restore(); } } } +nsRect +nsCSSRendering::GetBoxShadowInnerPaddingRect(nsIFrame* aFrame, + const nsRect& aFrameArea) +{ + Sides skipSides = aFrame->GetSkipSides(); + nsRect frameRect = + ::BoxDecorationRectForBorder(aFrame, aFrameArea, skipSides); + + nsRect paddingRect = frameRect; + nsMargin border = aFrame->GetUsedBorder(); + paddingRect.Deflate(border); + return paddingRect; +} + +bool +nsCSSRendering::CanPaintBoxShadowInner(nsIFrame* aFrame) +{ + nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow; + if (!shadows) + return false; + + if (aFrame->IsThemed() && aFrame->GetContent() && + !nsContentUtils::IsChromeDoc(aFrame->GetContent()->GetUncomposedDoc())) { + // There's no way of getting hold of a shape corresponding to a + // "padding-box" for native-themed widgets, so just don't draw + // inner box-shadows for them. But we allow chrome to paint inner + // box shadows since chrome can be aware of the platform theme. + return false; + } + + return true; +} + +bool +nsCSSRendering::GetShadowInnerRadii(nsIFrame* aFrame, + const nsRect& aFrameArea, + RectCornerRadii& aOutInnerRadii) +{ + // Get any border radius, since box-shadow must also have rounded corners + // if the frame does. + nscoord twipsRadii[8]; + nsRect frameRect = + ::BoxDecorationRectForBorder(aFrame, aFrameArea, aFrame->GetSkipSides()); + nsSize sz = frameRect.Size(); + nsMargin border = aFrame->GetUsedBorder(); + bool hasBorderRadius = aFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii); + const nscoord twipsPerPixel = aFrame->PresContext()->DevPixelsToAppUnits(1); + + RectCornerRadii borderRadii; + + hasBorderRadius = GetBorderRadii(frameRect, aFrameArea, aFrame, borderRadii); + if (hasBorderRadius) { + ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii); + + Float borderSizes[4] = { + Float(border.top / twipsPerPixel), + Float(border.right / twipsPerPixel), + Float(border.bottom / twipsPerPixel), + Float(border.left / twipsPerPixel) + }; + nsCSSBorderRenderer::ComputeInnerRadii(borderRadii, + borderSizes, + &aOutInnerRadii); + } + + return hasBorderRadius; +} + void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aFrameArea) { - nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow; - if (!shadows) + if (!CanPaintBoxShadowInner(aForFrame)) { return; - if (aForFrame->IsThemed() && aForFrame->GetContent() && - !nsContentUtils::IsChromeDoc(aForFrame->GetContent()->GetUncomposedDoc())) { - // There's no way of getting hold of a shape corresponding to a - // "padding-box" for native-themed widgets, so just don't draw - // inner box-shadows for them. But we allow chrome to paint inner - // box shadows since chrome can be aware of the platform theme. - return; - } - + } + + nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow; NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame || aFrameArea.Size() == aForFrame->GetSize(), "unexpected size"); - Sides skipSides = aForFrame->GetSkipSides(); - nsRect frameRect = - ::BoxDecorationRectForBorder(aForFrame, aFrameArea, skipSides); - nsRect paddingRect = frameRect; - nsMargin border = aForFrame->GetUsedBorder(); - paddingRect.Deflate(border); - - // Get any border radius, since box-shadow must also have rounded corners - // if the frame does. - nscoord twipsRadii[8]; - nsSize sz = frameRect.Size(); - bool hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii); - const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); + nsRect paddingRect = GetBoxShadowInnerPaddingRect(aForFrame, aFrameArea); RectCornerRadii innerRadii; - if (hasBorderRadius) { - RectCornerRadii borderRadii; - - ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii); - Float borderSizes[4] = { - Float(border.top / twipsPerPixel), - Float(border.right / twipsPerPixel), - Float(border.bottom / twipsPerPixel), - Float(border.left / twipsPerPixel) - }; - nsCSSBorderRenderer::ComputeInnerRadii(borderRadii, borderSizes, - &innerRadii); - } + bool hasBorderRadius = GetShadowInnerRadii(aForFrame, + aFrameArea, + innerRadii); + + const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); for (uint32_t i = shadows->Length(); i > 0; --i) { nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1); if (!shadowItem->mInset) continue; // shadowPaintRect: the area to paint on the temp surface // shadowClipRect: the area on the temporary surface within shadowPaintRect // that we will NOT paint in nscoord blurRadius = shadowItem->mRadius; nsMargin blurMargin = nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel); nsRect shadowPaintRect = paddingRect; shadowPaintRect.Inflate(blurMargin); - Rect shadowPaintGfxRect = NSRectToRect(shadowPaintRect, twipsPerPixel); - shadowPaintGfxRect.RoundOut(); - // Round the spread radius to device pixels (by truncation). // This mostly matches what we do for borders, except that we don't round // up values between zero and one device pixels to one device pixel. // This way of rounding is symmetric around zero, which makes sense for // the spread radius. int32_t spreadDistance = shadowItem->mSpread / twipsPerPixel; nscoord spreadDistanceAppUnits = aPresContext->DevPixelsToAppUnits(spreadDistance);
--- a/layout/painting/nsCSSRendering.h +++ b/layout/painting/nsCSSRendering.h @@ -370,21 +370,31 @@ struct nsCSSRendering { */ static void Init(); /** * Clean up any static variables used by nsCSSRendering. */ static void Shutdown(); + static bool GetShadowInnerRadii(nsIFrame* aFrame, + const nsRect& aFrameArea, + RectCornerRadii& aOutInnerRadii); + static nsRect GetBoxShadowInnerPaddingRect(nsIFrame* aFrame, + const nsRect& aFrameArea); + static bool CanPaintBoxShadowInner(nsIFrame* aFrame); static void PaintBoxShadowInner(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, nsIFrame* aForFrame, const nsRect& aFrameArea); + static bool GetBorderRadii(const nsRect& aFrameRect, + const nsRect& aBorderRect, + nsIFrame* aFrame, + RectCornerRadii& aOutRadii); static nsRect GetShadowRect(const nsRect aFrameArea, bool aNativeTheme, nsIFrame* aForFrame); static mozilla::gfx::Color GetShadowColor(nsCSSShadowItem* aShadow, nsIFrame* aFrame, float aOpacity); // Returns if the frame has a themed frame. // aMaybeHasBorderRadius will return false if we can early detect
--- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -4849,47 +4849,59 @@ nsDisplayBoxShadowOuter::CreateWebRender nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow; if (!shadows) return; bool hasBorderRadius; bool nativeTheme = nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius); + // Don't need the full size of the shadow rect like we do in + // nsCSSRendering since WR takes care of calculations for blur + // and spread radius. + nsRect shadowRect = nsCSSRendering::GetShadowRect(borderRect, + nativeTheme, + mFrame); + + RectCornerRadii borderRadii; + if (hasBorderRadius) { + hasBorderRadius = nsCSSRendering::GetBorderRadii(shadowRect, + borderRect, + mFrame, + borderRadii); + MOZ_ASSERT(borderRadii.AreRadiiSame(), "WR only supports uniform borders"); + } + // Everything here is in app units, change to device units. for (uint32_t i = 0; i < rects.Length(); ++i) { Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel); nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow; for (uint32_t j = shadows->Length(); j > 0; j--) { nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1); - // Don't need the full size of the shadow rect like we do in - // nsCSSRendering since WR takes care of calculations for blur - // and spread radius. - nsRect shadowRect = nsCSSRendering::GetShadowRect(borderRect, - nativeTheme, - mFrame); + gfx::Color shadowColor = nsCSSRendering::GetShadowColor(shadow, mFrame, mOpacity); shadowRect.MoveBy(shadow->mXOffset, shadow->mYOffset); // Now translate everything to device pixels. Point shadowOffset; shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel); shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel); Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel); deviceBoxRect = aLayer->RelativeToParent(deviceBoxRect); Rect deviceClipRect = aLayer->RelativeToParent(clipRect + shadowOffset); float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel); - // TODO: Calculate the border radius here. - float borderRadius = 0.0; + // TODO: support non-uniform border radius. + float borderRadius = hasBorderRadius ? borderRadii.TopLeft().width + : 0.0; float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel); aCommands.AppendElement(OpDPPushBoxShadow( wr::ToWrRect(deviceBoxRect), wr::ToWrRect(deviceClipRect), wr::ToWrRect(deviceBoxRect), wr::ToWrPoint(shadowOffset), wr::ToWrColor(shadowColor), @@ -4949,16 +4961,98 @@ nsDisplayBoxShadowInner::Paint(nsDisplay for (uint32_t i = 0; i < rects.Length(); ++i) { gfx->Save(); gfx->Clip(NSRectToSnappedRect(rects[i], appUnitsPerDevPixel, *drawTarget)); nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame, borderRect); gfx->Restore(); } } +LayerState +nsDisplayBoxShadowInner::GetLayerState(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aParameters) +{ + if (gfxPrefs::LayersAllowInsetBoxShadow()) { + return LAYER_ACTIVE; + } + + return LAYER_NONE; +} + +already_AddRefed<Layer> +nsDisplayBoxShadowInner::BuildLayer(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, + const ContainerLayerParameters& aContainerParameters) +{ + return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters); +} + +void +nsDisplayBoxShadowInner::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands, + WebRenderDisplayItemLayer* aLayer) +{ + if (!nsCSSRendering::CanPaintBoxShadowInner(mFrame)) { + return; + } + + int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); + nsPoint offset = ToReferenceFrame(); + nsRect borderRect = nsRect(offset, mFrame->GetSize()); + + AutoTArray<nsRect,10> rects; + nsRegion visible = aLayer->GetVisibleRegion().ToAppUnits(appUnitsPerDevPixel); + ComputeDisjointRectangles(visible, &rects); + + nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow; + + for (uint32_t i = 0; i < rects.Length(); ++i) { + Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel); + + for (uint32_t i = shadows->Length(); i > 0; --i) { + nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1); + if (!shadowItem->mInset) { + continue; + } + + nsRect shadowRect = + nsCSSRendering::GetBoxShadowInnerPaddingRect(mFrame, borderRect); + RectCornerRadii innerRadii; + nsCSSRendering::GetShadowInnerRadii(mFrame, borderRect, innerRadii); + + // Now translate everything to device pixels. + Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel); + Rect deviceClipRect = aLayer->RelativeToParent(clipRect); + Color shadowColor = nsCSSRendering::GetShadowColor(shadowItem, mFrame, 1.0); + + Point shadowOffset; + shadowOffset.x = (shadowItem->mXOffset / appUnitsPerDevPixel); + shadowOffset.y = (shadowItem->mYOffset / appUnitsPerDevPixel); + + float blurRadius = float(shadowItem->mRadius) / float(appUnitsPerDevPixel); + // TODO: WR doesn't support non-uniform border radii + float borderRadius = innerRadii.TopLeft().width; + // NOTE: Any spread radius > 0 will render nothing. WR Bug. + float spreadRadius = float(shadowItem->mSpread) / float(appUnitsPerDevPixel); + + aCommands.AppendElement(OpDPPushBoxShadow( + wr::ToWrRect(deviceBoxRect), + wr::ToWrRect(deviceClipRect), + wr::ToWrRect(deviceBoxRect), + wr::ToWrPoint(shadowOffset), + wr::ToWrColor(shadowColor), + blurRadius, + spreadRadius, + borderRadius, + WrBoxShadowClipMode::Inset + )); + } + } +} + bool nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion) { if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) { return false; } // Store the actual visible region
--- a/layout/painting/nsDisplayList.h +++ b/layout/painting/nsDisplayList.h @@ -3427,16 +3427,25 @@ public: if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) { // nsDisplayBoxShadowInner is based around the padding rect, but it can // touch pixels outside of this. We should invalidate the entire bounds. bool snap; aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); } } + 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(nsTArray<WebRenderCommand>& aCommands, + WebRenderDisplayItemLayer* aLayer) override; + private: nsRegion mVisibleRegion; }; /** * The standard display item to paint the CSS outline of a frame. */ class nsDisplayOutline : public nsDisplayItem {