зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1340317 - Support box shadow outer offset and spread radius in WebRender box shadows. r=lsalzman
This commit is contained in:
Родитель
8ec93b1895
Коммит
b4d5056da5
|
@ -227,6 +227,14 @@ static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
|
|||
return ToWrRect(IntRectToRect(rect));
|
||||
}
|
||||
|
||||
static inline WrPoint ToWrPoint(const gfx::Point& point)
|
||||
{
|
||||
WrPoint p;
|
||||
p.x = point.x;
|
||||
p.y = point.y;
|
||||
return p;
|
||||
}
|
||||
|
||||
struct ByteBuffer
|
||||
{
|
||||
ByteBuffer(size_t aLength, uint8_t* aData)
|
||||
|
|
|
@ -283,6 +283,7 @@ struct WrPoint
|
|||
return x == aRhs.x && y == aRhs.y;
|
||||
}
|
||||
|
||||
operator mozilla::gfx::Point() const { return mozilla::gfx::Point(x, y); }
|
||||
};
|
||||
|
||||
struct WrImageMask
|
||||
|
|
|
@ -1369,6 +1369,56 @@ nsCSSRendering::EndFrameTreesLocked()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSSRendering::HasBoxShadowNativeTheme(nsIFrame* aFrame,
|
||||
bool& aMaybeHasBorderRadius)
|
||||
{
|
||||
const nsStyleDisplay* styleDisplay = aFrame->StyleDisplay();
|
||||
nsITheme::Transparency transparency;
|
||||
if (aFrame->IsThemed(styleDisplay, &transparency)) {
|
||||
aMaybeHasBorderRadius = false;
|
||||
// For opaque (rectangular) theme widgets we can take the generic
|
||||
// border-box path with border-radius disabled.
|
||||
return transparency != nsITheme::eOpaque;
|
||||
}
|
||||
|
||||
aMaybeHasBorderRadius = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
gfx::Color
|
||||
nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
|
||||
nsIFrame* aFrame,
|
||||
float aOpacity)
|
||||
{
|
||||
// Get the shadow color; if not specified, use the foreground color
|
||||
nscolor shadowColor;
|
||||
if (aShadow->mHasColor)
|
||||
shadowColor = aShadow->mColor;
|
||||
else
|
||||
shadowColor = aFrame->StyleColor()->mColor;
|
||||
|
||||
Color color = Color::FromABGR(shadowColor);
|
||||
color.a *= aOpacity;
|
||||
return color;
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsCSSRendering::GetShadowRect(const nsRect aFrameArea,
|
||||
bool aNativeTheme,
|
||||
nsIFrame* aForFrame)
|
||||
{
|
||||
nsRect frameRect = aNativeTheme ?
|
||||
aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
|
||||
aFrameArea;
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
|
@ -1383,25 +1433,11 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
|||
return;
|
||||
|
||||
bool hasBorderRadius;
|
||||
bool nativeTheme; // mutually exclusive with hasBorderRadius
|
||||
// mutually exclusive with hasBorderRadius
|
||||
bool nativeTheme = HasBoxShadowNativeTheme(aForFrame, hasBorderRadius);
|
||||
const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
|
||||
nsITheme::Transparency transparency;
|
||||
if (aForFrame->IsThemed(styleDisplay, &transparency)) {
|
||||
// We don't respect border-radius for native-themed widgets
|
||||
hasBorderRadius = false;
|
||||
// For opaque (rectangular) theme widgets we can take the generic
|
||||
// border-box path with border-radius disabled.
|
||||
nativeTheme = transparency != nsITheme::eOpaque;
|
||||
} else {
|
||||
nativeTheme = false;
|
||||
hasBorderRadius = true; // we'll update this below
|
||||
}
|
||||
|
||||
nsRect frameRect = nativeTheme ?
|
||||
aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
|
||||
aFrameArea;
|
||||
Sides skipSides = aForFrame->GetSkipSides();
|
||||
frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect, skipSides);
|
||||
nsRect frameRect = GetShadowRect(aFrameArea, nativeTheme, aForFrame);
|
||||
|
||||
// Get any border radius, since box-shadow must also have rounded corners if
|
||||
// the frame does.
|
||||
|
@ -1465,15 +1501,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
|||
shadowGfxRectPlusBlur.RoundOut();
|
||||
MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
|
||||
|
||||
// Set the shadow color; if not specified, use the foreground color
|
||||
nscolor shadowColor;
|
||||
if (shadowItem->mHasColor)
|
||||
shadowColor = shadowItem->mColor;
|
||||
else
|
||||
shadowColor = aForFrame->StyleColor()->mColor;
|
||||
|
||||
Color gfxShadowColor(Color::FromABGR(shadowColor));
|
||||
gfxShadowColor.a *= aOpacity;
|
||||
Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
|
||||
|
||||
if (nativeTheme) {
|
||||
nsContextBoxBlur blurringArea;
|
||||
|
@ -1547,6 +1575,7 @@ nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
|
|||
|
||||
// Clip the shadow so that we only get the part that applies to aForFrame.
|
||||
nsRect fragmentClip = shadowRectPlusBlur;
|
||||
Sides skipSides = aForFrame->GetSkipSides();
|
||||
if (!skipSides.IsEmpty()) {
|
||||
if (skipSides.Left()) {
|
||||
nscoord xmost = fragmentClip.XMost();
|
||||
|
@ -1740,11 +1769,7 @@ nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
|
|||
Rect shadowGfxRect = NSRectToRect(paddingRect, twipsPerPixel);
|
||||
shadowGfxRect.Round();
|
||||
|
||||
// Set the shadow color; if not specified, use the foreground color
|
||||
Color shadowColor = Color::FromABGR(shadowItem->mHasColor ?
|
||||
shadowItem->mColor :
|
||||
aForFrame->StyleColor()->mColor);
|
||||
|
||||
Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
|
||||
renderContext->Save();
|
||||
|
||||
// This clips the outside border radius.
|
||||
|
|
|
@ -354,6 +354,7 @@ struct nsBackgroundLayerState {
|
|||
};
|
||||
|
||||
struct nsCSSRendering {
|
||||
typedef mozilla::gfx::Color Color;
|
||||
typedef mozilla::gfx::CompositionOp CompositionOp;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::Float Float;
|
||||
|
@ -379,6 +380,17 @@ struct nsCSSRendering {
|
|||
nsIFrame* aForFrame,
|
||||
const nsRect& aFrameArea);
|
||||
|
||||
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
|
||||
// that we don't have a border radius.
|
||||
static bool HasBoxShadowNativeTheme(nsIFrame* aFrame,
|
||||
bool& aMaybeHasBorderRadius);
|
||||
static void PaintBoxShadowOuter(nsPresContext* aPresContext,
|
||||
nsRenderingContext& aRenderingContext,
|
||||
nsIFrame* aForFrame,
|
||||
|
|
|
@ -4771,45 +4771,54 @@ nsDisplayBoxShadowOuter::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCo
|
|||
if (!shadows)
|
||||
return;
|
||||
|
||||
bool hasBorderRadius;
|
||||
bool nativeTheme = nsCSSRendering::HasBoxShadowNativeTheme(mFrame,
|
||||
hasBorderRadius);
|
||||
|
||||
// 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);
|
||||
Rect gfxBorderRect = NSRectToRect(borderRect, appUnitsPerDevPixel);
|
||||
nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
|
||||
|
||||
Rect deviceClipRect = aLayer->RelativeToParent(clipRect);
|
||||
Rect deviceBoxRect = aLayer->RelativeToParent(gfxBorderRect);
|
||||
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);
|
||||
|
||||
for (uint32_t j = shadows->Length(); j > 0; --j) {
|
||||
nsCSSShadowItem* shadowItem = shadows->ShadowAt(j - 1);
|
||||
nscoord blurRadius = shadowItem->mRadius;
|
||||
float gfxBlurRadius = blurRadius / appUnitsPerDevPixel;
|
||||
// Now translate everything to device pixels.
|
||||
Point shadowOffset;
|
||||
shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel);
|
||||
shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel);
|
||||
|
||||
// TODO: Have to refactor our nsCSSRendering
|
||||
// to get the acual rects correct.
|
||||
nscolor shadowColor;
|
||||
if (shadowItem->mHasColor)
|
||||
shadowColor = shadowItem->mColor;
|
||||
else
|
||||
shadowColor = mFrame->StyleColor()->mColor;
|
||||
Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel);
|
||||
deviceBoxRect = aLayer->RelativeToParent(deviceBoxRect);
|
||||
|
||||
Color gfxShadowColor(Color::FromABGR(shadowColor));
|
||||
gfxShadowColor.a *= mOpacity;
|
||||
Rect deviceClipRect = aLayer->RelativeToParent(clipRect + shadowOffset);
|
||||
|
||||
WrPoint offset;
|
||||
offset.x = shadowItem->mXOffset;
|
||||
offset.y = shadowItem->mYOffset;
|
||||
float blurRadius = shadow->mRadius / appUnitsPerDevPixel;
|
||||
// TODO: Calculate the border radius here.
|
||||
float borderRadius = 0.0;
|
||||
float spreadRadius = shadow->mSpread / appUnitsPerDevPixel;
|
||||
|
||||
aCommands.AppendElement(OpDPPushBoxShadow(
|
||||
wr::ToWrRect(deviceBoxRect),
|
||||
wr::ToWrRect(deviceClipRect),
|
||||
wr::ToWrRect(deviceBoxRect),
|
||||
offset,
|
||||
wr::ToWrColor(gfxShadowColor),
|
||||
gfxBlurRadius,
|
||||
0,
|
||||
0,
|
||||
wr::ToWrPoint(shadowOffset),
|
||||
wr::ToWrColor(shadowColor),
|
||||
blurRadius,
|
||||
spreadRadius,
|
||||
borderRadius,
|
||||
WrBoxShadowClipMode::Outset
|
||||
));
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче