Bug 562815 part 6 - Check if property is cached in rule tree; r=dbaron

--HG--
extra : rebase_source : 9a7d2388bd00e2c8177cebc9d2a1339626cdd3ab
This commit is contained in:
Brian Birtles 2011-08-23 08:34:12 +09:00
parent 74603ec212
commit 3e8804de84
6 changed files with 143 additions and 51 deletions

View File

@ -387,13 +387,10 @@ ValueFromStringHelper(nsCSSProperty aPropID,
}
nsDependentSubstring subString(aString, subStringBegin);
if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
PR_TRUE, aStyleAnimValue)) {
PR_TRUE, aStyleAnimValue,
aIsContextSensitive)) {
return PR_FALSE;
}
if (aIsContextSensitive) {
// XXX
*aIsContextSensitive = PR_TRUE;
}
if (isNegative) {
InvertSign(aStyleAnimValue);
}

View File

@ -744,6 +744,10 @@ public:
NS_ASSERTION(IsRoot(), "should only be called on root of rule tree");
return HaveChildren() || mStyleData.mInheritedData || mStyleData.mResetData;
}
PRBool NodeHasCachedData(const nsStyleStructID aSID) {
return !!mStyleData.GetStyleData(aSID);
}
};
#endif

View File

@ -1926,48 +1926,13 @@ LookupStyleContext(dom::Element* aElement)
return nsComputedDOMStyle::GetStyleContextForElement(aElement, nsnull, shell);
}
/**
* Helper function: StyleWithRuleAdded
* Creates a custom style context as a sibling of the given element's
* nsStyleContext with the given css::StyleRule added.
*
* @param aTargetElement The element whose style context we'll use as a
* sibling for our custom style context.
* @param aStyleRule The style rule to add to the style context.
* @return The generated custom nsStyleContext, or nsnull on failure.
*/
already_AddRefed<nsStyleContext>
StyleWithRuleAdded(dom::Element* aTargetElement,
css::StyleRule* aStyleRule)
{
NS_ABORT_IF_FALSE(aTargetElement, "null target element");
NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
"element needs to be in a document "
"if we're going to look up its style context");
NS_ABORT_IF_FALSE(aStyleRule, "null style rule");
// Look up style context for our target element
nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
if (!styleContext) {
return nsnull;
}
aStyleRule->RuleMatched();
// Create a temporary nsStyleContext for the style rule
nsCOMArray<nsIStyleRule> ruleArray;
ruleArray.AppendObject(aStyleRule);
nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
return styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
}
PRBool
nsStyleAnimation::ComputeValue(nsCSSProperty aProperty,
dom::Element* aTargetElement,
const nsAString& aSpecifiedValue,
PRBool aUseSVGMode,
Value& aComputedValue)
Value& aComputedValue,
PRBool* aIsContextSensitive)
{
NS_ABORT_IF_FALSE(aTargetElement, "null target element");
NS_ABORT_IF_FALSE(aTargetElement->GetCurrentDoc(),
@ -1984,18 +1949,66 @@ nsStyleAnimation::ComputeValue(nsCSSProperty aProperty,
if (!styleRule) {
return PR_FALSE;
}
nsRefPtr<nsStyleContext> tmpStyleContext =
StyleWithRuleAdded(aTargetElement, styleRule);
if (!tmpStyleContext) {
return PR_FALSE;
}
if (nsCSSProps::IsShorthand(aProperty) ||
nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
if (nsCSSProps::IsShorthand(aProperty) ||
nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
// Just capture the specified value
aComputedValue.SetUnparsedStringValue(nsString(aSpecifiedValue));
if (aIsContextSensitive) {
// Since we're just returning the string as-is, aComputedValue isn't going
// to change depending on the context
*aIsContextSensitive = PR_FALSE;
}
return PR_TRUE;
}
// Look up style context for our target element
nsRefPtr<nsStyleContext> styleContext = LookupStyleContext(aTargetElement);
if (!styleContext) {
return PR_FALSE;
}
nsStyleSet* styleSet = styleContext->PresContext()->StyleSet();
nsRefPtr<nsStyleContext> tmpStyleContext;
if (aIsContextSensitive) {
nsCOMArray<nsIStyleRule> ruleArray;
ruleArray.AppendObject(styleSet->InitialStyleRule());
ruleArray.AppendObject(styleRule);
styleRule->RuleMatched();
tmpStyleContext =
styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
if (!tmpStyleContext) {
return PR_FALSE;
}
// Force walk of rule tree
nsStyleStructID sid = nsCSSProps::kSIDTable[aProperty];
tmpStyleContext->GetStyleData(sid);
// If the rule node will have cached style data if the value is not
// context-sensitive. So if there's nothing cached, it's not context
// sensitive.
*aIsContextSensitive =
!tmpStyleContext->GetRuleNode()->NodeHasCachedData(sid);
}
// If we're not concerned whether the property is context sensitive then just
// add the rule to a new temporary style context alongside the target
// element's style context.
// Also, if we previously discovered that this property IS context-sensitive
// then we need to throw the temporary style context out since the property's
// value may have been biased by the 'initial' values supplied.
if (!aIsContextSensitive || *aIsContextSensitive) {
nsCOMArray<nsIStyleRule> ruleArray;
ruleArray.AppendObject(styleRule);
styleRule->RuleMatched();
tmpStyleContext =
styleSet->ResolveStyleByAddingRules(styleContext, ruleArray);
if (!tmpStyleContext) {
return PR_FALSE;
}
}
// Extract computed value of our property from the temporary style rule
return ExtractComputedValue(aProperty, tmpStyleContext, aComputedValue);
}

View File

@ -175,13 +175,22 @@ public:
* @param aUseSVGMode A flag to indicate whether we should parse
* |aSpecifiedValue| in SVG mode.
* @param [out] aComputedValue The resulting computed value.
* @param [out] aIsContextSensitive
* Set to PR_TRUE if |aSpecifiedValue| may produce
* a different |aComputedValue| depending on other CSS
* properties on |aTargetElement| or its ancestors.
* PR_FALSE otherwise.
* Note that the operation of this method is
* significantly faster when |aIsContextSensitive| is
* nsnull.
* @return PR_TRUE on success, PR_FALSE on failure.
*/
static PRBool ComputeValue(nsCSSProperty aProperty,
mozilla::dom::Element* aElement,
mozilla::dom::Element* aTargetElement,
const nsAString& aSpecifiedValue,
PRBool aUseSVGMode,
Value& aComputedValue);
Value& aComputedValue,
PRBool* aIsContextSensitive = nsnull);
/**
* Creates a specified value for the given computed value.

View File

@ -57,6 +57,7 @@
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsContentUtils.h"
#include "nsRuleData.h"
#include "nsRuleProcessorData.h"
#include "nsTransitionManager.h"
#include "nsAnimationManager.h"
@ -80,6 +81,50 @@ nsEmptyStyleRule::List(FILE* out, PRInt32 aIndent) const
}
#endif
NS_IMPL_ISUPPORTS1(nsInitialStyleRule, nsIStyleRule)
/* virtual */ void
nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
{
// Iterate over the property groups
for (nsStyleStructID sid = nsStyleStructID(0);
sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
if (aRuleData->mSIDs & (1 << sid)) {
// Iterate over nsCSSValues within the property group
nsCSSValue * const value_start =
aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
for (nsCSSValue *value = value_start,
*value_end = value + nsCSSProps::PropertyCountInStruct(sid);
value != value_end; ++value) {
// If MathML is disabled take care not to set MathML properties (or we
// will trigger assertions in nsRuleNode)
if (sid == eStyleStruct_Font &&
!aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
size_t index = value - value_start;
if (index == nsCSSProps::PropertyIndexInStruct(
eCSSProperty_script_level) ||
index == nsCSSProps::PropertyIndexInStruct(
eCSSProperty_script_size_multiplier) ||
index == nsCSSProps::PropertyIndexInStruct(
eCSSProperty_script_min_size)) {
continue;
}
}
if (value->GetUnit() == eCSSUnit_Null) {
value->SetInitialValue();
}
}
}
}
}
#ifdef DEBUG
/* virtual */ void
nsInitialStyleRule::List(FILE* out, PRInt32 aIndent) const
{
}
#endif
static const nsStyleSet::sheetType gCSSSheetTypes[] = {
nsStyleSet::eAgentSheet,
nsStyleSet::eUserSheet,
@ -1565,3 +1610,12 @@ nsStyleSet::EnsureUniqueInnerOnCSSSheets()
}
return res;
}
nsIStyleRule*
nsStyleSet::InitialStyleRule()
{
if (!mInitialStyleRule) {
mInitialStyleRule = new nsInitialStyleRule;
}
return mInitialStyleRule;
}

View File

@ -74,6 +74,15 @@ class nsEmptyStyleRule : public nsIStyleRule
#endif
};
class nsInitialStyleRule : public nsIStyleRule
{
NS_DECL_ISUPPORTS
virtual void MapRuleInfoInto(nsRuleData* aRuleData);
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
};
// The style set object is created by the document viewer and ownership is
// then handed off to the PresShell. Only the PresShell should delete a
// style set.
@ -309,6 +318,8 @@ class nsStyleSet
nsCSSStyleSheet::EnsureUniqueInnerResult EnsureUniqueInnerOnCSSSheets();
nsIStyleRule* InitialStyleRule();
private:
// Not to be implemented
nsStyleSet(const nsStyleSet& aCopy);
@ -400,6 +411,10 @@ class nsStyleSet
// apply into different branches of the rule tree.
nsRefPtr<nsEmptyStyleRule> mFirstLineRule, mFirstLetterRule;
// Style rule which sets all properties to their initial values for
// determining when context-sensitive values are in use.
nsRefPtr<nsInitialStyleRule> mInitialStyleRule;
PRUint16 mBatching;
// Old rule trees, which should only be non-empty between