зеркало из https://github.com/mozilla/pjs.git
Bug 629200 part 1 - Make MaybeCheckSameAttrVal work on parsed attributes instead of strings; r=bz
This commit is contained in:
Родитель
614777e8a0
Коммит
c949bd39d5
|
@ -81,6 +81,7 @@ CPPSRCS = \
|
|||
nsAtomListUtils.cpp \
|
||||
nsAttrAndChildArray.cpp \
|
||||
nsAttrValue.cpp \
|
||||
nsAttrValueOrString.cpp \
|
||||
nsCCUncollectableMarker.cpp \
|
||||
nsChannelPolicy.cpp \
|
||||
nsCommentNode.cpp \
|
||||
|
|
|
@ -314,6 +314,19 @@ nsAttrValue::SetTo(const nsIntMargin& aValue)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SetToSerialized(const nsAttrValue& aOther)
|
||||
{
|
||||
if (aOther.Type() != nsAttrValue::eString &&
|
||||
aOther.Type() != nsAttrValue::eAtom) {
|
||||
nsAutoString val;
|
||||
aOther.ToString(val);
|
||||
SetTo(val);
|
||||
} else {
|
||||
SetTo(aOther);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsAttrValue::SwapValueWith(nsAttrValue& aOther)
|
||||
{
|
||||
|
@ -419,6 +432,29 @@ nsAttrValue::ToString(nsAString& aResult) const
|
|||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom>
|
||||
nsAttrValue::GetAsAtom() const
|
||||
{
|
||||
switch (Type()) {
|
||||
case eString:
|
||||
return do_GetAtom(GetStringValue());
|
||||
|
||||
case eAtom:
|
||||
{
|
||||
nsIAtom* atom = GetAtomValue();
|
||||
NS_ADDREF(atom);
|
||||
return atom;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
nsAutoString val;
|
||||
ToString(val);
|
||||
return do_GetAtom(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nsCheapString
|
||||
nsAttrValue::GetStringValue() const
|
||||
{
|
||||
|
@ -751,6 +787,36 @@ nsAttrValue::Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
|
|||
return aValue->Equals(val);
|
||||
}
|
||||
|
||||
bool
|
||||
nsAttrValue::EqualsAsStrings(const nsAttrValue& aOther) const
|
||||
{
|
||||
if (Type() == aOther.Type()) {
|
||||
return Equals(aOther);
|
||||
}
|
||||
|
||||
// We need to serialize at least one nsAttrValue before passing to
|
||||
// Equals(const nsAString&), but we can avoid unnecessarily serializing both
|
||||
// by checking if one is already of a string type.
|
||||
bool thisIsString = (BaseType() == eStringBase || BaseType() == eAtomBase);
|
||||
const nsAttrValue& lhs = thisIsString ? *this : aOther;
|
||||
const nsAttrValue& rhs = thisIsString ? aOther : *this;
|
||||
|
||||
switch (rhs.BaseType()) {
|
||||
case eAtomBase:
|
||||
return lhs.Equals(rhs.GetAtomValue(), eCaseMatters);
|
||||
|
||||
case eStringBase:
|
||||
return lhs.Equals(rhs.GetStringValue(), eCaseMatters);
|
||||
|
||||
default:
|
||||
{
|
||||
nsAutoString val;
|
||||
rhs.ToString(val);
|
||||
return lhs.Equals(val, eCaseMatters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
|
||||
{
|
||||
|
|
|
@ -136,9 +136,23 @@ public:
|
|||
void SetTo(mozilla::css::StyleRule* aValue, const nsAString* aSerialized);
|
||||
void SetTo(const nsIntMargin& aValue);
|
||||
|
||||
/**
|
||||
* Sets this object with the string or atom representation of aValue.
|
||||
*
|
||||
* After calling this method, this object will have type eString unless the
|
||||
* type of aValue is eAtom, in which case this object will also have type
|
||||
* eAtom.
|
||||
*/
|
||||
void SetToSerialized(const nsAttrValue& aValue);
|
||||
|
||||
void SwapValueWith(nsAttrValue& aOther);
|
||||
|
||||
void ToString(nsAString& aResult) const;
|
||||
/**
|
||||
* Returns the value of this object as an atom. If necessary, the value will
|
||||
* first be serialised using ToString before converting to an atom.
|
||||
*/
|
||||
already_AddRefed<nsIAtom> GetAsAtom() const;
|
||||
|
||||
// Methods to get value. These methods do not convert so only use them
|
||||
// to retrieve the datatype that this nsAttrValue has.
|
||||
|
@ -175,6 +189,15 @@ public:
|
|||
bool Equals(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
bool Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const;
|
||||
|
||||
/**
|
||||
* Compares this object with aOther according to their string representation.
|
||||
*
|
||||
* For example, when called on an object with type eInteger and value 4, and
|
||||
* given aOther of type eString and value "4", EqualsAsStrings will return
|
||||
* true (while Equals will return false).
|
||||
*/
|
||||
bool EqualsAsStrings(const nsAttrValue& aOther) const;
|
||||
|
||||
/**
|
||||
* Returns true if this AttrValue is equal to the given atom, or is an
|
||||
* array which contains the given atom.
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAttrValueOrString.h"
|
||||
|
||||
const nsAString&
|
||||
nsAttrValueOrString::String() const
|
||||
{
|
||||
if (mStringPtr) {
|
||||
return *mStringPtr;
|
||||
}
|
||||
|
||||
if (mAttrValue->Type() == nsAttrValue::eString) {
|
||||
mCheapString = mAttrValue->GetStringValue();
|
||||
mStringPtr = &mCheapString;
|
||||
return *mStringPtr;
|
||||
}
|
||||
|
||||
mAttrValue->ToString(mCheapString);
|
||||
mStringPtr = &mCheapString;
|
||||
return *mStringPtr;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* A wrapper to contain either an nsAttrValue or an nsAString. This is useful
|
||||
* because constructing an nsAttrValue from an nsAString can be expensive when
|
||||
* the buffer of the string is not shared.
|
||||
*
|
||||
* Since a raw pointer to the passed-in string is kept, this class should only
|
||||
* be used on the stack.
|
||||
*/
|
||||
|
||||
#ifndef nsAttrValueOrString_h___
|
||||
#define nsAttrValueOrString_h___
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsAttrValue.h"
|
||||
|
||||
class NS_STACK_CLASS nsAttrValueOrString
|
||||
{
|
||||
public:
|
||||
nsAttrValueOrString(const nsAString& aValue)
|
||||
: mAttrValue(nsnull)
|
||||
, mStringPtr(&aValue)
|
||||
, mCheapString(nsnull)
|
||||
{ }
|
||||
nsAttrValueOrString(const nsAttrValue& aValue)
|
||||
: mAttrValue(&aValue)
|
||||
, mStringPtr(nsnull)
|
||||
, mCheapString(nsnull)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Returns a reference to the string value of the contents of this object.
|
||||
*
|
||||
* When this object points to a string or an nsAttrValue of string or atom
|
||||
* type this should be fairly cheap. Other nsAttrValue types will be
|
||||
* serialized the first time this is called and cached from thereon.
|
||||
*/
|
||||
const nsAString& String() const;
|
||||
|
||||
/**
|
||||
* Compares the string representation of this object with the string
|
||||
* representation of an nsAttrValue.
|
||||
*/
|
||||
bool EqualsAsStrings(const nsAttrValue& aOther) const
|
||||
{
|
||||
if (mStringPtr) {
|
||||
return aOther.Equals(*mStringPtr, eCaseMatters);
|
||||
}
|
||||
return aOther.EqualsAsStrings(*mAttrValue);
|
||||
}
|
||||
|
||||
protected:
|
||||
const nsAttrValue* mAttrValue;
|
||||
mutable const nsAString* mStringPtr;
|
||||
mutable nsCheapString mCheapString;
|
||||
};
|
||||
|
||||
#endif // nsAttrValueOrString_h___
|
|
@ -86,6 +86,7 @@
|
|||
#include "nsMutationEvent.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsAttrValueOrString.h"
|
||||
#ifdef MOZ_XUL
|
||||
#include "nsXULElement.h"
|
||||
#endif /* MOZ_XUL */
|
||||
|
@ -4979,10 +4980,14 @@ nsGenericElement::CopyInnerTo(nsGenericElement* aDst) const
|
|||
}
|
||||
|
||||
bool
|
||||
nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify, nsAutoString* aOldValue,
|
||||
PRUint8* aModType, bool* aHasListeners)
|
||||
nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify,
|
||||
nsAttrValue& aOldValue,
|
||||
PRUint8* aModType,
|
||||
bool* aHasListeners)
|
||||
{
|
||||
bool modification = false;
|
||||
*aHasListeners = aNotify &&
|
||||
|
@ -5000,16 +5005,19 @@ nsGenericElement::MaybeCheckSameAttrVal(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
if (info.mValue) {
|
||||
// Check whether the old value is the same as the new one. Note that we
|
||||
// only need to actually _get_ the old value if we have listeners.
|
||||
bool valueMatches;
|
||||
if (*aHasListeners) {
|
||||
// Need to store the old value
|
||||
info.mValue->ToString(*aOldValue);
|
||||
valueMatches = aValue.Equals(*aOldValue);
|
||||
} else {
|
||||
NS_ABORT_IF_FALSE(aNotify,
|
||||
"Either hasListeners or aNotify should be true.");
|
||||
valueMatches = info.mValue->Equals(aValue, eCaseMatters);
|
||||
// Need to store the old value.
|
||||
//
|
||||
// If the current attribute value contains a pointer to some other data
|
||||
// structure that gets updated in the process of setting the attribute
|
||||
// we'll no longer have the old value of the attribute. Therefore, we
|
||||
// should serialize the attribute value now to keep a snapshot.
|
||||
//
|
||||
// We have to serialize the value anyway in order to create the
|
||||
// mutation event so there's no cost in doing it now.
|
||||
aOldValue.SetToSerialized(*info.mValue);
|
||||
}
|
||||
bool valueMatches = aValue.EqualsAsStrings(*info.mValue);
|
||||
if (valueMatches && aPrefix == info.mName->GetPrefix()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -5039,10 +5047,11 @@ nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
|
||||
PRUint8 modType;
|
||||
bool hasListeners;
|
||||
nsAutoString oldValue;
|
||||
nsAttrValueOrString value(aValue);
|
||||
nsAttrValue oldValue;
|
||||
|
||||
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, aValue, aNotify,
|
||||
&oldValue, &modType, &hasListeners)) {
|
||||
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5082,19 +5091,18 @@ nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoString value;
|
||||
aParsedValue.ToString(value);
|
||||
|
||||
PRUint8 modType;
|
||||
bool hasListeners;
|
||||
nsAutoString oldValue;
|
||||
nsAttrValueOrString value(aParsedValue);
|
||||
nsAttrValue oldValue;
|
||||
|
||||
if (MaybeCheckSameAttrVal(aNamespaceID, aName, aPrefix, value, aNotify,
|
||||
&oldValue, &modType, &hasListeners)) {
|
||||
oldValue, &modType, &hasListeners)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value, aNotify);
|
||||
nsresult rv = BeforeSetAttr(aNamespaceID, aName, &value.String(), aNotify);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aNotify) {
|
||||
|
@ -5103,14 +5111,14 @@ nsGenericElement::SetParsedAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
|
||||
return SetAttrAndNotify(aNamespaceID, aName, aPrefix, oldValue,
|
||||
aParsedValue, modType, hasListeners, aNotify,
|
||||
&value);
|
||||
&value.String());
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAString& aOldValue,
|
||||
const nsAttrValue& aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
PRUint8 aModType,
|
||||
bool aFireMutation,
|
||||
|
@ -5182,8 +5190,8 @@ nsGenericElement::SetAttrAndNotify(PRInt32 aNamespaceID,
|
|||
if (!newValue.IsEmpty()) {
|
||||
mutation.mNewAttrValue = do_GetAtom(newValue);
|
||||
}
|
||||
if (!aOldValue.IsEmpty()) {
|
||||
mutation.mPrevAttrValue = do_GetAtom(aOldValue);
|
||||
if (!aOldValue.IsEmptyString()) {
|
||||
mutation.mPrevAttrValue = aOldValue.GetAsAtom();
|
||||
}
|
||||
mutation.mAttrChange = aModType;
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ class nsINodeInfo;
|
|||
class nsIControllers;
|
||||
class nsEventListenerManager;
|
||||
class nsIScrollableFrame;
|
||||
class nsAttrValueOrString;
|
||||
class nsContentList;
|
||||
class nsDOMTokenList;
|
||||
struct nsRect;
|
||||
|
@ -289,16 +290,18 @@ public:
|
|||
* have mutation listeners (in which case it's cheap to just return false
|
||||
* and let the caller go ahead and set the value).
|
||||
* @param aOldValue Set to the old value of the attribute, but only if there
|
||||
* are event listeners
|
||||
* are event listeners. If set, the type of aOldValue will be either
|
||||
* nsAttrValue::eString or nsAttrValue::eAtom.
|
||||
* @param aModType Set to nsIDOMMutationEvent::MODIFICATION or to
|
||||
* nsIDOMMutationEvent::ADDITION, but only if this helper returns true
|
||||
* @param aHasListeners Set to true if there are mutation event listeners
|
||||
* listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
|
||||
*/
|
||||
bool MaybeCheckSameAttrVal(PRInt32 aNamespaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
bool aNotify, nsAutoString* aOldValue,
|
||||
PRUint8* aModType, bool* aHasListeners);
|
||||
nsIAtom* aPrefix,
|
||||
const nsAttrValueOrString& aValue,
|
||||
bool aNotify, nsAttrValue& aOldValue,
|
||||
PRUint8* aModType, bool* aHasListeners);
|
||||
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix,
|
||||
const nsAString& aValue, bool aNotify);
|
||||
virtual nsresult SetParsedAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
|
||||
|
@ -656,7 +659,7 @@ protected:
|
|||
nsresult SetAttrAndNotify(PRInt32 aNamespaceID,
|
||||
nsIAtom* aName,
|
||||
nsIAtom* aPrefix,
|
||||
const nsAString& aOldValue,
|
||||
const nsAttrValue& aOldValue,
|
||||
nsAttrValue& aParsedValue,
|
||||
PRUint8 aModType,
|
||||
bool aFireMutation,
|
||||
|
|
|
@ -167,7 +167,7 @@ nsStyledElementNotElementCSSInlineStyle::SetInlineStyleRule(css::StyleRule* aSty
|
|||
{
|
||||
SetMayHaveStyle();
|
||||
bool modification = false;
|
||||
nsAutoString oldValueStr;
|
||||
nsAttrValue oldValue;
|
||||
|
||||
bool hasListeners = aNotify &&
|
||||
nsContentUtils::HasMutationListeners(this,
|
||||
|
@ -182,8 +182,12 @@ nsStyledElementNotElementCSSInlineStyle::SetInlineStyleRule(css::StyleRule* aSty
|
|||
// save the old attribute so we can set up the mutation event properly
|
||||
// XXXbz if the old rule points to the same declaration as the new one,
|
||||
// this is getting the new attr value, not the old one....
|
||||
nsAutoString oldValueStr;
|
||||
modification = GetAttr(kNameSpaceID_None, nsGkAtoms::style,
|
||||
oldValueStr);
|
||||
if (modification) {
|
||||
oldValue.SetTo(oldValueStr);
|
||||
}
|
||||
}
|
||||
else if (aNotify && IsInDoc()) {
|
||||
modification = !!mAttrsAndChildren.GetAttr(nsGkAtoms::style);
|
||||
|
@ -197,7 +201,7 @@ nsStyledElementNotElementCSSInlineStyle::SetInlineStyleRule(css::StyleRule* aSty
|
|||
static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION);
|
||||
|
||||
return SetAttrAndNotify(kNameSpaceID_None, nsGkAtoms::style, nsnull,
|
||||
oldValueStr, attrValue, modType, hasListeners,
|
||||
oldValue, attrValue, modType, hasListeners,
|
||||
aNotify, nsnull);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче