/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsIStyleContext.h" #include "nsStyleConsts.h" #include "nsString.h" #include "nsUnitConversion.h" #include "nsIPresContext.h" #include "nsIStyleRule.h" #include "nsISupportsArray.h" #include "nsCRT.h" #include "nsIFrame.h" //#define DEBUG_REFS static NS_DEFINE_IID(kIStyleContextIID, NS_ISTYLECONTEXT_IID); #define DELETE_ARRAY_IF(array) if (array) { delete[] array; array = nsnull; } // -------------------- // nsStyleFont // nsStyleFont::nsStyleFont(const nsFont& aVariableFont, const nsFont& aFixedFont) : mFont(aVariableFont), mFixedFont(aFixedFont) { } nsStyleFont::~nsStyleFont(void) { } struct StyleFontImpl : public nsStyleFont { StyleFontImpl(const nsFont& aVariableFont, const nsFont& aFixedFont) : nsStyleFont(aVariableFont, aFixedFont) {} void ResetFrom(const nsStyleFont* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleFontImpl& aOther) const; private: // These are not allowed StyleFontImpl(const StyleFontImpl& aOther); StyleFontImpl& operator=(const StyleFontImpl& aOther); }; void StyleFontImpl::ResetFrom(const nsStyleFont* aParent, nsIPresContext* aPresContext) { if (nsnull != aParent) { mFont = aParent->mFont; mFixedFont = aParent->mFixedFont; mFlags = aParent->mFlags; } else { aPresContext->GetDefaultFont(mFont); aPresContext->GetDefaultFixedFont(mFixedFont); mFlags = NS_STYLE_FONT_DEFAULT; } } PRInt32 StyleFontImpl::CalcDifference(const StyleFontImpl& aOther) const { if (mFont.Equals(aOther.mFont) && mFixedFont.Equals(aOther.mFixedFont) && (mFlags == aOther.mFlags)) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_REFLOW; } // -------------------- // nsStyleColor // nsStyleColor::nsStyleColor(void) { } nsStyleColor::~nsStyleColor(void) { } struct StyleColorImpl: public nsStyleColor { StyleColorImpl(void) { } void ResetFrom(const nsStyleColor* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleColorImpl& aOther) const; private: // These are not allowed StyleColorImpl(const StyleColorImpl& aOther); StyleColorImpl& operator=(const StyleColorImpl& aOther); }; void StyleColorImpl::ResetFrom(const nsStyleColor* aParent, nsIPresContext* aPresContext) { if (nsnull != aParent) { mColor = aParent->mColor; mOpacity = aParent->mOpacity; } else { if (nsnull != aPresContext) { aPresContext->GetDefaultColor(&mColor); } else { mColor = NS_RGB(0x00, 0x00, 0x00); } mOpacity = 1.0f; } mBackgroundFlags = NS_STYLE_BG_COLOR_TRANSPARENT | NS_STYLE_BG_IMAGE_NONE; if (nsnull != aPresContext) { aPresContext->GetDefaultBackgroundColor(&mBackgroundColor); aPresContext->GetDefaultBackgroundImageAttachment(&mBackgroundAttachment); aPresContext->GetDefaultBackgroundImageRepeat(&mBackgroundRepeat); aPresContext->GetDefaultBackgroundImageOffset(&mBackgroundXPosition, &mBackgroundYPosition); aPresContext->GetDefaultBackgroundImage(mBackgroundImage); } else { mBackgroundColor = NS_RGB(192,192,192); mBackgroundAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; mBackgroundRepeat = NS_STYLE_BG_REPEAT_XY; mBackgroundXPosition = 0; mBackgroundYPosition = 0; } mCursor = NS_STYLE_CURSOR_AUTO; } PRInt32 StyleColorImpl::CalcDifference(const StyleColorImpl& aOther) const { if ((mColor == aOther.mColor) && (mBackgroundAttachment == aOther.mBackgroundAttachment) && (mBackgroundFlags == aOther.mBackgroundFlags) && (mBackgroundRepeat == aOther.mBackgroundRepeat) && (mBackgroundColor == aOther.mBackgroundColor) && (mBackgroundXPosition == aOther.mBackgroundXPosition) && (mBackgroundYPosition == aOther.mBackgroundYPosition) && (mBackgroundImage == aOther.mBackgroundImage) && (mCursor == aOther.mCursor) && (mCursorImage == aOther.mCursorImage) && (mOpacity == aOther.mOpacity)) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_VISUAL; } // -------------------- // nsStyleSpacing // // XXX this is here to support deprecated calc spacing methods only static nscoord kBorderWidths[3]; static PRBool kWidthsInitialized = PR_FALSE; nsStyleSpacing::nsStyleSpacing(void) { } #define NS_SPACING_MARGIN 0 #define NS_SPACING_PADDING 1 #define NS_SPACING_BORDER 2 static nscoord CalcSideFor(const nsIFrame* aFrame, const nsStyleCoord& aCoord, PRUint8 aSpacing, PRUint8 aSide, const nscoord* aEnumTable, PRInt32 aNumEnums) { nscoord result = 0; switch (aCoord.GetUnit()) { case eStyleUnit_Auto: // Auto margins are handled by layout break; case eStyleUnit_Inherit: nsIFrame* parentFrame; aFrame->GetParent(&parentFrame); // XXX may not be direct parent... if (nsnull != parentFrame) { nsIStyleContext* parentContext; parentFrame->GetStyleContext(&parentContext); if (nsnull != parentContext) { const nsStyleSpacing* parentSpacing = (const nsStyleSpacing*)parentContext->GetStyleData(eStyleStruct_Spacing); nsMargin parentMargin; switch (aSpacing) { case NS_SPACING_MARGIN: parentSpacing->CalcMarginFor(parentFrame, parentMargin); break; case NS_SPACING_PADDING: parentSpacing->CalcPaddingFor(parentFrame, parentMargin); break; case NS_SPACING_BORDER: parentSpacing->CalcBorderFor(parentFrame, parentMargin); break; } switch (aSide) { case NS_SIDE_LEFT: result = parentMargin.left; break; case NS_SIDE_TOP: result = parentMargin.top; break; case NS_SIDE_RIGHT: result = parentMargin.right; break; case NS_SIDE_BOTTOM: result = parentMargin.bottom; break; } NS_RELEASE(parentContext); } } break; case eStyleUnit_Percent: { nscoord baseWidth = 0; PRBool isBase = PR_FALSE; nsIFrame* frame; aFrame->GetParent(&frame); while (nsnull != frame) { frame->IsPercentageBase(isBase); if (isBase) { nsSize size; frame->GetSize(size); baseWidth = size.width; // not really width, need to subtract out padding... break; } frame->GetParent(&frame); } result = (nscoord)((float)baseWidth * aCoord.GetPercentValue()); } break; case eStyleUnit_Coord: result = aCoord.GetCoordValue(); break; case eStyleUnit_Enumerated: if (nsnull != aEnumTable) { PRInt32 value = aCoord.GetIntValue(); if ((0 <= value) && (value < aNumEnums)) { return aEnumTable[aCoord.GetIntValue()]; } } break; case eStyleUnit_Null: case eStyleUnit_Normal: case eStyleUnit_Integer: case eStyleUnit_Proportional: default: result = 0; break; } if ((NS_SPACING_PADDING == aSpacing) || (NS_SPACING_BORDER == aSpacing)) { if (result < 0) { result = 0; } } return result; } static void CalcSidesFor(const nsIFrame* aFrame, const nsStyleSides& aSides, PRUint8 aSpacing, const nscoord* aEnumTable, PRInt32 aNumEnums, nsMargin& aResult) { nsStyleCoord coord; aResult.left = CalcSideFor(aFrame, aSides.GetLeft(coord), aSpacing, NS_SIDE_LEFT, aEnumTable, aNumEnums); aResult.top = CalcSideFor(aFrame, aSides.GetTop(coord), aSpacing, NS_SIDE_TOP, aEnumTable, aNumEnums); aResult.right = CalcSideFor(aFrame, aSides.GetRight(coord), aSpacing, NS_SIDE_RIGHT, aEnumTable, aNumEnums); aResult.bottom = CalcSideFor(aFrame, aSides.GetBottom(coord), aSpacing, NS_SIDE_BOTTOM, aEnumTable, aNumEnums); } void nsStyleSpacing::CalcMarginFor(const nsIFrame* aFrame, nsMargin& aMargin) const { if (mHasCachedMargin) { aMargin = mCachedMargin; } else { CalcSidesFor(aFrame, mMargin, NS_SPACING_MARGIN, nsnull, 0, aMargin); } } void nsStyleSpacing::CalcPaddingFor(const nsIFrame* aFrame, nsMargin& aPadding) const { if (mHasCachedPadding) { aPadding = mCachedPadding; } else { CalcSidesFor(aFrame, mPadding, NS_SPACING_PADDING, nsnull, 0, aPadding); } } void nsStyleSpacing::CalcBorderFor(const nsIFrame* aFrame, nsMargin& aBorder) const { if (mHasCachedBorder) { aBorder = mCachedBorder; } else { CalcSidesFor(aFrame, mBorder, NS_SPACING_BORDER, kBorderWidths, 3, aBorder); } } void nsStyleSpacing::CalcBorderPaddingFor(const nsIFrame* aFrame, nsMargin& aBorderPadding) const { if (mHasCachedPadding && mHasCachedBorder) { aBorderPadding = mCachedBorderPadding; } else { nsMargin border; CalcBorderFor(aFrame, border); CalcPaddingFor(aFrame, aBorderPadding); aBorderPadding += border; } } PRBool nsStyleSpacing::GetMargin(nsMargin& aMargin) const { if (mHasCachedMargin) { aMargin = mCachedMargin; return PR_TRUE; } return PR_FALSE; } PRBool nsStyleSpacing::GetPadding(nsMargin& aPadding) const { if (mHasCachedPadding) { aPadding = mCachedPadding; return PR_TRUE; } return PR_FALSE; } PRBool nsStyleSpacing::GetBorder(nsMargin& aBorder) const { if (mHasCachedBorder) { aBorder = mCachedBorder; return PR_TRUE; } return PR_FALSE; } PRBool nsStyleSpacing::GetBorderPadding(nsMargin& aBorderPadding) const { if (mHasCachedPadding && mHasCachedBorder) { aBorderPadding = mCachedBorderPadding; return PR_TRUE; } return PR_FALSE; } #define BORDER_COLOR_DEFINED 0x80 #define BORDER_COLOR_SPECIAL 0x40 #define BORDER_STYLE_MASK 0x3F PRUint8 nsStyleSpacing::GetBorderStyle(PRUint8 aSide) const { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); return (mBorderStyle[aSide] & BORDER_STYLE_MASK); } void nsStyleSpacing::SetBorderStyle(PRUint8 aSide, PRUint8 aStyle) { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); mBorderStyle[aSide] &= ~BORDER_STYLE_MASK; mBorderStyle[aSide] |= (aStyle & BORDER_STYLE_MASK); } PRBool nsStyleSpacing::GetBorderColor(PRUint8 aSide, nscolor& aColor) const { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); if ((mBorderStyle[aSide] & BORDER_COLOR_SPECIAL) == 0) { aColor = mBorderColor[aSide]; return PR_TRUE; } return PR_FALSE; } void nsStyleSpacing::SetBorderColor(PRUint8 aSide, nscolor aColor) { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); mBorderColor[aSide] = aColor; mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL; mBorderStyle[aSide] |= BORDER_COLOR_DEFINED; } void nsStyleSpacing::SetBorderTransparent(PRUint8 aSide) { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); mBorderStyle[aSide] |= (BORDER_COLOR_DEFINED | BORDER_COLOR_SPECIAL); } void nsStyleSpacing::UnsetBorderColor(PRUint8 aSide) { NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side"); mBorderStyle[aSide] &= BORDER_STYLE_MASK; } PRBool nsStyleSpacing::GetOutlineWidth(nscoord& aWidth) const { if (mHasCachedOutline) { aWidth = mCachedOutlineWidth; return PR_TRUE; } return PR_FALSE; } PRUint8 nsStyleSpacing::GetOutlineStyle(void) const { return (mOutlineStyle & BORDER_STYLE_MASK); } void nsStyleSpacing::SetOutlineStyle(PRUint8 aStyle) { mOutlineStyle &= ~BORDER_STYLE_MASK; mOutlineStyle |= (aStyle & BORDER_STYLE_MASK); } PRBool nsStyleSpacing::GetOutlineColor(nscolor& aColor) const { if ((mOutlineStyle & BORDER_COLOR_SPECIAL) == 0) { aColor = mOutlineColor; return PR_TRUE; } return PR_FALSE; } void nsStyleSpacing::SetOutlineColor(nscolor aColor) { mOutlineColor = aColor; mOutlineStyle &= ~BORDER_COLOR_SPECIAL; mOutlineStyle |= BORDER_COLOR_DEFINED; } void nsStyleSpacing::SetOutlineInvert(void) { mOutlineStyle |= (BORDER_COLOR_DEFINED | BORDER_COLOR_SPECIAL); } struct StyleSpacingImpl: public nsStyleSpacing { StyleSpacingImpl(void) : nsStyleSpacing() {} void ResetFrom(const nsStyleSpacing* aParent, nsIPresContext* aPresContext); void RecalcData(nsIPresContext* aPresContext, nscolor color); PRInt32 CalcDifference(const StyleSpacingImpl& aOther) const; }; void StyleSpacingImpl::ResetFrom(const nsStyleSpacing* aParent, nsIPresContext* aPresContext) { // XXX support kBorderWidhts until deprecated methods are removed if (! kWidthsInitialized) { float pixelsToTwips = 20.0f; if (aPresContext) { aPresContext->GetPixelsToTwips(&pixelsToTwips); } kBorderWidths[NS_STYLE_BORDER_WIDTH_THIN] = NSIntPixelsToTwips(1, pixelsToTwips); kBorderWidths[NS_STYLE_BORDER_WIDTH_MEDIUM] = NSIntPixelsToTwips(3, pixelsToTwips); kBorderWidths[NS_STYLE_BORDER_WIDTH_THICK] = NSIntPixelsToTwips(5, pixelsToTwips); kWidthsInitialized = PR_TRUE; } // spacing values not inherited mMargin.Reset(); mPadding.Reset(); nsStyleCoord medium(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated); mBorder.SetLeft(medium); mBorder.SetTop(medium); mBorder.SetRight(medium); mBorder.SetBottom(medium); mBorderStyle[0] = NS_STYLE_BORDER_STYLE_NONE; mBorderStyle[1] = NS_STYLE_BORDER_STYLE_NONE; mBorderStyle[2] = NS_STYLE_BORDER_STYLE_NONE; mBorderStyle[3] = NS_STYLE_BORDER_STYLE_NONE; mBorderColor[0] = NS_RGB(0, 0, 0); mBorderColor[1] = NS_RGB(0, 0, 0); mBorderColor[2] = NS_RGB(0, 0, 0); mBorderColor[3] = NS_RGB(0, 0, 0); mBorderRadius.SetCoordValue(0); mOutlineWidth = medium; mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE; mOutlineColor = NS_RGB(0, 0, 0); mFloatEdge = NS_STYLE_FLOAT_EDGE_CONTENT; mHasCachedMargin = PR_FALSE; mHasCachedPadding = PR_FALSE; mHasCachedBorder = PR_FALSE; mHasCachedOutline = PR_FALSE; } inline PRBool IsFixedUnit(nsStyleUnit aUnit, PRBool aEnumOK) { return PRBool((aUnit == eStyleUnit_Null) || (aUnit == eStyleUnit_Coord) || (aEnumOK && (aUnit == eStyleUnit_Enumerated))); } static PRBool IsFixedData(const nsStyleSides& aSides, PRBool aEnumOK) { return PRBool(IsFixedUnit(aSides.GetLeftUnit(), aEnumOK) && IsFixedUnit(aSides.GetTopUnit(), aEnumOK) && IsFixedUnit(aSides.GetRightUnit(), aEnumOK) && IsFixedUnit(aSides.GetBottomUnit(), aEnumOK)); } static nscoord CalcCoord(const nsStyleCoord& aCoord, const nscoord* aEnumTable, PRInt32 aNumEnums) { switch (aCoord.GetUnit()) { case eStyleUnit_Null: return 0; case eStyleUnit_Coord: return aCoord.GetCoordValue(); case eStyleUnit_Enumerated: if (nsnull != aEnumTable) { PRInt32 value = aCoord.GetIntValue(); if ((0 <= value) && (value < aNumEnums)) { return aEnumTable[aCoord.GetIntValue()]; } } break; default: NS_ERROR("bad unit type"); break; } return 0; } void StyleSpacingImpl::RecalcData(nsIPresContext* aPresContext, nscolor aColor) { nscoord borderWidths[3]; float pixelsToTwips = 20.0f; if (aPresContext) { aPresContext->GetPixelsToTwips(&pixelsToTwips); } borderWidths[NS_STYLE_BORDER_WIDTH_THIN] = NSIntPixelsToTwips(1, pixelsToTwips); borderWidths[NS_STYLE_BORDER_WIDTH_MEDIUM] = NSIntPixelsToTwips(3, pixelsToTwips); borderWidths[NS_STYLE_BORDER_WIDTH_THICK] = NSIntPixelsToTwips(5, pixelsToTwips); if (IsFixedData(mMargin, PR_FALSE)) { nsStyleCoord coord; mCachedMargin.left = CalcCoord(mMargin.GetLeft(coord), nsnull, 0); mCachedMargin.top = CalcCoord(mMargin.GetTop(coord), nsnull, 0); mCachedMargin.right = CalcCoord(mMargin.GetRight(coord), nsnull, 0); mCachedMargin.bottom = CalcCoord(mMargin.GetBottom(coord), nsnull, 0); mHasCachedMargin = PR_TRUE; } else { mHasCachedMargin = PR_FALSE; } if (IsFixedData(mPadding, PR_FALSE)) { nsStyleCoord coord; mCachedPadding.left = CalcCoord(mPadding.GetLeft(coord), nsnull, 0); mCachedPadding.top = CalcCoord(mPadding.GetTop(coord), nsnull, 0); mCachedPadding.right = CalcCoord(mPadding.GetRight(coord), nsnull, 0); mCachedPadding.bottom = CalcCoord(mPadding.GetBottom(coord), nsnull, 0); mHasCachedPadding = PR_TRUE; } else { mHasCachedPadding = PR_FALSE; } if (((NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_LEFT))|| IsFixedUnit(mBorder.GetLeftUnit(), PR_TRUE)) && ((NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_TOP)) || IsFixedUnit(mBorder.GetTopUnit(), PR_TRUE)) && ((NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_RIGHT)) || IsFixedUnit(mBorder.GetRightUnit(), PR_TRUE)) && ((NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_BOTTOM)) || IsFixedUnit(mBorder.GetBottomUnit(), PR_TRUE))) { nsStyleCoord coord; if (NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_LEFT)) { mCachedBorder.left = 0; } else { mCachedBorder.left = CalcCoord(mBorder.GetLeft(coord), borderWidths, 3); } if (NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_TOP)) { mCachedBorder.top = 0; } else { mCachedBorder.top = CalcCoord(mBorder.GetTop(coord), borderWidths, 3); } if (NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_RIGHT)) { mCachedBorder.right = 0; } else { mCachedBorder.right = CalcCoord(mBorder.GetRight(coord), borderWidths, 3); } if (NS_STYLE_BORDER_STYLE_NONE == GetBorderStyle(NS_SIDE_BOTTOM)) { mCachedBorder.bottom = 0; } else { mCachedBorder.bottom = CalcCoord(mBorder.GetBottom(coord), borderWidths, 3); } mHasCachedBorder = PR_TRUE; } else { mHasCachedBorder = PR_FALSE; } if (mHasCachedBorder && mHasCachedPadding) { mCachedBorderPadding = mCachedPadding; mCachedBorderPadding += mCachedBorder; } if ((mBorderStyle[NS_SIDE_TOP] & BORDER_COLOR_DEFINED) == 0) { mBorderColor[NS_SIDE_TOP] = aColor; } if ((mBorderStyle[NS_SIDE_BOTTOM] & BORDER_COLOR_DEFINED) == 0) { mBorderColor[NS_SIDE_BOTTOM] = aColor; } if ((mBorderStyle[NS_SIDE_LEFT]& BORDER_COLOR_DEFINED) == 0) { mBorderColor[NS_SIDE_LEFT] = aColor; } if ((mBorderStyle[NS_SIDE_RIGHT] & BORDER_COLOR_DEFINED) == 0) { mBorderColor[NS_SIDE_RIGHT] = aColor; } if ((NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) || IsFixedUnit(mOutlineWidth.GetUnit(), PR_TRUE)) { if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) { mCachedOutlineWidth = 0; } else { mCachedOutlineWidth = CalcCoord(mOutlineWidth, borderWidths, 3); } mHasCachedOutline = PR_TRUE; } else { mHasCachedOutline = PR_FALSE; } } PRInt32 StyleSpacingImpl::CalcDifference(const StyleSpacingImpl& aOther) const { if ((mMargin == aOther.mMargin) && (mPadding == aOther.mPadding) && (mBorder == aOther.mBorder) && (mFloatEdge == aOther.mFloatEdge)) { PRInt32 ix; for (ix = 0; ix < 4; ix++) { if ((mBorderStyle[ix] != aOther.mBorderStyle[ix]) || (mBorderColor[ix] != aOther.mBorderColor[ix])) { if ((mBorderStyle[ix] != aOther.mBorderStyle[ix]) && ((NS_STYLE_BORDER_STYLE_NONE == mBorderStyle[ix]) || (NS_STYLE_BORDER_STYLE_NONE == aOther.mBorderStyle[ix]))) { return NS_STYLE_HINT_REFLOW; // border on or off } return NS_STYLE_HINT_VISUAL; } } if ((mOutlineWidth != aOther.mOutlineWidth) || (mOutlineStyle != aOther.mOutlineStyle) || (mOutlineColor != aOther.mOutlineColor) || (mBorderRadius != aOther.mBorderRadius)) { return NS_STYLE_HINT_VISUAL; } return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_REFLOW; } // -------------------- // nsStyleList // nsStyleList::nsStyleList(void) { } nsStyleList::~nsStyleList(void) { } struct StyleListImpl: public nsStyleList { StyleListImpl(void) { } void ResetFrom(const nsStyleList* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleListImpl& aOther) const; }; void StyleListImpl::ResetFrom(const nsStyleList* aParent, nsIPresContext* aPresContext) { if (nsnull != aParent) { mListStyleType = aParent->mListStyleType; mListStyleImage = aParent->mListStyleImage; mListStylePosition = aParent->mListStylePosition; } else { mListStyleType = NS_STYLE_LIST_STYLE_BASIC; mListStylePosition = NS_STYLE_LIST_STYLE_POSITION_OUTSIDE; mListStyleImage.Truncate(); } } PRInt32 StyleListImpl::CalcDifference(const StyleListImpl& aOther) const { if (mListStylePosition == aOther.mListStylePosition) { if (mListStyleImage == aOther.mListStyleImage) { if (mListStyleType == aOther.mListStyleType) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_VISUAL; } return NS_STYLE_HINT_CONTENT; } return NS_STYLE_HINT_REFLOW; } // -------------------- // nsStylePosition // nsStylePosition::nsStylePosition(void) { } struct StylePositionImpl: public nsStylePosition { StylePositionImpl(void) { } void ResetFrom(const nsStylePosition* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StylePositionImpl& aOther) const; private: // These are not allowed StylePositionImpl(const StylePositionImpl& aOther); StylePositionImpl& operator=(const StylePositionImpl& aOther); }; void StylePositionImpl::ResetFrom(const nsStylePosition* aParent, nsIPresContext* aPresContext) { // positioning values not inherited mPosition = NS_STYLE_POSITION_NORMAL; nsStyleCoord autoCoord(eStyleUnit_Auto); mOffset.SetLeft(autoCoord); mOffset.SetTop(autoCoord); mOffset.SetRight(autoCoord); mOffset.SetBottom(autoCoord); mWidth.SetAutoValue(); mMinWidth.SetCoordValue(0); mMaxWidth.Reset(); mHeight.SetAutoValue(); mMinHeight.SetCoordValue(0); mMaxHeight.Reset(); mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT; mZIndex.SetAutoValue(); } PRInt32 StylePositionImpl::CalcDifference(const StylePositionImpl& aOther) const { if (mPosition == aOther.mPosition) { if ((mOffset == aOther.mOffset) && (mWidth == aOther.mWidth) && (mMinWidth == aOther.mMinWidth) && (mMaxWidth == aOther.mMaxWidth) && (mHeight == aOther.mHeight) && (mMinHeight == aOther.mMinHeight) && (mMaxHeight == aOther.mMaxHeight) && (mBoxSizing == aOther.mBoxSizing) && (mZIndex == aOther.mZIndex)) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_REFLOW; } return NS_STYLE_HINT_FRAMECHANGE; } // -------------------- // nsStyleText // nsStyleText::nsStyleText(void) { } struct StyleTextImpl: public nsStyleText { StyleTextImpl(void) { } void ResetFrom(const nsStyleText* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleTextImpl& aOther) const; }; void StyleTextImpl::ResetFrom(const nsStyleText* aParent, nsIPresContext* aPresContext) { // These properties not inherited mTextDecoration = NS_STYLE_TEXT_DECORATION_NONE; mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated); // mVerticalAlign.Reset(); TBI if (nsnull != aParent) { mTextAlign = aParent->mTextAlign; mTextTransform = aParent->mTextTransform; mWhiteSpace = aParent->mWhiteSpace; mLetterSpacing = aParent->mLetterSpacing; mLineHeight.SetInheritValue(); mTextIndent = aParent->mTextIndent; mWordSpacing = aParent->mWordSpacing; } else { mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT; mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE; mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL; mLetterSpacing.SetNormalValue(); mLineHeight.SetNormalValue(); mTextIndent.SetCoordValue(0); mWordSpacing.SetNormalValue(); } } PRInt32 StyleTextImpl::CalcDifference(const StyleTextImpl& aOther) const { if ((mTextAlign == aOther.mTextAlign) && (mTextTransform == aOther.mTextTransform) && (mWhiteSpace == aOther.mWhiteSpace) && (mLetterSpacing == aOther.mLetterSpacing) && (mLineHeight == aOther.mLineHeight) && (mTextIndent == aOther.mTextIndent) && (mWordSpacing == aOther.mWordSpacing) && (mVerticalAlign == aOther.mVerticalAlign)) { if (mTextDecoration == aOther.mTextDecoration) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_VISUAL; } return NS_STYLE_HINT_REFLOW; } // -------------------- // nsStyleDisplay // nsStyleDisplay::nsStyleDisplay(void) { } struct StyleDisplayImpl: public nsStyleDisplay { StyleDisplayImpl(void) { } void ResetFrom(const nsStyleDisplay* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleDisplayImpl& aOther) const; }; void StyleDisplayImpl::ResetFrom(const nsStyleDisplay* aParent, nsIPresContext* aPresContext) { if (nsnull != aParent) { mDirection = aParent->mDirection; mVisible = aParent->mVisible; } else { mDirection = NS_STYLE_DIRECTION_LTR; mVisible = NS_STYLE_VISIBILITY_VISIBLE; } mDisplay = NS_STYLE_DISPLAY_INLINE; mFloats = NS_STYLE_FLOAT_NONE; mBreakType = NS_STYLE_CLEAR_NONE; mBreakBefore = PR_FALSE; mBreakAfter = PR_FALSE; mOverflow = NS_STYLE_OVERFLOW_VISIBLE; mClipFlags = NS_STYLE_CLIP_AUTO; mClip.SizeTo(0,0,0,0); } PRInt32 StyleDisplayImpl::CalcDifference(const StyleDisplayImpl& aOther) const { if ((mDisplay == aOther.mDisplay) && (mFloats == aOther.mFloats) && (mOverflow == aOther.mOverflow)) { if ((mDirection == aOther.mDirection) && (mBreakType == aOther.mBreakType) && (mBreakBefore == aOther.mBreakBefore) && (mBreakAfter == aOther.mBreakAfter)) { if ((mVisible == aOther.mVisible) && (mClipFlags == aOther.mClipFlags) && (mClip == aOther.mClip)) { return NS_STYLE_HINT_NONE; } if ((mVisible != aOther.mVisible) && ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) || (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible))) { return NS_STYLE_HINT_REFLOW; } return NS_STYLE_HINT_VISUAL; } return NS_STYLE_HINT_REFLOW; } return NS_STYLE_HINT_FRAMECHANGE; } // -------------------- // nsStyleTable // nsStyleTable::nsStyleTable(void) { } struct StyleTableImpl: public nsStyleTable { StyleTableImpl(void); void ResetFrom(const nsStyleTable* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleTableImpl& aOther) const; }; StyleTableImpl::StyleTableImpl() { ResetFrom(nsnull, nsnull); } void StyleTableImpl::ResetFrom(const nsStyleTable* aParent, nsIPresContext* aPresContext) { // values not inherited mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO; mCols = NS_STYLE_TABLE_COLS_NONE; mFrame = NS_STYLE_TABLE_FRAME_NONE; mRules = NS_STYLE_TABLE_RULES_NONE; mCellPadding.Reset(); mSpan = 1; if (aParent) { // handle inherited properties mBorderCollapse = aParent->mBorderCollapse; mEmptyCells = aParent->mEmptyCells; mCaptionSide = aParent->mCaptionSide; mBorderSpacingX = aParent->mBorderSpacingX; mBorderSpacingY = aParent->mBorderSpacingY; mSpanWidth = aParent->mSpanWidth; } else { mBorderCollapse = NS_STYLE_BORDER_COLLAPSE; mEmptyCells = NS_STYLE_TABLE_EMPTY_CELLS_HIDE; mCaptionSide = NS_SIDE_TOP; mBorderSpacingX.Reset(); mBorderSpacingY.Reset(); mSpanWidth.Reset(); } } PRInt32 StyleTableImpl::CalcDifference(const StyleTableImpl& aOther) const { if ((mLayoutStrategy == aOther.mLayoutStrategy) && (mFrame == aOther.mFrame) && (mRules == aOther.mRules) && (mBorderCollapse == aOther.mBorderCollapse) && (mBorderSpacingX == aOther.mBorderSpacingX) && (mBorderSpacingY == aOther.mBorderSpacingY) && (mCellPadding == aOther.mCellPadding) && (mCaptionSide == aOther.mCaptionSide) && (mCols == aOther.mCols) && (mSpan == aOther.mSpan) && (mSpanWidth == aOther.mSpanWidth)) { if (mEmptyCells == aOther.mEmptyCells) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_VISUAL; } return NS_STYLE_HINT_REFLOW; } //----------------------- // nsStyleContent // nsStyleContent::nsStyleContent(void) : mMarkerOffset(), mContentCount(0), mContents(nsnull), mIncrementCount(0), mIncrements(nsnull), mResetCount(0), mResets(nsnull), mQuotesCount(0), mQuotes(nsnull) { } nsStyleContent::~nsStyleContent(void) { DELETE_ARRAY_IF(mContents); DELETE_ARRAY_IF(mIncrements); DELETE_ARRAY_IF(mResets); DELETE_ARRAY_IF(mQuotes); } nsresult nsStyleContent::GetContentAt(PRUint32 aIndex, nsStyleContentType& aType, nsString& aContent) const { if (aIndex < mContentCount) { aType = mContents[aIndex].mType; aContent = mContents[aIndex].mContent; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::AllocateContents(PRUint32 aCount) { if (aCount != mContentCount) { DELETE_ARRAY_IF(mContents); if (aCount) { mContents = new nsStyleContentData[aCount]; if (! mContents) { mContentCount = 0; return NS_ERROR_OUT_OF_MEMORY; } } mContentCount = aCount; } return NS_OK; } nsresult nsStyleContent::SetContentAt(PRUint32 aIndex, nsStyleContentType aType, const nsString& aContent) { if (aIndex < mContentCount) { mContents[aIndex].mType = aType; if (aType < eStyleContentType_OpenQuote) { mContents[aIndex].mContent = aContent; } else { mContents[aIndex].mContent.Truncate(); } return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::GetCounterIncrementAt(PRUint32 aIndex, nsString& aCounter, PRInt32& aIncrement) const { if (aIndex < mIncrementCount) { aCounter = mIncrements[aIndex].mCounter; aIncrement = mIncrements[aIndex].mValue; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::AllocateCounterIncrements(PRUint32 aCount) { if (aCount != mIncrementCount) { DELETE_ARRAY_IF(mIncrements); if (aCount) { mIncrements = new nsStyleCounterData[aCount]; if (! mIncrements) { mIncrementCount = 0; return NS_ERROR_OUT_OF_MEMORY; } } mIncrementCount = aCount; } return NS_OK; } nsresult nsStyleContent::SetCounterIncrementAt(PRUint32 aIndex, const nsString& aCounter, PRInt32 aIncrement) { if (aIndex < mIncrementCount) { mIncrements[aIndex].mCounter = aCounter; mIncrements[aIndex].mValue = aIncrement; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::GetCounterResetAt(PRUint32 aIndex, nsString& aCounter, PRInt32& aValue) const { if (aIndex < mResetCount) { aCounter = mResets[aIndex].mCounter; aValue = mResets[aIndex].mValue; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::AllocateCounterResets(PRUint32 aCount) { if (aCount != mResetCount) { DELETE_ARRAY_IF(mResets); if (aCount) { mResets = new nsStyleCounterData[aCount]; if (! mResets) { mResetCount = 0; return NS_ERROR_OUT_OF_MEMORY; } } mResetCount = aCount; } return NS_OK; } nsresult nsStyleContent::SetCounterResetAt(PRUint32 aIndex, const nsString& aCounter, PRInt32 aValue) { if (aIndex < mResetCount) { mResets[aIndex].mCounter = aCounter; mResets[aIndex].mValue = aValue; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::GetQuotesAt(PRUint32 aIndex, nsString& aOpen, nsString& aClose) const { if (aIndex < mQuotesCount) { aIndex *= 2; aOpen = mQuotes[aIndex]; aClose = mQuotes[++aIndex]; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } nsresult nsStyleContent::AllocateQuotes(PRUint32 aCount) { if (aCount != mQuotesCount) { DELETE_ARRAY_IF(mQuotes); if (aCount) { mQuotes = new nsString[aCount * 2]; if (! mQuotes) { mQuotesCount = 0; return NS_ERROR_OUT_OF_MEMORY; } } mQuotesCount = aCount; } return NS_OK; } nsresult nsStyleContent::SetQuotesAt(PRUint32 aIndex, const nsString& aOpen, const nsString& aClose) { if (aIndex < mQuotesCount) { aIndex *= 2; mQuotes[aIndex] = aOpen; mQuotes[++aIndex] = aClose; return NS_OK; } return NS_ERROR_ILLEGAL_VALUE; } struct StyleContentImpl: public nsStyleContent { StyleContentImpl(void) : nsStyleContent() { }; void ResetFrom(const StyleContentImpl* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleContentImpl& aOther) const; }; void StyleContentImpl::ResetFrom(const StyleContentImpl* aParent, nsIPresContext* aPresContext) { // reset data mMarkerOffset.Reset(); mContentCount = 0; DELETE_ARRAY_IF(mContents); mIncrementCount = 0; DELETE_ARRAY_IF(mIncrements); mResetCount = 0; DELETE_ARRAY_IF(mResets); // inherited data if (aParent) { if (NS_SUCCEEDED(AllocateQuotes(aParent->mQuotesCount))) { PRUint32 ix = (mQuotesCount * 2); while (0 < ix--) { mQuotes[ix] = aParent->mQuotes[ix]; } } } else { mQuotesCount = 0; DELETE_ARRAY_IF(mQuotes); } } PRInt32 StyleContentImpl::CalcDifference(const StyleContentImpl& aOther) const { if (mContentCount == aOther.mContentCount) { if ((mMarkerOffset == aOther.mMarkerOffset) && (mIncrementCount == aOther.mIncrementCount) && (mResetCount == aOther.mResetCount) && (mQuotesCount == aOther.mQuotesCount)) { PRUint32 ix = mContentCount; while (0 < ix--) { if ((mContents[ix].mType != aOther.mContents[ix].mType) || (mContents[ix].mContent != aOther.mContents[ix].mContent)) { return NS_STYLE_HINT_REFLOW; } } ix = mIncrementCount; while (0 < ix--) { if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) || (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) { return NS_STYLE_HINT_REFLOW; } } ix = mResetCount; while (0 < ix--) { if ((mResets[ix].mValue != aOther.mResets[ix].mValue) || (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) { return NS_STYLE_HINT_REFLOW; } } ix = (mQuotesCount * 2); while (0 < ix--) { if (mQuotes[ix] != aOther.mQuotes[ix]) { return NS_STYLE_HINT_REFLOW; } } return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_REFLOW; } return NS_STYLE_HINT_FRAMECHANGE; } //----------------------- // nsStyleUserInterface // nsStyleUserInterface::nsStyleUserInterface(void) { } struct StyleUserInterfaceImpl: public nsStyleUserInterface { StyleUserInterfaceImpl(void) { } void ResetFrom(const nsStyleUserInterface* aParent, nsIPresContext* aPresContext); PRInt32 CalcDifference(const StyleUserInterfaceImpl& aOther) const; private: // These are not allowed StyleUserInterfaceImpl(const StyleUserInterfaceImpl& aOther); StyleUserInterfaceImpl& operator=(const StyleUserInterfaceImpl& aOther); }; void StyleUserInterfaceImpl::ResetFrom(const nsStyleUserInterface* aParent, nsIPresContext* aPresContext) { if (aParent) { mUserInput = aParent->mUserInput; mModifyContent = aParent->mModifyContent; mAutoSelect = aParent->mAutoSelect; mAutoTab = aParent->mAutoTab; } else { mUserInput = NS_STYLE_USER_INPUT_AUTO; mModifyContent = NS_STYLE_MODIFY_CONTENT_READ_ONLY; mAutoSelect = NS_STYLE_AUTO_SELECT_NONE; mAutoTab = NS_STYLE_AUTO_TAB_AUTO; } mSelectionStyle = NS_STYLE_SELECTION_STYLE_ANY; mKeyEquivalent = PRUnichar(0); // XXX what type should this be? mResizer = NS_STYLE_RESIZER_AUTO; } PRInt32 StyleUserInterfaceImpl::CalcDifference(const StyleUserInterfaceImpl& aOther) const { if ((mUserInput == aOther.mUserInput) && (mResizer == aOther.mResizer)) { if ((mModifyContent == aOther.mModifyContent) && (mSelectionStyle == aOther.mSelectionStyle)) { if ((mAutoSelect == aOther.mAutoSelect) && (mKeyEquivalent == aOther.mKeyEquivalent) && (mAutoTab == aOther.mAutoTab) && (mResizer == aOther.mResizer)) { return NS_STYLE_HINT_NONE; } return NS_STYLE_HINT_CONTENT; } return NS_STYLE_HINT_VISUAL; } if ((mUserInput != aOther.mUserInput) && ((NS_STYLE_USER_INPUT_NONE == mUserInput) || (NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) { return NS_STYLE_HINT_FRAMECHANGE; } return NS_STYLE_HINT_VISUAL; } //---------------------------------------------------------------------- class StyleContextImpl : public nsIStyleContext { public: StyleContextImpl(nsIStyleContext* aParent, nsIAtom* aPseudoTag, nsISupportsArray* aRules, nsIPresContext* aPresContext); virtual ~StyleContextImpl(); NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW NS_DECL_ISUPPORTS virtual nsIStyleContext* GetParent(void) const; virtual nsISupportsArray* GetStyleRules(void) const; virtual PRInt32 GetStyleRuleCount(void) const; NS_IMETHOD GetPseudoType(nsIAtom*& aPseudoTag) const; NS_IMETHOD FindChildWithRules(const nsIAtom* aPseudoTag, nsISupportsArray* aRules, nsIStyleContext*& aResult); virtual PRBool Equals(const nsIStyleContext* aOther) const; virtual PRUint32 HashValue(void) const; NS_IMETHOD RemapStyle(nsIPresContext* aPresContext); virtual const nsStyleStruct* GetStyleData(nsStyleStructID aSID); virtual nsStyleStruct* GetMutableStyleData(nsStyleStructID aSID); virtual void ForceUnique(void); virtual void RecalcAutomaticData(nsIPresContext* aPresContext); NS_IMETHOD CalcStyleDifference(nsIStyleContext* aOther, PRInt32& aHint) const; virtual void List(FILE* out, PRInt32 aIndent); protected: void AppendChild(StyleContextImpl* aChild); void RemoveChild(StyleContextImpl* aChild); StyleContextImpl* mParent; StyleContextImpl* mChild; StyleContextImpl* mEmptyChild; StyleContextImpl* mPrevSibling; StyleContextImpl* mNextSibling; nsIAtom* mPseudoTag; PRUint32 mRuleHash; nsISupportsArray* mRules; PRInt32 mDataCode; // the style data... StyleFontImpl mFont; StyleColorImpl mColor; StyleSpacingImpl mSpacing; StyleListImpl mList; StylePositionImpl mPosition; StyleTextImpl mText; StyleDisplayImpl mDisplay; StyleTableImpl mTable; StyleContentImpl mContent; StyleUserInterfaceImpl mUserInterface; #ifdef DEBUG_REFS PRInt32 mInstance; #endif }; static PRInt32 gLastDataCode; #ifdef DEBUG_REFS static PRInt32 gInstanceCount; static PRInt32 gInstrument = 6; #endif static PRBool HashStyleRule(nsISupports* aRule, void* aData) { *((PRUint32*)aData) ^= PRUint32(aRule); return PR_TRUE; } StyleContextImpl::StyleContextImpl(nsIStyleContext* aParent, nsIAtom* aPseudoTag, nsISupportsArray* aRules, nsIPresContext* aPresContext) : mParent((StyleContextImpl*)aParent), mChild(nsnull), mEmptyChild(nsnull), mPseudoTag(aPseudoTag), mRules(aRules), mDataCode(-1), mFont(aPresContext->GetDefaultFontDeprecated(), aPresContext->GetDefaultFixedFontDeprecated()), mColor(), mSpacing(), mList(), mPosition(), mText(), mDisplay(), mTable(), mContent(), mUserInterface() { NS_INIT_REFCNT(); NS_IF_ADDREF(mPseudoTag); NS_IF_ADDREF(mRules); mNextSibling = this; mPrevSibling = this; if (nsnull != mParent) { NS_ADDREF(mParent); mParent->AppendChild(this); } mRuleHash = 0; if (nsnull != mRules) { mRules->EnumerateForwards(HashStyleRule, &mRuleHash); } RemapStyle(aPresContext); #ifdef DEBUG_REFS mInstance = ++gInstanceCount; fprintf(stdout, "%d of %d + StyleContext\n", mInstance, gInstanceCount); #endif } StyleContextImpl::~StyleContextImpl() { NS_ASSERTION((nsnull == mChild) && (nsnull == mEmptyChild), "destructing context with children"); if (mParent) { mParent->RemoveChild(this); NS_RELEASE(mParent); } NS_IF_RELEASE(mPseudoTag); NS_IF_RELEASE(mRules); #ifdef DEBUG_REFS fprintf(stdout, "%d of %d - StyleContext\n", mInstance, gInstanceCount); --gInstanceCount; #endif } #ifdef LOG_ADDREF_RELEASE extern "C" { void __log_addref(void* p, int oldrc, int newrc); void __log_release(void* p, int oldrc, int newrc); } NS_IMPL_QUERY_INTERFACE(StyleContextImpl, kIStyleContextIID) nsrefcnt StyleContextImpl::AddRef(void) { NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); __log_addref((void*) this, mRefCnt, mRefCnt + 1); return ++mRefCnt; } nsrefcnt StyleContextImpl::Release(void) { __log_release((void*) this, mRefCnt, mRefCnt - 1); NS_PRECONDITION(0 != mRefCnt, "dup release"); if (--mRefCnt == 0) { NS_DELETEXPCOM(this); return 0; } return mRefCnt; } #else #ifdef DEBUG_REFS NS_IMPL_QUERY_INTERFACE(StyleContextImpl, kIStyleContextIID) nsrefcnt StyleContextImpl::AddRef(void) { if ((gInstrument == -1) || (mInstance == gInstrument)) { fprintf(stdout, "%d AddRef StyleContext %d\n", mRefCnt + 1, mInstance); } return ++mRefCnt; } nsrefcnt StyleContextImpl::Release(void) { if ((gInstrument == -1) || (mInstance == gInstrument)) { fprintf(stdout, "%d Release StyleContext %d\n", mRefCnt - 1, mInstance); } if (--mRefCnt == 0) { delete this; return 0; } return mRefCnt; } #else NS_IMPL_ISUPPORTS(StyleContextImpl, kIStyleContextIID) #endif #endif nsIStyleContext* StyleContextImpl::GetParent(void) const { NS_IF_ADDREF(mParent); return mParent; } void StyleContextImpl::AppendChild(StyleContextImpl* aChild) { if (0 == aChild->GetStyleRuleCount()) { if (nsnull == mEmptyChild) { mEmptyChild = aChild; } else { aChild->mNextSibling = mEmptyChild; aChild->mPrevSibling = mEmptyChild->mPrevSibling; mEmptyChild->mPrevSibling->mNextSibling = aChild; mEmptyChild->mPrevSibling = aChild; } } else { if (nsnull == mChild) { mChild = aChild; } else { aChild->mNextSibling = mChild; aChild->mPrevSibling = mChild->mPrevSibling; mChild->mPrevSibling->mNextSibling = aChild; mChild->mPrevSibling = aChild; } } } void StyleContextImpl::RemoveChild(StyleContextImpl* aChild) { NS_ASSERTION((nsnull != aChild) && (this == aChild->mParent), "bad argument"); if ((nsnull == aChild) || (this != aChild->mParent)) { return; } if (0 == aChild->GetStyleRuleCount()) { // is empty if (aChild->mPrevSibling != aChild) { // has siblings if (mEmptyChild == aChild) { mEmptyChild = mEmptyChild->mNextSibling; } } else { NS_ASSERTION(mEmptyChild == aChild, "bad sibling pointers"); mEmptyChild = nsnull; } } else { // isn't empty if (aChild->mPrevSibling != aChild) { // has siblings if (mChild == aChild) { mChild = mChild->mNextSibling; } } else { NS_ASSERTION(mChild == aChild, "bad sibling pointers"); if (mChild == aChild) { mChild = nsnull; } } } aChild->mPrevSibling->mNextSibling = aChild->mNextSibling; aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling; aChild->mNextSibling = aChild; aChild->mPrevSibling = aChild; } nsISupportsArray* StyleContextImpl::GetStyleRules(void) const { NS_IF_ADDREF(mRules); return mRules; } PRInt32 StyleContextImpl::GetStyleRuleCount(void) const { if (nsnull != mRules) { PRUint32 cnt; nsresult rv = mRules->Count(&cnt); if (NS_FAILED(rv)) return 0; // XXX error? return cnt; } return 0; } NS_IMETHODIMP StyleContextImpl::GetPseudoType(nsIAtom*& aPseudoTag) const { aPseudoTag = mPseudoTag; NS_IF_ADDREF(aPseudoTag); return NS_OK; } NS_IMETHODIMP StyleContextImpl::FindChildWithRules(const nsIAtom* aPseudoTag, nsISupportsArray* aRules, nsIStyleContext*& aResult) { aResult = nsnull; if ((nsnull != mChild) || (nsnull != mEmptyChild)) { StyleContextImpl* child; PRInt32 ruleCount; if (aRules) { PRUint32 cnt; nsresult rv = aRules->Count(&cnt); if (NS_FAILED(rv)) return rv; ruleCount = cnt; } else ruleCount = 0; if (0 == ruleCount) { if (nsnull != mEmptyChild) { child = mEmptyChild; do { if ((0 == child->mDataCode) && // only look at children with un-twiddled data (aPseudoTag == child->mPseudoTag)) { aResult = child; break; } child = child->mNextSibling; } while (child != mEmptyChild); } } else if (nsnull != mChild) { PRUint32 hash = 0; aRules->EnumerateForwards(HashStyleRule, &hash); child = mChild; do { PRUint32 cnt; if ((0 == child->mDataCode) && // only look at children with un-twiddled data (child->mRuleHash == hash) && (child->mPseudoTag == aPseudoTag) && (nsnull != child->mRules) && NS_SUCCEEDED(child->mRules->Count(&cnt)) && (PRInt32)cnt == ruleCount) { if (child->mRules->Equals(aRules)) { aResult = child; break; } } child = child->mNextSibling; } while (child != mChild); } } NS_IF_ADDREF(aResult); return NS_OK; } PRBool StyleContextImpl::Equals(const nsIStyleContext* aOther) const { PRBool result = PR_TRUE; const StyleContextImpl* other = (StyleContextImpl*)aOther; if (other != this) { if (mParent != other->mParent) { result = PR_FALSE; } else if (mDataCode != other->mDataCode) { result = PR_FALSE; } else if (mPseudoTag != other->mPseudoTag) { result = PR_FALSE; } else { if ((nsnull != mRules) && (nsnull != other->mRules)) { if (mRuleHash == other->mRuleHash) { result = mRules->Equals(other->mRules); } else { result = PR_FALSE; } } else { result = PRBool((nsnull == mRules) && (nsnull == other->mRules)); } } } return result; } PRUint32 StyleContextImpl::HashValue(void) const { return mRuleHash; } const nsStyleStruct* StyleContextImpl::GetStyleData(nsStyleStructID aSID) { nsStyleStruct* result = nsnull; switch (aSID) { case eStyleStruct_Font: result = &mFont; break; case eStyleStruct_Color: result = &mColor; break; case eStyleStruct_Spacing: result = &mSpacing; break; case eStyleStruct_List: result = &mList; break; case eStyleStruct_Position: result = &mPosition; break; case eStyleStruct_Text: result = &mText; break; case eStyleStruct_Display: result = &mDisplay; break; case eStyleStruct_Table: result = &mTable; break; case eStyleStruct_Content: result = &mContent; break; case eStyleStruct_UserInterface: result = &mUserInterface; break; default: NS_ERROR("Invalid style struct id"); break; } return result; } nsStyleStruct* StyleContextImpl::GetMutableStyleData(nsStyleStructID aSID) { nsStyleStruct* result = nsnull; switch (aSID) { case eStyleStruct_Font: result = &mFont; break; case eStyleStruct_Color: result = &mColor; break; case eStyleStruct_Spacing: result = &mSpacing; break; case eStyleStruct_List: result = &mList; break; case eStyleStruct_Position: result = &mPosition; break; case eStyleStruct_Text: result = &mText; break; case eStyleStruct_Display: result = &mDisplay; break; case eStyleStruct_Table: result = &mTable; break; case eStyleStruct_Content: result = &mContent; break; case eStyleStruct_UserInterface: result = &mUserInterface; break; default: NS_ERROR("Invalid style struct id"); break; } if (nsnull != result) { if (0 == mDataCode) { // mDataCode = ++gLastDataCode; // XXX temp disable, this is still used but not needed to force unique } } return result; } struct MapStyleData { MapStyleData(nsIStyleContext* aStyleContext, nsIPresContext* aPresContext) { mStyleContext = aStyleContext; mPresContext = aPresContext; } nsIStyleContext* mStyleContext; nsIPresContext* mPresContext; }; static PRBool MapStyleRuleFont(nsISupports* aRule, void* aData) { nsIStyleRule* rule = (nsIStyleRule*)aRule; MapStyleData* data = (MapStyleData*)aData; rule->MapFontStyleInto(data->mStyleContext, data->mPresContext); return PR_TRUE; } static PRBool MapStyleRule(nsISupports* aRule, void* aData) { nsIStyleRule* rule = (nsIStyleRule*)aRule; MapStyleData* data = (MapStyleData*)aData; rule->MapStyleInto(data->mStyleContext, data->mPresContext); return PR_TRUE; } NS_IMETHODIMP StyleContextImpl::RemapStyle(nsIPresContext* aPresContext) { mDataCode = -1; if (nsnull != mParent) { mFont.ResetFrom(&(mParent->mFont), aPresContext); mColor.ResetFrom(&(mParent->mColor), aPresContext); mSpacing.ResetFrom(&(mParent->mSpacing), aPresContext); mList.ResetFrom(&(mParent->mList), aPresContext); mPosition.ResetFrom(&(mParent->mPosition), aPresContext); mText.ResetFrom(&(mParent->mText), aPresContext); mDisplay.ResetFrom(&(mParent->mDisplay), aPresContext); mTable.ResetFrom(&(mParent->mTable), aPresContext); mContent.ResetFrom(&(mParent->mContent), aPresContext); mUserInterface.ResetFrom(&(mParent->mUserInterface), aPresContext); } else { mFont.ResetFrom(nsnull, aPresContext); mColor.ResetFrom(nsnull, aPresContext); mSpacing.ResetFrom(nsnull, aPresContext); mList.ResetFrom(nsnull, aPresContext); mPosition.ResetFrom(nsnull, aPresContext); mText.ResetFrom(nsnull, aPresContext); mDisplay.ResetFrom(nsnull, aPresContext); mTable.ResetFrom(nsnull, aPresContext); mContent.ResetFrom(nsnull, aPresContext); mUserInterface.ResetFrom(nsnull, aPresContext); } PRUint32 cnt = 0; if (mRules) { nsresult rv = mRules->Count(&cnt); NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed"); } if (0 < cnt) { MapStyleData data(this, aPresContext); mRules->EnumerateForwards(MapStyleRuleFont, &data); if (mFont.mFlags & NS_STYLE_FONT_USE_FIXED) { mFont.mFont = mFont.mFixedFont; } mRules->EnumerateForwards(MapStyleRule, &data); } if (-1 == mDataCode) { mDataCode = 0; } nsCompatibility quirkMode = eCompatibility_Standard; aPresContext->GetCompatibilityMode(&quirkMode); if (eCompatibility_NavQuirks == quirkMode) { if ((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) { StyleContextImpl* holdParent = mParent; mParent = nsnull; // cut off all inheritance. this really blows // XXX the style we do preserve is visibility, direction PRUint8 visible = mDisplay.mVisible; PRUint8 direction = mDisplay.mDirection; // time to emulate a sub-document // This is ugly, but we need to map style once to determine display type // then reset and map it again so that all local style is preserved if (mDisplay.mDisplay != NS_STYLE_DISPLAY_TABLE) { mFont.ResetFrom(nsnull, aPresContext); } mColor.ResetFrom(nsnull, aPresContext); mSpacing.ResetFrom(nsnull, aPresContext); mList.ResetFrom(nsnull, aPresContext); mText.ResetFrom(nsnull, aPresContext); mPosition.ResetFrom(nsnull, aPresContext); mDisplay.ResetFrom(nsnull, aPresContext); mTable.ResetFrom(nsnull, aPresContext); mContent.ResetFrom(nsnull, aPresContext); mUserInterface.ResetFrom(nsnull, aPresContext); mDisplay.mVisible = visible; mDisplay.mDirection = direction; PRUint32 numRules = 0; if (mRules) { nsresult rv = mRules->Count(&numRules); NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed"); } if (0 < numRules) { MapStyleData data(this, aPresContext); mRules->EnumerateForwards(MapStyleRuleFont, &data); if (mFont.mFlags & NS_STYLE_FONT_USE_FIXED) { mFont.mFont = mFont.mFixedFont; } mRules->EnumerateForwards(MapStyleRule, &data); } // reset all font data for tables again if (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) { mFont.ResetFrom(nsnull, aPresContext); } mParent = holdParent; } } RecalcAutomaticData(aPresContext); if (nsnull != mChild) { StyleContextImpl* child = mChild; do { child->RemapStyle(aPresContext); child = child->mNextSibling; } while (mChild != child); } if (nsnull != mEmptyChild) { StyleContextImpl* child = mEmptyChild; do { child->RemapStyle(aPresContext); child = child->mNextSibling; } while (mEmptyChild != child); } return NS_OK; } void StyleContextImpl::ForceUnique(void) { if (mDataCode <= 0) { mDataCode = ++gLastDataCode; } } void StyleContextImpl::RecalcAutomaticData(nsIPresContext* aPresContext) { mSpacing.RecalcData(aPresContext, mColor.mColor); } NS_IMETHODIMP StyleContextImpl::CalcStyleDifference(nsIStyleContext* aOther, PRInt32& aHint) const { if (aOther) { PRInt32 hint; const StyleContextImpl* other = (const StyleContextImpl*)aOther; aHint = mFont.CalcDifference(other->mFont); if (aHint < NS_STYLE_HINT_MAX) { hint = mColor.CalcDifference(other->mColor); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mSpacing.CalcDifference(other->mSpacing); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mList.CalcDifference(other->mList); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mPosition.CalcDifference(other->mPosition); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mText.CalcDifference(other->mText); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mDisplay.CalcDifference(other->mDisplay); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mTable.CalcDifference(other->mTable); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mContent.CalcDifference(other->mContent); if (aHint < hint) { aHint = hint; } } if (aHint < NS_STYLE_HINT_MAX) { hint = mUserInterface.CalcDifference(other->mUserInterface); if (aHint < hint) { aHint = hint; } } } return NS_OK; } void StyleContextImpl::List(FILE* out, PRInt32 aIndent) { // Indent PRInt32 ix; for (ix = aIndent; --ix >= 0; ) fputs(" ", out); fprintf(out, "%p(%d) ", this, mRefCnt); if (nsnull != mPseudoTag) { nsAutoString buffer; mPseudoTag->ToString(buffer); fputs(buffer, out); fputs(" ", out); } PRInt32 count = GetStyleRuleCount(); if (0 < count) { fputs("{\n", out); for (ix = 0; ix < count; ix++) { nsIStyleRule* rule = (nsIStyleRule*)mRules->ElementAt(ix); rule->List(out, aIndent + 1); NS_RELEASE(rule); } for (ix = aIndent; --ix >= 0; ) fputs(" ", out); fputs("}\n", out); } else { fputs("{}\n", out); } if (nsnull != mChild) { StyleContextImpl* child = mChild; do { child->List(out, aIndent + 1); child = child->mNextSibling; } while (mChild != child); } if (nsnull != mEmptyChild) { StyleContextImpl* child = mEmptyChild; do { child->List(out, aIndent + 1); child = child->mNextSibling; } while (mEmptyChild != child); } } NS_LAYOUT nsresult NS_NewStyleContext(nsIStyleContext** aInstancePtrResult, nsIStyleContext* aParentContext, nsIAtom* aPseudoTag, nsISupportsArray* aRules, nsIPresContext* aPresContext) { NS_PRECONDITION(nsnull != aInstancePtrResult, "null ptr"); if (nsnull == aInstancePtrResult) { return NS_ERROR_NULL_POINTER; } StyleContextImpl* context = new StyleContextImpl(aParentContext, aPseudoTag, aRules, aPresContext); if (nsnull == context) { return NS_ERROR_OUT_OF_MEMORY; } return context->QueryInterface(kIStyleContextIID, (void **) aInstancePtrResult); }