Bug 476738. Implement 'inset' box-shadows. r+sr=roc,r=dbaron

This commit is contained in:
Michael Ventnor 2009-02-10 21:45:13 +13:00
Родитель 4a08835d68
Коммит 7a2af3b188
27 изменённых файлов: 342 добавлений и 63 удалений

Просмотреть файл

@ -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<gfxContext> 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,

Просмотреть файл

@ -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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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")
};
/**

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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));

Просмотреть файл

@ -0,0 +1 @@
<div style="background-color: grey; width: 300px; height: 300px; -moz-border-radius: 5px; position: absolute; top: 20px; left: 20px;">inset</div><div style="-moz-border-radius: 5px; width: 300px; height: 300px; background-color: white; position: absolute; top: 40px; left: 40px;">&nbsp;</div>

Просмотреть файл

@ -0,0 +1 @@
<div style="-moz-box-shadow: 20px 20px grey inset; width: 300px; height: 300px; -moz-border-radius: 5px; position: absolute; top: 20px; left: 20px;">inset</div>

Просмотреть файл

@ -0,0 +1 @@
<div style="background-color: blue; border: 2px solid red; -moz-border-radius: 10px; width: 300px; height: 300px; position: absolute; top: 10px; left: 10px;">inset and outset</div><div style="-moz-border-radius: 10px; background-color: green; width: 304px; height: 304px; position: absolute; top: 10px; left: 360px;">&nbsp;</div>

Просмотреть файл

@ -0,0 +1 @@
<div style="border: 2px red solid; -moz-border-radius: 10px; width: 300px; height: 300px; -moz-box-shadow: 500px 500px 0px 20px blue inset, 350px 0px green; position: absolute; top: 10px; left: 10px;">inset and outset</div>

Просмотреть файл

@ -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

Просмотреть файл

@ -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<nsCSSValue::Array> val = nsCSSValue::Array::Create(5);
nsRefPtr<nsCSSValue::Array> 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

Просмотреть файл

@ -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)

Просмотреть файл

@ -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,

Просмотреть файл

@ -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[];

Просмотреть файл

@ -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);

Просмотреть файл

@ -113,7 +113,7 @@ private:
nsresult GetCSSShadowArray(nsCSSShadowArray* aArray,
const nscolor& aDefaultColor,
PRBool aUsesSpread,
PRBool aIsBoxShadow,
nsIDOMCSSValue** aValue);
/* Properties Queryable as CSSValues */

Просмотреть файл

@ -2937,7 +2937,7 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
already_AddRefed<nsCSSShadowArray>
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);

Просмотреть файл

@ -712,7 +712,7 @@ protected:
NS_HIDDEN_(already_AddRefed<nsCSSShadowArray>)
GetShadowData(nsCSSValueList* aList,
nsStyleContext* aContext,
PRBool aUsesSpread,
PRBool aIsBoxShadow,
PRBool& inherited);
private:

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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",

Просмотреть файл

@ -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() &&

Просмотреть файл

@ -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);