Diff
Modified: trunk/Source/WebCore/ChangeLog (199359 => 199360)
--- trunk/Source/WebCore/ChangeLog 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/ChangeLog 2016-04-12 16:21:50 UTC (rev 199360)
@@ -1,3 +1,47 @@
+2016-04-12 Chris Dumez <[email protected]>
+
+ Lazily update tokens in DOMTokenList when the associated attribute value changes
+ https://bugs.webkit.org/show_bug.cgi?id=156474
+
+ Reviewed by Ryosuke Niwa.
+
+ Lazily update tokens in DOMTokenList when the associated attribute value
+ changes for performance. Constructing the sanitized vector of tokens
+ every time the associated Element attribute changes is too expensive.
+ Instead, we mark the vector as dirty whenever the attribute changes, and
+ we only construct the sanitized vector when it is actually required.
+
+ Also do some renaming for clarity.
+
+ There is no web-exposed behavior change.
+
+ * dom/Element.cpp:
+ (WebCore::Element::classAttributeChanged):
+ * html/DOMTokenList.cpp:
+ (WebCore::DOMTokenList::contains):
+ (WebCore::DOMTokenList::addInternal):
+ (WebCore::DOMTokenList::removeInternal):
+ (WebCore::DOMTokenList::toggle):
+ (WebCore::DOMTokenList::value):
+ (WebCore::DOMTokenList::setValue):
+ (WebCore::DOMTokenList::updateTokensFromAttributeValue):
+ (WebCore::DOMTokenList::associatedAttributeValueChanged):
+ (WebCore::DOMTokenList::updateAssociatedAttributeFromTokens):
+ (WebCore::DOMTokenList::tokens):
+ (WebCore::DOMTokenList::DOMTokenList): Deleted.
+ * html/DOMTokenList.h:
+ (WebCore::DOMTokenList::tokens):
+ (WebCore::DOMTokenList::length):
+ (WebCore::DOMTokenList::item):
+ * html/HTMLAnchorElement.cpp:
+ (WebCore::HTMLAnchorElement::parseAttribute):
+ * html/HTMLIFrameElement.cpp:
+ (WebCore::HTMLIFrameElement::parseAttribute):
+ * html/HTMLLinkElement.cpp:
+ (WebCore::HTMLLinkElement::parseAttribute):
+ * html/HTMLOutputElement.cpp:
+ (WebCore::HTMLOutputElement::parseAttribute):
+
2016-04-12 Darin Adler <[email protected]>
Remove UsePointersEvenForNonNullableObjectArguments from HTMLMediaElement
Modified: trunk/Source/WebCore/dom/Element.cpp (199359 => 199360)
--- trunk/Source/WebCore/dom/Element.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/dom/Element.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -1330,7 +1330,7 @@
if (hasRareData()) {
if (auto* classList = elementRareData()->classList())
- classList->attributeValueChanged(newClassString);
+ classList->associatedAttributeValueChanged(newClassString);
}
}
Modified: trunk/Source/WebCore/html/DOMTokenList.cpp (199359 => 199360)
--- trunk/Source/WebCore/html/DOMTokenList.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/DOMTokenList.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -40,7 +40,6 @@
: m_element(element)
, m_attributeName(attributeName)
{
- setValueInternal(m_element.getAttribute(m_attributeName));
}
bool DOMTokenList::validateToken(const String& token, ExceptionCode& ec)
@@ -72,26 +71,27 @@
bool DOMTokenList::contains(const AtomicString& token) const
{
- return m_tokens.contains(token);
+ return tokens().contains(token);
}
-inline void DOMTokenList::addInternal(const String* tokens, size_t length, ExceptionCode& ec)
+inline void DOMTokenList::addInternal(const String* newTokens, size_t length, ExceptionCode& ec)
{
// This is usually called with a single token.
- Vector<AtomicString, 1> uniqueTokens;
- uniqueTokens.reserveInitialCapacity(length);
+ Vector<AtomicString, 1> uniqueNewTokens;
+ uniqueNewTokens.reserveInitialCapacity(length);
+ auto& tokens = this->tokens();
for (size_t i = 0; i < length; ++i) {
- if (!validateToken(tokens[i], ec))
+ if (!validateToken(newTokens[i], ec))
return;
- if (!m_tokens.contains(tokens[i]) && !uniqueTokens.contains(tokens[i]))
- uniqueTokens.uncheckedAppend(tokens[i]);
+ if (!tokens.contains(newTokens[i]) && !uniqueNewTokens.contains(newTokens[i]))
+ uniqueNewTokens.uncheckedAppend(newTokens[i]);
}
- if (!uniqueTokens.isEmpty())
- m_tokens.appendVector(uniqueTokens);
+ if (!uniqueNewTokens.isEmpty())
+ tokens.appendVector(uniqueNewTokens);
- updateAfterTokenChange();
+ updateAssociatedAttributeFromTokens();
}
void DOMTokenList::add(const Vector<String>& tokens, ExceptionCode& ec)
@@ -104,15 +104,16 @@
addInternal(&token.string(), 1, ec);
}
-inline void DOMTokenList::removeInternal(const String* tokens, size_t length, ExceptionCode& ec)
+inline void DOMTokenList::removeInternal(const String* tokensToRemove, size_t length, ExceptionCode& ec)
{
- if (!validateTokens(tokens, length, ec))
+ if (!validateTokens(tokensToRemove, length, ec))
return;
+ auto& tokens = this->tokens();
for (size_t i = 0; i < length; ++i)
- m_tokens.removeFirst(tokens[i]);
+ tokens.removeFirst(tokensToRemove[i]);
- updateAfterTokenChange();
+ updateAssociatedAttributeFromTokens();
}
void DOMTokenList::remove(const Vector<String>& tokens, ExceptionCode& ec)
@@ -130,10 +131,12 @@
if (!validateToken(token, ec))
return false;
- if (m_tokens.contains(token)) {
+ auto& tokens = this->tokens();
+
+ if (tokens.contains(token)) {
if (!force.valueOr(false)) {
- m_tokens.removeFirst(token);
- updateAfterTokenChange();
+ tokens.removeFirst(token);
+ updateAssociatedAttributeFromTokens();
return false;
}
return true;
@@ -142,8 +145,8 @@
if (force && !force.value())
return false;
- m_tokens.append(token);
- updateAfterTokenChange();
+ tokens.append(token);
+ updateAssociatedAttributeFromTokens();
return true;
}
@@ -152,7 +155,7 @@
if (m_cachedValue.isNull()) {
// https://dom.spec.whatwg.org/#concept-ordered-set-serializer
StringBuilder builder;
- for (auto& token : m_tokens) {
+ for (auto& token : tokens()) {
if (!builder.isEmpty())
builder.append(' ');
builder.append(token);
@@ -160,16 +163,17 @@
m_cachedValue = builder.toAtomicString();
ASSERT(!m_cachedValue.isNull());
}
+ ASSERT(!m_tokensNeedUpdating);
return m_cachedValue;
}
void DOMTokenList::setValue(const String& value)
{
- setValueInternal(value);
- updateAfterTokenChange();
+ updateTokensFromAttributeValue(value);
+ updateAssociatedAttributeFromTokens();
}
-void DOMTokenList::setValueInternal(const WTF::String& value)
+void DOMTokenList::updateTokensFromAttributeValue(const String& value)
{
// Clear tokens but not capacity.
m_tokens.shrink(0);
@@ -195,24 +199,38 @@
}
m_tokens.shrinkToFit();
+ m_tokensNeedUpdating = false;
m_cachedValue = nullAtom;
}
-void DOMTokenList::attributeValueChanged(const AtomicString& newValue)
+void DOMTokenList::associatedAttributeValueChanged(const AtomicString&)
{
// Do not reset the DOMTokenList value if the attribute value was changed by us.
- if (m_isUpdatingAttributeValue)
+ if (m_inUpdateAssociatedAttributeFromTokens)
return;
- setValueInternal(newValue);
+ m_tokensNeedUpdating = true;
+ m_cachedValue = nullAtom;
}
-void DOMTokenList::updateAfterTokenChange()
+// https://dom.spec.whatwg.org/#concept-dtl-update
+void DOMTokenList::updateAssociatedAttributeFromTokens()
{
+ ASSERT(!m_tokensNeedUpdating);
+
m_cachedValue = nullAtom;
- TemporaryChange<bool> inAttributeUpdate(m_isUpdatingAttributeValue, true);
- m_element.setAttribute(m_attributeName, value());
+ TemporaryChange<bool> inAttributeUpdate(m_inUpdateAssociatedAttributeFromTokens, true);
+ m_element.setAttributeWithoutSynchronization(m_attributeName, value());
+ ASSERT_WITH_MESSAGE(m_cachedValue, "Calling value() should have cached its results");
}
+Vector<AtomicString>& DOMTokenList::tokens()
+{
+ if (m_tokensNeedUpdating)
+ updateTokensFromAttributeValue(m_element.fastGetAttribute(m_attributeName));
+ ASSERT(!m_tokensNeedUpdating);
+ return m_tokens;
+}
+
} // namespace WebCore
Modified: trunk/Source/WebCore/html/DOMTokenList.h (199359 => 199360)
--- trunk/Source/WebCore/html/DOMTokenList.h 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/DOMTokenList.h 2016-04-12 16:21:50 UTC (rev 199360)
@@ -39,8 +39,9 @@
WTF_MAKE_NONCOPYABLE(DOMTokenList); WTF_MAKE_FAST_ALLOCATED;
public:
DOMTokenList(Element&, const QualifiedName& attributeName);
- void attributeValueChanged(const AtomicString&);
+ void associatedAttributeValueChanged(const AtomicString&);
+
void ref() { m_element.ref(); }
void deref() { m_element.deref(); }
@@ -62,9 +63,12 @@
const AtomicString& value() const;
private:
- void setValueInternal(const String&);
- void updateAfterTokenChange();
+ void updateTokensFromAttributeValue(const String&);
+ void updateAssociatedAttributeFromTokens();
+ Vector<AtomicString>& tokens();
+ const Vector<AtomicString>& tokens() const { return const_cast<DOMTokenList&>(*this).tokens(); }
+
static bool validateToken(const String&, ExceptionCode&);
static bool validateTokens(const String* tokens, size_t length, ExceptionCode&);
void addInternal(const String* tokens, size_t length, ExceptionCode&);
@@ -72,19 +76,21 @@
Element& m_element;
const WebCore::QualifiedName& m_attributeName;
- bool m_isUpdatingAttributeValue { false };
+ bool m_inUpdateAssociatedAttributeFromTokens { false };
+ bool m_tokensNeedUpdating { true };
Vector<AtomicString> m_tokens;
mutable AtomicString m_cachedValue;
};
inline unsigned DOMTokenList::length() const
{
- return m_tokens.size();
+ return tokens().size();
}
inline const AtomicString& DOMTokenList::item(unsigned index) const
{
- return index < m_tokens.size() ? m_tokens[index] : nullAtom;
+ auto& tokens = this->tokens();
+ return index < tokens.size() ? tokens[index] : nullAtom;
}
} // namespace WebCore
Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (199359 => 199360)
--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -252,7 +252,7 @@
if (SpaceSplitString::spaceSplitStringContainsValue(value, "noreferrer", true))
m_linkRelations |= RelationNoReferrer;
if (m_relList)
- m_relList->attributeValueChanged(value);
+ m_relList->associatedAttributeValueChanged(value);
}
else
HTMLElement::parseAttribute(name, value);
Modified: trunk/Source/WebCore/html/HTMLIFrameElement.cpp (199359 => 199360)
--- trunk/Source/WebCore/html/HTMLIFrameElement.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLIFrameElement.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -85,7 +85,7 @@
{
if (name == sandboxAttr) {
if (m_sandbox)
- m_sandbox->attributeValueChanged(value);
+ m_sandbox->associatedAttributeValueChanged(value);
String invalidTokens;
setSandboxFlags(value.isNull() ? SandboxNone : SecurityContext::parseSandboxPolicy(value, invalidTokens));
Modified: trunk/Source/WebCore/html/HTMLLinkElement.cpp (199359 => 199360)
--- trunk/Source/WebCore/html/HTMLLinkElement.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLLinkElement.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -141,7 +141,7 @@
if (name == relAttr) {
m_relAttribute = LinkRelAttribute(value);
if (m_relList)
- m_relList->attributeValueChanged(value);
+ m_relList->associatedAttributeValueChanged(value);
process();
return;
}
@@ -160,7 +160,7 @@
}
if (name == sizesAttr) {
if (m_sizes)
- m_sizes->attributeValueChanged(value);
+ m_sizes->associatedAttributeValueChanged(value);
process();
return;
}
Modified: trunk/Source/WebCore/html/HTMLOutputElement.cpp (199359 => 199360)
--- trunk/Source/WebCore/html/HTMLOutputElement.cpp 2016-04-12 16:16:50 UTC (rev 199359)
+++ trunk/Source/WebCore/html/HTMLOutputElement.cpp 2016-04-12 16:21:50 UTC (rev 199360)
@@ -68,7 +68,7 @@
{
if (name == forAttr) {
if (m_tokens)
- m_tokens->attributeValueChanged(value);
+ m_tokens->associatedAttributeValueChanged(value);
} else
HTMLFormControlElement::parseAttribute(name, value);
}