Bug 212633 - "Add support for CSS3 box-shadow" (parsing support) [p=ventnor.bugzilla@gmail.com (Michael Ventnor) r+sr=dbaron]

This commit is contained in:
Michael Ventnor 2008-07-07 19:56:52 -05:00
parent 0b959cc689
commit b3e218a0a8
17 changed files with 385 additions and 252 deletions

View File

@ -406,7 +406,7 @@ interface nsIDOMCSS2Properties : nsISupports
// raises(DOMException) on setting
};
[scriptable, uuid(8a5b178d-c805-4f8e-8992-fa7c5c11d08e)]
[scriptable, uuid(816581b0-3d89-11dd-ae16-0800200c9a66)]
interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
{
/* Non-DOM 2 extensions */
@ -593,4 +593,7 @@ interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
attribute DOMString MozStackSizing;
// raises(DOMException) on setting
attribute DOMString MozBoxShadow;
// raises(DOMException) on setting
};

View File

@ -1291,13 +1291,13 @@ nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
nsIFrame* aFrame)
{
const nsStyleText* textStyle = aFrame->GetStyleText();
if (!textStyle->mShadowArray)
if (!textStyle->mTextShadow)
return aTextAndDecorationsRect;
nsRect resultRect = aTextAndDecorationsRect;
for (PRUint32 i = 0; i < textStyle->mShadowArray->Length(); ++i) {
for (PRUint32 i = 0; i < textStyle->mTextShadow->Length(); ++i) {
nsRect tmpRect(aTextAndDecorationsRect);
nsTextShadowItem* shadow = textStyle->mShadowArray->ShadowAt(i);
nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
nscoord xOffset = shadow->mXOffset.GetCoordValue();
nscoord yOffset = shadow->mYOffset.GetCoordValue();
nscoord blurRadius = shadow->mRadius.GetCoordValue();

View File

@ -267,9 +267,9 @@ nsHTMLContainerFrame::DisplayTextDecorations(nsDisplayListBuilder* aBuilder,
// it. So draw the shadows as part of the display list.
const nsStyleText* textStyle = GetStyleText();
if (textStyle->mShadowArray) {
for (PRUint32 i = textStyle->mShadowArray->Length(); i > 0; --i) {
nsTextShadowItem* shadow = textStyle->mShadowArray->ShadowAt(i - 1);
if (textStyle->mTextShadow) {
for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i - 1);
nscoord blurRadius = shadow->mRadius.GetCoordValue();
nscolor shadowColor;

View File

@ -396,7 +396,7 @@ protected:
void PaintOneShadow(PRUint32 aOffset,
PRUint32 aLength,
nsTextShadowItem* aShadowDetails,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider,
const gfxRect& aDirtyRect,
const gfxPoint& aFramePt,

View File

@ -3961,7 +3961,7 @@ PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
void
nsTextFrame::PaintOneShadow(PRUint32 aOffset, PRUint32 aLength,
nsTextShadowItem* aShadowDetails,
nsCSSShadowItem* aShadowDetails,
PropertyProvider* aProvider, const gfxRect& aDirtyRect,
const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
gfxContext* aCtx, const nscolor& aForegroundColor)
@ -4268,13 +4268,13 @@ nsTextFrame::PaintText(nsIRenderingContext* aRenderingContext, nsPoint aPt,
// Paint the text shadow before doing any foreground stuff
const nsStyleText* textStyle = GetStyleText();
if (textStyle->mShadowArray) {
if (textStyle->mTextShadow) {
// Text shadow happens with the last value being painted at the back,
// ie. it is painted first.
for (PRUint32 i = textStyle->mShadowArray->Length(); i > 0; --i) {
for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
PaintOneShadow(provider.GetStart().GetSkippedOffset(),
ComputeTransformedLength(provider),
textStyle->mShadowArray->ShadowAt(i - 1), &provider,
textStyle->mTextShadow->ShadowAt(i - 1), &provider,
dirtyRect, framePt, textBaselinePt, ctx,
textPaintStyle.GetTextColor());
}

View File

@ -245,6 +245,7 @@ PRBool nsCSSDeclaration::AppendValueToString(nsCSSProperty aProperty, nsAString&
if (val) {
if (aProperty == eCSSProperty_cursor
|| aProperty == eCSSProperty_text_shadow
|| aProperty == eCSSProperty_box_shadow
#ifdef MOZ_SVG
|| aProperty == eCSSProperty_stroke_dasharray
#endif

View File

@ -358,7 +358,11 @@ protected:
PRBool ParseQuotes(nsresult& aErrorCode);
PRBool ParseSize(nsresult& aErrorCode);
PRBool ParseTextDecoration(nsresult& aErrorCode, nsCSSValue& aValue);
nsCSSValueList* ParseCSSShadowList(nsresult& aErrorCode,
PRBool aUsesSpread);
PRBool ParseTextShadow(nsresult& aErrorCode);
PRBool ParseBoxShadow(nsresult& aErrorCode);
#ifdef MOZ_SVG
PRBool ParsePaint(nsresult& aErrorCode,
@ -4549,6 +4553,8 @@ PRBool CSSParserImpl::ParseProperty(nsresult& aErrorCode,
return ParseSize(aErrorCode);
case eCSSProperty_text_shadow:
return ParseTextShadow(aErrorCode);
case eCSSProperty_box_shadow:
return ParseBoxShadow(aErrorCode);
#ifdef MOZ_SVG
case eCSSProperty_fill:
@ -4695,6 +4701,7 @@ PRBool CSSParserImpl::ParseSingleValueProperty(nsresult& aErrorCode,
case eCSSProperty_quotes:
case eCSSProperty_size:
case eCSSProperty_text_shadow:
case eCSSProperty_box_shadow:
case eCSSProperty_COUNT:
#ifdef MOZ_SVG
case eCSSProperty_fill:
@ -6436,7 +6443,8 @@ PRBool CSSParserImpl::ParseTextDecoration(nsresult& aErrorCode, nsCSSValue& aVal
return PR_FALSE;
}
PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
nsCSSValueList* CSSParserImpl::ParseCSSShadowList(nsresult& aErrorCode,
PRBool aUsesSpread)
{
nsAutoParseCompoundProperty compound(this);
@ -6449,14 +6457,10 @@ PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
IndexX,
IndexY,
IndexRadius,
IndexSpread,
IndexColor
};
// This variable is set to true if we already parsed an "end of property"
// token. We can't unget it, as ExpectEndProperty already ungets the token in
// some cases, and we can't detect that.
PRBool atEOP = PR_FALSE;
nsCSSValueList *list = nsnull;
for (nsCSSValueList **curp = &list, *cur; ; curp = &cur->mNext) {
cur = *curp = new nsCSSValueList();
@ -6474,7 +6478,7 @@ PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
nsCSSUnit unit = cur->mValue.GetUnit();
if (unit != eCSSUnit_None && unit != eCSSUnit_Inherit &&
unit != eCSSUnit_Initial) {
nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(4);
nsRefPtr<nsCSSValue::Array> val = nsCSSValue::Array::Create(5);
if (!val) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
break;
@ -6491,7 +6495,7 @@ PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
haveColor = PR_TRUE;
val->Item(IndexColor) = cur->mValue;
// Parse the x coordinate
// Parse the X coordinate
if (!ParseVariant(aErrorCode, val->Item(IndexX), VARIANT_LENGTH,
nsnull)) {
break;
@ -6504,22 +6508,25 @@ PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
break;
}
// Peek the next token to determine whether it's the radius or the color
// EOF is fine too (properties can end in EOF)
PRBool haveRadius = PR_FALSE;
if (GetToken(aErrorCode, PR_TRUE)) {
// The radius is a length, and all lengths are dimensions
haveRadius = mToken.IsDimension();
// Now unget the token, we didn't consume it
UngetToken();
// Optional radius. Ignore errors except if they pass a negative
// value which we must reject. If we use ParsePositiveVariant we can't
// tell the difference between an unspecified radius and a negative
// radius, so that's why we don't use it.
if (ParseVariant(aErrorCode, val->Item(IndexRadius), VARIANT_LENGTH, nsnull) &&
val->Item(IndexRadius).GetFloatValue() < 0) {
break;
}
if (haveRadius) {
// Optional radius
if (!ParseVariant(aErrorCode, val->Item(IndexRadius), VARIANT_LENGTH,
nsnull)) {
break;
}
if (aUsesSpread) {
// Optional spread (ignore errors)
ParseVariant(aErrorCode, val->Item(IndexSpread), VARIANT_LENGTH,
nsnull);
}
if (!haveColor) {
// Optional color (ignore errors)
ParseVariant(aErrorCode, val->Item(IndexColor), VARIANT_COLOR,
nsnull);
}
// Might be at a comma now
@ -6527,48 +6534,45 @@ PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
// Go to next value
continue;
}
if (!haveColor) {
// Now, we are either at the end of the property, or have a color (or
// have an error)
if (ExpectEndProperty(aErrorCode)) {
atEOP = PR_TRUE;
} else {
// Clear the error from ExpectEndProperty - not a real error (if we
// have a color here)
CLEAR_ERROR();
// Since we're not at the end of the property, we must have a color,
// or report an error.
if (!ParseVariant(aErrorCode, val->Item(IndexColor), VARIANT_COLOR,
nsnull)) {
break;
}
if (ExpectSymbol(aErrorCode, ',', PR_TRUE)) {
// Parse next value
continue;
}
}
}
}
if (!atEOP && !ExpectEndProperty(aErrorCode)) {
// Error
if (!ExpectEndProperty(aErrorCode)) {
// If we don't have a comma to delimit the next value, we
// must be at the end of the property. Otherwise we've hit
// something else, which is an error.
break;
}
// Only success case here, since having the failure case at the
// end allows more sharing of code.
mTempData.SetPropertyBit(eCSSProperty_text_shadow);
mTempData.mText.mTextShadow = list;
aErrorCode = NS_OK;
return PR_TRUE;
return list;
}
// Have failure case at the end so we can |break| to get to it.
delete list;
return PR_FALSE;
return nsnull;
}
PRBool CSSParserImpl::ParseTextShadow(nsresult& aErrorCode)
{
nsCSSValueList* list = ParseCSSShadowList(aErrorCode, PR_FALSE);
if (!list)
return PR_FALSE;
mTempData.SetPropertyBit(eCSSProperty_text_shadow);
mTempData.mText.mTextShadow = list;
return PR_TRUE;
}
PRBool CSSParserImpl::ParseBoxShadow(nsresult& aErrorCode)
{
nsCSSValueList* list = ParseCSSShadowList(aErrorCode, PR_TRUE);
if (!list)
return PR_FALSE;
mTempData.SetPropertyBit(eCSSProperty_box_shadow);
mTempData.mMargin.mBoxShadow = list;
return PR_TRUE;
}
#ifdef MOZ_SVG

View File

@ -366,6 +366,7 @@ CSS_PROP_BORDER(border-top-style, border_top_style, BorderTopStyle, Margin, mBor
CSS_PROP_BORDER(border-top-width, border_top_width, BorderTopWidth, Margin, mBorderWidth.mTop, eCSSType_Value, kBorderWidthKTable)
CSS_PROP_SHORTHAND(border-width, border_width, BorderWidth)
CSS_PROP_POSITION(bottom, bottom, Bottom, Position, mOffset.mBottom, eCSSType_Value, nsnull)
CSS_PROP_BORDER(-moz-box-shadow, box_shadow, MozBoxShadow, Margin, mBoxShadow, eCSSType_ValueList, nsnull)
CSS_PROP_POSITION(-moz-box-sizing, box_sizing, MozBoxSizing, Position, mBoxSizing, eCSSType_Value, kBoxSizingKTable) // XXX bug 3935
CSS_PROP_TABLEBORDER(caption-side, caption_side, CaptionSide, Table, mCaptionSide, eCSSType_Value, kCaptionSideKTable)
CSS_PROP_DISPLAY(clear, clear, Clear, Display, mClear, eCSSType_Value, kClearKTable)

View File

@ -226,6 +226,7 @@ nsCSSDisplay::~nsCSSDisplay(void)
// --- nsCSSMargin -----------------
nsCSSMargin::nsCSSMargin(void)
: mBoxShadow(nsnull)
{
MOZ_COUNT_CTOR(nsCSSMargin);
}
@ -233,6 +234,7 @@ nsCSSMargin::nsCSSMargin(void)
nsCSSMargin::~nsCSSMargin(void)
{
MOZ_COUNT_DTOR(nsCSSMargin);
CSS_IF_DELETE(mBoxShadow);
}
// --- nsCSSPosition -----------------

View File

@ -354,6 +354,7 @@ struct nsCSSMargin : public nsCSSStruct {
nsCSSValue mOutlineOffset;
nsCSSRect mOutlineRadius; // (extension)
nsCSSValue mFloatEdge; // NEW
nsCSSValueList* mBoxShadow;
private:
nsCSSMargin(const nsCSSMargin& aOther); // NOT IMPLEMENTED
};

View File

@ -1569,6 +1569,92 @@ nsComputedDOMStyle::GetOutlineRadiusFor(PRUint8 aSide, nsIDOMCSSValue** aValue)
return CallQueryInterface(val, aValue);
}
nsresult
nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
const nscolor& aDefaultColor,
PRBool aUsesSpread,
nsIDOMCSSValue** aValue)
{
if (!aArray) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsGkAtoms::none);
return CallQueryInterface(val, aValue);
}
static nsStyleCoord nsCSSShadowItem::* const shadowValuesNoSpread[] = {
&nsCSSShadowItem::mXOffset,
&nsCSSShadowItem::mYOffset,
&nsCSSShadowItem::mRadius
};
static nsStyleCoord nsCSSShadowItem::* const shadowValuesWithSpread[] = {
&nsCSSShadowItem::mXOffset,
&nsCSSShadowItem::mYOffset,
&nsCSSShadowItem::mRadius,
&nsCSSShadowItem::mSpread
};
nsStyleCoord nsCSSShadowItem::* const * shadowValues;
PRUint32 shadowValuesLength;
if (aUsesSpread) {
shadowValues = shadowValuesWithSpread;
shadowValuesLength = NS_ARRAY_LENGTH(shadowValuesWithSpread);
} else {
shadowValues = shadowValuesNoSpread;
shadowValuesLength = NS_ARRAY_LENGTH(shadowValuesNoSpread);
}
nsDOMCSSValueList *valueList = GetROCSSValueList(PR_TRUE);
NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
for (nsCSSShadowItem *item = aArray->ShadowAt(0),
*item_end = item + aArray->Length();
item < item_end; ++item) {
nsDOMCSSValueList *itemList = GetROCSSValueList(PR_FALSE);
if (!itemList || !valueList->AppendCSSValue(itemList)) {
delete itemList;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
// Color is either the specified shadow color or the foreground color
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
if (!val || !itemList->AppendCSSValue(val)) {
delete val;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
nscolor shadowColor;
if (item->mHasColor) {
shadowColor = item->mColor;
} else {
shadowColor = aDefaultColor;
}
SetToRGBAColor(val, shadowColor);
// Set the offsets, blur radius, and spread if available
for (PRUint32 i = 0; i < shadowValuesLength; ++i) {
val = GetROCSSPrimitiveValue();
if (!val || !itemList->AppendCSSValue(val)) {
delete val;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
SetValueToCoord(val, item->*(shadowValues[i]));
}
}
return CallQueryInterface(valueList, aValue);
}
nsresult
nsComputedDOMStyle::GetBoxShadow(nsIDOMCSSValue** aValue)
{
return GetCSSShadowArray(GetStyleBorder()->mBoxShadow,
GetStyleColor()->mColor,
PR_TRUE, aValue);
}
nsresult
nsComputedDOMStyle::GetZIndex(nsIDOMCSSValue** aValue)
{
@ -1794,60 +1880,9 @@ nsComputedDOMStyle::GetTextIndent(nsIDOMCSSValue** aValue)
nsresult
nsComputedDOMStyle::GetTextShadow(nsIDOMCSSValue** aValue)
{
const nsStyleText* text = GetStyleText();
if (!text->mShadowArray) {
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
val->SetIdent(nsGkAtoms::none);
return CallQueryInterface(val, aValue);
}
static const nsStyleCoord nsTextShadowItem::*shadowValues[] = {
&nsTextShadowItem::mXOffset,
&nsTextShadowItem::mYOffset,
&nsTextShadowItem::mRadius
};
nsDOMCSSValueList *valueList = GetROCSSValueList(PR_TRUE);
NS_ENSURE_TRUE(valueList, NS_ERROR_OUT_OF_MEMORY);
for (nsTextShadowItem *item = text->mShadowArray->ShadowAt(0),
*item_end = item + text->mShadowArray->Length();
item < item_end; ++item) {
nsDOMCSSValueList *itemList = GetROCSSValueList(PR_FALSE);
if (!itemList || !valueList->AppendCSSValue(itemList)) {
delete itemList;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
// Color is either the specified shadow color or the foreground color
nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
if (!val || !itemList->AppendCSSValue(val)) {
delete val;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
nscolor shadowColor;
if (item->mHasColor) {
shadowColor = item->mColor;
} else {
shadowColor = GetStyleColor()->mColor;
}
SetToRGBAColor(val, shadowColor);
// Set the offsets and blur radius
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(shadowValues); ++i) {
val = GetROCSSPrimitiveValue();
if (!val || !itemList->AppendCSSValue(val)) {
delete val;
delete valueList;
return NS_ERROR_OUT_OF_MEMORY;
}
SetValueToCoord(val, item->*(shadowValues[i]));
}
}
return CallQueryInterface(valueList, aValue);
return GetCSSShadowArray(GetStyleText()->mTextShadow,
GetStyleColor()->mColor,
PR_FALSE, aValue);
}
nsresult
@ -3866,6 +3901,7 @@ nsComputedDOMStyle::GetQueryablePropertyMap(PRUint32* aLength)
COMPUTED_STYLE_MAP_ENTRY(box_ordinal_group, BoxOrdinalGroup),
COMPUTED_STYLE_MAP_ENTRY(box_orient, BoxOrient),
COMPUTED_STYLE_MAP_ENTRY(box_pack, BoxPack),
COMPUTED_STYLE_MAP_ENTRY(box_shadow, BoxShadow),
COMPUTED_STYLE_MAP_ENTRY(box_sizing, BoxSizing),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_count, ColumnCount),
COMPUTED_STYLE_MAP_ENTRY(_moz_column_width, ColumnWidth),

View File

@ -110,6 +110,11 @@ private:
PRBool GetLineHeightCoord(nscoord& aCoord);
nsresult GetCSSShadowArray(nsCSSShadowArray* aArray,
const nscolor& aDefaultColor,
PRBool aUsesSpread,
nsIDOMCSSValue** aValue);
/* Properties Queryable as CSSValues */
nsresult GetAppearance(nsIDOMCSSValue** aValue);
@ -194,6 +199,9 @@ private:
nsresult GetBorderRadiusTopRight(nsIDOMCSSValue** aValue);
nsresult GetFloatEdge(nsIDOMCSSValue** aValue);
/* Box Shadow */
nsresult GetBoxShadow(nsIDOMCSSValue** aValue);
/* Margin Properties */
nsresult GetMarginWidth(nsIDOMCSSValue** aValue);
nsresult GetMarginTopWidth(nsIDOMCSSValue** aValue);

View File

@ -1230,7 +1230,9 @@ nsRuleNode::GetBorderData(nsStyleContext* aContext)
nsRuleData ruleData(NS_STYLE_INHERIT_BIT(Border), mPresContext, aContext);
ruleData.mMarginData = &marginData;
return WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
const void* res = WalkRuleTree(eStyleStruct_Border, aContext, &ruleData, &marginData);
marginData.mBoxShadow = nsnull; // We are sharing with some style rule. It really owns the data.
return res;
}
const void*
@ -2616,6 +2618,60 @@ nsRuleNode::ComputeFontData(void* aStartStruct,
COMPUTE_END_INHERITED(Font, font)
}
already_AddRefed<nsCSSShadowArray>
nsRuleNode::GetShadowData(nsCSSValueList* aList,
nsStyleContext* aContext,
PRBool aUsesSpread,
PRBool& inherited)
{
PRUint32 arrayLength = 0;
for (nsCSSValueList *list2 = aList; list2; list2 = list2->mNext)
++arrayLength;
NS_ASSERTION(arrayLength > 0, "Non-null text-shadow list, yet we counted 0 items.");
nsCSSShadowArray* shadowList = new(arrayLength) nsCSSShadowArray(arrayLength);
if (!shadowList)
return nsnull;
for (nsCSSShadowItem* item = shadowList->ShadowAt(0);
aList;
aList = aList->mNext, ++item) {
nsCSSValue::Array *arr = aList->mValue.GetArrayValue();
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
SetCoord(arr->Item(0), item->mXOffset, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
SetCoord(arr->Item(1), item->mYOffset, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
// Blur radius is optional in the current box-shadow spec
if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
SetCoord(arr->Item(2), item->mRadius, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
} else {
item->mRadius.SetCoordValue(0);
}
// Find the spread radius
if (aUsesSpread && arr->Item(3).GetUnit() != eCSSUnit_Null) {
SetCoord(arr->Item(3), item->mSpread, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
} else {
item->mSpread.SetCoordValue(0);
}
if (arr->Item(4).GetUnit() != eCSSUnit_Null) {
item->mHasColor = PR_TRUE;
// 2nd argument can be bogus since inherit is not a valid color
SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
inherited);
}
}
NS_ADDREF(shadowList);
return shadowList;
}
const void*
nsRuleNode::ComputeTextData(void* aStartStruct,
const nsRuleDataStruct& aData,
@ -2633,49 +2689,16 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
// text-shadow: none, list, inherit, initial
nsCSSValueList* list = textData.mTextShadow;
if (list) {
text->mShadowArray = nsnull;
text->mTextShadow = nsnull;
// Don't need to handle none/initial explicitly: The above assignment
// takes care of that
if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
inherited = PR_TRUE;
text->mShadowArray = parentText->mShadowArray;
text->mTextShadow = parentText->mTextShadow;
} else if (eCSSUnit_Array == list->mValue.GetUnit()) {
// List of arrays
PRUint32 arrayLength = 0;
for (nsCSSValueList *list2 = list; list2; list2 = list2->mNext)
++arrayLength;
NS_ASSERTION(arrayLength > 0, "Non-null text-shadow list, yet we counted 0 items.");
text->mShadowArray = new(arrayLength) nsTextShadowArray(arrayLength);
if (text->mShadowArray) {
for (nsTextShadowItem* item = text->mShadowArray->ShadowAt(0);
list;
list = list->mNext, ++item) {
nsCSSValue::Array *arr = list->mValue.GetArrayValue();
// OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
SetCoord(arr->Item(0), item->mXOffset, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
SetCoord(arr->Item(1), item->mYOffset, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
// Blur radius is optional in the text-shadow rule. If not available,
// set it to 0.
if (arr->Item(2).GetUnit() != eCSSUnit_Null) {
SetCoord(arr->Item(2), item->mRadius, nsStyleCoord(),
SETCOORD_LENGTH, aContext, mPresContext, inherited);
} else {
item->mRadius.SetCoordValue(0);
}
if (arr->Item(3).GetUnit() != eCSSUnit_Null) {
item->mHasColor = PR_TRUE;
// 2nd argument can be bogus since inherit is not a valid color
SetColor(arr->Item(3), 0, mPresContext, aContext, item->mColor,
inherited);
}
}
}
text->mTextShadow = GetShadowData(list, aContext, PR_FALSE, inherited);
}
}
@ -3684,6 +3707,21 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder,
Margin, marginData)
// -moz-box-shadow: none, list, inherit, initial
nsCSSValueList* list = marginData.mBoxShadow;
if (list) {
// This handles 'none' and 'initial'
border->mBoxShadow = nsnull;
if (eCSSUnit_Inherit == list->mValue.GetUnit()) {
inherited = PR_TRUE;
border->mBoxShadow = parentBorder->mBoxShadow;
} else if (eCSSUnit_Array == list->mValue.GetUnit()) {
// List of arrays
border->mBoxShadow = GetShadowData(list, aContext, PR_TRUE, inherited);
}
}
// border-width, border-*-width: length, enum, inherit
nsStyleCoord coord;
nsCSSRect ourBorderWidth(marginData.mBorderWidth);

View File

@ -55,6 +55,7 @@ class nsILanguageAtomService;
struct nsRuleData;
class nsIStyleRule;
struct nsCSSStruct;
struct nsCSSValueList;
// Copy of typedef that's in nsCSSStruct.h, for compilation speed.
typedef nsCSSStruct nsRuleDataStruct;
@ -671,6 +672,12 @@ protected:
NS_HIDDEN_(const void*) GetSVGResetData(nsStyleContext* aContext);
#endif
NS_HIDDEN_(already_AddRefed<nsCSSShadowArray>)
GetShadowData(nsCSSValueList* aList,
nsStyleContext* aContext,
PRBool aUsesSpread,
PRBool& inherited);
private:
nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent,
nsIStyleRule* aRule, PRUint8 aLevel, PRBool aIsImportant)

View File

@ -104,6 +104,9 @@ static PRBool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
return EqualURIs(uri1, uri2);
}
static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
nsCSSShadowArray* rhs);
// --------------------
// nsStyleFont
//
@ -366,6 +369,7 @@ nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
}
mBorderColors = nsnull;
mBoxShadow = nsnull;
mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT;
@ -373,8 +377,13 @@ nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
}
nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
: mActualBorder(aSrc.mActualBorder),
mTwipsPerPixel(aSrc.mTwipsPerPixel),
mBorder(aSrc.mBorder),
mBorderRadius(aSrc.mBorderRadius),
mFloatEdge(aSrc.mFloatEdge),
mBoxShadow(aSrc.mBoxShadow)
{
memcpy((nsStyleBorder*)this, &aSrc, sizeof(nsStyleBorder));
mBorderColors = nsnull;
if (aSrc.mBorderColors) {
EnsureBorderColors();
@ -384,6 +393,11 @@ nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
else
mBorderColors[i] = nsnull;
}
NS_FOR_CSS_SIDES(side) {
mBorderStyle[side] = aSrc.mBorderStyle[side];
mBorderColor[side] = aSrc.mBorderColor[side];
}
}
void*
@ -438,8 +452,8 @@ nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
}
}
return NS_STYLE_HINT_NONE;
// Decide what to do with regards to box-shadow
return CalcShadowDifference(mBoxShadow, aOther.mBoxShadow);
}
return NS_STYLE_HINT_REFLOW;
}
@ -1543,12 +1557,12 @@ nsChangeHint nsStyleTextReset::MaxDifference()
#endif
// --------------------
// nsTextShadowArray
// nsTextShadowItem
// nsCSSShadowArray
// nsCSSShadowItem
//
nsrefcnt
nsTextShadowArray::Release()
nsCSSShadowArray::Release()
{
mRefCnt--;
if (mRefCnt == 0) {
@ -1558,6 +1572,23 @@ nsTextShadowArray::Release()
return mRefCnt;
}
static nsChangeHint
CalcShadowDifference(nsCSSShadowArray* lhs,
nsCSSShadowArray* rhs)
{
if (lhs == rhs)
return NS_STYLE_HINT_NONE;
if (!lhs || !rhs || lhs->Length() != rhs->Length())
return NS_STYLE_HINT_REFLOW;
for (PRUint32 i = 0; i < lhs->Length(); ++i) {
if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i))
return NS_STYLE_HINT_REFLOW;
}
return NS_STYLE_HINT_NONE;
}
// --------------------
// nsStyleText
//
@ -1573,7 +1604,7 @@ nsStyleText::nsStyleText(void)
mTextIndent.SetCoordValue(0);
mWordSpacing.SetNormalValue();
mShadowArray = nsnull;
mTextShadow = nsnull;
}
nsStyleText::nsStyleText(const nsStyleText& aSource)
@ -1584,7 +1615,7 @@ nsStyleText::nsStyleText(const nsStyleText& aSource)
mLineHeight(aSource.mLineHeight),
mTextIndent(aSource.mTextIndent),
mWordSpacing(aSource.mWordSpacing),
mShadowArray(aSource.mShadowArray)
mTextShadow(aSource.mTextShadow)
{ }
nsStyleText::~nsStyleText(void) { }
@ -1600,19 +1631,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
(mWordSpacing != aOther.mWordSpacing))
return NS_STYLE_HINT_REFLOW;
if ((!mShadowArray && !aOther.mShadowArray) ||
mShadowArray == aOther.mShadowArray)
return NS_STYLE_HINT_NONE;
if (!mShadowArray || !aOther.mShadowArray ||
(mShadowArray->Length() != aOther.mShadowArray->Length()))
return NS_STYLE_HINT_REFLOW;
for (PRUint32 i = 0; i < mShadowArray->Length(); ++i) {
if (*mShadowArray->ShadowAt(i) != *aOther.mShadowArray->ShadowAt(i))
return NS_STYLE_HINT_REFLOW;
}
return NS_STYLE_HINT_NONE;
return CalcShadowDifference(mTextShadow, aOther.mTextShadow);
}
#ifdef DEBUG

View File

@ -306,6 +306,83 @@ struct nsBorderColors {
}
};
struct nsCSSShadowItem {
nsStyleCoord mXOffset; // length (coord, chars)
nsStyleCoord mYOffset; // length (coord, chars)
nsStyleCoord mRadius; // length (coord, chars)
nsStyleCoord mSpread; // length (coord, chars)
nscolor mColor;
PRPackedBool mHasColor; // Whether mColor should be used
nsCSSShadowItem() : mHasColor(PR_FALSE) {
MOZ_COUNT_CTOR(nsCSSShadowItem);
}
~nsCSSShadowItem() {
MOZ_COUNT_DTOR(nsCSSShadowItem);
}
PRBool operator==(const nsCSSShadowItem& aOther) {
return (mXOffset == aOther.mXOffset &&
mYOffset == aOther.mYOffset &&
mRadius == aOther.mRadius &&
mHasColor == aOther.mHasColor &&
mSpread == aOther.mSpread &&
(!mHasColor || mColor == aOther.mColor));
}
PRBool operator!=(const nsCSSShadowItem& aOther) {
return !(*this == aOther);
}
};
class nsCSSShadowArray {
public:
void* operator new(size_t aBaseSize, PRUint32 aArrayLen) {
// We can allocate both this nsCSSShadowArray and the
// actual array in one allocation. The amount of memory to
// allocate is equal to the class's size + the number of bytes for all
// but the first array item (because aBaseSize includes one
// item, see the private declarations)
return ::operator new(aBaseSize +
(aArrayLen - 1) * sizeof(nsCSSShadowItem));
}
nsCSSShadowArray(PRUint32 aArrayLen) :
mLength(aArrayLen), mRefCnt(0)
{
MOZ_COUNT_CTOR(nsCSSShadowArray);
for (PRUint32 i = 1; i < mLength; ++i) {
// Make sure we call the constructors of each nsCSSShadowItem
// (the first one is called for us because we declared it under private)
new (&mArray[i]) nsCSSShadowItem();
}
}
~nsCSSShadowArray() {
MOZ_COUNT_DTOR(nsCSSShadowArray);
for (PRUint32 i = 1; i < mLength; ++i) {
mArray[i].~nsCSSShadowItem();
}
}
nsrefcnt AddRef() { return ++mRefCnt; }
nsrefcnt Release();
PRUint32 Length() const { return mLength; }
nsCSSShadowItem* ShadowAt(PRUint32 i) {
NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
return &mArray[i];
}
const nsCSSShadowItem* ShadowAt(PRUint32 i) const {
NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
return &mArray[i];
}
private:
PRUint32 mLength;
PRUint32 mRefCnt;
nsCSSShadowItem mArray[1]; // This MUST be the last item
};
// Border widths are rounded to the nearest-below integer number of pixels,
// but values between zero and one device pixels are always rounded up to
// one device pixel.
@ -341,6 +418,7 @@ struct nsStyleBorder {
nsStyleSides mBorderRadius; // [reset] length, percent
PRUint8 mFloatEdge; // [reset] see nsStyleConsts.h
nsBorderColors** mBorderColors; // [reset] multiple levels of color for a border.
nsRefPtr<nsCSSShadowArray> mBoxShadow; // [reset] NULL for 'none'
void EnsureBorderColors() {
if (!mBorderColors) {
@ -669,80 +747,6 @@ struct nsStyleTextReset {
nsStyleCoord mVerticalAlign; // [reset] see nsStyleConsts.h for enums
};
struct nsTextShadowItem {
nsStyleCoord mXOffset; // length (coord, chars)
nsStyleCoord mYOffset; // length (coord, chars)
nsStyleCoord mRadius; // length (coord, chars)
nscolor mColor;
PRPackedBool mHasColor; // Whether mColor should be used
nsTextShadowItem() : mHasColor(PR_FALSE) {
MOZ_COUNT_CTOR(nsTextShadowItem);
}
~nsTextShadowItem() {
MOZ_COUNT_DTOR(nsTextShadowItem);
}
PRBool operator==(const nsTextShadowItem& aOther) {
return (mXOffset == aOther.mXOffset &&
mYOffset == aOther.mYOffset &&
mRadius == aOther.mRadius &&
mHasColor == aOther.mHasColor &&
(!mHasColor || mColor == aOther.mColor));
}
PRBool operator!=(const nsTextShadowItem& aOther) {
return !(*this == aOther);
}
};
class nsTextShadowArray {
public:
void* operator new(size_t aBaseSize, PRUint32 aArrayLen) {
// We can allocate both this nsTextShadowArray and the
// actual array in one allocation. The amount of memory to
// allocate is equal to the class's size + the number of bytes for all
// but the first array item (because aBaseSize includes one
// item, see the private declarations)
return ::operator new(aBaseSize +
(aArrayLen - 1) * sizeof(nsTextShadowItem));
}
nsTextShadowArray(PRUint32 aArrayLen) :
mLength(aArrayLen), mRefCnt(0)
{
MOZ_COUNT_CTOR(nsTextShadowArray);
for (PRUint32 i = 1; i < mLength; ++i) {
// Make sure we call the constructors of each nsTextShadowItem
// (the first one is called for us because we declared it under private)
new (&mArray[i]) nsTextShadowItem();
}
}
~nsTextShadowArray() {
MOZ_COUNT_DTOR(nsTextShadowArray);
for (PRUint32 i = 1; i < mLength; ++i) {
mArray[i].~nsTextShadowItem();
}
}
nsrefcnt AddRef() { return ++mRefCnt; }
nsrefcnt Release();
PRUint32 Length() const { return mLength; }
nsTextShadowItem* ShadowAt(PRUint32 i) {
NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
return &mArray[i];
}
const nsTextShadowItem* ShadowAt(PRUint32 i) const {
NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
return &mArray[i];
}
private:
PRUint32 mLength;
PRUint32 mRefCnt;
nsTextShadowItem mArray[1]; // This MUST be the last item
};
struct nsStyleText {
nsStyleText(void);
nsStyleText(const nsStyleText& aOther);
@ -770,7 +774,7 @@ struct nsStyleText {
nsStyleCoord mTextIndent; // [inherited]
nsStyleCoord mWordSpacing; // [inherited]
nsRefPtr<nsTextShadowArray> mShadowArray; // [inherited] NULL in case of a zero-length
nsRefPtr<nsCSSShadowArray> mTextShadow; // [inherited] NULL in case of a zero-length
PRBool WhiteSpaceIsSignificant() const {
return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||

View File

@ -300,6 +300,15 @@ var gCSSProperties = {
other_values: [ "center", "end", "justify" ],
invalid_values: []
},
"-moz-box-shadow": {
domProp: "MozBoxShadow",
inherited: false,
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" ]
},
"-moz-box-sizing": {
domProp: "MozBoxSizing",
inherited: false,