diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 5700695c5c5..33e2c583718 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -1050,37 +1050,38 @@ GetBorderRadiusTwips(const nsStyleCorners& aBorderRadius, } void -nsCSSRendering::PaintBoxShadow(nsPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - nsIFrame* aForFrame, - const nsPoint& aForFramePt, - const nsRect& aDirtyRect) +nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aFrameArea, + const nsRect& aDirtyRect) { const nsStyleBorder* styleBorder = aForFrame->GetStyleBorder(); if (!styleBorder->mBoxShadow) return; - nsMargin borderValues = styleBorder->GetActualBorder(); PRIntn sidesToSkip = aForFrame->GetSkipSides(); - nsRect frameRect = nsRect(aForFramePt, aForFrame->GetSize()); // Get any border radius, since box-shadow must also have rounded corners if the frame does nscoord twipsRadii[8]; PRBool hasBorderRadius = GetBorderRadiusTwips(styleBorder->mBorderRadius, - frameRect.width, twipsRadii); + aFrameArea.width, twipsRadii); nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); gfxCornerSizes borderRadii; - ComputePixelRadii(twipsRadii, frameRect, sidesToSkip, + ComputePixelRadii(twipsRadii, aFrameArea, sidesToSkip, twipsPerPixel, &borderRadii); - gfxRect frameGfxRect = RectToGfxRect(frameRect, twipsPerPixel); + gfxRect frameGfxRect = RectToGfxRect(aFrameArea, twipsPerPixel); frameGfxRect.Round(); gfxRect dirtyGfxRect = RectToGfxRect(aDirtyRect, twipsPerPixel); for (PRUint32 i = styleBorder->mBoxShadow->Length(); i > 0; --i) { nsCSSShadowItem* shadowItem = styleBorder->mBoxShadow->ShadowAt(i - 1); - gfxRect shadowRect(frameRect.x, frameRect.y, frameRect.width, frameRect.height); + if (shadowItem->mInset) + continue; + + gfxRect shadowRect(aFrameArea.x, aFrameArea.y, aFrameArea.width, aFrameArea.height); shadowRect.MoveBy(gfxPoint(shadowItem->mXOffset, shadowItem->mYOffset)); shadowRect.Outset(shadowItem->mSpread); @@ -1143,6 +1144,120 @@ nsCSSRendering::PaintBoxShadow(nsPresContext* aPresContext, } } +void +nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aFrameArea, + const nsRect& aDirtyRect) +{ + const nsStyleBorder* styleBorder = aForFrame->GetStyleBorder(); + if (!styleBorder->mBoxShadow) + return; + + // Get any border radius, since box-shadow must also have rounded corners if the frame does + nscoord twipsRadii[8]; + PRBool hasBorderRadius = GetBorderRadiusTwips(styleBorder->mBorderRadius, + aFrameArea.width, twipsRadii); + nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1); + + nsRect paddingRect = aFrameArea; + nsMargin border = aForFrame->GetUsedBorder(); + aForFrame->ApplySkipSides(border); + paddingRect.Deflate(border); + + gfxCornerSizes innerRadii; + if (hasBorderRadius) { + gfxCornerSizes borderRadii; + PRIntn sidesToSkip = aForFrame->GetSkipSides(); + + ComputePixelRadii(twipsRadii, aFrameArea, sidesToSkip, + twipsPerPixel, &borderRadii); + gfxFloat borderSizes[4] = { + border.top / twipsPerPixel, border.right / twipsPerPixel, + border.bottom / twipsPerPixel, border.left / twipsPerPixel + }; + nsCSSBorderRenderer::ComputeInnerRadii(borderRadii, borderSizes, + &innerRadii); + } + + gfxRect frameGfxRect = RectToGfxRect(paddingRect, twipsPerPixel); + frameGfxRect.Round(); + gfxRect dirtyGfxRect = RectToGfxRect(aDirtyRect, twipsPerPixel); + + for (PRUint32 i = styleBorder->mBoxShadow->Length(); i > 0; --i) { + nsCSSShadowItem* shadowItem = styleBorder->mBoxShadow->ShadowAt(i - 1); + if (!shadowItem->mInset) + continue; + + /* + * shadowRect: the frame's padding rect + * shadowPaintRect: the area to paint on the temp surface, larger than shadowRect + * so that blurs still happen properly near the edges + * shadowClipRect: the area on the temporary surface within shadowPaintRect + * that we will NOT paint in + */ + nscoord blurRadius = shadowItem->mRadius; + gfxRect shadowRect(paddingRect.x, paddingRect.y, paddingRect.width, paddingRect.height); + gfxRect shadowPaintRect = shadowRect; + shadowPaintRect.Outset(blurRadius); + + gfxRect shadowClipRect = shadowRect; + shadowClipRect.MoveBy(gfxPoint(shadowItem->mXOffset, shadowItem->mYOffset)); + shadowClipRect.Inset(shadowItem->mSpread); + + shadowRect.ScaleInverse(twipsPerPixel); + shadowRect.Round(); + shadowPaintRect.ScaleInverse(twipsPerPixel); + shadowPaintRect.RoundOut(); + shadowClipRect.ScaleInverse(twipsPerPixel); + shadowClipRect.Round(); + + gfxContext* renderContext = aRenderingContext.ThebesContext(); + nsRefPtr shadowContext; + nsContextBoxBlur blurringArea; + + // shadowPaintRect is already in device pixels, pass 1 as the appunits/pixel value + blurRadius /= twipsPerPixel; + shadowContext = blurringArea.Init(shadowPaintRect, blurRadius, 1, renderContext, dirtyGfxRect); + if (!shadowContext) + continue; + + // Set the shadow color; if not specified, use the foreground color + nscolor shadowColor; + if (shadowItem->mHasColor) + shadowColor = shadowItem->mColor; + else + shadowColor = aForFrame->GetStyleColor()->mColor; + + renderContext->Save(); + renderContext->SetColor(gfxRGBA(shadowColor)); + + // Clip the context to the area of the frame's padding rect, so no part of the + // shadow is painted outside + renderContext->NewPath(); + if (hasBorderRadius) + renderContext->RoundedRectangle(shadowRect, innerRadii, PR_FALSE); + else + renderContext->Rectangle(shadowRect); + renderContext->Clip(); + + // Fill the temporary surface minus the area within the frame that we should + // not paint in, and blur and apply it + shadowContext->NewPath(); + shadowContext->Rectangle(shadowPaintRect); + if (hasBorderRadius) + shadowContext->RoundedRectangle(shadowClipRect, innerRadii, PR_FALSE); + else + shadowContext->Rectangle(shadowClipRect); + shadowContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD); + shadowContext->Fill(); + + blurringArea.DoPaint(); + renderContext->Restore(); + } +} + void nsCSSRendering::PaintBackground(nsPresContext* aPresContext, nsIRenderingContext& aRenderingContext, diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index 824bd1f5606..f575572c253 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -61,11 +61,17 @@ struct nsCSSRendering { */ static void Shutdown(); - static void PaintBoxShadow(nsPresContext* aPresContext, - nsIRenderingContext& aRenderingContext, - nsIFrame* aForFrame, - const nsPoint& aForFramePt, - const nsRect& aDirtyRect); + static void PaintBoxShadowInner(nsPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aFrameArea, + const nsRect& aDirtyRect); + + static void PaintBoxShadowOuter(nsPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + nsIFrame* aForFrame, + const nsRect& aFrameArea, + const nsRect& aDirtyRect); /** * Render the border for an element using css rendering rules diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 3d0cafe07bb..18ac26a1426 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -647,21 +647,21 @@ nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder, } void -nsDisplayBoxShadow::Paint(nsDisplayListBuilder* aBuilder, +nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, const nsRect& aDirtyRect) { nsPoint offset = aBuilder->ToReferenceFrame(mFrame); - nsCSSRendering::PaintBoxShadow(mFrame->PresContext(), *aCtx, - mFrame, offset, aDirtyRect); + nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame, + nsRect(offset, mFrame->GetSize()), aDirtyRect); } nsRect -nsDisplayBoxShadow::GetBounds(nsDisplayListBuilder* aBuilder) { +nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame); } PRBool -nsDisplayBoxShadow::OptimizeVisibility(nsDisplayListBuilder* aBuilder, - nsRegion* aVisibleRegion) { +nsDisplayBoxShadowOuter::OptimizeVisibility(nsDisplayListBuilder* aBuilder, + nsRegion* aVisibleRegion) { if (!nsDisplayItem::OptimizeVisibility(aBuilder, aVisibleRegion)) return PR_FALSE; @@ -677,6 +677,14 @@ nsDisplayBoxShadow::OptimizeVisibility(nsDisplayListBuilder* aBuilder, return PR_TRUE; } +void +nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder, + nsIRenderingContext* aCtx, const nsRect& aDirtyRect) { + nsPoint offset = aBuilder->ToReferenceFrame(mFrame); + nsCSSRendering::PaintBoxShadowInner(mFrame->PresContext(), *aCtx, mFrame, + nsRect(offset, mFrame->GetSize()), aDirtyRect); +} + nsDisplayWrapList::nsDisplayWrapList(nsIFrame* aFrame, nsDisplayList* aList) : nsDisplayItem(aFrame) { mList.AppendToTop(aList); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 129dba7af7b..b9121038a78 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -1037,16 +1037,16 @@ private: }; /** - * The standard display item to paint the CSS box-shadow of a frame. + * The standard display item to paint the outer CSS box-shadows of a frame. */ -class nsDisplayBoxShadow : public nsDisplayItem { +class nsDisplayBoxShadowOuter : public nsDisplayItem { public: - nsDisplayBoxShadow(nsIFrame* aFrame) : nsDisplayItem(aFrame) { - MOZ_COUNT_CTOR(nsDisplayBoxShadow); + nsDisplayBoxShadowOuter(nsIFrame* aFrame) : nsDisplayItem(aFrame) { + MOZ_COUNT_CTOR(nsDisplayBoxShadowOuter); } #ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayBoxShadow() { - MOZ_COUNT_DTOR(nsDisplayBoxShadow); + virtual ~nsDisplayBoxShadowOuter() { + MOZ_COUNT_DTOR(nsDisplayBoxShadowOuter); } #endif @@ -1054,7 +1054,26 @@ public: const nsRect& aDirtyRect); virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); virtual PRBool OptimizeVisibility(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion); - NS_DISPLAY_DECL_NAME("BoxShadow") + NS_DISPLAY_DECL_NAME("BoxShadowOuter") +}; + +/** + * The standard display item to paint the inner CSS box-shadows of a frame. + */ +class nsDisplayBoxShadowInner : public nsDisplayItem { +public: + nsDisplayBoxShadowInner(nsIFrame* aFrame) : nsDisplayItem(aFrame) { + MOZ_COUNT_CTOR(nsDisplayBoxShadowInner); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayBoxShadowInner() { + MOZ_COUNT_DTOR(nsDisplayBoxShadowInner); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, + const nsRect& aDirtyRect); + NS_DISPLAY_DECL_NAME("BoxShadowInner") }; /** diff --git a/layout/base/nsStyleConsts.h b/layout/base/nsStyleConsts.h index 1440ec260e8..ce1a49062bf 100644 --- a/layout/base/nsStyleConsts.h +++ b/layout/base/nsStyleConsts.h @@ -100,6 +100,9 @@ #define NS_STYLE_BOX_SIZING_PADDING 1 #define NS_STYLE_BOX_SIZING_BORDER 2 +// box-shadow +#define NS_STYLE_BOX_SHADOW_INSET 0 + // float-edge #define NS_STYLE_FLOAT_EDGE_CONTENT 0 #define NS_STYLE_FLOAT_EDGE_MARGIN 1 diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 69e60a29226..d65bb6a359b 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -91,6 +91,44 @@ nsButtonFrameRenderer::isDisabled() nsGkAtoms::disabled); } +class nsDisplayButtonBoxShadowOuter : public nsDisplayItem { +public: + nsDisplayButtonBoxShadowOuter(nsButtonFrameRenderer* aRenderer) + : nsDisplayItem(aRenderer->GetFrame()), mBFR(aRenderer) { + MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayButtonBoxShadowOuter() { + MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter); + } +#endif + + virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx, + const nsRect& aDirtyRect); + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder); + NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter") +private: + nsButtonFrameRenderer* mBFR; +}; + +nsRect +nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { + return mFrame->GetOverflowRect() + aBuilder->ToReferenceFrame(mFrame); +} + +void +nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder, + nsIRenderingContext* aCtx, + const nsRect& aDirtyRect) { + nsRect frameRect = nsRect(aBuilder->ToReferenceFrame(mFrame), mFrame->GetSize()); + + nsRect buttonRect; + mBFR->GetButtonRect(frameRect, buttonRect); + + nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame, + buttonRect, aDirtyRect); +} + class nsDisplayButtonBorderBackground : public nsDisplayItem { public: nsDisplayButtonBorderBackground(nsButtonFrameRenderer* aRenderer) @@ -164,6 +202,12 @@ nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder, nsDisplayList* aBackground, nsDisplayList* aForeground) { + if (mFrame->GetStyleBorder()->mBoxShadow) { + nsresult rv = aBackground->AppendNewToTop(new (aBuilder) + nsDisplayButtonBoxShadowOuter(this)); + NS_ENSURE_SUCCESS(rv, rv); + } + nsresult rv = aBackground->AppendNewToTop(new (aBuilder) nsDisplayButtonBorderBackground(this)); NS_ENSURE_SUCCESS(rv, rv); @@ -226,6 +270,8 @@ nsButtonFrameRenderer::PaintBorderAndBackground(nsPresContext* aPresContext, nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, mFrame, aDirtyRect, buttonRect, PR_FALSE); + nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext, + mFrame, buttonRect, aDirtyRect); nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame, aDirtyRect, buttonRect, *border, context); } diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index 21e8b087e17..996ca2c2eb0 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -215,13 +215,15 @@ nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // the background/border display item won't do anything, and if it isn't empty, // we need to paint the outline if (IsVisibleForPainting(aBuilder)) { - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayBoxShadow(this)); - NS_ENSURE_SUCCESS(rv, rv); + if (GetStyleBorder()->mBoxShadow) { + nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) + nsDisplayBoxShadowOuter(this)); + NS_ENSURE_SUCCESS(rv, rv); + } // don't bother checking to see if we really have a border or background. // we usually will have a border. - rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) + nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) nsDisplayFieldSetBorderBackground(this)); NS_ENSURE_SUCCESS(rv, rv); @@ -279,6 +281,9 @@ nsFieldSetFrame::PaintBorderBackground(nsIRenderingContext& aRenderingContext, nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, aDirtyRect, rect, PR_TRUE); + nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext, + this, rect, aDirtyRect); + if (mLegendFrame) { // Use the rect of the legend frame, not mLegendRect, so we draw our diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index 39e4c54737a..9f609f5119e 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -557,7 +557,7 @@ nsFileControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // box-shadow if (GetStyleBorder()->mBoxShadow) { nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayBoxShadow(this)); + nsDisplayBoxShadowOuter(this)); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp index 49035773f47..1964b9c0bc1 100644 --- a/layout/forms/nsHTMLButtonControlFrame.cpp +++ b/layout/forms/nsHTMLButtonControlFrame.cpp @@ -182,11 +182,7 @@ nsHTMLButtonControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, { nsDisplayList onTop; if (IsVisibleForPainting(aBuilder)) { - nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayBoxShadow(this)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop); + nsresult rv = mRenderer.DisplayButton(aBuilder, aLists.BorderBackground(), &onTop); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 5e375aeb23b..6eecf65ef0c 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -915,9 +915,10 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder, if (!IsVisibleForPainting(aBuilder)) return NS_OK; - if (GetStyleBorder()->mBoxShadow) { + PRBool hasBoxShadow = !!(GetStyleBorder()->mBoxShadow); + if (hasBoxShadow) { nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) - nsDisplayBoxShadow(this)); + nsDisplayBoxShadowOuter(this)); NS_ENSURE_SUCCESS(rv, rv); } @@ -930,6 +931,12 @@ nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder, nsDisplayBackground(this)); NS_ENSURE_SUCCESS(rv, rv); } + + if (hasBoxShadow) { + nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) + nsDisplayBoxShadowInner(this)); + NS_ENSURE_SUCCESS(rv, rv); + } if (HasBorder()) { nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder) @@ -3824,6 +3831,10 @@ ComputeOutlineAndEffectsRect(nsIFrame* aFrame, PRBool* aAnyOutlineOrEffects, for (PRUint32 i = 0; i < boxShadows->Length(); ++i) { nsRect tmpRect = r; nsCSSShadowItem* shadow = boxShadows->ShadowAt(i); + + // inset shadows are never painted outside the frame + if (shadow->mInset) + continue; nscoord outsetRadius = shadow->mRadius + shadow->mSpread; tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset)); diff --git a/layout/reftests/box-shadow/boxshadow-inner-basic-ref.html b/layout/reftests/box-shadow/boxshadow-inner-basic-ref.html new file mode 100644 index 00000000000..a8903216593 --- /dev/null +++ b/layout/reftests/box-shadow/boxshadow-inner-basic-ref.html @@ -0,0 +1 @@ +
inset
 
diff --git a/layout/reftests/box-shadow/boxshadow-inner-basic.html b/layout/reftests/box-shadow/boxshadow-inner-basic.html new file mode 100644 index 00000000000..968e665f3ad --- /dev/null +++ b/layout/reftests/box-shadow/boxshadow-inner-basic.html @@ -0,0 +1 @@ +
inset
diff --git a/layout/reftests/box-shadow/boxshadow-mixed-ref.html b/layout/reftests/box-shadow/boxshadow-mixed-ref.html new file mode 100644 index 00000000000..2e9fee7f1eb --- /dev/null +++ b/layout/reftests/box-shadow/boxshadow-mixed-ref.html @@ -0,0 +1 @@ +
inset and outset
 
diff --git a/layout/reftests/box-shadow/boxshadow-mixed.html b/layout/reftests/box-shadow/boxshadow-mixed.html new file mode 100644 index 00000000000..2ed2658ce89 --- /dev/null +++ b/layout/reftests/box-shadow/boxshadow-mixed.html @@ -0,0 +1 @@ +
inset and outset
diff --git a/layout/reftests/box-shadow/reftest.list b/layout/reftests/box-shadow/reftest.list index 1b85f88d615..cf858950918 100644 --- a/layout/reftests/box-shadow/reftest.list +++ b/layout/reftests/box-shadow/reftest.list @@ -8,3 +8,5 @@ == boxshadow-rounding.html boxshadow-rounding-ref.html == boxshadow-button.html boxshadow-button-ref.html == boxshadow-fileupload.html boxshadow-fileupload-ref.html +== boxshadow-inner-basic.html boxshadow-inner-basic-ref.html +== boxshadow-mixed.html boxshadow-mixed-ref.html diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index d08288160fa..dcfd44d11fb 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -433,7 +433,7 @@ protected: PRBool ParseSize(); PRBool ParseTextDecoration(nsCSSValue& aValue); - nsCSSValueList* ParseCSSShadowList(PRBool aUsesSpread); + nsCSSValueList* ParseCSSShadowList(PRBool aIsBoxShadow); PRBool ParseTextShadow(); PRBool ParseBoxShadow(); @@ -7686,7 +7686,7 @@ CSSParserImpl::ParseTextDecoration(nsCSSValue& aValue) } nsCSSValueList* -CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) +CSSParserImpl::ParseCSSShadowList(PRBool aIsBoxShadow) { nsAutoParseCompoundProperty compound(this); @@ -7700,7 +7700,8 @@ CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) IndexY, IndexRadius, IndexSpread, - IndexColor + IndexColor, + IndexInset }; nsCSSValueList *list = nsnull; @@ -7710,9 +7711,18 @@ CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); break; } + + nsCSSValue isInset; + if (aIsBoxShadow) { + // Optional inset keyword (ignore errors) + ParseVariant(isInset, VARIANT_KEYWORD, + nsCSSProps::kBoxShadowTypeKTable); + } + + PRBool isFirstToken = (cur == list && isInset.GetUnit() == eCSSUnit_Null); if (!ParseVariant(cur->mValue, - (cur == list) ? VARIANT_HC | VARIANT_LENGTH | VARIANT_NONE - : VARIANT_COLOR | VARIANT_LENGTH, + isFirstToken ? VARIANT_HC | VARIANT_LENGTH | VARIANT_NONE + : VARIANT_COLOR | VARIANT_LENGTH, nsnull)) { break; } @@ -7720,7 +7730,7 @@ CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) nsCSSUnit unit = cur->mValue.GetUnit(); if (unit != eCSSUnit_None && unit != eCSSUnit_Inherit && unit != eCSSUnit_Initial) { - nsRefPtr val = nsCSSValue::Array::Create(5); + nsRefPtr val = nsCSSValue::Array::Create(6); if (!val) { mScanner.SetLowLevelError(NS_ERROR_OUT_OF_MEMORY); break; @@ -7759,7 +7769,7 @@ CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) break; } - if (aUsesSpread) { + if (aIsBoxShadow) { // Optional spread (ignore errors) ParseVariant(val->Item(IndexSpread), VARIANT_LENGTH, nsnull); @@ -7771,6 +7781,14 @@ CSSParserImpl::ParseCSSShadowList(PRBool aUsesSpread) nsnull); } + if (aIsBoxShadow && isInset.GetUnit() == eCSSUnit_Null) { + // Optional inset keyword (ignore errors) + ParseVariant(val->Item(IndexInset), VARIANT_KEYWORD, + nsCSSProps::kBoxShadowTypeKTable); + } else if (isInset.GetUnit() == eCSSUnit_Enumerated) { + val->Item(IndexInset) = isInset; + } + // Might be at a comma now if (ExpectSymbol(',', PR_TRUE)) { // Go to next value diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index ccddebef851..36c6f7e0176 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -390,7 +390,7 @@ CSS_PROP_BORDER(border-top-style, border_top_style, BorderTopStyle, CSS_PROPERTY CSS_PROP_BORDER(border-top-width, border_top_width, BorderTopWidth, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER, Margin, mBorderWidth.mTop, eCSSType_Value, kBorderWidthKTable) CSS_PROP_SHORTHAND(border-width, border_width, BorderWidth, 0) CSS_PROP_POSITION(bottom, bottom, Bottom, 0, Position, mOffset.mBottom, eCSSType_Value, nsnull) -CSS_PROP_BORDER(-moz-box-shadow, box_shadow, MozBoxShadow, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER | CSS_PROPERTY_VALUE_LIST_USES_COMMAS, Margin, mBoxShadow, eCSSType_ValueList, nsnull) +CSS_PROP_BORDER(-moz-box-shadow, box_shadow, MozBoxShadow, CSS_PROPERTY_APPLIES_TO_FIRST_LETTER | CSS_PROPERTY_VALUE_LIST_USES_COMMAS, Margin, mBoxShadow, eCSSType_ValueList, kBoxShadowTypeKTable) CSS_PROP_POSITION(-moz-box-sizing, box_sizing, MozBoxSizing, 0, Position, mBoxSizing, eCSSType_Value, kBoxSizingKTable) // XXX bug 3935 CSS_PROP_TABLEBORDER(caption-side, caption_side, CaptionSide, 0, Table, mCaptionSide, eCSSType_Value, kCaptionSideKTable) CSS_PROP_DISPLAY(clear, clear, Clear, 0, Display, mClear, eCSSType_Value, kClearKTable) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index b4c280b3364..c88b3512395 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -570,6 +570,11 @@ const PRInt32 nsCSSProps::kBoxPropSourceKTable[] = { eCSSKeyword_UNKNOWN,-1 }; +const PRInt32 nsCSSProps::kBoxShadowTypeKTable[] = { + eCSSKeyword_inset, NS_STYLE_BOX_SHADOW_INSET, + eCSSKeyword_UNKNOWN,-1 +}; + const PRInt32 nsCSSProps::kBoxSizingKTable[] = { eCSSKeyword_content_box, NS_STYLE_BOX_SIZING_CONTENT, eCSSKeyword_border_box, NS_STYLE_BOX_SIZING_BORDER, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index 7edb68684cd..175af58750a 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -188,6 +188,7 @@ public: static const PRInt32 kColorInterpolationKTable[]; #endif static const PRInt32 kBoxPropSourceKTable[]; + static const PRInt32 kBoxShadowTypeKTable[]; static const PRInt32 kBoxSizingKTable[]; static const PRInt32 kCaptionSideKTable[]; static const PRInt32 kClearKTable[]; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index f4814ffc42a..599432aa3e5 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -1795,7 +1795,7 @@ nsComputedDOMStyle::GetEllipseRadii(const nsStyleCorners& aRadius, nsresult nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray, const nscolor& aDefaultColor, - PRBool aUsesSpread, + PRBool aIsBoxShadow, nsIDOMCSSValue** aValue) { if (!aArray) { @@ -1819,7 +1819,7 @@ nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray, nscoord nsCSSShadowItem::* const * shadowValues; PRUint32 shadowValuesLength; - if (aUsesSpread) { + if (aIsBoxShadow) { shadowValues = shadowValuesWithSpread; shadowValuesLength = NS_ARRAY_LENGTH(shadowValuesWithSpread); } else { @@ -1865,6 +1865,19 @@ nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray, } val->SetAppUnits(item->*(shadowValues[i])); } + + if (item->mInset && aIsBoxShadow) { + // This is an inset box-shadow + val = GetROCSSPrimitiveValue(); + if (!val || !itemList->AppendCSSValue(val)) { + delete val; + delete valueList; + return NS_ERROR_OUT_OF_MEMORY; + } + val->SetIdent( + nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET, + nsCSSProps::kBoxShadowTypeKTable)); + } } return CallQueryInterface(valueList, aValue); diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 2e96b41b60d..7e063aa6c8a 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -113,7 +113,7 @@ private: nsresult GetCSSShadowArray(nsCSSShadowArray* aArray, const nscolor& aDefaultColor, - PRBool aUsesSpread, + PRBool aIsBoxShadow, nsIDOMCSSValue** aValue); /* Properties Queryable as CSSValues */ diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 2e3deda9f9e..39a2a2824c4 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -2937,7 +2937,7 @@ nsRuleNode::ComputeFontData(void* aStartStruct, already_AddRefed nsRuleNode::GetShadowData(nsCSSValueList* aList, nsStyleContext* aContext, - PRBool aUsesSpread, + PRBool aIsBoxShadow, PRBool& canStoreInRuleTree) { PRUint32 arrayLength = 0; @@ -2981,7 +2981,7 @@ nsRuleNode::GetShadowData(nsCSSValueList* aList, } // Find the spread radius - if (aUsesSpread && arr->Item(3).GetUnit() != eCSSUnit_Null) { + if (aIsBoxShadow && arr->Item(3).GetUnit() != eCSSUnit_Null) { unitOK = SetCoord(arr->Item(3), tempCoord, nsStyleCoord(), SETCOORD_LENGTH, aContext, mPresContext, canStoreInRuleTree); @@ -2998,6 +2998,14 @@ nsRuleNode::GetShadowData(nsCSSValueList* aList, canStoreInRuleTree); NS_ASSERTION(unitOK, "unexpected unit"); } + + if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) { + NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET, + "invalid keyword type for box shadow"); + item->mInset = PR_TRUE; + } else { + item->mInset = PR_FALSE; + } } NS_ADDREF(shadowList); diff --git a/layout/style/nsRuleNode.h b/layout/style/nsRuleNode.h index 8fb3329602e..64270016062 100644 --- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -712,7 +712,7 @@ protected: NS_HIDDEN_(already_AddRefed) GetShadowData(nsCSSValueList* aList, nsStyleContext* aContext, - PRBool aUsesSpread, + PRBool aIsBoxShadow, PRBool& inherited); private: diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 62b520e7b66..de7b1cd35fb 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -307,6 +307,7 @@ struct nsCSSShadowItem { nscolor mColor; PRPackedBool mHasColor; // Whether mColor should be used + PRPackedBool mInset; nsCSSShadowItem() : mHasColor(PR_FALSE) { MOZ_COUNT_CTOR(nsCSSShadowItem); @@ -321,6 +322,7 @@ struct nsCSSShadowItem { mRadius == aOther.mRadius && mHasColor == aOther.mHasColor && mSpread == aOther.mSpread && + mInset == aOther.mInset && (!mHasColor || mColor == aOther.mColor)); } PRBool operator!=(const nsCSSShadowItem& aOther) { diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index c244d998f3d..bdaaf2f4477 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -333,8 +333,8 @@ var gCSSProperties = { type: CSS_TYPE_LONGHAND, initial_values: [ "none" ], prerequisites: { "color": "blue" }, - other_values: [ "2px 2px", "2px 2px 1px", "2px 2px 2px 2px", "blue 3px 2px", "2px 2px 1px 5px green", "2px 2px red", "green 2px 2px 1px", "green 2px 2px, blue 1px 3px 4px", "currentColor 3px 3px", "blue 2px 2px, currentColor 1px 2px, 1px 2px 3px 2px orange", "3px 0 0 0" ], - invalid_values: [ "3% 3%", "1px 1px 1px 1px 1px", "2px 2px, none", "red 2px 2px blue", "inherit, 2px 2px", "2px 2px, inherit", "2px 2px -5px" ] + other_values: [ "2px 2px", "2px 2px 1px", "2px 2px 2px 2px", "blue 3px 2px", "2px 2px 1px 5px green", "2px 2px red", "green 2px 2px 1px", "green 2px 2px, blue 1px 3px 4px", "currentColor 3px 3px", "blue 2px 2px, currentColor 1px 2px, 1px 2px 3px 2px orange", "3px 0 0 0", "inset 2px 2px 3px 4px black", "2px -2px green inset, 4px 4px 3px blue, inset 2px 2px" ], + invalid_values: [ "3% 3%", "1px 1px 1px 1px 1px", "2px 2px, none", "red 2px 2px blue", "inherit, 2px 2px", "2px 2px, inherit", "2px 2px -5px", "inset 4px 4px black inset", "inset inherit", "inset none" ] }, "-moz-box-sizing": { domProp: "MozBoxSizing", diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index 9e0d8e58a92..f090203c700 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -446,8 +446,10 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, currentItem->UpdateForFrameBackground(this); } - if (GetStyleBorder()->mBoxShadow) { - nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadow(this); + // display outset box-shadows if we need to. + PRBool hasBoxShadow = !!(GetStyleBorder()->mBoxShadow); + if (hasBoxShadow) { + nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadowOuter(this); nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); } @@ -464,6 +466,13 @@ nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, NS_ENSURE_SUCCESS(rv, rv); item->UpdateForFrameBackground(this); } + + // display inset box-shadows if we need to. + if (hasBoxShadow) { + nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadowInner(this); + nsresult rv = aLists.BorderBackground()->AppendNewToTop(item); + NS_ENSURE_SUCCESS(rv, rv); + } // display borders if we need to if (!tableFrame->IsBorderCollapse() && HasBorder() && diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 8d7718faecf..102e90f6a07 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1373,10 +1373,11 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, NS_ASSERTION(currentItem, "No current table item!"); currentItem->UpdateForFrameBackground(aFrame); - // Paint the box-shadow for the table frames - if (aFrame->IsVisibleForPainting(aBuilder) && - aFrame->GetStyleBorder()->mBoxShadow) { - nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadow(aFrame); + // Paint the outset box-shadows for the table frames + PRBool hasBoxShadow = aFrame->IsVisibleForPainting(aBuilder) && + aFrame->GetStyleBorder()->mBoxShadow; + if (hasBoxShadow) { + nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadowOuter(aFrame); nsresult rv = lists->BorderBackground()->AppendNewToTop(item); NS_ENSURE_SUCCESS(rv, rv); } @@ -1391,6 +1392,13 @@ nsTableFrame::DisplayGenericTablePart(nsDisplayListBuilder* aBuilder, NS_ENSURE_SUCCESS(rv, rv); } + // Paint the inset box-shadows for the table frames + if (hasBoxShadow) { + nsDisplayItem* item = new (aBuilder) nsDisplayBoxShadowInner(aFrame); + nsresult rv = lists->BorderBackground()->AppendNewToTop(item); + NS_ENSURE_SUCCESS(rv, rv); + } + nsresult rv = aTraversal(aBuilder, aFrame, aDirtyRect, *lists); NS_ENSURE_SUCCESS(rv, rv);