Significantly reduce the amount of time we blow on style reresolution by

tracking the attributes which appear in CSS selectors, and only firing
a complete reresolution when we change one of those.  In the irrelevant-attr
case, we just let the frame update itself and get on with our lives right
away.  Fixed 38378, r=brendan, booyah.

Also, when setting an attribute to the same value that it currently holds,
don't think about it especially hard, and _don't_ go anywhere near the
style code.  Fixed 21879, r=brendan, boo_yah_.
This commit is contained in:
shaver%mozilla.org 2000-05-16 02:43:33 +00:00
Родитель d251adb613
Коммит 8f7d1fbff0
23 изменённых файлов: 577 добавлений и 88 удалений

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

@ -71,6 +71,11 @@ public:
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
};
#endif /* nsIStyleSheet_h___ */

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

@ -191,6 +191,9 @@ public:
NS_DECL_NSITIMERECORDER
#endif
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
StyleSetImpl(const StyleSetImpl& aCopy);
@ -1354,6 +1357,46 @@ void StyleSetImpl::ResetUniqueStyleItems(void)
uniqueItems->Clear();
}
struct AttributeContentPair {
nsIAtom *attribute;
nsIContent *content;
};
static PRBool
EnumAffectsStyle(nsISupports *aElement, void *aData)
{
nsIStyleSheet *sheet = NS_STATIC_CAST(nsIStyleSheet *, aElement);
AttributeContentPair *pair = (AttributeContentPair *)aData;
PRBool affects;
if (NS_FAILED(sheet->AttributeAffectsStyle(pair->attribute, pair->content,
affects)) || affects)
return PR_FALSE; // stop checking
return PR_TRUE;
}
NS_IMETHODIMP
StyleSetImpl::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
AttributeContentPair pair;
pair.attribute = aAttribute;
pair.content = aContent;
/* check until we find a sheet that will be affected */
if ((mDocSheets && !mDocSheets->EnumerateForwards(EnumAffectsStyle, &pair)) ||
(mOverrideSheets && !mOverrideSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mBackstopSheets && !mBackstopSheets->EnumerateForwards(EnumAffectsStyle,
&pair))) {
aAffects = PR_TRUE;
} else {
aAffects = PR_FALSE;
}
return NS_OK;
}
/******************************************************************************
* SizeOf method:
*

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

@ -1280,12 +1280,22 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
return result;
}
// don't do any update if old == new
nsAutoString strValue;
result = GetAttribute(aNameSpaceID, aAttribute, strValue);
if ((NS_CONTENT_ATTR_NOT_THERE != result) && aValue.Equals(strValue)) {
NS_RELEASE(htmlContent);
return NS_OK;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
// set as string value to avoid another string copy
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
if (nsnull != sheet) {

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

@ -459,6 +459,7 @@ public:
nsINameSpace* mNameSpace;
PRInt32 mDefaultNameSpaceID;
nsHashtable mRelevantAttributes;
static nsIIOService* gIOService;
static nsrefcnt gRefcnt;
@ -518,6 +519,15 @@ public:
NS_IMETHOD AppendStyleSheet(nsICSSStyleSheet* aSheet);
NS_IMETHOD InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Find attributes in selector for rule, for use with AttributeAffectsStyle
NS_IMETHOD CheckRuleForAttributes(nsICSSRule* aRule);
// XXX do these belong here or are they generic?
NS_IMETHOD PrependStyleRule(nsICSSRule* aRule);
NS_IMETHOD AppendStyleRule(nsICSSRule* aRule);
@ -1090,7 +1100,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
mURL(nsnull),
mOrderedRules(nsnull),
mNameSpace(nsnull),
mDefaultNameSpaceID(kNameSpaceID_None)
mDefaultNameSpaceID(kNameSpaceID_None),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1117,12 +1128,24 @@ CloneRuleInto(nsISupports* aRule, void* aArray)
return PR_TRUE;
}
static PRBool
CopyRelevantAttributes(nsHashKey *aAttrKey, void *aAtom, void *aTable)
{
nsHashtable *table = NS_STATIC_CAST(nsHashtable *, aTable);
AtomKey *key = NS_STATIC_CAST(AtomKey *, aAttrKey);
table->Put(key, key->mAtom);
// we don't need to addref the atom here, because we're also copying the
// rules when we clone, and that will add a ref for us
return PR_TRUE;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
nsICSSStyleSheet* aParentSheet)
: mSheets(),
mURL(aCopy.mURL),
mNameSpace(nsnull),
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID)
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1144,6 +1167,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
else {
mOrderedRules = nsnull;
}
aCopy.mRelevantAttributes.Enumerate(CopyRelevantAttributes,
&mRelevantAttributes);
RebuildNameSpaces();
}
@ -1840,6 +1865,21 @@ CSSStyleSheetImpl::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
return result;
}
NS_IMETHODIMP
CSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
AtomKey key(aAttribute);
aAffects = !!mInner->mRelevantAttributes.Get(&key);
for (CSSStyleSheetImpl *child = mFirstChild;
child && !aAffects;
child = child->mNext) {
child->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
return NS_OK;
}
NS_IMETHODIMP
CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
{
@ -1859,6 +1899,8 @@ CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
if (nsICSSRule::NAMESPACE_RULE == type) {
// no api to prepend a namespace (ugh), release old ones and re-create them all
mInner->RebuildNameSpaces();
} else {
CheckRuleForAttributes(aRule);
}
}
}
@ -1906,12 +1948,59 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
mInner->mNameSpace = newNameSpace; // takes ref
}
}
} else {
CheckRuleForAttributes(aRule);
}
}
}
return NS_OK;
}
static PRBool
CheckRuleForAttributesEnum(nsISupports *aRule, void *aData)
{
nsICSSRule *rule = NS_STATIC_CAST(nsICSSRule *, aRule);
CSSStyleSheetImpl *sheet = NS_STATIC_CAST(CSSStyleSheetImpl *, aData);
return NS_SUCCEEDED(sheet->CheckRuleForAttributes(rule));
}
NS_IMETHODIMP
CSSStyleSheetImpl::CheckRuleForAttributes(nsICSSRule *aRule)
{
PRInt32 ruleType;
aRule->GetType(ruleType);
switch (ruleType) {
case nsICSSRule::MEDIA_RULE: {
nsICSSMediaRule *mediaRule = (nsICSSMediaRule *)aRule;
return mediaRule->EnumerateRulesForwards(CheckRuleForAttributesEnum,
(void *)this);
}
case nsICSSRule::STYLE_RULE: {
nsICSSStyleRule *styleRule = NS_STATIC_CAST(nsICSSStyleRule *, aRule);
nsCSSSelector *iter;
for (iter = styleRule->FirstSelector(); iter; iter = iter->mNext) {
nsAttrSelector *sel;
for (sel = iter->mAttrList; sel; sel = sel->mNext) {
/* store it in this sheet's attributes-that-matter table */
/* XXX store tag name too, but handle collisions */
#ifdef DEBUG_shaver_off
nsAutoString str;
sel->mAttr->ToString(str);
char * chars = str.ToNewCString();
fprintf(stderr, "[%s@%p]", chars, this);
nsAllocator::Free(chars);
#endif
AtomKey key(sel->mAttr);
mInner->mRelevantAttributes.Put(&key, sel->mAttr);
}
}
} /* fall-through */
default:
return NS_OK;
}
}
NS_IMETHODIMP
CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const
{

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

@ -367,6 +367,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLCSSStyleSheetImpl(const HTMLCSSStyleSheetImpl& aCopy);
@ -761,6 +765,16 @@ void HTMLCSSStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &a
}
}
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX can attributes affect rules in these?
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For backwards compatibility and convenience
NS_HTML nsresult
NS_NewHTMLCSSStyleSheet(nsIHTMLCSSStyleSheet** aInstancePtrResult, nsIURI* aURL,

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

@ -654,6 +654,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy);
@ -1506,6 +1510,16 @@ void HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSiz
// that's it
}
NS_IMETHODIMP
HTMLStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX we should be checking to see if this is an href on an <A> being
// XXX tweaked, in which case we really want to restyle
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For convenience and backwards compatibility
NS_HTML nsresult

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

@ -9539,9 +9539,24 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
changeList.AppendChange(primaryFrame, aContent, maxHint);
nsCOMPtr<nsIFrameManager> frameManager;
shell->GetFrameManager(getter_AddRefs(frameManager));
frameManager->ComputeStyleChangeFor(aPresContext, primaryFrame,
aNameSpaceID, aAttribute,
changeList, aHint, maxHint);
PRBool affects;
frameManager->AttributeAffectsStyle(aAttribute, aContent, affects);
if (affects) {
#ifdef DEBUG_shaver
fputc('+', stderr);
#endif
// there is an effect, so compute it
frameManager->ComputeStyleChangeFor(aPresContext, primaryFrame,
aNameSpaceID, aAttribute,
changeList, aHint, maxHint);
} else {
#ifdef DEBUG_shaver
fputc('-', stderr);
#endif
// let this frame update itself, but don't walk the whole frame tree
maxHint = NS_STYLE_HINT_VISUAL;
}
switch (maxHint) { // maxHint is hint for primary only
case NS_STYLE_HINT_RECONSTRUCT_ALL:

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

@ -235,6 +235,8 @@ public:
nsStyleChangeList& aChangeList,
PRInt32 aMinChange,
PRInt32& aTopLevelChange);
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
@ -1386,6 +1388,12 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
return mStyleSet->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
static nsresult
CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)

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

@ -146,6 +146,10 @@ public:
PRInt32 aMinChange,
PRInt32& aTopLevelChange) = 0;
// Determine whether an attribute affects style
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
/**
* Capture/restore frame state for the frame subtree rooted at aFrame.
* aState is the document state storage object onto which each frame

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

@ -186,6 +186,11 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;
virtual void ResetUniqueStyleItems(void) = 0;
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
#ifdef DEBUG_SC_SHARING
// add and remove from the cache of all contexts
NS_IMETHOD AddStyleContext(nsIStyleContext *aNewStyleContext) = 0;

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

@ -1,76 +0,0 @@
/* -*- 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.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#ifndef nsIStyleSheet_h___
#define nsIStyleSheet_h___
#include <stdio.h>
#include "nsISupports.h"
class nsISizeOfHandler;
class nsIAtom;
class nsString;
class nsIURI;
class nsIStyleRule;
class nsISupportsArray;
class nsIPresContext;
class nsIContent;
class nsIDocument;
class nsIStyleContext;
class nsIStyleRuleProcessor;
// IID for the nsIStyleSheet interface {8c4a80a0-ad6a-11d1-8031-006008159b5a}
#define NS_ISTYLE_SHEET_IID \
{0x8c4a80a0, 0xad6a, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
class nsIStyleSheet : public nsISupports {
public:
static const nsIID& GetIID() { static nsIID iid = NS_ISTYLE_SHEET_IID; return iid; }
// basic style sheet data
NS_IMETHOD GetURL(nsIURI*& aURL) const = 0;
NS_IMETHOD GetTitle(nsString& aTitle) const = 0;
NS_IMETHOD GetType(nsString& aType) const = 0;
NS_IMETHOD GetMediumCount(PRInt32& aCount) const = 0;
NS_IMETHOD GetMediumAt(PRInt32 aIndex, nsIAtom*& aMedium) const = 0;
NS_IMETHOD UseForMedium(nsIAtom* aMedium) const = 0;
NS_IMETHOD GetEnabled(PRBool& aEnabled) const = 0;
NS_IMETHOD SetEnabled(PRBool aEnabled) = 0;
// style sheet owner info
NS_IMETHOD GetParentSheet(nsIStyleSheet*& aParent) const = 0; // may be null
NS_IMETHOD GetOwningDocument(nsIDocument*& aDocument) const = 0; // may be null
NS_IMETHOD SetOwningDocument(nsIDocument* aDocument) = 0;
// style rule processor access
NS_IMETHOD GetStyleRuleProcessor(nsIStyleRuleProcessor*& aProcessor,
nsIStyleRuleProcessor* aPrevProcessor) = 0;
// XXX style rule enumerations
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;
};
#endif /* nsIStyleSheet_h___ */

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

@ -191,6 +191,9 @@ public:
NS_DECL_NSITIMERECORDER
#endif
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
StyleSetImpl(const StyleSetImpl& aCopy);
@ -1354,6 +1357,46 @@ void StyleSetImpl::ResetUniqueStyleItems(void)
uniqueItems->Clear();
}
struct AttributeContentPair {
nsIAtom *attribute;
nsIContent *content;
};
static PRBool
EnumAffectsStyle(nsISupports *aElement, void *aData)
{
nsIStyleSheet *sheet = NS_STATIC_CAST(nsIStyleSheet *, aElement);
AttributeContentPair *pair = (AttributeContentPair *)aData;
PRBool affects;
if (NS_FAILED(sheet->AttributeAffectsStyle(pair->attribute, pair->content,
affects)) || affects)
return PR_FALSE; // stop checking
return PR_TRUE;
}
NS_IMETHODIMP
StyleSetImpl::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
AttributeContentPair pair;
pair.attribute = aAttribute;
pair.content = aContent;
/* check until we find a sheet that will be affected */
if ((mDocSheets && !mDocSheets->EnumerateForwards(EnumAffectsStyle, &pair)) ||
(mOverrideSheets && !mOverrideSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mBackstopSheets && !mBackstopSheets->EnumerateForwards(EnumAffectsStyle,
&pair))) {
aAffects = PR_TRUE;
} else {
aAffects = PR_FALSE;
}
return NS_OK;
}
/******************************************************************************
* SizeOf method:
*

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

@ -235,6 +235,8 @@ public:
nsStyleChangeList& aChangeList,
PRInt32 aMinChange,
PRInt32& aTopLevelChange);
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
nsIFrame* aFrame,
@ -1386,6 +1388,12 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
return NS_OK;
}
NS_IMETHODIMP
FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
return mStyleSet->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
static nsresult
CaptureFrameStateFor(nsIPresContext* aPresContext, nsIFrame* aFrame, nsILayoutHistoryState* aState)

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

@ -1280,12 +1280,22 @@ nsGenericHTMLElement::SetAttribute(PRInt32 aNameSpaceID,
return result;
}
// don't do any update if old == new
nsAutoString strValue;
result = GetAttribute(aNameSpaceID, aAttribute, strValue);
if ((NS_CONTENT_ATTR_NOT_THERE != result) && aValue.Equals(strValue)) {
NS_RELEASE(htmlContent);
return NS_OK;
}
if (aNotify && (nsnull != mDocument)) {
mDocument->BeginUpdate();
}
// set as string value to avoid another string copy
PRBool impact = NS_STYLE_HINT_NONE;
htmlContent->GetMappedAttributeImpact(aAttribute, impact);
if (nsnull != mDocument) { // set attr via style sheet
nsIHTMLStyleSheet* sheet = GetAttrStyleSheet(mDocument);
if (nsnull != sheet) {

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

@ -9539,9 +9539,24 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
changeList.AppendChange(primaryFrame, aContent, maxHint);
nsCOMPtr<nsIFrameManager> frameManager;
shell->GetFrameManager(getter_AddRefs(frameManager));
frameManager->ComputeStyleChangeFor(aPresContext, primaryFrame,
aNameSpaceID, aAttribute,
changeList, aHint, maxHint);
PRBool affects;
frameManager->AttributeAffectsStyle(aAttribute, aContent, affects);
if (affects) {
#ifdef DEBUG_shaver
fputc('+', stderr);
#endif
// there is an effect, so compute it
frameManager->ComputeStyleChangeFor(aPresContext, primaryFrame,
aNameSpaceID, aAttribute,
changeList, aHint, maxHint);
} else {
#ifdef DEBUG_shaver
fputc('-', stderr);
#endif
// let this frame update itself, but don't walk the whole frame tree
maxHint = NS_STYLE_HINT_VISUAL;
}
switch (maxHint) { // maxHint is hint for primary only
case NS_STYLE_HINT_RECONSTRUCT_ALL:

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

@ -459,6 +459,7 @@ public:
nsINameSpace* mNameSpace;
PRInt32 mDefaultNameSpaceID;
nsHashtable mRelevantAttributes;
static nsIIOService* gIOService;
static nsrefcnt gRefcnt;
@ -518,6 +519,15 @@ public:
NS_IMETHOD AppendStyleSheet(nsICSSStyleSheet* aSheet);
NS_IMETHOD InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Find attributes in selector for rule, for use with AttributeAffectsStyle
NS_IMETHOD CheckRuleForAttributes(nsICSSRule* aRule);
// XXX do these belong here or are they generic?
NS_IMETHOD PrependStyleRule(nsICSSRule* aRule);
NS_IMETHOD AppendStyleRule(nsICSSRule* aRule);
@ -1090,7 +1100,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
mURL(nsnull),
mOrderedRules(nsnull),
mNameSpace(nsnull),
mDefaultNameSpaceID(kNameSpaceID_None)
mDefaultNameSpaceID(kNameSpaceID_None),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1117,12 +1128,24 @@ CloneRuleInto(nsISupports* aRule, void* aArray)
return PR_TRUE;
}
static PRBool
CopyRelevantAttributes(nsHashKey *aAttrKey, void *aAtom, void *aTable)
{
nsHashtable *table = NS_STATIC_CAST(nsHashtable *, aTable);
AtomKey *key = NS_STATIC_CAST(AtomKey *, aAttrKey);
table->Put(key, key->mAtom);
// we don't need to addref the atom here, because we're also copying the
// rules when we clone, and that will add a ref for us
return PR_TRUE;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
nsICSSStyleSheet* aParentSheet)
: mSheets(),
mURL(aCopy.mURL),
mNameSpace(nsnull),
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID)
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1144,6 +1167,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
else {
mOrderedRules = nsnull;
}
aCopy.mRelevantAttributes.Enumerate(CopyRelevantAttributes,
&mRelevantAttributes);
RebuildNameSpaces();
}
@ -1840,6 +1865,21 @@ CSSStyleSheetImpl::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
return result;
}
NS_IMETHODIMP
CSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
AtomKey key(aAttribute);
aAffects = !!mInner->mRelevantAttributes.Get(&key);
for (CSSStyleSheetImpl *child = mFirstChild;
child && !aAffects;
child = child->mNext) {
child->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
return NS_OK;
}
NS_IMETHODIMP
CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
{
@ -1859,6 +1899,8 @@ CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
if (nsICSSRule::NAMESPACE_RULE == type) {
// no api to prepend a namespace (ugh), release old ones and re-create them all
mInner->RebuildNameSpaces();
} else {
CheckRuleForAttributes(aRule);
}
}
}
@ -1906,12 +1948,59 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
mInner->mNameSpace = newNameSpace; // takes ref
}
}
} else {
CheckRuleForAttributes(aRule);
}
}
}
return NS_OK;
}
static PRBool
CheckRuleForAttributesEnum(nsISupports *aRule, void *aData)
{
nsICSSRule *rule = NS_STATIC_CAST(nsICSSRule *, aRule);
CSSStyleSheetImpl *sheet = NS_STATIC_CAST(CSSStyleSheetImpl *, aData);
return NS_SUCCEEDED(sheet->CheckRuleForAttributes(rule));
}
NS_IMETHODIMP
CSSStyleSheetImpl::CheckRuleForAttributes(nsICSSRule *aRule)
{
PRInt32 ruleType;
aRule->GetType(ruleType);
switch (ruleType) {
case nsICSSRule::MEDIA_RULE: {
nsICSSMediaRule *mediaRule = (nsICSSMediaRule *)aRule;
return mediaRule->EnumerateRulesForwards(CheckRuleForAttributesEnum,
(void *)this);
}
case nsICSSRule::STYLE_RULE: {
nsICSSStyleRule *styleRule = NS_STATIC_CAST(nsICSSStyleRule *, aRule);
nsCSSSelector *iter;
for (iter = styleRule->FirstSelector(); iter; iter = iter->mNext) {
nsAttrSelector *sel;
for (sel = iter->mAttrList; sel; sel = sel->mNext) {
/* store it in this sheet's attributes-that-matter table */
/* XXX store tag name too, but handle collisions */
#ifdef DEBUG_shaver_off
nsAutoString str;
sel->mAttr->ToString(str);
char * chars = str.ToNewCString();
fprintf(stderr, "[%s@%p]", chars, this);
nsAllocator::Free(chars);
#endif
AtomKey key(sel->mAttr);
mInner->mRelevantAttributes.Put(&key, sel->mAttr);
}
}
} /* fall-through */
default:
return NS_OK;
}
}
NS_IMETHODIMP
CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const
{

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

@ -367,6 +367,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLCSSStyleSheetImpl(const HTMLCSSStyleSheetImpl& aCopy);
@ -761,6 +765,16 @@ void HTMLCSSStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &a
}
}
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX can attributes affect rules in these?
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For backwards compatibility and convenience
NS_HTML nsresult
NS_NewHTMLCSSStyleSheet(nsIHTMLCSSStyleSheet** aInstancePtrResult, nsIURI* aURL,

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

@ -654,6 +654,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy);
@ -1506,6 +1510,16 @@ void HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSiz
// that's it
}
NS_IMETHODIMP
HTMLStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX we should be checking to see if this is an href on an <A> being
// XXX tweaked, in which case we really want to restyle
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For convenience and backwards compatibility
NS_HTML nsresult

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

@ -459,6 +459,7 @@ public:
nsINameSpace* mNameSpace;
PRInt32 mDefaultNameSpaceID;
nsHashtable mRelevantAttributes;
static nsIIOService* gIOService;
static nsrefcnt gRefcnt;
@ -518,6 +519,15 @@ public:
NS_IMETHOD AppendStyleSheet(nsICSSStyleSheet* aSheet);
NS_IMETHOD InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Find attributes in selector for rule, for use with AttributeAffectsStyle
NS_IMETHOD CheckRuleForAttributes(nsICSSRule* aRule);
// XXX do these belong here or are they generic?
NS_IMETHOD PrependStyleRule(nsICSSRule* aRule);
NS_IMETHOD AppendStyleRule(nsICSSRule* aRule);
@ -1090,7 +1100,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
mURL(nsnull),
mOrderedRules(nsnull),
mNameSpace(nsnull),
mDefaultNameSpaceID(kNameSpaceID_None)
mDefaultNameSpaceID(kNameSpaceID_None),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1117,12 +1128,24 @@ CloneRuleInto(nsISupports* aRule, void* aArray)
return PR_TRUE;
}
static PRBool
CopyRelevantAttributes(nsHashKey *aAttrKey, void *aAtom, void *aTable)
{
nsHashtable *table = NS_STATIC_CAST(nsHashtable *, aTable);
AtomKey *key = NS_STATIC_CAST(AtomKey *, aAttrKey);
table->Put(key, key->mAtom);
// we don't need to addref the atom here, because we're also copying the
// rules when we clone, and that will add a ref for us
return PR_TRUE;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
nsICSSStyleSheet* aParentSheet)
: mSheets(),
mURL(aCopy.mURL),
mNameSpace(nsnull),
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID)
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID),
mRelevantAttributes()
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
if (gRefcnt++ == 0) {
@ -1144,6 +1167,8 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
else {
mOrderedRules = nsnull;
}
aCopy.mRelevantAttributes.Enumerate(CopyRelevantAttributes,
&mRelevantAttributes);
RebuildNameSpaces();
}
@ -1840,6 +1865,21 @@ CSSStyleSheetImpl::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
return result;
}
NS_IMETHODIMP
CSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
AtomKey key(aAttribute);
aAffects = !!mInner->mRelevantAttributes.Get(&key);
for (CSSStyleSheetImpl *child = mFirstChild;
child && !aAffects;
child = child->mNext) {
child->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
return NS_OK;
}
NS_IMETHODIMP
CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
{
@ -1859,6 +1899,8 @@ CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
if (nsICSSRule::NAMESPACE_RULE == type) {
// no api to prepend a namespace (ugh), release old ones and re-create them all
mInner->RebuildNameSpaces();
} else {
CheckRuleForAttributes(aRule);
}
}
}
@ -1906,12 +1948,59 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
mInner->mNameSpace = newNameSpace; // takes ref
}
}
} else {
CheckRuleForAttributes(aRule);
}
}
}
return NS_OK;
}
static PRBool
CheckRuleForAttributesEnum(nsISupports *aRule, void *aData)
{
nsICSSRule *rule = NS_STATIC_CAST(nsICSSRule *, aRule);
CSSStyleSheetImpl *sheet = NS_STATIC_CAST(CSSStyleSheetImpl *, aData);
return NS_SUCCEEDED(sheet->CheckRuleForAttributes(rule));
}
NS_IMETHODIMP
CSSStyleSheetImpl::CheckRuleForAttributes(nsICSSRule *aRule)
{
PRInt32 ruleType;
aRule->GetType(ruleType);
switch (ruleType) {
case nsICSSRule::MEDIA_RULE: {
nsICSSMediaRule *mediaRule = (nsICSSMediaRule *)aRule;
return mediaRule->EnumerateRulesForwards(CheckRuleForAttributesEnum,
(void *)this);
}
case nsICSSRule::STYLE_RULE: {
nsICSSStyleRule *styleRule = NS_STATIC_CAST(nsICSSStyleRule *, aRule);
nsCSSSelector *iter;
for (iter = styleRule->FirstSelector(); iter; iter = iter->mNext) {
nsAttrSelector *sel;
for (sel = iter->mAttrList; sel; sel = sel->mNext) {
/* store it in this sheet's attributes-that-matter table */
/* XXX store tag name too, but handle collisions */
#ifdef DEBUG_shaver_off
nsAutoString str;
sel->mAttr->ToString(str);
char * chars = str.ToNewCString();
fprintf(stderr, "[%s@%p]", chars, this);
nsAllocator::Free(chars);
#endif
AtomKey key(sel->mAttr);
mInner->mRelevantAttributes.Put(&key, sel->mAttr);
}
}
} /* fall-through */
default:
return NS_OK;
}
}
NS_IMETHODIMP
CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const
{

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

@ -367,6 +367,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLCSSStyleSheetImpl(const HTMLCSSStyleSheetImpl& aCopy);
@ -761,6 +765,16 @@ void HTMLCSSStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &a
}
}
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX can attributes affect rules in these?
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For backwards compatibility and convenience
NS_HTML nsresult
NS_NewHTMLCSSStyleSheet(nsIHTMLCSSStyleSheet** aInstancePtrResult, nsIURI* aURL,

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

@ -654,6 +654,10 @@ public:
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy);
@ -1506,6 +1510,16 @@ void HTMLStyleSheetImpl::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSiz
// that's it
}
NS_IMETHODIMP
HTMLStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX we should be checking to see if this is an href on an <A> being
// XXX tweaked, in which case we really want to restyle
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For convenience and backwards compatibility
NS_HTML nsresult

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

@ -71,6 +71,11 @@ public:
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
virtual void SizeOf(nsISizeOfHandler *aSizeofHandler, PRUint32 &aSize) = 0;
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
};
#endif /* nsIStyleSheet_h___ */

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

@ -191,6 +191,9 @@ public:
NS_DECL_NSITIMERECORDER
#endif
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
StyleSetImpl(const StyleSetImpl& aCopy);
@ -1354,6 +1357,46 @@ void StyleSetImpl::ResetUniqueStyleItems(void)
uniqueItems->Clear();
}
struct AttributeContentPair {
nsIAtom *attribute;
nsIContent *content;
};
static PRBool
EnumAffectsStyle(nsISupports *aElement, void *aData)
{
nsIStyleSheet *sheet = NS_STATIC_CAST(nsIStyleSheet *, aElement);
AttributeContentPair *pair = (AttributeContentPair *)aData;
PRBool affects;
if (NS_FAILED(sheet->AttributeAffectsStyle(pair->attribute, pair->content,
affects)) || affects)
return PR_FALSE; // stop checking
return PR_TRUE;
}
NS_IMETHODIMP
StyleSetImpl::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
AttributeContentPair pair;
pair.attribute = aAttribute;
pair.content = aContent;
/* check until we find a sheet that will be affected */
if ((mDocSheets && !mDocSheets->EnumerateForwards(EnumAffectsStyle, &pair)) ||
(mOverrideSheets && !mOverrideSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mBackstopSheets && !mBackstopSheets->EnumerateForwards(EnumAffectsStyle,
&pair))) {
aAffects = PR_TRUE;
} else {
aAffects = PR_FALSE;
}
return NS_OK;
}
/******************************************************************************
* SizeOf method:
*