Merge from Chromium at DEPS revision r219274
This commit was generated by merge_to_master.py.
Change-Id: I4217737c165f68da34d720aa074431613911dc68
diff --git a/Source/core/dom/Attr.h b/Source/core/dom/Attr.h
index 3673be2..21b3685 100644
--- a/Source/core/dom/Attr.h
+++ b/Source/core/dom/Attr.h
@@ -63,6 +63,12 @@
void attachToElement(Element*);
void detachFromElementWithValue(const AtomicString&);
+ virtual const AtomicString& localName() const OVERRIDE { return m_name.localName(); }
+ virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
+ virtual const AtomicString& prefix() const OVERRIDE { return m_name.prefix(); }
+
+ virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE;
+
private:
Attr(Element*, const QualifiedName&);
Attr(Document*, const QualifiedName&, const AtomicString& value);
@@ -72,12 +78,6 @@
virtual String nodeName() const OVERRIDE { return name(); }
virtual NodeType nodeType() const OVERRIDE { return ATTRIBUTE_NODE; }
- virtual const AtomicString& localName() const OVERRIDE { return m_name.localName(); }
- virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
- virtual const AtomicString& prefix() const OVERRIDE { return m_name.prefix(); }
-
- virtual void setPrefix(const AtomicString&, ExceptionState&);
-
virtual String nodeValue() const OVERRIDE { return value(); }
virtual void setNodeValue(const String&);
virtual PassRefPtr<Node> cloneNode(bool deep = true);
diff --git a/Source/core/dom/Attr.idl b/Source/core/dom/Attr.idl
index 97c7c46..0dcdb02 100644
--- a/Source/core/dom/Attr.idl
+++ b/Source/core/dom/Attr.idl
@@ -35,5 +35,11 @@
// DOM Level 3
readonly attribute boolean isId;
+
+ // DOM 4
+
+ [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString prefix;
+ [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString namespaceURI;
+ [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
};
diff --git a/Source/core/dom/CharacterData.cpp b/Source/core/dom/CharacterData.cpp
index 7221496..50b44c3 100644
--- a/Source/core/dom/CharacterData.cpp
+++ b/Source/core/dom/CharacterData.cpp
@@ -29,6 +29,7 @@
#include "core/dom/MutationEvent.h"
#include "core/dom/MutationObserverInterestGroup.h"
#include "core/dom/MutationRecord.h"
+#include "core/dom/ProcessingInstruction.h"
#include "core/dom/Text.h"
#include "core/editing/FrameSelection.h"
#include "core/inspector/InspectorInstrumentation.h"
@@ -97,7 +98,7 @@
ASSERT(!renderer() || isTextNode());
if (isTextNode())
- toText(this)->updateTextRenderer(oldLength, 0);
+ toText(this)->updateTextRenderer(oldLength, 0, DeprecatedAttachNow);
document()->incDOMTreeVersion();
@@ -107,16 +108,16 @@
return characterLengthLimit;
}
-void CharacterData::appendData(const String& data)
+void CharacterData::appendData(const String& data, AttachBehavior attachBehavior)
{
String newStr = m_data + data;
- setDataAndUpdate(newStr, m_data.length(), 0, data.length());
+ setDataAndUpdate(newStr, m_data.length(), 0, data.length(), attachBehavior);
// FIXME: Should we call textInserted here?
}
-void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& es)
+void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& es, AttachBehavior attachBehavior)
{
if (offset > length()) {
es.throwDOMException(IndexSizeError);
@@ -126,12 +127,12 @@
String newStr = m_data;
newStr.insert(data, offset);
- setDataAndUpdate(newStr, offset, 0, data.length());
+ setDataAndUpdate(newStr, offset, 0, data.length(), attachBehavior);
document()->textInserted(this, offset, data.length());
}
-void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& es)
+void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& es, AttachBehavior attachBehavior)
{
if (offset > length()) {
es.throwDOMException(IndexSizeError);
@@ -147,12 +148,12 @@
String newStr = m_data;
newStr.remove(offset, realCount);
- setDataAndUpdate(newStr, offset, count, 0);
+ setDataAndUpdate(newStr, offset, count, 0, attachBehavior);
document()->textRemoved(this, offset, realCount);
}
-void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& es)
+void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& es, AttachBehavior attachBehavior)
{
if (offset > length()) {
es.throwDOMException(IndexSizeError);
@@ -169,7 +170,7 @@
newStr.remove(offset, realCount);
newStr.insert(data, offset);
- setDataAndUpdate(newStr, offset, count, data.length());
+ setDataAndUpdate(newStr, offset, count, data.length(), attachBehavior);
// update the markers for spell checking and grammar checking
document()->textRemoved(this, offset, realCount);
@@ -191,14 +192,17 @@
setData(nodeValue);
}
-void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength)
+void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, AttachBehavior attachBehavior)
{
String oldData = m_data;
m_data = newData;
ASSERT(!renderer() || isTextNode());
if (isTextNode())
- toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength);
+ toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength, attachBehavior);
+
+ if (nodeType() == PROCESSING_INSTRUCTION_NODE)
+ toProcessingInstruction(this)->checkStyleSheet();
if (document()->frame())
document()->frame()->selection()->textWasReplaced(this, offsetOfReplacedData, oldLength, newLength);
diff --git a/Source/core/dom/CharacterData.h b/Source/core/dom/CharacterData.h
index 8077364..473456e 100644
--- a/Source/core/dom/CharacterData.h
+++ b/Source/core/dom/CharacterData.h
@@ -37,10 +37,10 @@
void setData(const String&);
unsigned length() const { return m_data.length(); }
String substringData(unsigned offset, unsigned count, ExceptionState&);
- void appendData(const String&);
- void insertData(unsigned offset, const String&, ExceptionState&);
- void deleteData(unsigned offset, unsigned count, ExceptionState&);
- void replaceData(unsigned offset, unsigned count, const String&, ExceptionState&);
+ void appendData(const String&, AttachBehavior = AttachLazily);
+ void insertData(unsigned offset, const String&, ExceptionState&, AttachBehavior = AttachLazily);
+ void deleteData(unsigned offset, unsigned count, ExceptionState&, AttachBehavior = AttachLazily);
+ void replaceData(unsigned offset, unsigned count, const String&, ExceptionState&, AttachBehavior = AttachLazily);
bool containsOnlyWhitespace() const;
@@ -66,15 +66,15 @@
}
void didModifyData(const String& oldValue);
+ String m_data;
+
private:
virtual String nodeValue() const OVERRIDE FINAL;
virtual void setNodeValue(const String&) OVERRIDE FINAL;
virtual bool isCharacterDataNode() const OVERRIDE FINAL { return true; }
virtual int maxCharacterOffset() const OVERRIDE FINAL;
virtual bool offsetInCharacters() const OVERRIDE FINAL;
- void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength);
-
- String m_data;
+ void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, AttachBehavior = AttachLazily);
};
} // namespace WebCore
diff --git a/Source/core/dom/Clipboard.cpp b/Source/core/dom/Clipboard.cpp
index 0c7f725..ee98d9f 100644
--- a/Source/core/dom/Clipboard.cpp
+++ b/Source/core/dom/Clipboard.cpp
@@ -26,8 +26,8 @@
#include "config.h"
#include "core/dom/Clipboard.h"
+#include "core/fetch/ImageResource.h"
#include "core/fileapi/FileList.h"
-#include "core/loader/cache/ImageResource.h"
namespace WebCore {
diff --git a/Source/core/dom/Clipboard.h b/Source/core/dom/Clipboard.h
index a32134b..bc861de 100644
--- a/Source/core/dom/Clipboard.h
+++ b/Source/core/dom/Clipboard.h
@@ -27,7 +27,7 @@
#include "bindings/v8/ScriptWrappable.h"
#include "core/dom/ClipboardAccessPolicy.h"
#include "core/dom/Node.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourcePtr.h"
#include "core/page/DragActions.h"
#include "core/platform/DragImage.h"
#include "core/platform/graphics/IntPoint.h"
diff --git a/Source/core/dom/ContainerNode.cpp b/Source/core/dom/ContainerNode.cpp
index 1b26b71..c184a5e 100644
--- a/Source/core/dom/ContainerNode.cpp
+++ b/Source/core/dom/ContainerNode.cpp
@@ -27,6 +27,7 @@
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "core/dom/ChildListMutationScope.h"
#include "core/dom/ContainerNodeAlgorithms.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/EventNames.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/FullscreenElementStack.h"
@@ -173,10 +174,6 @@
return false;
}
- if (newChild->inDocument() && newChild->isDocumentTypeNode()) {
- es.throwDOMException(HierarchyRequestError);
- return false;
- }
if (containsConsideringHostElements(newChild, newParent)) {
es.throwDOMException(HierarchyRequestError);
return false;
diff --git a/Source/core/dom/ContainerNode.h b/Source/core/dom/ContainerNode.h
index 86f37de..f795436 100644
--- a/Source/core/dom/ContainerNode.h
+++ b/Source/core/dom/ContainerNode.h
@@ -87,6 +87,9 @@
Node* lastChild() const { return m_lastChild; }
bool hasChildNodes() const { return m_firstChild; }
+ bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
+ bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
+
// ParentNode interface API
PassRefPtr<HTMLCollection> children();
Element* firstElementChild() const;
@@ -96,10 +99,10 @@
unsigned childNodeCount() const;
Node* childNode(unsigned index) const;
- void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
- void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
+ void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
+ void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
- void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
+ void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
// These methods are only used during parsing.
// They don't send DOM mutation events or handle reparenting.
diff --git a/Source/core/dom/ContainerNodeAlgorithms.cpp b/Source/core/dom/ContainerNodeAlgorithms.cpp
index 59d65ed..9f4eeac 100644
--- a/Source/core/dom/ContainerNodeAlgorithms.cpp
+++ b/Source/core/dom/ContainerNodeAlgorithms.cpp
@@ -28,10 +28,20 @@
#include "core/dom/Element.h"
#include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLFrameOwnerElement.h"
namespace WebCore {
+class ShadowRootVector : public Vector<RefPtr<ShadowRoot> > {
+public:
+ explicit ShadowRootVector(ElementShadow* tree)
+ {
+ for (ShadowRoot* root = tree->youngestShadowRoot(); root; root = root->olderShadowRoot())
+ append(root);
+ }
+};
+
void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoDocument(ContainerNode* node)
{
ChildNodesLazySnapshot snapshot(node);
@@ -121,7 +131,7 @@
unsigned count = 0;
if (node->isElementNode()) {
- if (node->isFrameOwnerElement() && toFrameOwnerElement(node)->contentFrame())
+ if (node->isFrameOwnerElement() && toHTMLFrameOwnerElement(node)->contentFrame())
count++;
if (ElementShadow* shadow = toElement(node)->shadow()) {
diff --git a/Source/core/dom/ContainerNodeAlgorithms.h b/Source/core/dom/ContainerNodeAlgorithms.h
index f02eb7f..ebd5263 100644
--- a/Source/core/dom/ContainerNodeAlgorithms.h
+++ b/Source/core/dom/ContainerNodeAlgorithms.h
@@ -23,7 +23,6 @@
#define ContainerNodeAlgorithms_h
#include "core/dom/Document.h"
-#include "core/dom/NodeTraversal.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "wtf/Assertions.h"
@@ -289,7 +288,7 @@
return;
if (root->isHTMLElement() && root->isFrameOwnerElement())
- m_frameOwners.append(toFrameOwnerElement(root));
+ m_frameOwners.append(toHTMLFrameOwnerElement(root));
for (Node* child = root->firstChild(); child; child = child->nextSibling())
collectFrameOwners(child);
diff --git a/Source/core/dom/CustomElement.cpp b/Source/core/dom/CustomElement.cpp
index 6ffcd2a..0529882 100644
--- a/Source/core/dom/CustomElement.cpp
+++ b/Source/core/dom/CustomElement.cpp
@@ -33,78 +33,103 @@
#include "HTMLNames.h"
#include "MathMLNames.h"
+#include "RuntimeEnabledFeatures.h"
#include "SVGNames.h"
#include "core/dom/CustomElementCallbackScheduler.h"
-#include "core/dom/CustomElementUpgradeCandidateMap.h"
+#include "core/dom/CustomElementObserver.h"
#include "core/dom/Element.h"
namespace WebCore {
-Vector<AtomicString>& CustomElement::allowedCustomTagNames()
+Vector<AtomicString>& CustomElement::embedderCustomElementNames()
{
- DEFINE_STATIC_LOCAL(Vector<AtomicString>, tagNames, ());
- return tagNames;
+ DEFINE_STATIC_LOCAL(Vector<AtomicString>, names, ());
+ return names;
}
-void CustomElement::allowTagName(const AtomicString& localName)
+void CustomElement::addEmbedderCustomElementName(const AtomicString& name)
{
- AtomicString lower = localName.lower();
- if (isCustomTagName(lower))
+ AtomicString lower = name.lower();
+ if (isValidName(lower, EmbedderNames))
return;
- allowedCustomTagNames().append(lower);
+ embedderCustomElementNames().append(lower);
}
-bool CustomElement::isValidTypeName(const AtomicString& name)
+static CustomElement::NameSet enabledNameSet()
{
- if (notFound != allowedCustomTagNames().find(name))
- return true;
+ return CustomElement::NameSet((RuntimeEnabledFeatures::customElementsEnabled() ? CustomElement::StandardNames : 0) | (RuntimeEnabledFeatures::embedderCustomElementsEnabled() ? CustomElement::EmbedderNames : 0));
+}
- if (allowedCustomTagNames().size() > 0)
- return false;
+bool CustomElement::isValidName(const AtomicString& name, NameSet validNames)
+{
+ validNames = NameSet(validNames & enabledNameSet());
- if (notFound == name.find('-'))
- return false;
+ if ((validNames & EmbedderNames) && notFound != embedderCustomElementNames().find(name))
+ return Document::isValidName(name);
- DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ());
- if (reservedNames.isEmpty()) {
- reservedNames.append(MathMLNames::annotation_xmlTag.localName());
- reservedNames.append(SVGNames::color_profileTag.localName());
- reservedNames.append(SVGNames::font_faceTag.localName());
- reservedNames.append(SVGNames::font_face_srcTag.localName());
- reservedNames.append(SVGNames::font_face_uriTag.localName());
- reservedNames.append(SVGNames::font_face_formatTag.localName());
- reservedNames.append(SVGNames::font_face_nameTag.localName());
- reservedNames.append(SVGNames::missing_glyphTag.localName());
+ if ((validNames & StandardNames) && notFound != name.find('-')) {
+ DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ());
+ if (reservedNames.isEmpty()) {
+ reservedNames.append(MathMLNames::annotation_xmlTag.localName());
+ reservedNames.append(SVGNames::color_profileTag.localName());
+ reservedNames.append(SVGNames::font_faceTag.localName());
+ reservedNames.append(SVGNames::font_face_srcTag.localName());
+ reservedNames.append(SVGNames::font_face_uriTag.localName());
+ reservedNames.append(SVGNames::font_face_formatTag.localName());
+ reservedNames.append(SVGNames::font_face_nameTag.localName());
+ reservedNames.append(SVGNames::missing_glyphTag.localName());
+ }
+
+ if (notFound == reservedNames.find(name))
+ return Document::isValidName(name.string());
}
- if (notFound != reservedNames.find(name))
- return false;
-
- return Document::isValidName(name.string());
-}
-
-bool CustomElement::isCustomTagName(const AtomicString& localName)
-{
- return isValidTypeName(localName);
+ return false;
}
void CustomElement::define(Element* element, PassRefPtr<CustomElementDefinition> passDefinition)
{
RefPtr<CustomElementDefinition> definition(passDefinition);
- element->setCustomElementState(Element::Defined);
- definitions().add(element, definition);
- CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
+
+ switch (element->customElementState()) {
+ case Element::NotCustomElement:
+ case Element::Upgraded:
+ ASSERT_NOT_REACHED();
+ break;
+
+ case Element::WaitingForParser:
+ definitions().add(element, definition);
+ break;
+
+ case Element::WaitingForUpgrade:
+ definitions().add(element, definition);
+ CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
+ break;
+ }
}
CustomElementDefinition* CustomElement::definitionFor(Element* element)
{
- return definitions().get(element);
+ CustomElementDefinition* definition = definitions().get(element);
+ ASSERT(definition);
+ return definition;
+}
+
+void CustomElement::didFinishParsingChildren(Element* element)
+{
+ ASSERT(element->customElementState() == Element::WaitingForParser);
+ element->setCustomElementState(Element::WaitingForUpgrade);
+
+ CustomElementObserver::notifyElementDidFinishParsingChildren(element);
+
+ if (CustomElementDefinition* definition = definitions().get(element))
+ CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
}
void CustomElement::attributeDidChange(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
{
ASSERT(element->customElementState() == Element::Upgraded);
- CustomElementCallbackScheduler::scheduleAttributeChangedCallback(definitions().get(element)->callbacks(), element, name, oldValue, newValue);
+ CustomElementCallbackScheduler::scheduleAttributeChangedCallback(definitionFor(element)->callbacks(), element, name, oldValue, newValue);
}
void CustomElement::didEnterDocument(Element* element, Document* document)
@@ -112,7 +137,7 @@
ASSERT(element->customElementState() == Element::Upgraded);
if (!document->defaultView())
return;
- CustomElementCallbackScheduler::scheduleEnteredDocumentCallback(definitions().get(element)->callbacks(), element);
+ CustomElementCallbackScheduler::scheduleEnteredDocumentCallback(definitionFor(element)->callbacks(), element);
}
void CustomElement::didLeaveDocument(Element* element, Document* document)
@@ -120,7 +145,7 @@
ASSERT(element->customElementState() == Element::Upgraded);
if (!document->defaultView())
return;
- CustomElementCallbackScheduler::scheduleLeftDocumentCallback(definitions().get(element)->callbacks(), element);
+ CustomElementCallbackScheduler::scheduleLeftDocumentCallback(definitionFor(element)->callbacks(), element);
}
void CustomElement::wasDestroyed(Element* element)
@@ -130,13 +155,11 @@
ASSERT_NOT_REACHED();
break;
- case Element::UpgradeCandidate:
- CustomElementUpgradeCandidateMap::elementWasDestroyed(element);
- break;
-
- case Element::Defined:
+ case Element::WaitingForParser:
+ case Element::WaitingForUpgrade:
case Element::Upgraded:
definitions().remove(element);
+ CustomElementObserver::notifyElementWasDestroyed(element);
break;
}
}
@@ -148,18 +171,6 @@
ASSERT(result.isNewEntry);
}
-void CustomElement::DefinitionMap::remove(Element* element)
-{
- m_definitions.remove(element);
-}
-
-CustomElementDefinition* CustomElement::DefinitionMap::get(Element* element)
-{
- DefinitionMap::ElementDefinitionHashMap::const_iterator it = m_definitions.find(element);
- ASSERT(it != m_definitions.end());
- return it->value.get();
-}
-
CustomElement::DefinitionMap& CustomElement::definitions()
{
DEFINE_STATIC_LOCAL(DefinitionMap, map, ());
diff --git a/Source/core/dom/CustomElement.h b/Source/core/dom/CustomElement.h
index 4fc4b57..07ba3c0 100644
--- a/Source/core/dom/CustomElement.h
+++ b/Source/core/dom/CustomElement.h
@@ -46,13 +46,13 @@
class CustomElement {
public:
- // FIXME: CustomElementRegistry requires isValidTypeName to be a
- // superset of isCustomTagName; consider either merging these or
- // separating them completely into
- // isCustomTagName/isTypeExtensionName.
- static bool isValidTypeName(const AtomicString& type);
- static bool isCustomTagName(const AtomicString& localName);
- static void allowTagName(const AtomicString& localName);
+ enum NameSet {
+ EmbedderNames = 1 << 0,
+ StandardNames = 1 << 1,
+ AllNames = EmbedderNames | StandardNames
+ };
+ static bool isValidName(const AtomicString& name, NameSet validNames = AllNames);
+ static void addEmbedderCustomElementName(const AtomicString& name);
// API for registration contexts
static void define(Element*, PassRefPtr<CustomElementDefinition>);
@@ -62,6 +62,7 @@
// API for Element to kick off changes
+ static void didFinishParsingChildren(Element*);
static void attributeDidChange(Element*, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue);
static void didEnterDocument(Element*, Document*);
static void didLeaveDocument(Element*, Document*);
@@ -70,7 +71,7 @@
private:
CustomElement();
- static Vector<AtomicString>& allowedCustomTagNames();
+ static Vector<AtomicString>& embedderCustomElementNames();
// Maps resolved elements to their definitions
@@ -81,8 +82,8 @@
~DefinitionMap() { }
void add(Element*, PassRefPtr<CustomElementDefinition>);
- void remove(Element*);
- CustomElementDefinition* get(Element*);
+ void remove(Element* element) { m_definitions.remove(element); }
+ CustomElementDefinition* get(Element* element) const { return m_definitions.get(element); }
private:
typedef HashMap<Element*, RefPtr<CustomElementDefinition> > ElementDefinitionHashMap;
diff --git a/Source/core/dom/CustomElementCallbackDispatcher.cpp b/Source/core/dom/CustomElementCallbackDispatcher.cpp
index 405d7cf..41d5ecf 100644
--- a/Source/core/dom/CustomElementCallbackDispatcher.cpp
+++ b/Source/core/dom/CustomElementCallbackDispatcher.cpp
@@ -113,14 +113,6 @@
}
}
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::createCallbackQueue(PassRefPtr<Element> element)
-{
- Element* key = element.get();
- ElementCallbackQueueMap::AddResult result = m_elementCallbackQueueMap.add(key, CustomElementCallbackQueue::create(element));
- ASSERT(result.isNewEntry);
- return result.iterator->value.get();
-}
-
CustomElementCallbackQueue* CustomElementCallbackDispatcher::ensureCallbackQueue(PassRefPtr<Element> element)
{
Element* key = element.get();
@@ -130,34 +122,38 @@
return it->value.get();
}
+// Finds or creates the callback queue for element. If the
+// createdCallback has not finished running, the callback queue is not
+// moved to the top-of-stack. Otherwise like
+// scheduleInCurrentElementQueue.
+CustomElementCallbackQueue* CustomElementCallbackDispatcher::schedule(PassRefPtr<Element> element)
+{
+ CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element);
+ if (!callbackQueue->inCreatedCallback())
+ ensureInCurrentElementQueue(callbackQueue);
+ return callbackQueue;
+}
+
// Finds or creates the callback queue for element. If the element's
// callback queue is scheduled in an earlier processing stack frame,
// its owner is set to the element queue on the top of the processing
// stack. Because callback queues are processed exhaustively, this
// effectively moves the callback queue to the top of the stack.
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::ensureInCurrentElementQueue(PassRefPtr<Element> element)
+CustomElementCallbackQueue* CustomElementCallbackDispatcher::scheduleInCurrentElementQueue(PassRefPtr<Element> element)
{
- CustomElementCallbackQueue* queue = ensureCallbackQueue(element);
- bool isInCurrentQueue = queue->owner() == currentElementQueue();
- if (!isInCurrentQueue) {
- queue->setOwner(currentElementQueue());
- m_flattenedProcessingStack.append(queue);
- ++s_elementQueueEnd;
- }
- return queue;
+ CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element);
+ ensureInCurrentElementQueue(callbackQueue);
+ return callbackQueue;
}
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::createAtFrontOfCurrentElementQueue(PassRefPtr<Element> element)
+void CustomElementCallbackDispatcher::ensureInCurrentElementQueue(CustomElementCallbackQueue* callbackQueue)
{
- CustomElementCallbackQueue* queue = createCallbackQueue(element);
- queue->setOwner(currentElementQueue());
+ if (callbackQueue->owner() == currentElementQueue())
+ return;
- // The created callback is unique in being prepended to the front
- // of the element queue
- m_flattenedProcessingStack.insert(inCallbackDeliveryScope() ? s_elementQueueStart : kNumSentinels, queue);
+ callbackQueue->setOwner(currentElementQueue());
+ m_flattenedProcessingStack.append(callbackQueue);
++s_elementQueueEnd;
-
- return queue;
}
} // namespace WebCore
diff --git a/Source/core/dom/CustomElementCallbackDispatcher.h b/Source/core/dom/CustomElementCallbackDispatcher.h
index 74c0ae7..f26ec9b 100644
--- a/Source/core/dom/CustomElementCallbackDispatcher.h
+++ b/Source/core/dom/CustomElementCallbackDispatcher.h
@@ -73,8 +73,8 @@
protected:
friend class CustomElementCallbackScheduler;
- CustomElementCallbackQueue* createAtFrontOfCurrentElementQueue(PassRefPtr<Element>);
- CustomElementCallbackQueue* ensureInCurrentElementQueue(PassRefPtr<Element>);
+ CustomElementCallbackQueue* schedule(PassRefPtr<Element>);
+ CustomElementCallbackQueue* scheduleInCurrentElementQueue(PassRefPtr<Element>);
private:
CustomElementCallbackDispatcher()
@@ -106,8 +106,8 @@
static void processElementQueueAndPop();
void processElementQueueAndPop(size_t start, size_t end);
- CustomElementCallbackQueue* createCallbackQueue(PassRefPtr<Element>);
CustomElementCallbackQueue* ensureCallbackQueue(PassRefPtr<Element>);
+ void ensureInCurrentElementQueue(CustomElementCallbackQueue*);
// The processing stack, flattened. Element queues lower in the
// stack appear toward the head of the vector. The first element
diff --git a/Source/core/dom/CustomElementCallbackInvocation.cpp b/Source/core/dom/CustomElementCallbackInvocation.cpp
index 82e50e1..4974dc0 100644
--- a/Source/core/dom/CustomElementCallbackInvocation.cpp
+++ b/Source/core/dom/CustomElementCallbackInvocation.cpp
@@ -45,6 +45,7 @@
private:
virtual void dispatch(Element*) OVERRIDE;
+ virtual bool isCreated() const OVERRIDE { return true; }
};
void CreatedInvocation::dispatch(Element* element)
diff --git a/Source/core/dom/CustomElementCallbackInvocation.h b/Source/core/dom/CustomElementCallbackInvocation.h
index c6f0818..d2f8135 100644
--- a/Source/core/dom/CustomElementCallbackInvocation.h
+++ b/Source/core/dom/CustomElementCallbackInvocation.h
@@ -49,6 +49,7 @@
virtual ~CustomElementCallbackInvocation() { }
virtual void dispatch(Element*) = 0;
+ virtual bool isCreated() const { return false; }
protected:
CustomElementCallbackInvocation(PassRefPtr<CustomElementLifecycleCallbacks> callbacks)
diff --git a/Source/core/dom/CustomElementCallbackQueue.cpp b/Source/core/dom/CustomElementCallbackQueue.cpp
index d5641bd..7078364 100644
--- a/Source/core/dom/CustomElementCallbackQueue.cpp
+++ b/Source/core/dom/CustomElementCallbackQueue.cpp
@@ -44,16 +44,22 @@
: m_element(element)
, m_owner(-1)
, m_index(0)
+ , m_inCreatedCallback(false)
{
}
void CustomElementCallbackQueue::processInElementQueue(ElementQueue caller)
{
+ ASSERT(!m_inCreatedCallback);
+
while (m_index < m_queue.size() && owner() == caller) {
+ m_inCreatedCallback = m_queue[m_index]->isCreated();
+
// dispatch() may cause recursion which steals this callback
// queue and reenters processInQueue. owner() == caller
// detects this recursion and cedes processing.
m_queue[m_index++]->dispatch(m_element.get());
+ m_inCreatedCallback = false;
}
if (owner() == caller && m_index == m_queue.size()) {
diff --git a/Source/core/dom/CustomElementCallbackQueue.h b/Source/core/dom/CustomElementCallbackQueue.h
index 7e39486..430766f 100644
--- a/Source/core/dom/CustomElementCallbackQueue.h
+++ b/Source/core/dom/CustomElementCallbackQueue.h
@@ -56,6 +56,7 @@
void append(PassOwnPtr<CustomElementCallbackInvocation> invocation) { m_queue.append(invocation); }
void processInElementQueue(ElementQueue);
+ bool inCreatedCallback() const { return m_inCreatedCallback; }
private:
CustomElementCallbackQueue(PassRefPtr<Element>);
@@ -64,6 +65,7 @@
Vector<OwnPtr<CustomElementCallbackInvocation> > m_queue;
ElementQueue m_owner;
size_t m_index;
+ bool m_inCreatedCallback;
};
}
diff --git a/Source/core/dom/CustomElementCallbackScheduler.cpp b/Source/core/dom/CustomElementCallbackScheduler.cpp
index 4a95d2b..79252ba 100644
--- a/Source/core/dom/CustomElementCallbackScheduler.cpp
+++ b/Source/core/dom/CustomElementCallbackScheduler.cpp
@@ -43,7 +43,7 @@
if (!callbacks->hasAttributeChangedCallback())
return;
- CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+ CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
queue->append(CustomElementCallbackInvocation::createAttributeChangedInvocation(callbacks, name, oldValue, newValue));
}
@@ -52,7 +52,7 @@
if (!callbacks->hasCreatedCallback())
return;
- CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().createAtFrontOfCurrentElementQueue(element);
+ CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().scheduleInCurrentElementQueue(element);
queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::Created));
}
@@ -61,7 +61,7 @@
if (!callbacks->hasEnteredDocumentCallback())
return;
- CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+ CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::EnteredDocument));
}
@@ -70,7 +70,7 @@
if (!callbacks->hasLeftDocumentCallback())
return;
- CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+ CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::LeftDocument));
}
diff --git a/Source/core/dom/CustomElementException.cpp b/Source/core/dom/CustomElementException.cpp
new file mode 100644
index 0000000..b5752a8
--- /dev/null
+++ b/Source/core/dom/CustomElementException.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/dom/CustomElementException.h"
+
+#include "bindings/v8/ExceptionState.h"
+#include "core/dom/ExceptionCode.h"
+
+namespace WebCore {
+
+String CustomElementException::preamble(const AtomicString& type)
+{
+ return "Failed to call 'register' on 'Document' for type '" + type + "': ";
+}
+
+void CustomElementException::throwException(Reason reason, const AtomicString& type, ExceptionState& es)
+{
+ switch (reason) {
+ case CannotRegisterFromExtension:
+ es.throwDOMException(NotSupportedError, preamble(type) + "elements cannot be registered from extensions.");
+ return;
+
+ case ConstructorPropertyNotConfigurable:
+ es.throwDOMException(NotSupportedError, preamble(type) + "prototype constructor property is not configurable.");
+ return;
+
+ case ContextDestroyedCheckingPrototype:
+ es.throwDOMException(InvalidStateError, preamble(type) + "the context is no longer valid.");
+ return;
+
+ case ContextDestroyedCreatingCallbacks:
+ es.throwDOMException(InvalidStateError);
+ return;
+
+ case ContextDestroyedRegisteringDefinition:
+ es.throwDOMException(NotSupportedError);
+ return;
+
+ case InvalidName:
+ es.throwDOMException(InvalidCharacterError, preamble(type) + ": '" + type + "' is not a valid name.");
+ return;
+
+ case NotYetImplemented:
+ es.throwDOMException(InvalidStateError);
+ return;
+
+ case PrototypeDoesNotExtendHTMLElementSVGElementNamespace:
+ es.throwDOMException(NamespaceError, preamble(type) + "the prototype does not extend an HTML or SVG element.");
+ return;
+
+ case PrototypeDoesNotExtendHTMLElementSVGElementPrototype:
+ es.throwDOMException(InvalidStateError, preamble(type) + "the prototype does not extend an HTML or SVG element.");
+ return;
+
+ case PrototypeInUse:
+ es.throwDOMException(NotSupportedError, preamble(type) + "prototype is already in-use as an interface prototype object.");
+ return;
+
+ case PrototypeNotAnObject:
+ es.throwDOMException(InvalidStateError, preamble(type) + "the prototype option is not an object.");
+ return;
+
+ case TypeAlreadyRegistered:
+ es.throwDOMException(InvalidStateError, preamble(type) + "a type with that name is already registered.");
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/CustomElementException.h b/Source/core/dom/CustomElementException.h
new file mode 100644
index 0000000..622ef22
--- /dev/null
+++ b/Source/core/dom/CustomElementException.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CustomElementException_h
+#define CustomElementException_h
+
+#include "wtf/text/AtomicString.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ExceptionState;
+
+class CustomElementException {
+public:
+ enum Reason {
+ CannotRegisterFromExtension,
+ ConstructorPropertyNotConfigurable,
+ ContextDestroyedCheckingPrototype,
+ ContextDestroyedCreatingCallbacks,
+ ContextDestroyedRegisteringDefinition,
+ InvalidName,
+ NotYetImplemented,
+ PrototypeDoesNotExtendHTMLElementSVGElementNamespace,
+ PrototypeDoesNotExtendHTMLElementSVGElementPrototype,
+ PrototypeInUse,
+ PrototypeNotAnObject,
+ TypeAlreadyRegistered
+ };
+
+ static void throwException(Reason, const AtomicString& type, ExceptionState&);
+
+private:
+ CustomElementException();
+
+ static String preamble(const AtomicString& type);
+};
+
+}
+
+#endif // CustomElementException_h
diff --git a/Source/core/dom/CustomElementObserver.cpp b/Source/core/dom/CustomElementObserver.cpp
new file mode 100644
index 0000000..45f1350
--- /dev/null
+++ b/Source/core/dom/CustomElementObserver.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/dom/CustomElementObserver.h"
+
+namespace WebCore {
+
+CustomElementObserver::ElementObserverMap& CustomElementObserver::elementObservers()
+{
+ DEFINE_STATIC_LOCAL(ElementObserverMap, map, ());
+ return map;
+}
+
+void CustomElementObserver::notifyElementDidFinishParsingChildren(Element* element)
+{
+ ElementObserverMap::iterator it = elementObservers().find(element);
+ if (it == elementObservers().end())
+ return;
+ it->value->elementDidFinishParsingChildren(element);
+}
+
+void CustomElementObserver::notifyElementWasDestroyed(Element* element)
+{
+ ElementObserverMap::iterator it = elementObservers().find(element);
+ if (it == elementObservers().end())
+ return;
+ it->value->elementWasDestroyed(element);
+}
+
+void CustomElementObserver::observe(Element* element)
+{
+ ElementObserverMap::AddResult result = elementObservers().add(element, this);
+ ASSERT(result.isNewEntry);
+}
+
+void CustomElementObserver::unobserve(Element* element)
+{
+ CustomElementObserver* observer = elementObservers().take(element);
+ ASSERT(observer == this);
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/CustomElementObserver.h b/Source/core/dom/CustomElementObserver.h
new file mode 100644
index 0000000..ab7c57d
--- /dev/null
+++ b/Source/core/dom/CustomElementObserver.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CustomElementObserver_h
+#define CustomElementObserver_h
+
+#include "wtf/HashMap.h"
+
+namespace WebCore {
+
+class Element;
+
+class CustomElementObserver {
+public:
+ CustomElementObserver() { }
+ virtual ~CustomElementObserver() { }
+
+ // API for CustomElement to kick off notifications
+
+ static void notifyElementDidFinishParsingChildren(Element*);
+ static void notifyElementWasDestroyed(Element*);
+
+protected:
+ void observe(Element*);
+ void unobserve(Element*);
+
+ virtual void elementDidFinishParsingChildren(Element*) = 0;
+ virtual void elementWasDestroyed(Element* element) { unobserve(element); }
+
+private:
+ // Maps elements to the observer watching them. At most one per
+ // element at a time.
+ typedef HashMap<Element*, CustomElementObserver*> ElementObserverMap;
+ static ElementObserverMap& elementObservers();
+};
+
+}
+
+#endif // CustomElementObserver_h
diff --git a/Source/core/dom/CustomElementRegistrationContext.cpp b/Source/core/dom/CustomElementRegistrationContext.cpp
index 4589e7e..bedaf5e 100644
--- a/Source/core/dom/CustomElementRegistrationContext.cpp
+++ b/Source/core/dom/CustomElementRegistrationContext.cpp
@@ -35,6 +35,7 @@
#include "SVGNames.h"
#include "bindings/v8/ExceptionState.h"
#include "core/dom/CustomElement.h"
+#include "core/dom/CustomElementCallbackScheduler.h"
#include "core/dom/CustomElementDefinition.h"
#include "core/dom/Element.h"
#include "core/html/HTMLElement.h"
@@ -44,9 +45,9 @@
namespace WebCore {
-void CustomElementRegistrationContext::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& type, ExceptionState& es)
+void CustomElementRegistrationContext::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& type, CustomElement::NameSet validNames, ExceptionState& es)
{
- CustomElementDefinition* definition = m_registry.registerElement(document, constructorBuilder, type, es);
+ CustomElementDefinition* definition = m_registry.registerElement(document, constructorBuilder, type, validNames, es);
if (!definition)
return;
@@ -57,9 +58,9 @@
didResolveElement(definition, *it);
}
-PassRefPtr<Element> CustomElementRegistrationContext::createCustomTagElement(Document* document, const QualifiedName& tagName)
+PassRefPtr<Element> CustomElementRegistrationContext::createCustomTagElement(Document* document, const QualifiedName& tagName, CreationMode mode)
{
- ASSERT(CustomElement::isCustomTagName(tagName.localName()));
+ ASSERT(CustomElement::isValidName(tagName.localName()));
if (!document)
return 0;
@@ -75,6 +76,7 @@
return Element::create(tagName, document);
}
+ element->setCustomElementState(mode == CreatedByParser ? Element::WaitingForParser : Element::WaitingForUpgrade);
resolve(element.get(), nullAtom);
return element.release();
}
@@ -88,7 +90,7 @@
{
// If an element has a custom tag name it takes precedence over
// the "is" attribute (if any).
- const AtomicString& type = CustomElement::isCustomTagName(element->localName())
+ const AtomicString& type = CustomElement::isValidName(element->localName())
? element->localName()
: typeExtension;
ASSERT(!type.isNull());
@@ -108,14 +110,10 @@
void CustomElementRegistrationContext::didCreateUnresolvedElement(const CustomElementDescriptor& descriptor, Element* element)
{
+ ASSERT(element->customElementState() == Element::WaitingForParser || element->customElementState() == Element::WaitingForUpgrade);
m_candidates.add(descriptor, element);
}
-void CustomElementRegistrationContext::customElementWasDestroyed(Element* element)
-{
- m_candidates.remove(element);
-}
-
PassRefPtr<CustomElementRegistrationContext> CustomElementRegistrationContext::create()
{
return adoptRef(new CustomElementRegistrationContext());
@@ -129,7 +127,7 @@
setTypeExtension(element, type);
}
-void CustomElementRegistrationContext::setTypeExtension(Element* element, const AtomicString& type)
+void CustomElementRegistrationContext::setTypeExtension(Element* element, const AtomicString& type, CreationMode mode)
{
if (!element->isHTMLElement() && !element->isSVGElement())
return;
@@ -144,7 +142,9 @@
}
// Custom tags take precedence over type extensions
- ASSERT(!CustomElement::isCustomTagName(element->localName()));
+ ASSERT(!CustomElement::isValidName(element->localName()));
+
+ element->setCustomElementState(mode == CreatedByParser ? Element::WaitingForParser : Element::WaitingForUpgrade);
if (CustomElementRegistrationContext* context = element->document()->registrationContext())
context->didGiveTypeExtension(element, type);
diff --git a/Source/core/dom/CustomElementRegistrationContext.h b/Source/core/dom/CustomElementRegistrationContext.h
index 64099d3..7b8449f 100644
--- a/Source/core/dom/CustomElementRegistrationContext.h
+++ b/Source/core/dom/CustomElementRegistrationContext.h
@@ -54,15 +54,17 @@
~CustomElementRegistrationContext() { }
// Definitions
- void registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& type, ExceptionState&);
+ void registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& type, CustomElement::NameSet validNames, ExceptionState&);
// Instance creation
- PassRefPtr<Element> createCustomTagElement(Document*, const QualifiedName&);
- static void setIsAttributeAndTypeExtension(Element*, const AtomicString& type);
- static void setTypeExtension(Element*, const AtomicString& type);
+ enum CreationMode {
+ CreatedByParser,
+ NotCreatedByParser
+ };
- // Instance lifecycle
- void customElementWasDestroyed(Element*);
+ PassRefPtr<Element> createCustomTagElement(Document*, const QualifiedName&, CreationMode = NotCreatedByParser);
+ static void setIsAttributeAndTypeExtension(Element*, const AtomicString& type);
+ static void setTypeExtension(Element*, const AtomicString& type, CreationMode = NotCreatedByParser);
protected:
CustomElementRegistrationContext() { }
diff --git a/Source/core/dom/CustomElementRegistry.cpp b/Source/core/dom/CustomElementRegistry.cpp
index 9d9195c..b734c82 100644
--- a/Source/core/dom/CustomElementRegistry.cpp
+++ b/Source/core/dom/CustomElementRegistry.cpp
@@ -34,12 +34,11 @@
#include "HTMLNames.h"
#include "SVGNames.h"
#include "bindings/v8/CustomElementConstructorBuilder.h"
-#include "bindings/v8/ExceptionState.h"
#include "core/dom/CustomElement.h"
#include "core/dom/CustomElementDefinition.h"
+#include "core/dom/CustomElementException.h"
#include "core/dom/CustomElementRegistrationContext.h"
#include "core/dom/DocumentLifecycleObserver.h"
-#include "core/dom/ExceptionCode.h"
namespace WebCore {
@@ -59,7 +58,7 @@
bool m_wentAway;
};
-CustomElementDefinition* CustomElementRegistry::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& userSuppliedName, ExceptionState& es)
+CustomElementDefinition* CustomElementRegistry::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& userSuppliedName, CustomElement::NameSet validNames, ExceptionState& es)
{
// FIXME: In every instance except one it is the
// CustomElementConstructorBuilder that observes document
@@ -67,31 +66,30 @@
// consolidated in one place.
RegistrationContextObserver observer(document);
- if (!constructorBuilder->isFeatureAllowed()) {
- es.throwDOMException(NotSupportedError);
- return 0;
- }
-
AtomicString type = userSuppliedName.lower();
- if (!CustomElement::isValidTypeName(type)) {
- es.throwDOMException(InvalidCharacterError);
+
+ if (!constructorBuilder->isFeatureAllowed()) {
+ CustomElementException::throwException(CustomElementException::CannotRegisterFromExtension, type, es);
return 0;
}
- if (!constructorBuilder->validateOptions()) {
- es.throwDOMException(InvalidStateError);
+ if (!CustomElement::isValidName(type, validNames)) {
+ CustomElementException::throwException(CustomElementException::InvalidName, type, es);
return 0;
}
+ if (!constructorBuilder->validateOptions(type, es))
+ return 0;
+
QualifiedName tagName = nullQName();
if (!constructorBuilder->findTagName(type, tagName)) {
- es.throwDOMException(NamespaceError);
+ CustomElementException::throwException(CustomElementException::PrototypeDoesNotExtendHTMLElementSVGElementNamespace, type, es);
return 0;
}
ASSERT(tagName.namespaceURI() == HTMLNames::xhtmlNamespaceURI || tagName.namespaceURI() == SVGNames::svgNamespaceURI);
if (m_registeredTypeNames.contains(type)) {
- es.throwDOMException(InvalidStateError);
+ CustomElementException::throwException(CustomElementException::TypeAlreadyRegistered, type, es);
return 0;
}
@@ -102,23 +100,21 @@
// Consulting the constructor builder could execute script and
// kill the document.
if (observer.registrationContextWentAway()) {
- es.throwDOMException(InvalidStateError);
+ CustomElementException::throwException(CustomElementException::ContextDestroyedCreatingCallbacks, type, es);
return 0;
}
const CustomElementDescriptor descriptor(type, tagName.namespaceURI(), tagName.localName());
RefPtr<CustomElementDefinition> definition = CustomElementDefinition::create(descriptor, lifecycleCallbacks);
- if (!constructorBuilder->createConstructor(document, definition.get())) {
- es.throwDOMException(NotSupportedError);
+ if (!constructorBuilder->createConstructor(document, definition.get(), es))
return 0;
- }
m_definitions.add(descriptor, definition);
m_registeredTypeNames.add(descriptor.type());
if (!constructorBuilder->didRegisterDefinition(definition.get())) {
- es.throwDOMException(NotSupportedError);
+ CustomElementException::throwException(CustomElementException::ContextDestroyedRegisteringDefinition, type, es);
return 0;
}
diff --git a/Source/core/dom/CustomElementRegistry.h b/Source/core/dom/CustomElementRegistry.h
index c9ff8db..d1a79bd 100644
--- a/Source/core/dom/CustomElementRegistry.h
+++ b/Source/core/dom/CustomElementRegistry.h
@@ -31,6 +31,7 @@
#ifndef CustomElementRegistry_h
#define CustomElementRegistry_h
+#include "core/dom/CustomElement.h"
#include "core/dom/CustomElementDefinition.h"
#include "core/dom/CustomElementDescriptor.h"
#include "core/dom/CustomElementDescriptorHash.h"
@@ -54,7 +55,7 @@
CustomElementRegistry() { }
virtual ~CustomElementRegistry() { }
- CustomElementDefinition* registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& name, ExceptionState&);
+ CustomElementDefinition* registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& name, CustomElement::NameSet validNames, ExceptionState&);
CustomElementDefinition* find(const CustomElementDescriptor&) const;
private:
diff --git a/Source/core/dom/CustomElementUpgradeCandidateMap.cpp b/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
index c84bcb7..8583eb2 100644
--- a/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
+++ b/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
@@ -39,14 +39,12 @@
{
UpgradeCandidateMap::const_iterator::Keys end = m_upgradeCandidates.end().keys();
for (UpgradeCandidateMap::const_iterator::Keys it = m_upgradeCandidates.begin().keys(); it != end; ++it)
- unregisterForElementDestructionNotification(*it, this);
+ unobserve(*it);
}
void CustomElementUpgradeCandidateMap::add(const CustomElementDescriptor& descriptor, Element* element)
{
- element->setCustomElementState(Element::UpgradeCandidate);
-
- registerForElementDestructionNotification(element, this);
+ observe(element);
UpgradeCandidateMap::AddResult result = m_upgradeCandidates.add(element, descriptor);
ASSERT(result.isNewEntry);
@@ -59,8 +57,18 @@
void CustomElementUpgradeCandidateMap::remove(Element* element)
{
- unregisterForElementDestructionNotification(element, this);
+ unobserve(element);
+ removeCommon(element);
+}
+void CustomElementUpgradeCandidateMap::elementWasDestroyed(Element* element)
+{
+ CustomElementObserver::elementWasDestroyed(element);
+ removeCommon(element);
+}
+
+void CustomElementUpgradeCandidateMap::removeCommon(Element* element)
+{
UpgradeCandidateMap::iterator candidate = m_upgradeCandidates.find(element);
ASSERT(candidate != m_upgradeCandidates.end());
@@ -70,42 +78,33 @@
m_upgradeCandidates.remove(candidate);
}
+void CustomElementUpgradeCandidateMap::elementDidFinishParsingChildren(Element* element)
+{
+ // An upgrade candidate finished parsing; reorder so that eventual
+ // upgrade order matches finished-parsing order.
+ moveToEnd(element);
+}
+
+void CustomElementUpgradeCandidateMap::moveToEnd(Element* element)
+{
+ UpgradeCandidateMap::iterator candidate = m_upgradeCandidates.find(element);
+ ASSERT(candidate != m_upgradeCandidates.end());
+
+ UnresolvedDefinitionMap::iterator elements = m_unresolvedDefinitions.find(candidate->value);
+ ASSERT(elements != m_unresolvedDefinitions.end());
+ elements->value.appendOrMoveToLast(element);
+}
+
ListHashSet<Element*> CustomElementUpgradeCandidateMap::takeUpgradeCandidatesFor(const CustomElementDescriptor& descriptor)
{
const ListHashSet<Element*>& candidates = m_unresolvedDefinitions.take(descriptor);
for (ElementSet::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate) {
- unregisterForElementDestructionNotification(*candidate, this);
+ unobserve(*candidate);
m_upgradeCandidates.remove(*candidate);
}
return candidates;
}
-void CustomElementUpgradeCandidateMap::elementWasDestroyed(Element* element)
-{
- DestructionObserverMap::iterator it = destructionObservers().find(element);
- if (it == destructionObservers().end())
- return;
- it->value->remove(element); // will also remove the destruction observer
-}
-
-CustomElementUpgradeCandidateMap::DestructionObserverMap& CustomElementUpgradeCandidateMap::destructionObservers()
-{
- DEFINE_STATIC_LOCAL(DestructionObserverMap, map, ());
- return map;
-}
-
-void CustomElementUpgradeCandidateMap::registerForElementDestructionNotification(Element* element, CustomElementUpgradeCandidateMap* observer)
-{
- DestructionObserverMap::AddResult result = destructionObservers().add(element, observer);
- ASSERT(result.isNewEntry);
-}
-
-void CustomElementUpgradeCandidateMap::unregisterForElementDestructionNotification(Element* element, CustomElementUpgradeCandidateMap* observer)
-{
- CustomElementUpgradeCandidateMap* map = destructionObservers().take(element);
- ASSERT(map == observer);
-}
-
}
diff --git a/Source/core/dom/CustomElementUpgradeCandidateMap.h b/Source/core/dom/CustomElementUpgradeCandidateMap.h
index 2814c0a..f9f2311 100644
--- a/Source/core/dom/CustomElementUpgradeCandidateMap.h
+++ b/Source/core/dom/CustomElementUpgradeCandidateMap.h
@@ -33,6 +33,7 @@
#include "core/dom/CustomElementDescriptor.h"
#include "core/dom/CustomElementDescriptorHash.h"
+#include "core/dom/CustomElementObserver.h"
#include "wtf/HashMap.h"
#include "wtf/ListHashSet.h"
#include "wtf/Noncopyable.h"
@@ -41,26 +42,26 @@
class Element;
-class CustomElementUpgradeCandidateMap {
+class CustomElementUpgradeCandidateMap : CustomElementObserver {
WTF_MAKE_NONCOPYABLE(CustomElementUpgradeCandidateMap);
public:
CustomElementUpgradeCandidateMap() { }
~CustomElementUpgradeCandidateMap();
- static void elementWasDestroyed(Element*);
+ // API for CustomElementRegistrationContext to save and take candidates
+
+ typedef ListHashSet<Element*> ElementSet;
void add(const CustomElementDescriptor&, Element*);
void remove(Element*);
-
- typedef ListHashSet<Element*> ElementSet;
ElementSet takeUpgradeCandidatesFor(const CustomElementDescriptor&);
private:
- // Maps elements to upgrade candidate maps observing their destruction
- typedef HashMap<Element*, CustomElementUpgradeCandidateMap*> DestructionObserverMap;
- static DestructionObserverMap& destructionObservers();
- static void registerForElementDestructionNotification(Element*, CustomElementUpgradeCandidateMap*);
- static void unregisterForElementDestructionNotification(Element*, CustomElementUpgradeCandidateMap*);
+ virtual void elementWasDestroyed(Element*) OVERRIDE;
+ void removeCommon(Element*);
+
+ virtual void elementDidFinishParsingChildren(Element*) OVERRIDE;
+ void moveToEnd(Element*);
typedef HashMap<Element*, CustomElementDescriptor> UpgradeCandidateMap;
UpgradeCandidateMap m_upgradeCandidates;
diff --git a/Source/core/dom/DOMError.h b/Source/core/dom/DOMError.h
index 74d4d17..a66d0e2 100644
--- a/Source/core/dom/DOMError.h
+++ b/Source/core/dom/DOMError.h
@@ -59,10 +59,11 @@
const String& name() const { return m_name; }
const String& message() const { return m_message; }
-private:
+protected:
explicit DOMError(const String& name);
- explicit DOMError(const String& name, const String& message);
+ DOMError(const String& name, const String& message);
+private:
const String m_name;
const String m_message;
};
diff --git a/Source/core/dom/DOMException.cpp b/Source/core/dom/DOMException.cpp
index 7510e27..348a94e 100644
--- a/Source/core/dom/DOMException.cpp
+++ b/Source/core/dom/DOMException.cpp
@@ -86,22 +86,24 @@
return tableIndex < tableSize ? &coreExceptions[tableIndex] : 0;
}
-DOMException::DOMException(unsigned short code, const String& name, const String& message)
+DOMException::DOMException(unsigned short code, const String& name, const String& sanitizedMessage, const String& unsanitizedMessage)
{
ASSERT(name);
m_code = code;
m_name = name;
- m_message = message;
+ m_sanitizedMessage = sanitizedMessage;
+ m_unsanitizedMessage = unsanitizedMessage;
ScriptWrappable::init(this);
}
-PassRefPtr<DOMException> DOMException::create(ExceptionCode ec, const String& message)
+PassRefPtr<DOMException> DOMException::create(ExceptionCode ec, const String& sanitizedMessage, const String& unsanitizedMessage)
{
const CoreException* entry = getErrorEntry(ec);
ASSERT(entry);
return adoptRef(new DOMException(entry->code,
entry->name ? entry->name : "Error",
- message.isNull() ? String(entry->message) : message));
+ sanitizedMessage.isNull() ? String(entry->message) : sanitizedMessage,
+ unsanitizedMessage));
}
String DOMException::toString() const
@@ -109,6 +111,11 @@
return name() + ": " + message();
}
+String DOMException::toStringForConsole() const
+{
+ return name() + ": " + messageForConsole();
+}
+
String DOMException::getErrorName(ExceptionCode ec)
{
const CoreException* entry = getErrorEntry(ec);
diff --git a/Source/core/dom/DOMException.h b/Source/core/dom/DOMException.h
index ca96483..825cf50 100644
--- a/Source/core/dom/DOMException.h
+++ b/Source/core/dom/DOMException.h
@@ -40,24 +40,30 @@
class DOMException : public RefCounted<DOMException>, public ScriptWrappable {
public:
- static PassRefPtr<DOMException> create(ExceptionCode, const String& message = String());
+ static PassRefPtr<DOMException> create(ExceptionCode, const String& sanitizedMessage = String(), const String& unsanitizedMessage = String());
unsigned short code() const { return m_code; }
String name() const { return m_name; }
- String message() const { return m_message; }
+ // This is the message that's exposed to JavaScript: never return unsanitized data.
+ String message() const { return m_sanitizedMessage; }
String toString() const;
+ // This is the message that's exposed to the console: if an unsanitized message is present, we prefer it.
+ String messageForConsole() const { return !m_unsanitizedMessage.isEmpty() ? m_unsanitizedMessage : m_sanitizedMessage; }
+ String toStringForConsole() const;
+
static String getErrorName(ExceptionCode);
static String getErrorMessage(ExceptionCode);
static unsigned short getLegacyErrorCode(ExceptionCode);
private:
- DOMException(unsigned short m_code, const String& name, const String& message);
+ DOMException(unsigned short m_code, const String& name, const String& sanitizedMessage, const String& unsanitizedMessage);
unsigned short m_code;
String m_name;
- String m_message;
+ String m_sanitizedMessage;
+ String m_unsanitizedMessage;
};
} // namespace WebCore
diff --git a/Source/core/dom/DOMImplementation.cpp b/Source/core/dom/DOMImplementation.cpp
index 14c51fe..3b888bc 100644
--- a/Source/core/dom/DOMImplementation.cpp
+++ b/Source/core/dom/DOMImplementation.cpp
@@ -184,7 +184,7 @@
if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
return 0;
- return DocumentType::create(0, qualifiedName, publicId, systemId);
+ return DocumentType::create(m_document, qualifiedName, publicId, systemId);
}
DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/)
@@ -213,16 +213,6 @@
return 0;
}
- // WrongDocumentError: Raised if doctype has already been used with a different document or was
- // created from a different implementation.
- // Hixie's interpretation of the DOM Core spec suggests we should prefer
- // other exceptions to WrongDocumentError (based on order mentioned in spec),
- // but this matches the new DOM Core spec (http://www.w3.org/TR/domcore/).
- if (doctype && doctype->document()) {
- es.throwDOMException(WrongDocumentError);
- return 0;
- }
-
if (doctype)
doc->appendChild(doctype);
if (documentElement)
diff --git a/Source/core/dom/DOMImplementation.idl b/Source/core/dom/DOMImplementation.idl
index 0d627f5..c110cb4 100644
--- a/Source/core/dom/DOMImplementation.idl
+++ b/Source/core/dom/DOMImplementation.idl
@@ -29,12 +29,12 @@
// DOM Level 2
- [RaisesException] DocumentType createDocumentType([TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString qualifiedName,
- [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString publicId,
- [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString systemId);
- [RaisesException] Document createDocument([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
- [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName,
- [TreatNullAs=NullString,Default=Undefined] optional DocumentType doctype);
+ [RaisesException] DocumentType createDocumentType([TreatNullAs=NullString] DOMString qualifiedName,
+ [TreatNullAs=NullString] DOMString publicId,
+ [TreatNullAs=NullString] DOMString systemId);
+ [RaisesException] Document createDocument([TreatNullAs=NullString] DOMString namespaceURI,
+ [TreatNullAs=NullString] DOMString qualifiedName,
+ [Default=Undefined] optional DocumentType doctype);
// DOMImplementationCSS interface from DOM Level 2 CSS
diff --git a/Source/core/dom/DataTransferItemList.h b/Source/core/dom/DataTransferItemList.h
index 91fd967..90d847f 100644
--- a/Source/core/dom/DataTransferItemList.h
+++ b/Source/core/dom/DataTransferItemList.h
@@ -56,8 +56,8 @@
virtual PassRefPtr<DataTransferItem> item(unsigned long index) = 0;
virtual void deleteItem(unsigned long index, ExceptionState&) = 0;
virtual void clear() = 0;
- virtual void add(const String& data, const String& type, ExceptionState&) = 0;
- virtual void add(PassRefPtr<File>) = 0;
+ virtual PassRefPtr<DataTransferItem> add(const String& data, const String& type, ExceptionState&) = 0;
+ virtual PassRefPtr<DataTransferItem> add(PassRefPtr<File>) = 0;
};
} // namespace WebCore
diff --git a/Source/core/dom/DataTransferItemList.idl b/Source/core/dom/DataTransferItemList.idl
index eec5c0c..0babe03 100644
--- a/Source/core/dom/DataTransferItemList.idl
+++ b/Source/core/dom/DataTransferItemList.idl
@@ -28,15 +28,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-[
- NoInterfaceObject
-] interface DataTransferItemList {
+interface DataTransferItemList {
readonly attribute long length;
- getter DataTransferItem item([Default=Undefined] optional unsigned long index);
+ [ImplementedAs=item] getter DataTransferItem (unsigned long index);
+ [RaisesException, ImplementedAs=deleteItem] void remove(unsigned long index);
void clear();
- void add(File? file);
- [RaisesException] void add([Default=Undefined] optional DOMString data,
- [Default=Undefined] optional DOMString type);
+ DataTransferItem add(File? file);
+ [RaisesException] DataTransferItem add(DOMString data, DOMString type);
};
diff --git a/Source/core/dom/Document.cpp b/Source/core/dom/Document.cpp
index 62dee7a..9dfe1b6 100644
--- a/Source/core/dom/Document.cpp
+++ b/Source/core/dom/Document.cpp
@@ -37,6 +37,7 @@
#include "XMLNames.h"
#include "bindings/v8/CustomElementConstructorBuilder.h"
#include "bindings/v8/Dictionary.h"
+#include "bindings/v8/ExceptionMessages.h"
#include "bindings/v8/ExceptionState.h"
#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "bindings/v8/ScriptController.h"
@@ -51,10 +52,10 @@
#include "core/css/StyleSheetList.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/dom/Attr.h"
+#include "core/dom/BeforeUnloadEvent.h"
#include "core/dom/CDATASection.h"
#include "core/dom/Comment.h"
#include "core/dom/ContextFeatures.h"
-#include "core/dom/CustomElement.h"
#include "core/dom/CustomElementRegistrationContext.h"
#include "core/dom/DOMImplementation.h"
#include "core/dom/DOMNamedFlowCollection.h"
@@ -66,6 +67,7 @@
#include "core/dom/DocumentStyleSheetCollection.h"
#include "core/dom/DocumentType.h"
#include "core/dom/Element.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/Event.h"
#include "core/dom/EventFactory.h"
#include "core/dom/EventListener.h"
@@ -97,6 +99,7 @@
#include "core/dom/shadow/ShadowRoot.h"
#include "core/editing/Editor.h"
#include "core/editing/FrameSelection.h"
+#include "core/fetch/ResourceFetcher.h"
#include "core/html/FormController.h"
#include "core/html/HTMLAllCollection.h"
#include "core/html/HTMLAnchorElement.h"
@@ -108,6 +111,7 @@
#include "core/html/HTMLHtmlElement.h"
#include "core/html/HTMLIFrameElement.h"
#include "core/html/HTMLImport.h"
+#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLLinkElement.h"
#include "core/html/HTMLNameCollection.h"
#include "core/html/HTMLScriptElement.h"
@@ -128,7 +132,6 @@
#include "core/loader/Prerenderer.h"
#include "core/loader/TextResourceDecoder.h"
#include "core/loader/appcache/ApplicationCacheHost.h"
-#include "core/loader/cache/ResourceFetcher.h"
#include "core/page/Chrome.h"
#include "core/page/ChromeClient.h"
#include "core/page/ContentSecurityPolicy.h"
@@ -144,7 +147,6 @@
#include "core/page/PageConsole.h"
#include "core/page/PointerLockController.h"
#include "core/page/Settings.h"
-#include "core/page/ValidationMessageClient.h"
#include "core/page/animation/AnimationController.h"
#include "core/page/scrolling/ScrollingCoordinator.h"
#include "core/platform/DateComponents.h"
@@ -401,7 +403,6 @@
, m_bParsing(false)
, m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
, m_inStyleRecalc(false)
- , m_closeAfterStyleRecalc(false)
, m_gotoAnchorNeededAfterStylesheetsLoad(false)
, m_containsValidityStyleRules(false)
, m_updateFocusAppearanceRestoresSelection(false)
@@ -435,6 +436,7 @@
, m_referrerPolicy(ReferrerPolicyDefault)
, m_directionSetOnDocumentElement(false)
, m_writingModeSetOnDocumentElement(false)
+ , m_didAllowNavigationViaBeforeUnloadConfirmationPanel(false)
, m_writeRecursionIsTooDeep(false)
, m_writeRecursionDepth(0)
, m_wheelEventHandlerCount(0)
@@ -715,7 +717,7 @@
RefPtr<Element> element;
- if (CustomElement::isCustomTagName(localName) && registrationContext())
+ if (CustomElement::isValidName(localName) && registrationContext())
element = registrationContext()->createCustomTagElement(this, QualifiedName(nullAtom, localName, xhtmlNamespaceURI));
else
element = createElement(localName, es);
@@ -739,7 +741,7 @@
}
RefPtr<Element> element;
- if (CustomElement::isCustomTagName(qName.localName()) && registrationContext())
+ if (CustomElement::isValidName(qName.localName()) && registrationContext())
element = registrationContext()->createCustomTagElement(this, qName);
else
element = createElementNS(namespaceURI, qualifiedName, es);
@@ -755,7 +757,7 @@
return registerElement(state, name, Dictionary(), es);
}
-ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& es)
+ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& es, CustomElement::NameSet validNames)
{
if (!registrationContext()) {
es.throwDOMException(NotSupportedError);
@@ -763,7 +765,7 @@
}
CustomElementConstructorBuilder constructorBuilder(state, &options);
- registrationContext()->registerElement(this, &constructorBuilder, name, es);
+ registrationContext()->registerElement(this, &constructorBuilder, name, validNames, es);
return constructorBuilder.bindingsReturnValue();
}
@@ -939,7 +941,7 @@
}
if (source->isFrameOwnerElement()) {
- HTMLFrameOwnerElement* frameOwnerElement = toFrameOwnerElement(source.get());
+ HTMLFrameOwnerElement* frameOwnerElement = toHTMLFrameOwnerElement(source.get());
if (frame() && frame()->tree()->isDescendantOf(frameOwnerElement->contentFrame())) {
es.throwDOMException(HierarchyRequestError);
return 0;
@@ -1082,8 +1084,11 @@
switch (readyState) {
case Loading:
- if (!m_documentTiming.domLoading)
+ if (!m_documentTiming.domLoading) {
m_documentTiming.domLoading = monotonicallyIncreasingTime();
+ if (RuntimeEnabledFeatures::webAnimationsEnabled())
+ m_timeline->setZeroTimeAsPerfTime(m_documentTiming.domLoading);
+ }
break;
case Interactive:
if (!m_documentTiming.domInteractive)
@@ -1293,6 +1298,7 @@
m_rawTitle = title;
+ StringWithDirection oldTitle = m_title;
if (m_rawTitle.string().isEmpty())
m_title = StringWithDirection();
else {
@@ -1301,8 +1307,11 @@
else
m_title = canonicalizedTitle<UChar>(this, m_rawTitle);
}
- if (Frame* f = frame())
- f->loader()->setTitle(m_title);
+
+ if (!m_frame || oldTitle == m_title)
+ return;
+ m_frame->loader()->history()->setCurrentItemTitle(m_title);
+ m_frame->loader()->client()->dispatchDidReceiveTitle(m_title);
}
void Document::setTitle(const String& title)
@@ -1314,7 +1323,7 @@
else if (!m_titleElement) {
if (HTMLElement* headElement = head()) {
m_titleElement = createElement(titleTag, false);
- headElement->appendChild(m_titleElement, ASSERT_NO_EXCEPTION, AttachLazily);
+ headElement->appendChild(m_titleElement);
}
}
@@ -1680,12 +1689,6 @@
}
}
- // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
- if (m_closeAfterStyleRecalc) {
- m_closeAfterStyleRecalc = false;
- implicitClose();
- }
-
STYLE_STATS_PRINT();
STYLE_STATS_CLEAR();
@@ -1888,11 +1891,8 @@
{
ASSERT(attached());
- if (page()) {
- page()->pointerLockController()->documentDetached(this);
- if (ValidationMessageClient* client = page()->validationMessageClient())
- client->documentDetached(*this);
- }
+ if (page())
+ page()->documentDetached(this);
if (this == topDocument())
clearAXObjectCache();
@@ -1953,6 +1953,12 @@
void Document::prepareForDestruction()
{
disconnectDescendantFrames();
+
+ // The process of disconnecting descendant frames could have already
+ // detached us.
+ if (!attached())
+ return;
+
if (DOMWindow* window = this->domWindow())
window->willDetachDocumentFromFrame();
detach();
@@ -2122,7 +2128,7 @@
// collection update in order to ensure they inherit all the relevant data
// from their parent.
if (shouldDisplaySeamlesslyWithParent())
- styleResolverChanged(DeferRecalcStyle);
+ styleResolverChanged(RecalcStyleDeferred);
m_parser = createParser();
setParsing(true);
@@ -2163,9 +2169,9 @@
return;
if (oldBody)
- documentElement()->replaceChild(newBody.release(), oldBody, es, AttachLazily);
+ documentElement()->replaceChild(newBody.release(), oldBody, es);
else
- documentElement()->appendChild(newBody.release(), es, AttachLazily);
+ documentElement()->appendChild(newBody.release(), es);
}
HTMLHeadElement* Document::head()
@@ -2210,11 +2216,7 @@
void Document::implicitClose()
{
- // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached.
- if (m_inStyleRecalc) {
- m_closeAfterStyleRecalc = true;
- return;
- }
+ ASSERT(!inStyleRecalc());
bool wasLocationChangePending = frame() && frame()->navigationScheduler()->locationChangePending();
bool doload = !parsing() && m_parser && !processingLoadEvent() && !wasLocationChangePending;
@@ -2322,6 +2324,95 @@
accessSVGExtensions()->startAnimations();
}
+bool Document::dispatchBeforeUnloadEvent(Chrome& chrome, Document* navigatingDocument)
+{
+ if (!m_domWindow)
+ return true;
+
+ if (!body())
+ return true;
+
+ RefPtr<Document> protect(this);
+
+ RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+ m_loadEventProgress = BeforeUnloadEventInProgress;
+ dispatchWindowEvent(beforeUnloadEvent.get(), this);
+ m_loadEventProgress = BeforeUnloadEventCompleted;
+ if (!beforeUnloadEvent->defaultPrevented())
+ defaultEventHandler(beforeUnloadEvent.get());
+ if (beforeUnloadEvent->result().isNull())
+ return true;
+
+ if (navigatingDocument->m_didAllowNavigationViaBeforeUnloadConfirmationPanel) {
+ addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation.");
+ return true;
+ }
+
+ String text = displayStringModifiedByEncoding(beforeUnloadEvent->result());
+ if (chrome.runBeforeUnloadConfirmPanel(text, m_frame)) {
+ navigatingDocument->m_didAllowNavigationViaBeforeUnloadConfirmationPanel = true;
+ return true;
+ }
+ return false;
+}
+
+void Document::dispatchUnloadEvents()
+{
+ RefPtr<Document> protect(this);
+ if (m_parser)
+ m_parser->stopParsing();
+
+ if (m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress) {
+ Element* currentFocusedElement = focusedElement();
+ if (currentFocusedElement && currentFocusedElement->hasTagName(inputTag))
+ toHTMLInputElement(currentFocusedElement)->endEditing();
+ if (m_loadEventProgress < PageHideInProgress) {
+ m_loadEventProgress = PageHideInProgress;
+ dispatchWindowEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), this);
+ if (!m_frame)
+ return;
+
+ // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
+ // while dispatching the event, so protect it to prevent writing the end
+ // time into freed memory.
+ RefPtr<DocumentLoader> documentLoader = m_frame->loader()->provisionalDocumentLoader();
+ m_loadEventProgress = UnloadEventInProgress;
+ RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
+ if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
+ DocumentLoadTiming* timing = documentLoader->timing();
+ ASSERT(timing->navigationStart());
+ timing->markUnloadEventStart();
+ dispatchWindowEvent(unloadEvent, this);
+ timing->markUnloadEventEnd();
+ } else {
+ m_frame->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
+ }
+ }
+ updateStyleIfNeeded();
+ m_loadEventProgress = UnloadEventHandled;
+ }
+
+ if (!m_frame)
+ return;
+
+ // Don't remove event listeners from a transitional empty document (see https://bugs.webkit.org/show_bug.cgi?id=28716 for more information).
+ bool keepEventListeners = m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader()->provisionalDocumentLoader()
+ && isSecureTransitionTo(m_frame->loader()->provisionalDocumentLoader()->url());
+ if (!keepEventListeners)
+ removeAllEventListeners();
+}
+
+Document::PageDismissalType Document::pageDismissalEventBeingDispatched() const
+{
+ if (m_loadEventProgress == BeforeUnloadEventInProgress)
+ return BeforeUnloadDismissal;
+ if (m_loadEventProgress == PageHideInProgress)
+ return PageHideDismissal;
+ if (m_loadEventProgress == UnloadEventInProgress)
+ return UnloadDismissal;
+ return NoDismissal;
+}
+
void Document::setParsing(bool b)
{
m_bParsing = b;
@@ -2424,7 +2515,7 @@
void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack)
{
- addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack);
+ internalAddMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack, 0);
}
void Document::setURL(const KURL& url)
@@ -2613,6 +2704,7 @@
void Document::seamlessParentUpdatedStylesheets()
{
+ m_styleSheetCollection->didModifySeamlessParentStyleSheet();
styleResolverChanged(RecalcStyleImmediately);
}
@@ -2690,7 +2782,7 @@
// -dwh
m_styleSheetCollection->setSelectedStylesheetSetName(content);
m_styleSheetCollection->setPreferredStylesheetSetName(content);
- styleResolverChanged(DeferRecalcStyle);
+ styleResolverChanged(RecalcStyleDeferred);
}
void Document::processHttpEquivRefresh(const String& content)
@@ -2751,10 +2843,15 @@
// intent, we must navigate away from the possibly partially-rendered document to a location that
// doesn't inherit the parent's SecurityOrigin.
frame->navigationScheduler()->scheduleLocationChange(securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
- addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
+ addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
}
}
+static bool isInvalidSeparator(UChar c)
+{
+ return c == ';';
+}
+
// Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
static bool isSeparator(UChar c)
{
@@ -2763,6 +2860,8 @@
void Document::processArguments(const String& features, void* data, ArgumentsCallback callback)
{
+ bool error = false;
+
// Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
int keyBegin, keyEnd;
int valueBegin, valueEnd;
@@ -2780,12 +2879,15 @@
keyBegin = i;
// skip to first separator
- while (!isSeparator(buffer[i]))
+ while (!isSeparator(buffer[i])) {
+ error |= isInvalidSeparator(buffer[i]);
i++;
+ }
keyEnd = i;
// skip to first '=', but don't skip past a ',' or the end of the string
while (buffer[i] != '=') {
+ error |= isInvalidSeparator(buffer[i]);
if (buffer[i] == ',' || i >= length)
break;
i++;
@@ -2800,8 +2902,10 @@
valueBegin = i;
// skip to first separator
- while (!isSeparator(buffer[i]))
+ while (!isSeparator(buffer[i])) {
+ error |= isInvalidSeparator(buffer[i]);
i++;
+ }
valueEnd = i;
ASSERT_WITH_SECURITY_IMPLICATION(i <= length);
@@ -2810,6 +2914,8 @@
String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
callback(keyString, valueString, this, data);
}
+ if (error)
+ reportViewportWarning(this, InvalidKeyValuePairSeparatorError, String(), String());
}
void Document::processViewport(const String& features, ViewportArguments::Type origin)
@@ -2982,31 +3088,11 @@
return true;
}
-PassRefPtr<Node> Document::cloneNode(bool deep)
+PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
{
- RefPtr<Document> clone = cloneDocumentWithoutChildren();
- clone->cloneDataFromDocument(*this);
- if (deep)
- cloneChildNodes(clone.get());
- return clone.release();
-}
-
-PassRefPtr<Document> Document::cloneDocumentWithoutChildren()
-{
- return create();
-}
-
-void Document::cloneDataFromDocument(const Document& other)
-{
- m_url = other.url();
- m_baseURL = other.baseURL();
- m_baseURLOverride = other.baseURLOverride();
- m_documentURI = other.documentURI();
-
- setCompatibilityMode(other.compatibilityMode());
- setContextFeatures(other.contextFeatures());
- setSecurityOrigin(other.securityOrigin());
- setDecoder(other.decoder());
+ // Spec says cloning Document nodes is "implementation dependent"
+ // so we do not support it...
+ return 0;
}
StyleSheetList* Document::styleSheets()
@@ -3029,7 +3115,7 @@
void Document::setSelectedStylesheetSet(const String& aString)
{
m_styleSheetCollection->setSelectedStylesheetSetName(aString);
- styleResolverChanged(DeferRecalcStyle);
+ styleResolverChanged(RecalcStyleDeferred);
}
void Document::evaluateMediaQueryList()
@@ -3050,7 +3136,7 @@
bool needsRecalc = m_styleSheetCollection->updateActiveStyleSheets(updateMode);
- if (updateType >= DeferRecalcStyle) {
+ if (updateType >= RecalcStyleDeferred) {
setNeedsStyleRecalc();
return;
}
@@ -3276,7 +3362,7 @@
m_focusedElement->setFocus(true);
if (m_focusedElement->isRootEditableElement())
- frame()->editor()->didBeginEditing();
+ frame()->editor()->didBeginEditing(m_focusedElement.get());
// eww, I suck. set the qt focus correctly
// ### find a better place in the code for this
@@ -3571,7 +3657,7 @@
String Document::cookie(ExceptionState& es) const
{
- if (page() && !page()->settings()->cookieEnabled())
+ if (page() && !page()->settings().cookieEnabled())
return String();
// FIXME: The HTML5 DOM spec states that this attribute can raise an
@@ -3579,7 +3665,13 @@
// browsing context.
if (!securityOrigin()->canAccessCookies()) {
- es.throwDOMException(SecurityError);
+ String accessDeniedMessage = "Access to 'cookie' is denied for this document.";
+ if (isSandboxed(SandboxOrigin))
+ es.throwSecurityError(accessDeniedMessage + " The document is sandboxed and lacks the 'allow-same-origin' flag.");
+ else if (url().protocolIs("data"))
+ es.throwSecurityError(accessDeniedMessage + " Cookies are disabled inside 'data:' URLs.");
+ else
+ es.throwSecurityError(accessDeniedMessage);
return String();
}
@@ -3592,7 +3684,7 @@
void Document::setCookie(const String& value, ExceptionState& es)
{
- if (page() && !page()->settings()->cookieEnabled())
+ if (page() && !page()->settings().cookieEnabled())
return;
// FIXME: The HTML5 DOM spec states that this attribute can raise an
@@ -3600,7 +3692,13 @@
// browsing context.
if (!securityOrigin()->canAccessCookies()) {
- es.throwDOMException(SecurityError);
+ String accessDeniedMessage = "Access to 'cookie' is denied for this document.";
+ if (isSandboxed(SandboxOrigin))
+ es.throwSecurityError(accessDeniedMessage + " The document is sandboxed and lacks the 'allow-same-origin' flag.");
+ else if (url().protocolIs("data"))
+ es.throwSecurityError(accessDeniedMessage + " Cookies are disabled inside 'data:' URLs.");
+ else
+ es.throwSecurityError(accessDeniedMessage);
return;
}
@@ -3613,8 +3711,8 @@
String Document::referrer() const
{
- if (frame())
- return frame()->loader()->referrer();
+ if (loader())
+ return loader()->request().httpReferrer();
return String();
}
@@ -3626,7 +3724,7 @@
void Document::setDomain(const String& newDomain, ExceptionState& es)
{
if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) {
- es.throwDOMException(SecurityError, "'document.domain' assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme.");
+ es.throwSecurityError(ExceptionMessages::failedToSet("domain", "Document", "assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme."));
return;
}
@@ -3648,17 +3746,17 @@
int oldLength = domain().length();
int newLength = newDomain.length();
- String exceptionMessage = "'document.domain' assignment failed: '" + newDomain + "' is not a suffix of '" + domain() + "'.";
+ String exceptionMessage = ExceptionMessages::failedToSet("domain", "Document", "'" + newDomain + "' is not a suffix of '" + domain() + "'.");
// e.g. newDomain = subdomain.www.example.com (25) and domain() = www.example.com (15)
if (newLength >= oldLength) {
- es.throwDOMException(SecurityError, exceptionMessage);
+ es.throwSecurityError(exceptionMessage);
return;
}
String test = domain();
// Check that it's a complete suffix, not e.g. "ample.com"
if (test[oldLength - newLength - 1] != '.') {
- es.throwDOMException(SecurityError, exceptionMessage);
+ es.throwSecurityError(exceptionMessage);
return;
}
@@ -3666,7 +3764,7 @@
// and we check that it's the same thing as newDomain
test.remove(0, oldLength - newLength);
if (test != newDomain) {
- es.throwDOMException(SecurityError, exceptionMessage);
+ es.throwSecurityError(exceptionMessage);
return;
}
@@ -4447,18 +4545,34 @@
m_haveExplicitlyDisabledDNSPrefetch = true;
}
-void Document::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
+void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state)
{
- if (!isContextThread()) {
- postTask(AddConsoleMessageTask::create(source, level, message));
- return;
- }
-
- if (Page* page = this->page())
- page->console()->addMessage(source, level, message, requestIdentifier, this);
+ internalAddMessage(source, level, message, sourceURL, lineNumber, 0, state);
}
-void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state, unsigned long requestIdentifier)
+void Document::internalAddMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state)
+{
+ if (!isContextThread()) {
+ postTask(AddConsoleMessageTask::create(source, level, message));
+ return;
+ }
+ Page* page = this->page();
+ if (!page)
+ return;
+
+ String messageURL = sourceURL;
+ if (!state && sourceURL.isNull() && !lineNumber) {
+ messageURL = url().string();
+ if (parsing() && !isInDocumentWrite() && scriptableDocumentParser()) {
+ ScriptableDocumentParser* parser = scriptableDocumentParser();
+ if (!parser->isWaitingForScripts() && !parser->isExecutingScript())
+ lineNumber = parser->lineNumber().oneBasedInt();
+ }
+ }
+ page->console().addMessage(source, level, message, messageURL, lineNumber, 0, callStack, state, 0);
+}
+
+void Document::addConsoleMessageWithRequestIdentifier(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
{
if (!isContextThread()) {
postTask(AddConsoleMessageTask::create(source, level, message));
@@ -4466,7 +4580,7 @@
}
if (Page* page = this->page())
- page->console()->addMessage(source, level, message, sourceURL, lineNumber, 0, callStack, state, requestIdentifier);
+ page->console().addMessage(source, level, message, String(), 0, 0, 0, 0, requestIdentifier);
}
struct PerformTaskContext {
@@ -4632,18 +4746,18 @@
{
if (!page())
return;
- if (Element* target = page()->pointerLockController()->element()) {
+ if (Element* target = page()->pointerLockController().element()) {
if (target->document() != this)
return;
}
- page()->pointerLockController()->requestPointerUnlock();
+ page()->pointerLockController().requestPointerUnlock();
}
Element* Document::webkitPointerLockElement() const
{
- if (!page() || page()->pointerLockController()->lockPending())
+ if (!page() || page()->pointerLockController().lockPending())
return 0;
- if (Element* element = page()->pointerLockController()->element()) {
+ if (Element* element = page()->pointerLockController().element()) {
if (element->document() == this)
return element;
}
@@ -4752,7 +4866,7 @@
if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
scrollingCoordinator->touchEventTargetRectsDidChange(this);
if (m_touchEventTargets->size() == 1)
- page->chrome().client()->needTouchEvents(true);
+ page->chrome().client().needTouchEvents(true);
}
}
@@ -4760,7 +4874,9 @@
{
if (!m_touchEventTargets.get())
return;
- ASSERT(m_touchEventTargets->contains(handler));
+ // TODO(rbyers): Re-enable this ASSERT - http://crbug.com/254203.
+ // The known failure is benign, but the fix somehow causes a perf regression.
+ // ASSERT(m_touchEventTargets->contains(handler));
m_touchEventTargets->remove(handler);
if (Document* parent = parentDocument()) {
parent->didRemoveTouchEventHandler(this);
@@ -4778,17 +4894,14 @@
if (frame->document() && frame->document()->hasTouchEventHandlers())
return;
}
- page->chrome().client()->needTouchEvents(false);
+ page->chrome().client().needTouchEvents(false);
}
void Document::didRemoveEventTargetNode(Node* handler)
{
if (m_touchEventTargets) {
- if (handler == this)
- m_touchEventTargets->clear();
- else
- m_touchEventTargets->removeAll(handler);
- if (m_touchEventTargets->isEmpty() && parentDocument())
+ m_touchEventTargets->removeAll(handler);
+ if ((handler == this || m_touchEventTargets->isEmpty()) && parentDocument())
parentDocument()->didRemoveEventTargetNode(this);
}
}
@@ -5121,7 +5234,7 @@
Vector<RefPtr<Element> > associatedFormControls;
copyToVector(m_associatedFormControls, associatedFormControls);
- frame()->page()->chrome().client()->didAssociateFormControls(associatedFormControls);
+ frame()->page()->chrome().client().didAssociateFormControls(associatedFormControls);
m_associatedFormControls.clear();
}
diff --git a/Source/core/dom/Document.h b/Source/core/dom/Document.h
index cd90543..f0145de 100644
--- a/Source/core/dom/Document.h
+++ b/Source/core/dom/Document.h
@@ -30,6 +30,7 @@
#include "bindings/v8/ScriptValue.h"
#include "core/dom/ContainerNode.h"
+#include "core/dom/CustomElement.h"
#include "core/dom/DOMTimeStamp.h"
#include "core/dom/DocumentEventQueue.h"
#include "core/dom/DocumentInit.h"
@@ -67,6 +68,7 @@
class ScriptResource;
class CanvasRenderingContext;
class CharacterData;
+class Chrome;
class Comment;
class ContentSecurityPolicyResponseHeaders;
class ContextFeatures;
@@ -168,9 +170,7 @@
PageshowEventPersisted = 1
};
-// FIXME: We should rename DeferRecalcStyle to RecalcStyleDeferred to be consitent.
-
-enum StyleResolverUpdateType { RecalcStyleImmediately, DeferRecalcStyle };
+enum StyleResolverUpdateType { RecalcStyleImmediately, RecalcStyleDeferred };
enum StyleResolverUpdateMode {
// Discards the StyleResolver and rebuilds it.
@@ -259,6 +259,7 @@
DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
@@ -448,9 +449,9 @@
// FIXME: Switch all callers of styleResolverChanged to these or better ones and then make them
// do something smarter.
- void removedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
- void addedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
- void modifiedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
+ void removedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
+ void addedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
+ void modifiedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
void didAccessStyleResolver();
@@ -545,6 +546,17 @@
// implicitClose() actually does the work of closing the input stream.
void implicitClose();
+ bool dispatchBeforeUnloadEvent(Chrome&, Document* navigatingDocument);
+ void dispatchUnloadEvents();
+
+ enum PageDismissalType {
+ NoDismissal = 0,
+ BeforeUnloadDismissal = 1,
+ PageHideDismissal = 2,
+ UnloadDismissal = 3
+ };
+ PageDismissalType pageDismissalEventBeingDispatched() const;
+
void cancelParsing();
void write(const SegmentedString& text, Document* ownerDocument = 0);
@@ -754,6 +766,8 @@
String title() const { return m_title.string(); }
void setTitle(const String&);
+ const StringWithDirection& titleWithDirection() const { return m_title; }
+
Element* titleElement() const { return m_titleElement.get(); }
void setTitleElement(const StringWithDirection&, Element* titleElement);
void removeTitle(Element* titleElement);
@@ -914,15 +928,15 @@
LoadEventTried,
LoadEventInProgress,
LoadEventCompleted,
+ BeforeUnloadEventInProgress,
+ BeforeUnloadEventCompleted,
+ PageHideInProgress,
UnloadEventInProgress,
UnloadEventHandled
};
bool loadEventStillNeeded() const { return m_loadEventProgress == LoadEventNotRun; }
bool processingLoadEvent() const { return m_loadEventProgress == LoadEventInProgress; }
bool loadEventFinished() const { return m_loadEventProgress >= LoadEventCompleted; }
- bool unloadEventStillNeeded() const { return m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress; }
- void unloadEventStarted() { m_loadEventProgress = UnloadEventInProgress; }
- void unloadEventWasHandled() { m_loadEventProgress = UnloadEventHandled; }
virtual bool isContextThread() const;
virtual bool isJSExecutionForbidden() const { return false; }
@@ -994,7 +1008,8 @@
PassRefPtr<Element> createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState&);
PassRefPtr<Element> createElementNS(const AtomicString& namespaceURI, const String& qualifiedName, const AtomicString& typeExtension, ExceptionState&);
ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, ExceptionState&);
- ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, const Dictionary& options, ExceptionState&);
+ // FIXME: When embedders switch to using WebDocument::registerEmbedderCustomElement, make the default name set StandardNames.
+ ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, const Dictionary& options, ExceptionState&, CustomElement::NameSet validNames = CustomElement::AllNames);
CustomElementRegistrationContext* registrationContext() { return m_registrationContext.get(); }
void setImport(HTMLImport*);
@@ -1011,7 +1026,7 @@
void decrementActiveParserCount();
void setContextFeatures(PassRefPtr<ContextFeatures>);
- ContextFeatures* contextFeatures() const { return m_contextFeatures.get(); }
+ ContextFeatures* contextFeatures() { return m_contextFeatures.get(); }
DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
@@ -1039,7 +1054,7 @@
void didAssociateFormControl(Element*);
- virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0);
+ void addConsoleMessageWithRequestIdentifier(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier);
virtual DOMWindow* executingWindow() OVERRIDE { return domWindow(); }
virtual void userEventWasHandled() OVERRIDE { resetLastHandledUserGestureTimestamp(); }
@@ -1062,8 +1077,6 @@
virtual void dispose() OVERRIDE;
- virtual PassRefPtr<Document> cloneDocumentWithoutChildren();
-
private:
friend class Node;
friend class IgnoreDestructiveWriteCountIncrementer;
@@ -1083,7 +1096,6 @@
virtual NodeType nodeType() const;
virtual bool childTypeAllowed(NodeType) const;
virtual PassRefPtr<Node> cloneNode(bool deep = true);
- void cloneDataFromDocument(const Document&);
virtual void refScriptExecutionContext() { ref(); }
virtual void derefScriptExecutionContext() { deref(); }
@@ -1092,7 +1104,8 @@
virtual const KURL& virtualURL() const; // Same as url(), but needed for ScriptExecutionContext to implement it without a performance loss for direct calls.
virtual KURL virtualCompleteURL(const String&) const; // Same as completeURL() for the same reason as above.
- virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0);
+ virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState*);
+ void internalAddMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState*);
virtual double timerAlignmentInterval() const;
@@ -1226,7 +1239,6 @@
Timer<Document> m_styleRecalcTimer;
bool m_inStyleRecalc;
- bool m_closeAfterStyleRecalc;
bool m_gotoAnchorNeededAfterStylesheetsLoad;
bool m_isDNSPrefetchEnabled;
@@ -1317,6 +1329,8 @@
bool m_directionSetOnDocumentElement;
bool m_writingModeSetOnDocumentElement;
+ bool m_didAllowNavigationViaBeforeUnloadConfirmationPanel;
+
DocumentTiming m_documentTiming;
RefPtr<MediaQueryMatcher> m_mediaQueryMatcher;
bool m_writeRecursionIsTooDeep;
diff --git a/Source/core/dom/Document.idl b/Source/core/dom/Document.idl
index 0fc91ba..bea2b66 100644
--- a/Source/core/dom/Document.idl
+++ b/Source/core/dom/Document.idl
@@ -33,10 +33,10 @@
DocumentFragment createDocumentFragment();
[PerWorldBindings] Text createTextNode([Default=Undefined] optional DOMString data);
Comment createComment([Default=Undefined] optional DOMString data);
- [RaisesException] CDATASection createCDATASection([Default=Undefined] optional DOMString data);
+ [RaisesException, MeasureAs=DocumentCreateCDATASection] CDATASection createCDATASection([Default=Undefined] optional DOMString data); // Removed from DOM4.
[RaisesException] ProcessingInstruction createProcessingInstruction([Default=Undefined] optional DOMString target,
[Default=Undefined] optional DOMString data);
- [RaisesException] Attr createAttribute([Default=Undefined] optional DOMString name);
+ [RaisesException, MeasureAs=DocumentCreateAttribute] Attr createAttribute([Default=Undefined] optional DOMString name); // Removed from DOM4.
[PerWorldBindings] NodeList getElementsByTagName([Default=Undefined] optional DOMString tagname);
// Introduced in DOM Level 2:
@@ -45,19 +45,19 @@
optional boolean deep);
[CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElementNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
[TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName);
- [RaisesException] Attr createAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
- [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName);
+ [RaisesException, MeasureAs=DocumentCreateAttributeNS] Attr createAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
+ [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName); // Removed from DOM4.
NodeList getElementsByTagNameNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
[Default=Undefined] optional DOMString localName);
[PerWorldBindings] Element getElementById([Default=Undefined] optional DOMString elementId);
// DOM Level 3 Core
- [TreatReturnedNullStringAs=Null] readonly attribute DOMString inputEncoding;
+ [TreatReturnedNullStringAs=Null, MeasureAs=DocumentInputEncoding] readonly attribute DOMString inputEncoding; // Removed from DOM4.
- [TreatReturnedNullStringAs=Null] readonly attribute DOMString xmlEncoding;
- [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString xmlVersion;
- [SetterRaisesException] attribute boolean xmlStandalone;
+ [TreatReturnedNullStringAs=Null, MeasureAs=DocumentXMLEncoding] readonly attribute DOMString xmlEncoding; // Removed from DOM4.
+ [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException, MeasureAs=DocumentXMLVersion] attribute DOMString xmlVersion; // Removed from DOM4.
+ [SetterRaisesException, MeasureAs=DocumentXMLStandalone] attribute boolean xmlStandalone; // Removed from DOM4.
[RaisesException, CustomElementCallbacks=Enable] Node adoptNode([Default=Undefined] optional Node source);
@@ -133,9 +133,8 @@
[Custom, Replaceable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds] readonly attribute Location location;
// IE extensions
-
- [TreatReturnedNullStringAs=Undefined, TreatNullAs=NullString] attribute DOMString charset;
- [TreatReturnedNullStringAs=Undefined] readonly attribute DOMString defaultCharset;
+ [MeasureAs=DocumentCharset, TreatReturnedNullStringAs=Undefined, TreatNullAs=NullString] attribute DOMString charset;
+ [MeasureAs=DocumentCharset, TreatReturnedNullStringAs=Undefined] readonly attribute DOMString defaultCharset;
[TreatReturnedNullStringAs=Undefined] readonly attribute DOMString readyState;
Element elementFromPoint([Default=Undefined] optional long x,
@@ -199,7 +198,8 @@
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseout;
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseover;
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseup;
- [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel;
+ [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel; // Deprecated in favor of onwheel.
+ [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onwheel;
[NotEnumerable] attribute EventHandler onreadystatechange;
[NotEnumerable] attribute EventHandler onscroll;
[NotEnumerable] attribute EventHandler onselect;
@@ -261,8 +261,8 @@
[Default=Undefined] optional float webkitForce);
[EnabledAtRuntime=touch, Custom, RaisesException] TouchList createTouchList();
- [DeprecateAs=PrefixedDocumentRegister, EnabledAtRuntime=customDOMElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor webkitRegister(DOMString name, optional Dictionary options);
- [EnabledAtRuntime=customDOMElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor register(DOMString name, optional Dictionary options);
+ [DeprecateAs=PrefixedDocumentRegister, EnabledAtRuntime=customElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor webkitRegister(DOMString name, optional Dictionary options);
+ [EnabledAtRuntime=customElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor register(DOMString name, optional Dictionary options);
[CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElement(DOMString localName, [TreatNullAs=NullString] DOMString typeExtension);
[CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElementNS([TreatNullAs=NullString] DOMString namespaceURI, DOMString qualifiedName,
[TreatNullAs=NullString] DOMString typeExtension);
diff --git a/Source/core/dom/DocumentInit.cpp b/Source/core/dom/DocumentInit.cpp
index 8c508d4..caa4f8f 100644
--- a/Source/core/dom/DocumentInit.cpp
+++ b/Source/core/dom/DocumentInit.cpp
@@ -88,7 +88,7 @@
PassRefPtr<CustomElementRegistrationContext> DocumentInit::registrationContext(Document* document) const
{
- if (!RuntimeEnabledFeatures::customDOMElementsEnabled())
+ if (!RuntimeEnabledFeatures::customElementsEnabled() && !RuntimeEnabledFeatures::embedderCustomElementsEnabled())
return 0;
if (!document->isHTMLDocument() && !document->isXHTMLDocument())
diff --git a/Source/core/dom/DocumentMarkerController.cpp b/Source/core/dom/DocumentMarkerController.cpp
index c47e8b8..168772b 100644
--- a/Source/core/dom/DocumentMarkerController.cpp
+++ b/Source/core/dom/DocumentMarkerController.cpp
@@ -160,7 +160,7 @@
DocumentMarker marker = list->at(i);
if (marker.startOffset() > toInsert.startOffset())
break;
- if (marker.type() == toInsert.type() && marker.endOffset() >= toInsert.startOffset()) {
+ if (marker.type() == toInsert.type() && marker.type() != DocumentMarker::TextMatch && marker.endOffset() >= toInsert.startOffset()) {
toInsert.setStartOffset(marker.startOffset());
list->remove(i);
numMarkers--;
@@ -175,7 +175,7 @@
DocumentMarker marker = list->at(j);
if (marker.startOffset() > toInsert.endOffset())
break;
- if (marker.type() == toInsert.type()) {
+ if (marker.type() == toInsert.type() && marker.type() != DocumentMarker::TextMatch) {
list->remove(j);
if (toInsert.endOffset() <= marker.endOffset()) {
toInsert.setEndOffset(marker.endOffset());
@@ -608,7 +608,7 @@
break;
// Skip marker that is wrong type or before target.
- if (marker.endOffset() < startOffset || marker.type() != DocumentMarker::TextMatch)
+ if (marker.endOffset() <= startOffset || marker.type() != DocumentMarker::TextMatch)
continue;
marker.setActiveMatch(active);
diff --git a/Source/core/dom/DocumentOrderedMap.cpp b/Source/core/dom/DocumentOrderedMap.cpp
index ee4c389..bd58170 100644
--- a/Source/core/dom/DocumentOrderedMap.cpp
+++ b/Source/core/dom/DocumentOrderedMap.cpp
@@ -33,11 +33,10 @@
#include "HTMLNames.h"
#include "core/dom/Element.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/TreeScope.h"
#include "core/html/HTMLLabelElement.h"
#include "core/html/HTMLMapElement.h"
-#include "core/html/HTMLNameCollection.h"
namespace WebCore {
@@ -48,11 +47,6 @@
return element->getIdAttribute().impl() == key;
}
-inline bool keyMatchesName(StringImpl* key, Element* element)
-{
- return element->getNameAttribute().impl() == key;
-}
-
inline bool keyMatchesMapName(StringImpl* key, Element* element)
{
return element->hasTagName(mapTag) && toHTMLMapElement(element)->getName().impl() == key;
@@ -71,6 +65,7 @@
void DocumentOrderedMap::clear()
{
m_map.clear();
+ m_duplicateCounts.clear();
}
void DocumentOrderedMap::add(StringImpl* key, Element* element)
@@ -78,15 +73,29 @@
ASSERT(key);
ASSERT(element);
- Map::AddResult addResult = m_map.add(key, MapEntry(element));
- if (addResult.isNewEntry)
- return;
+ if (!m_duplicateCounts.contains(key)) {
+ // Fast path. The key is not already in m_duplicateCounts, so we assume that it's
+ // also not already in m_map and try to add it. If that add succeeds, we're done.
+ Map::AddResult addResult = m_map.add(key, element);
+ if (addResult.isNewEntry)
+ return;
- MapEntry& entry = addResult.iterator->value;
- ASSERT(entry.count);
- entry.element = 0;
- entry.count++;
- entry.orderedList.clear();
+ // The add failed, so this key was already cached in m_map.
+ // There are multiple elements with this key. Remove the m_map
+ // cache for this key so get searches for it next time it is called.
+ m_map.remove(addResult.iterator);
+ m_duplicateCounts.add(key);
+ } else {
+ // There are multiple elements with this key. Remove the m_map
+ // cache for this key so get will search for it next time it is called.
+ Map::iterator cachedItem = m_map.find(key);
+ if (cachedItem != m_map.end()) {
+ m_map.remove(cachedItem);
+ m_duplicateCounts.add(key);
+ }
+ }
+
+ m_duplicateCounts.add(key);
}
void DocumentOrderedMap::remove(StringImpl* key, Element* element)
@@ -94,20 +103,11 @@
ASSERT(key);
ASSERT(element);
- Map::iterator it = m_map.find(key);
- ASSERT(it != m_map.end());
- MapEntry& entry = it->value;
-
- ASSERT(entry.count);
- if (entry.count == 1) {
- ASSERT(!entry.element || entry.element == element);
- m_map.remove(it);
- } else {
- if (entry.element == element)
- entry.element = 0;
- entry.count--;
- entry.orderedList.clear(); // FIXME: Remove the element instead if there are only few items left.
- }
+ Map::iterator cachedItem = m_map.find(key);
+ if (cachedItem != m_map.end() && cachedItem->value == element)
+ m_map.remove(cachedItem);
+ else
+ m_duplicateCounts.remove(key);
}
template<bool keyMatches(StringImpl*, Element*)>
@@ -116,23 +116,22 @@
ASSERT(key);
ASSERT(scope);
- Map::iterator it = m_map.find(key);
- if (it == m_map.end())
- return 0;
-
- MapEntry& entry = it->value;
- ASSERT(entry.count);
- if (entry.element)
- return entry.element;
-
- // We know there's at least one node that matches; iterate to find the first one.
- for (Element* element = ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
- if (!keyMatches(key, element))
- continue;
- entry.element = element;
+ Element* element = m_map.get(key);
+ if (element)
return element;
+
+ if (m_duplicateCounts.contains(key)) {
+ // We know there's at least one node that matches; iterate to find the first one.
+ for (element = ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
+ if (!keyMatches(key, element))
+ continue;
+ m_duplicateCounts.remove(key);
+ m_map.set(key, element);
+ return element;
+ }
+ ASSERT_NOT_REACHED();
}
- ASSERT_NOT_REACHED();
+
return 0;
}
@@ -141,11 +140,6 @@
return get<keyMatchesId>(key, scope);
}
-Element* DocumentOrderedMap::getElementByName(StringImpl* key, const TreeScope* scope) const
-{
- return get<keyMatchesName>(key, scope);
-}
-
Element* DocumentOrderedMap::getElementByMapName(StringImpl* key, const TreeScope* scope) const
{
return get<keyMatchesMapName>(key, scope);
@@ -161,31 +155,4 @@
return get<keyMatchesLabelForAttribute>(key, scope);
}
-const Vector<Element*>* DocumentOrderedMap::getAllElementsById(StringImpl* key, const TreeScope* scope) const
-{
- ASSERT(key);
- ASSERT(scope);
-
- Map::iterator it = m_map.find(key);
- if (it == m_map.end())
- return 0;
-
- MapEntry& entry = it->value;
- ASSERT(entry.count);
- if (!entry.count)
- return 0;
-
- if (entry.orderedList.isEmpty()) {
- entry.orderedList.reserveCapacity(entry.count);
- for (Element* element = entry.element ? entry.element : ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
- if (!keyMatchesId(key, element))
- continue;
- entry.orderedList.append(element);
- }
- ASSERT(entry.orderedList.size() == entry.count);
- }
-
- return &entry.orderedList;
-}
-
} // namespace WebCore
diff --git a/Source/core/dom/DocumentOrderedMap.h b/Source/core/dom/DocumentOrderedMap.h
index a86caf0..b6fc8e0 100644
--- a/Source/core/dom/DocumentOrderedMap.h
+++ b/Source/core/dom/DocumentOrderedMap.h
@@ -33,7 +33,6 @@
#include "wtf/HashCountedSet.h"
#include "wtf/HashMap.h"
-#include "wtf/Vector.h"
#include "wtf/text/StringImpl.h"
namespace WebCore {
@@ -48,60 +47,35 @@
void clear();
bool contains(StringImpl*) const;
- bool containsSingle(StringImpl*) const;
bool containsMultiple(StringImpl*) const;
-
// concrete instantiations of the get<>() method template
Element* getElementById(StringImpl*, const TreeScope*) const;
- Element* getElementByName(StringImpl*, const TreeScope*) const;
Element* getElementByMapName(StringImpl*, const TreeScope*) const;
Element* getElementByLowercasedMapName(StringImpl*, const TreeScope*) const;
Element* getElementByLabelForAttribute(StringImpl*, const TreeScope*) const;
- const Vector<Element*>* getAllElementsById(StringImpl*, const TreeScope*) const;
-
void checkConsistency() const;
private:
template<bool keyMatches(StringImpl*, Element*)> Element* get(StringImpl*, const TreeScope*) const;
- struct MapEntry {
- MapEntry()
- : element(0)
- , count(0)
- {
- }
- explicit MapEntry(Element* firstElement)
- : element(firstElement)
- , count(1)
- {
- }
+ typedef HashMap<StringImpl*, Element*> Map;
- Element* element;
- unsigned count;
- Vector<Element*> orderedList;
- };
-
- typedef HashMap<StringImpl*, MapEntry> Map;
-
+ // We maintain the invariant that m_duplicateCounts is the count of all elements with a given key
+ // excluding the one referenced in m_map, if any. This means it one less than the total count
+ // when the first node with a given key is cached, otherwise the same as the total count.
mutable Map m_map;
+ mutable HashCountedSet<StringImpl*> m_duplicateCounts;
};
-inline bool DocumentOrderedMap::containsSingle(StringImpl* id) const
-{
- Map::const_iterator it = m_map.find(id);
- return it != m_map.end() && it->value.count == 1;
-}
-
inline bool DocumentOrderedMap::contains(StringImpl* id) const
{
- return m_map.contains(id);
+ return m_map.contains(id) || m_duplicateCounts.contains(id);
}
inline bool DocumentOrderedMap::containsMultiple(StringImpl* id) const
{
- Map::const_iterator it = m_map.find(id);
- return it != m_map.end() && it->value.count > 1;
+ return m_duplicateCounts.contains(id);
}
} // namespace WebCore
diff --git a/Source/core/dom/DocumentStyleSheetCollection.cpp b/Source/core/dom/DocumentStyleSheetCollection.cpp
index 74ef2b1..bbcbe43 100644
--- a/Source/core/dom/DocumentStyleSheetCollection.cpp
+++ b/Source/core/dom/DocumentStyleSheetCollection.cpp
@@ -37,6 +37,8 @@
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/ProcessingInstruction.h"
+#include "core/dom/ShadowTreeStyleSheetCollection.h"
+#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLIFrameElement.h"
#include "core/html/HTMLLinkElement.h"
#include "core/html/HTMLStyleElement.h"
@@ -63,6 +65,7 @@
, m_usesBeforeAfterRulesOverride(false)
, m_usesRemUnits(false)
, m_collectionForDocument(document)
+ , m_needsDocumentStyleSheetsUpdate(true)
{
}
@@ -80,6 +83,55 @@
m_authorStyleSheets[i]->clearOwnerNode();
}
+void DocumentStyleSheetCollection::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope)
+{
+ if (treeScopes.isEmpty()) {
+ treeScopes.add(treeScope);
+ return;
+ }
+ if (treeScopes.contains(treeScope))
+ return;
+
+ TreeScopeSet::iterator begin = treeScopes.begin();
+ TreeScopeSet::iterator end = treeScopes.end();
+ TreeScopeSet::iterator it = end;
+ TreeScope* followingTreeScope = 0;
+ do {
+ --it;
+ TreeScope* n = *it;
+ unsigned short position = n->comparePosition(treeScope);
+ if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
+ treeScopes.insertBefore(followingTreeScope, treeScope);
+ return;
+ }
+ followingTreeScope = n;
+ } while (it != begin);
+
+ treeScopes.insertBefore(followingTreeScope, treeScope);
+}
+
+StyleSheetCollection* DocumentStyleSheetCollection::ensureStyleSheetCollectionFor(TreeScope* treeScope)
+{
+ if (treeScope == m_document)
+ return &m_collectionForDocument;
+
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::AddResult result = m_styleSheetCollectionMap.add(treeScope, nullptr);
+ if (result.isNewEntry)
+ result.iterator->value = adoptPtr(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
+ return result.iterator->value.get();
+}
+
+StyleSheetCollection* DocumentStyleSheetCollection::styleSheetCollectionFor(TreeScope* treeScope)
+{
+ if (treeScope == m_document)
+ return &m_collectionForDocument;
+
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::iterator it = m_styleSheetCollectionMap.find(treeScope);
+ if (it == m_styleSheetCollectionMap.end())
+ return 0;
+ return it->value.get();
+}
+
const Vector<RefPtr<StyleSheet> >& DocumentStyleSheetCollection::styleSheetsForStyleSheetList()
{
return m_collectionForDocument.styleSheetsForStyleSheetList();
@@ -90,6 +142,19 @@
return m_collectionForDocument.activeAuthorStyleSheets();
}
+void DocumentStyleSheetCollection::getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const
+{
+ activeAuthorStyleSheets.append(&m_collectionForDocument.activeAuthorStyleSheets());
+
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values begin = m_styleSheetCollectionMap.values().begin();
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values end = m_styleSheetCollectionMap.values().end();
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values it = begin;
+ for (; it != end; ++it) {
+ const StyleSheetCollection* collection = it->get();
+ activeAuthorStyleSheets.append(&collection->activeAuthorStyleSheets());
+ }
+}
+
void DocumentStyleSheetCollection::combineCSSFeatureFlags(const RuleFeatureSet& features)
{
// Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after).
@@ -188,9 +253,10 @@
void DocumentStyleSheetCollection::invalidateInjectedStyleSheetCache()
{
m_injectedStyleSheetCacheValid = false;
+ m_needsDocumentStyleSheetsUpdate = true;
// FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets
// and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet().
- m_document->styleResolverChanged(DeferRecalcStyle);
+ m_document->styleResolverChanged(RecalcStyleDeferred);
}
void DocumentStyleSheetCollection::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet)
@@ -198,6 +264,7 @@
ASSERT(!authorSheet->isUserStyleSheet());
m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
m_document->addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately);
+ m_needsDocumentStyleSheetsUpdate = true;
}
void DocumentStyleSheetCollection::addUserSheet(PassRefPtr<StyleSheetContents> userSheet)
@@ -205,16 +272,23 @@
ASSERT(userSheet->isUserStyleSheet());
m_userStyleSheets.append(CSSStyleSheet::create(userSheet, m_document));
m_document->addedStyleSheet(m_userStyleSheets.last().get(), RecalcStyleImmediately);
+ m_needsDocumentStyleSheetsUpdate = true;
}
// This method is called whenever a top-level stylesheet has finished loading.
-void DocumentStyleSheetCollection::removePendingSheet(RemovePendingSheetNotificationType notification)
+void DocumentStyleSheetCollection::removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType notification)
{
// Make sure we knew this sheet was pending, and that our count isn't out of sync.
ASSERT(m_pendingStylesheets > 0);
m_pendingStylesheets--;
+ TreeScope* treeScope = isHTMLStyleElement(styleSheetCandidateNode) ? styleSheetCandidateNode->treeScope() : m_document;
+ if (treeScope == m_document)
+ m_needsDocumentStyleSheetsUpdate = true;
+ else
+ m_dirtyTreeScopes.add(treeScope);
+
if (m_pendingStylesheets)
return;
@@ -230,21 +304,59 @@
void DocumentStyleSheetCollection::addStyleSheetCandidateNode(Node* node, bool createdByParser)
{
- m_collectionForDocument.addStyleSheetCandidateNode(node, createdByParser);
+ if (!node->inDocument())
+ return;
+
+ TreeScope* treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
+ ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+
+ StyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
+ ASSERT(collection);
+ collection->addStyleSheetCandidateNode(node, createdByParser);
+
+ if (treeScope == m_document) {
+ m_needsDocumentStyleSheetsUpdate = true;
+ return;
+ }
+
+ insertTreeScopeInDocumentOrder(m_activeTreeScopes, treeScope);
+ m_dirtyTreeScopes.add(treeScope);
}
void DocumentStyleSheetCollection::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode)
{
- m_collectionForDocument.removeStyleSheetCandidateNode(node, scopingNode);
+ TreeScope* treeScope = scopingNode ? scopingNode->treeScope() : m_document;
+ ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+
+ StyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
+ ASSERT(collection);
+ collection->removeStyleSheetCandidateNode(node, scopingNode);
+
+ if (treeScope == m_document) {
+ m_needsDocumentStyleSheetsUpdate = true;
+ return;
+ }
+ m_dirtyTreeScopes.add(treeScope);
+ m_activeTreeScopes.remove(treeScope);
}
-static bool styleSheetsUseRemUnits(const Vector<RefPtr<CSSStyleSheet> >& sheets)
+void DocumentStyleSheetCollection::modifiedStyleSheetCandidateNode(Node* node)
{
- for (unsigned i = 0; i < sheets.size(); ++i) {
- if (sheets[i]->contents()->usesRemUnits())
- return true;
+ if (!node->inDocument())
+ return;
+
+ TreeScope* treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
+ ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+ if (treeScope == m_document) {
+ m_needsDocumentStyleSheetsUpdate = true;
+ return;
}
- return false;
+ m_dirtyTreeScopes.add(treeScope);
+}
+
+bool DocumentStyleSheetCollection::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode)
+{
+ return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
}
bool DocumentStyleSheetCollection::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
@@ -260,18 +372,91 @@
if (!m_document->renderer() || !m_document->attached())
return false;
- StyleSheetCollection::StyleResolverUpdateType styleResolverUpdateType;
- bool requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode, styleResolverUpdateType);
+ bool requiresFullStyleRecalc = false;
+ if (m_needsDocumentStyleSheetsUpdate || updateMode == FullStyleUpdate)
+ requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode);
+
+ if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
+ TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
+ HashSet<TreeScope*> treeScopesRemoved;
+
+ for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
+ TreeScope* treeScope = *it;
+ ASSERT(treeScope != m_document);
+ ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope));
+ ASSERT(collection);
+ collection->updateActiveStyleSheets(this, updateMode);
+ if (!collection->hasStyleSheetCandidateNodes())
+ treeScopesRemoved.add(treeScope);
+ }
+ if (!treeScopesRemoved.isEmpty())
+ for (HashSet<TreeScope*>::iterator it = treeScopesRemoved.begin(); it != treeScopesRemoved.end(); ++it)
+ m_activeTreeScopes.remove(*it);
+ m_dirtyTreeScopes.clear();
+ }
+
+ if (StyleResolver* styleResolver = m_document->styleResolverIfExists()) {
+ styleResolver->finishAppendAuthorStyleSheets();
+ resetCSSFeatureFlags(styleResolver->ruleFeatureSet());
+ }
+
m_needsUpdateActiveStylesheetsOnStyleRecalc = false;
+ activeStyleSheetsUpdatedForInspector();
+ m_usesRemUnits = m_collectionForDocument.usesRemUnits();
- if (styleResolverUpdateType != StyleSheetCollection::Reconstruct)
- resetCSSFeatureFlags(m_document->styleResolver()->ruleFeatureSet());
-
- InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList());
- m_usesRemUnits = styleSheetsUseRemUnits(m_collectionForDocument.activeAuthorStyleSheets());
- m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
+ if (m_needsDocumentStyleSheetsUpdate || updateMode == FullStyleUpdate) {
+ m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
+ m_needsDocumentStyleSheetsUpdate = false;
+ }
return requiresFullStyleRecalc;
}
+void DocumentStyleSheetCollection::activeStyleSheetsUpdatedForInspector()
+{
+ if (m_activeTreeScopes.isEmpty()) {
+ InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList());
+ return;
+ }
+ Vector<RefPtr<StyleSheet> > activeStyleSheets;
+
+ activeStyleSheets.append(m_collectionForDocument.styleSheetsForStyleSheetList());
+
+ TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
+ TreeScopeSet::iterator end = m_activeTreeScopes.end();
+ for (TreeScopeSet::iterator it = begin; it != end; ++it) {
+ if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it))
+ activeStyleSheets.append(collection->styleSheetsForStyleSheetList());
+ }
+
+ // FIXME: Inspector needs a vector which has all active stylesheets.
+ // However, creating such a large vector might cause performance regression.
+ // Need to implement some smarter solution.
+ InspectorInstrumentation::activeStyleSheetsUpdated(m_document, activeStyleSheets);
+}
+
+void DocumentStyleSheetCollection::didRemoveShadowRoot(ShadowRoot* shadowRoot)
+{
+ m_styleSheetCollectionMap.remove(shadowRoot);
+}
+
+void DocumentStyleSheetCollection::appendActiveAuthorStyleSheets(StyleResolver* styleResolver)
+{
+ ASSERT(styleResolver);
+
+ styleResolver->setBuildScopedStyleTreeInDocumentOrder(true);
+ styleResolver->appendAuthorStyleSheets(0, m_collectionForDocument.activeAuthorStyleSheets());
+
+ TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
+ TreeScopeSet::iterator end = m_activeTreeScopes.end();
+ for (TreeScopeSet::iterator it = begin; it != end; ++it) {
+ if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) {
+ styleResolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped());
+ styleResolver->appendAuthorStyleSheets(0, collection->activeAuthorStyleSheets());
+ }
+ }
+ styleResolver->finishAppendAuthorStyleSheets();
+ styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
+}
+
}
diff --git a/Source/core/dom/DocumentStyleSheetCollection.h b/Source/core/dom/DocumentStyleSheetCollection.h
index bbafeb8..2dd47c5 100644
--- a/Source/core/dom/DocumentStyleSheetCollection.h
+++ b/Source/core/dom/DocumentStyleSheetCollection.h
@@ -64,6 +64,7 @@
void addStyleSheetCandidateNode(Node*, bool createdByParser);
void removeStyleSheetCandidateNode(Node*, ContainerNode* scopingNode = 0);
+ void modifiedStyleSheetCandidateNode(Node*);
void clearPageUserSheet();
void updatePageUserSheet();
@@ -87,7 +88,7 @@
RemovePendingSheetNotifyImmediately,
RemovePendingSheetNotifyLater
};
- void removePendingSheet(RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately);
+ void removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately);
bool hasPendingSheets() const { return m_pendingStylesheets > 0; }
@@ -105,9 +106,22 @@
void combineCSSFeatureFlags(const RuleFeatureSet&);
void resetCSSFeatureFlags(const RuleFeatureSet&);
+ void didModifySeamlessParentStyleSheet() { m_needsDocumentStyleSheetsUpdate = true; }
+ void didRemoveShadowRoot(ShadowRoot*);
+ void appendActiveAuthorStyleSheets(StyleResolver*);
+ void getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const;
+
private:
DocumentStyleSheetCollection(Document*);
+ StyleSheetCollection* ensureStyleSheetCollectionFor(TreeScope*);
+ StyleSheetCollection* styleSheetCollectionFor(TreeScope*);
+ void activeStyleSheetsUpdatedForInspector();
+ bool shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode);
+
+ typedef ListHashSet<TreeScope*, 16> TreeScopeSet;
+ static void insertTreeScopeInDocumentOrder(TreeScopeSet&, TreeScope*);
+
Document* m_document;
// Track the number of currently loading top-level stylesheets needed for rendering.
@@ -125,10 +139,14 @@
Vector<RefPtr<CSSStyleSheet> > m_userStyleSheets;
Vector<RefPtr<CSSStyleSheet> > m_authorStyleSheets;
- bool m_hadActiveLoadingStylesheet;
bool m_needsUpdateActiveStylesheetsOnStyleRecalc;
- StyleSheetCollection m_collectionForDocument;
+ StyleSheetCollectionForDocument m_collectionForDocument;
+ HashMap<TreeScope*, OwnPtr<StyleSheetCollection> > m_styleSheetCollectionMap;
+
+ TreeScopeSet m_dirtyTreeScopes;
+ TreeScopeSet m_activeTreeScopes;
+ bool m_needsDocumentStyleSheetsUpdate;
String m_preferredStylesheetSetName;
String m_selectedStylesheetSetName;
diff --git a/Source/core/dom/DocumentType.idl b/Source/core/dom/DocumentType.idl
index 8f192f3..510240a 100644
--- a/Source/core/dom/DocumentType.idl
+++ b/Source/core/dom/DocumentType.idl
@@ -22,14 +22,14 @@
// DOM Level 1
readonly attribute DOMString name;
- readonly attribute NamedNodeMap entities;
- readonly attribute NamedNodeMap notations;
+ [MeasureAs=DocumentTypeEntities] readonly attribute NamedNodeMap entities; // Removed from DOM4.
+ [MeasureAs=DocumentTypeNotations] readonly attribute NamedNodeMap notations; // Removed from DOM4.
// DOM Level 2
[TreatReturnedNullStringAs=Null] readonly attribute DOMString publicId;
[TreatReturnedNullStringAs=Null] readonly attribute DOMString systemId;
- [TreatReturnedNullStringAs=Null] readonly attribute DOMString internalSubset;
+ [TreatReturnedNullStringAs=Null, MeasureAs=DocumentTypeInternalSubset] readonly attribute DOMString internalSubset; // Removed from DOM4.
};
DocumentType implements ChildNode;
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index b7147bc..9577774 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -953,7 +953,7 @@
inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
{
if (name == isAttr)
- CustomElementRegistrationContext::setTypeExtension(this, newValue);
+ CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
attributeChanged(name, newValue, reason);
}
@@ -1053,7 +1053,7 @@
bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
{
ASSERT(elementShadow);
- const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
+ const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
if (isIdAttributeName(name)) {
AtomicString oldId = elementData()->idForStyleResolution();
@@ -1206,14 +1206,6 @@
return RenderObject::createObject(this, style);
}
-bool Element::isInert() const
-{
- const Element* dialog = document()->activeModalDialog();
- if (dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this))
- return true;
- return document()->ownerElement() && document()->ownerElement()->isInert();
-}
-
Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
{
// need to do superclass processing first so inDocument() is true
@@ -1229,6 +1221,9 @@
if (Element* after = pseudoElement(AFTER))
after->insertedInto(insertionPoint);
+ if (Element* backdrop = pseudoElement(BACKDROP))
+ backdrop->insertedInto(insertionPoint);
+
if (!insertionPoint->isInTreeScope())
return InsertionDone;
@@ -1279,7 +1274,7 @@
setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
if (document()->page())
- document()->page()->pointerLockController()->elementRemoved(this);
+ document()->page()->pointerLockController().elementRemoved(this);
setSavedLayerScrollOffset(IntSize());
@@ -1318,6 +1313,16 @@
StyleResolverParentPusher parentPusher(this);
WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
+ // We've already been through detach when doing a lazyAttach, but we might
+ // need to clear any state that's been added since then.
+ if (hasRareData() && styleChangeType() == LazyAttachStyleChange) {
+ ElementRareData* data = elementRareData();
+ data->clearComputedStyle();
+ data->resetDynamicRestyleObservations();
+ if (!context.resolvedStyle)
+ data->resetStyleState();
+ }
+
NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
createPseudoElementIfNeeded(BEFORE);
@@ -1534,10 +1539,11 @@
} else if (child->isElementNode()) {
Element* element = toElement(child);
+ bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
+
if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
element->setNeedsStyleRecalc();
- bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
@@ -1550,8 +1556,10 @@
forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
}
- if (shouldRecalcStyle(change, this))
+ if (shouldRecalcStyle(change, this)) {
updatePseudoElement(AFTER, change);
+ updatePseudoElement(BACKDROP, change);
+ }
clearNeedsStyleRecalc();
clearChildNeedsStyleRecalc();
@@ -1628,12 +1636,6 @@
return shadowRoot;
}
-Element* Element::uaShadowElementById(const AtomicString& id) const
-{
- ShadowRoot* shadowRoot = userAgentShadowRoot();
- return shadowRoot ? shadowRoot->getElementById(id) : 0;
-}
-
bool Element::supportsShadowElementForUserAgentShadow() const
{
return true;
@@ -1770,6 +1772,8 @@
checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
if (StyleResolver* styleResolver = document()->styleResolverIfExists())
styleResolver->popParentElement(this);
+ if (isCustomElement())
+ CustomElement::didFinishParsingChildren(this);
}
#ifndef NDEBUG
@@ -1827,7 +1831,7 @@
synchronizeAllAttributes();
UniqueElementData* elementData = ensureUniqueElementData();
- size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
+ size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase(this));
if (index != notFound) {
if (oldAttrNode)
detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
@@ -2630,7 +2634,7 @@
void Element::webkitRequestPointerLock()
{
if (document()->page())
- document()->page()->pointerLockController()->requestPointerLock(this);
+ document()->page()->pointerLockController().requestPointerLock(this);
}
SpellcheckAttributeState Element::spellcheckAttributeState() const
diff --git a/Source/core/dom/Element.h b/Source/core/dom/Element.h
index 7b075ce..556fe4f 100644
--- a/Source/core/dom/Element.h
+++ b/Source/core/dom/Element.h
@@ -87,7 +87,7 @@
const Attribute* attributeItem(unsigned index) const;
const Attribute* getAttributeItem(const QualifiedName&) const;
- size_t getAttributeItemIndex(const QualifiedName&) const;
+ size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
size_t getAttrIndex(Attr*) const;
@@ -216,6 +216,7 @@
DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
+ DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
// These four attribute event handler attributes are overridden by HTMLBodyElement
// and HTMLFrameSetElement to forward to the DOMWindow.
@@ -446,7 +447,6 @@
ShadowRoot* userAgentShadowRoot() const;
ShadowRoot* ensureUserAgentShadowRoot();
- Element* uaShadowElementById(const AtomicString& id) const;
virtual bool supportsShadowElementForUserAgentShadow() const;
virtual const AtomicString& shadowPseudoId() const { return !part().isEmpty() ? part() : pseudo(); }
@@ -594,7 +594,6 @@
// to event listeners, and prevents DOMActivate events from being sent at all.
virtual bool isDisabledFormControl() const { return false; }
- bool isInert() const;
virtual bool shouldBeReparentedUnderRenderView(const RenderStyle*) const { return isInTopLayer(); }
virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
@@ -644,6 +643,8 @@
InputMethodContext* inputMethodContext();
+ virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE FINAL;
+
protected:
Element(const QualifiedName& tagName, Document* document, ConstructionType type)
: ContainerNode(document, type)
@@ -663,7 +664,7 @@
virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
virtual void removedFrom(ContainerNode*) OVERRIDE;
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) OVERRIDE;
- virtual void removeAllEventListeners() OVERRIDE;
+ virtual void removeAllEventListeners() OVERRIDE FINAL;
virtual void willRecalcStyle(StyleChange);
virtual void didRecalcStyle(StyleChange);
@@ -728,7 +729,6 @@
void scrollByUnits(int units, ScrollGranularity);
- virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE FINAL;
virtual NodeType nodeType() const OVERRIDE FINAL;
virtual bool childTypeAllowed(NodeType) const OVERRIDE FINAL;
@@ -1037,12 +1037,12 @@
return static_cast<const ShareableElementData*>(this)->m_attributeArray;
}
-inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name) const
+inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
{
const Attribute* begin = attributeBase();
for (unsigned i = 0; i < length(); ++i) {
const Attribute& attribute = begin[i];
- if (attribute.name().matches(name))
+ if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
return i;
}
return notFound;
diff --git a/Source/core/dom/Element.idl b/Source/core/dom/Element.idl
index 0137af9..9af4c05 100644
--- a/Source/core/dom/Element.idl
+++ b/Source/core/dom/Element.idl
@@ -30,12 +30,11 @@
[RaisesException, CustomElementCallbacks=Enable] void setAttribute([Default=Undefined] optional DOMString name,
[Default=Undefined] optional DOMString value);
[CustomElementCallbacks=Enable] void removeAttribute([Default=Undefined] optional DOMString name);
- Attr getAttributeNode([Default=Undefined] optional DOMString name);
- [RaisesException, CustomElementCallbacks=Enable] Attr setAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr newAttr);
- [RaisesException, CustomElementCallbacks=Enable] Attr removeAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr oldAttr);
+ [MeasureAs=ElementGetAttributeNode] Attr getAttributeNode([Default=Undefined] optional DOMString name); // Removed from DOM4.
+ [RaisesException, CustomElementCallbacks=Enable, MeasureAs=ElementSetAttributeNode] Attr setAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr newAttr); // Removed from DOM4.
+ [RaisesException, CustomElementCallbacks=Enable, MeasureAs=ElementRemoveAttributeNode] Attr removeAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr oldAttr); // Removed from DOM4.
[PerWorldBindings] NodeList getElementsByTagName([Default=Undefined] optional DOMString name);
- // For ObjC this is defined on Node for legacy support.
[PerWorldBindings] readonly attribute NamedNodeMap attributes;
boolean hasAttributes();
@@ -50,8 +49,8 @@
DOMString localName);
NodeList getElementsByTagNameNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
[Default=Undefined] optional DOMString localName);
- Attr getAttributeNodeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
- [Default=Undefined] optional DOMString localName);
+ [MeasureAs=ElementGetAttributeNodeNS] Attr getAttributeNodeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
+ [Default=Undefined] optional DOMString localName); // Removed from DOM4.
[RaisesException, CustomElementCallbacks=Enable] Attr setAttributeNodeNS([Default=Undefined, StrictTypeChecking] optional Attr newAttr);
boolean hasAttribute(DOMString name);
boolean hasAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
@@ -63,6 +62,9 @@
// iht.com relies on id returning the empty string when no id is present.
// Other browsers do this as well. So we don't convert null to JS null.
[Reflect] attribute DOMString id;
+ [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString namespaceURI;
+ [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString prefix;
+ [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
// Common extensions
@@ -162,7 +164,8 @@
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseout;
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseover;
[NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseup;
- [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel;
+ [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel; // Deprecated in favor of onwheel.
+ [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onwheel;
[NotEnumerable, PerWorldBindings] attribute EventHandler onscroll;
[NotEnumerable, PerWorldBindings] attribute EventHandler onselect;
[NotEnumerable, PerWorldBindings] attribute EventHandler onsubmit;
diff --git a/Source/core/dom/ElementTraversal.h b/Source/core/dom/ElementTraversal.h
new file mode 100644
index 0000000..0278732
--- /dev/null
+++ b/Source/core/dom/ElementTraversal.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ElementTraversal_h
+#define ElementTraversal_h
+
+#include "core/dom/Element.h"
+#include "core/dom/NodeTraversal.h"
+
+namespace WebCore {
+
+namespace ElementTraversal {
+
+// First element child of the node.
+Element* firstWithin(const Node*);
+Element* firstWithin(const ContainerNode*);
+
+// Pre-order traversal skipping non-element nodes.
+Element* next(const Node*);
+Element* next(const Node*, const Node* stayWithin);
+Element* next(const ContainerNode*);
+Element* next(const ContainerNode*, const Node* stayWithin);
+
+// Like next, but skips children.
+Element* nextSkippingChildren(const Node*);
+Element* nextSkippingChildren(const Node*, const Node* stayWithin);
+Element* nextSkippingChildren(const ContainerNode*);
+Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
+
+// Pre-order traversal including the pseudo-elements.
+Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
+Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
+Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
+
+// Utility function to traverse only the element and pseudo-element siblings of a node.
+Element* pseudoAwarePreviousSibling(const Node*);
+
+template <class NodeType>
+inline Element* firstElementWithinTemplate(NodeType* current)
+{
+ // Except for the root containers, only elements can have element children.
+ Node* node = current->firstChild();
+ while (node && !node->isElementNode())
+ node = node->nextSibling();
+ return toElement(node);
+}
+inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
+inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementTemplate(NodeType* current)
+{
+ Node* node = NodeTraversal::next(current);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextSkippingChildren(node);
+ return toElement(node);
+}
+inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
+inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementTemplate(NodeType* current, const Node* stayWithin)
+{
+ Node* node = NodeTraversal::next(current, stayWithin);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextSkippingChildren(node, stayWithin);
+ return toElement(node);
+}
+inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
+inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
+
+template <class NodeType>
+inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current)
+{
+ Node* node = NodeTraversal::nextSkippingChildren(current);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextSkippingChildren(node);
+ return toElement(node);
+}
+inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
+inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
+{
+ Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextSkippingChildren(node, stayWithin);
+ return toElement(node);
+}
+inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
+inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
+
+inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
+{
+ Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
+ return toElement(node);
+}
+
+inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
+{
+ Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
+ return toElement(node);
+}
+
+inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
+{
+ Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
+ while (node && !node->isElementNode())
+ node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
+ return toElement(node);
+}
+
+inline Element* pseudoAwarePreviousSibling(const Node* current)
+{
+ Node* node = current->pseudoAwarePreviousSibling();
+ while (node && !node->isElementNode())
+ node = node->pseudoAwarePreviousSibling();
+ return toElement(node);
+}
+
+}
+
+}
+
+#endif
diff --git a/Source/core/dom/ErrorEvent.cpp b/Source/core/dom/ErrorEvent.cpp
index 7c4b3c1..ecb3d4b 100644
--- a/Source/core/dom/ErrorEvent.cpp
+++ b/Source/core/dom/ErrorEvent.cpp
@@ -50,7 +50,7 @@
ErrorEvent::ErrorEvent(const AtomicString& type, const ErrorEventInit& initializer)
: Event(type, initializer)
- , m_message(initializer.message)
+ , m_sanitizedMessage(initializer.message)
, m_fileName(initializer.filename)
, m_lineNumber(initializer.lineno)
, m_columnNumber(initializer.colno)
@@ -60,7 +60,7 @@
ErrorEvent::ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber)
: Event(eventNames().errorEvent, false, true)
- , m_message(message)
+ , m_sanitizedMessage(message)
, m_fileName(fileName)
, m_lineNumber(lineNumber)
, m_columnNumber(columnNumber)
@@ -68,6 +68,12 @@
ScriptWrappable::init(this);
}
+void ErrorEvent::setUnsanitizedMessage(const String& message)
+{
+ ASSERT(m_unsanitizedMessage.isEmpty());
+ m_unsanitizedMessage = message;
+}
+
ErrorEvent::~ErrorEvent()
{
}
diff --git a/Source/core/dom/ErrorEvent.h b/Source/core/dom/ErrorEvent.h
index 8215544..583f07f 100644
--- a/Source/core/dom/ErrorEvent.h
+++ b/Source/core/dom/ErrorEvent.h
@@ -65,19 +65,26 @@
}
virtual ~ErrorEvent();
- const String& message() const { return m_message; }
+ // As 'message' is exposed to JavaScript, never return unsanitizedMessage.
+ const String& message() const { return m_sanitizedMessage; }
const String& filename() const { return m_fileName; }
unsigned lineno() const { return m_lineNumber; }
unsigned colno() const { return m_columnNumber; }
+ // 'messageForConsole' is not exposed to JavaScript, and prefers 'm_unsanitizedMessage'.
+ const String& messageForConsole() const { return !m_unsanitizedMessage.isEmpty() ? m_unsanitizedMessage : m_sanitizedMessage; }
+
virtual const AtomicString& interfaceName() const;
+ void setUnsanitizedMessage(const String&);
+
private:
ErrorEvent();
ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber);
ErrorEvent(const AtomicString&, const ErrorEventInit&);
- String m_message;
+ String m_unsanitizedMessage;
+ String m_sanitizedMessage;
String m_fileName;
unsigned m_lineNumber;
unsigned m_columnNumber;
diff --git a/Source/core/dom/EventNames.h b/Source/core/dom/EventNames.h
index 0c01af9..098071d 100644
--- a/Source/core/dom/EventNames.h
+++ b/Source/core/dom/EventNames.h
@@ -125,6 +125,7 @@
macro(upgradeneeded) \
macro(versionchange) \
macro(webkitvisibilitychange) \
+ macro(wheel) \
macro(write) \
macro(writeend) \
macro(writestart) \
diff --git a/Source/core/dom/EventPathWalker.cpp b/Source/core/dom/EventPathWalker.cpp
index 4853df6..de1d4d0 100644
--- a/Source/core/dom/EventPathWalker.cpp
+++ b/Source/core/dom/EventPathWalker.cpp
@@ -27,7 +27,7 @@
#include "config.h"
#include "core/dom/EventPathWalker.h"
-#include "core/dom/shadow/ContentDistributor.h"
+#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
#include "core/dom/shadow/ShadowRoot.h"
@@ -58,7 +58,7 @@
ASSERT(m_node);
ASSERT(m_distributedNode);
if (ElementShadow* shadow = shadowOfParent(m_node)) {
- if (InsertionPoint* insertionPoint = shadow->distributor().findInsertionPointFor(m_distributedNode)) {
+ if (InsertionPoint* insertionPoint = shadow->findInsertionPointFor(m_distributedNode)) {
m_node = insertionPoint;
m_isVisitingInsertionPointInReprojection = true;
return;
diff --git a/Source/core/dom/EventTarget.cpp b/Source/core/dom/EventTarget.cpp
index db40321..30c6854 100644
--- a/Source/core/dom/EventTarget.cpp
+++ b/Source/core/dom/EventTarget.cpp
@@ -68,6 +68,11 @@
return 0;
}
+MessagePort* EventTarget::toMessagePort()
+{
+ return 0;
+}
+
inline DOMWindow* EventTarget::executingWindow()
{
if (ScriptExecutionContext* context = scriptExecutionContext())
@@ -176,11 +181,14 @@
{
}
-static AtomicString prefixedType(const Event* event)
+static AtomicString legacyType(const Event* event)
{
if (event->type() == eventNames().transitionendEvent)
return eventNames().webkitTransitionEndEvent;
+ if (event->type() == eventNames().wheelEvent)
+ return eventNames().mousewheelEvent;
+
return emptyString();
}
@@ -193,30 +201,30 @@
if (!d)
return true;
- EventListenerVector* listenerPrefixedVector = 0;
- AtomicString prefixedTypeName = prefixedType(event);
- if (!prefixedTypeName.isEmpty())
- listenerPrefixedVector = d->eventListenerMap.find(prefixedTypeName);
+ EventListenerVector* legacyListenersVector = 0;
+ AtomicString legacyTypeName = legacyType(event);
+ if (!legacyTypeName.isEmpty())
+ legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
- EventListenerVector* listenerUnprefixedVector = d->eventListenerMap.find(event->type());
+ EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
- if (listenerUnprefixedVector)
- fireEventListeners(event, d, *listenerUnprefixedVector);
- else if (listenerPrefixedVector) {
+ if (listenersVector) {
+ fireEventListeners(event, d, *listenersVector);
+ } else if (legacyListenersVector) {
AtomicString unprefixedTypeName = event->type();
- event->setType(prefixedTypeName);
- fireEventListeners(event, d, *listenerPrefixedVector);
+ event->setType(legacyTypeName);
+ fireEventListeners(event, d, *legacyListenersVector);
event->setType(unprefixedTypeName);
}
- if (!prefixedTypeName.isEmpty()) {
+ if (legacyTypeName == eventNames().webkitTransitionEndEvent) {
if (DOMWindow* executingWindow = this->executingWindow()) {
- if (listenerPrefixedVector) {
- if (listenerUnprefixedVector)
+ if (legacyListenersVector) {
+ if (listenersVector)
UseCounter::count(executingWindow, UseCounter::PrefixedAndUnprefixedTransitionEndEvent);
else
UseCounter::count(executingWindow, UseCounter::PrefixedTransitionEndEvent);
- } else if (listenerUnprefixedVector) {
+ } else if (listenersVector) {
UseCounter::count(executingWindow, UseCounter::UnprefixedTransitionEndEvent);
}
}
diff --git a/Source/core/dom/EventTarget.h b/Source/core/dom/EventTarget.h
index 633d2d2..267306a 100644
--- a/Source/core/dom/EventTarget.h
+++ b/Source/core/dom/EventTarget.h
@@ -38,8 +38,8 @@
namespace WebCore {
+ class ApplicationCache;
class AudioContext;
- class DOMApplicationCache;
class DOMWindow;
class DedicatedWorkerGlobalScope;
class Event;
@@ -106,6 +106,7 @@
virtual Node* toNode();
virtual DOMWindow* toDOMWindow();
+ virtual MessagePort* toMessagePort();
virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
diff --git a/Source/core/dom/EventTargetFactory.in b/Source/core/dom/EventTargetFactory.in
index 1929c1e..abe0c16 100644
--- a/Source/core/dom/EventTargetFactory.in
+++ b/Source/core/dom/EventTargetFactory.in
@@ -9,7 +9,7 @@
core/html/track/TextTrack
core/html/track/TextTrackCue
core/html/track/TextTrackList
-core/loader/appcache/DOMApplicationCache
+core/loader/appcache/ApplicationCache
core/page/EventSource
core/page/Performance
core/page/Window ImplementedAs=DOMWindow
diff --git a/Source/core/dom/FullscreenElementStack.cpp b/Source/core/dom/FullscreenElementStack.cpp
index 78dfe24..b72b25b 100644
--- a/Source/core/dom/FullscreenElementStack.cpp
+++ b/Source/core/dom/FullscreenElementStack.cpp
@@ -188,7 +188,7 @@
break;
// There is a previously-established user preference, security risk, or platform limitation.
- if (!document()->page() || !document()->page()->settings()->fullScreenEnabled())
+ if (!document()->page() || !document()->page()->settings().fullScreenEnabled())
break;
// 2. Let doc be element's node document. (i.e. "this")
@@ -240,7 +240,7 @@
// 5. Return, and run the remaining steps asynchronously.
// 6. Optionally, perform some animation.
m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
- document()->page()->chrome().client()->enterFullScreenForElement(element);
+ document()->page()->chrome().client().enterFullScreenForElement(element);
// 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
return;
@@ -331,12 +331,12 @@
// Only exit out of full screen window mode if there are no remaining elements in the
// full screen stack.
if (!newTop) {
- document()->page()->chrome().client()->exitFullScreenForElement(m_fullScreenElement.get());
+ document()->page()->chrome().client().exitFullScreenForElement(m_fullScreenElement.get());
return;
}
// Otherwise, notify the chrome of the new full screen element.
- document()->page()->chrome().client()->enterFullScreenForElement(newTop);
+ document()->page()->chrome().client().enterFullScreenForElement(newTop);
}
bool FullscreenElementStack::webkitFullscreenEnabled(Document* document)
@@ -360,7 +360,7 @@
if (!document()->page())
return;
- ASSERT(document()->page()->settings()->fullScreenEnabled());
+ ASSERT(document()->page()->settings().fullScreenEnabled());
if (m_fullScreenRenderer)
m_fullScreenRenderer->unwrapRenderer();
diff --git a/Source/core/dom/GestureEvent.cpp b/Source/core/dom/GestureEvent.cpp
index a4f5cf8..6423c0a 100644
--- a/Source/core/dom/GestureEvent.cpp
+++ b/Source/core/dom/GestureEvent.cpp
@@ -115,9 +115,6 @@
bool GestureEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
{
- if (isDisabledFormControl(dispatcher->node()))
- return true;
-
dispatcher->dispatch();
ASSERT(!event()->defaultPrevented());
return event()->defaultHandled() || event()->defaultPrevented();
diff --git a/Source/core/dom/MessageChannel.idl b/Source/core/dom/MessageChannel.idl
index 3d62729..f5b5165 100644
--- a/Source/core/dom/MessageChannel.idl
+++ b/Source/core/dom/MessageChannel.idl
@@ -26,13 +26,9 @@
[
GlobalContext=Window&WorkerGlobalScope,
- Constructor,
- ConstructorCallWith=ScriptExecutionContext,
CustomConstructor
] interface MessageChannel {
-
readonly attribute MessagePort port1;
readonly attribute MessagePort port2;
-
};
diff --git a/Source/core/dom/MessageEvent.cpp b/Source/core/dom/MessageEvent.cpp
index ce6e8fa..351275c 100644
--- a/Source/core/dom/MessageEvent.cpp
+++ b/Source/core/dom/MessageEvent.cpp
@@ -33,6 +33,11 @@
namespace WebCore {
+static inline bool isValidSource(EventTarget* source)
+{
+ return !source || source->toDOMWindow() || source->toMessagePort();
+}
+
MessageEventInit::MessageEventInit()
{
}
@@ -48,13 +53,14 @@
, m_dataType(DataTypeScriptValue)
, m_origin(initializer.origin)
, m_lastEventId(initializer.lastEventId)
- , m_source(initializer.source)
+ , m_source(isValidSource(initializer.source.get()) ? initializer.source : 0)
, m_ports(adoptPtr(new MessagePortArray(initializer.ports)))
{
ScriptWrappable::init(this);
+ ASSERT(isValidSource(m_source.get()));
}
-MessageEvent::MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray> ports)
+MessageEvent::MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray> ports)
: Event(eventNames().messageEvent, false, false)
, m_dataType(DataTypeScriptValue)
, m_origin(origin)
@@ -63,9 +69,10 @@
, m_ports(ports)
{
ScriptWrappable::init(this);
+ ASSERT(isValidSource(m_source.get()));
}
-MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray> ports)
+MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray> ports)
: Event(eventNames().messageEvent, false, false)
, m_dataType(DataTypeSerializedScriptValue)
, m_dataAsSerializedScriptValue(data)
@@ -77,6 +84,7 @@
ScriptWrappable::init(this);
if (m_dataAsSerializedScriptValue)
m_dataAsSerializedScriptValue->registerMemoryAllocatedWithCurrentScriptContext();
+ ASSERT(isValidSource(m_source.get()));
}
MessageEvent::MessageEvent(const String& data, const String& origin)
diff --git a/Source/core/dom/MessageEvent.h b/Source/core/dom/MessageEvent.h
index 7f54232..e6647c1 100644
--- a/Source/core/dom/MessageEvent.h
+++ b/Source/core/dom/MessageEvent.h
@@ -30,6 +30,7 @@
#include "bindings/v8/SerializedScriptValue.h"
#include "core/dom/Event.h"
+#include "core/dom/EventTarget.h"
#include "core/dom/MessagePort.h"
#include "core/fileapi/Blob.h"
#include "core/page/DOMWindow.h"
@@ -37,14 +38,12 @@
namespace WebCore {
-class DOMWindow;
-
struct MessageEventInit : public EventInit {
MessageEventInit();
String origin;
String lastEventId;
- RefPtr<DOMWindow> source;
+ RefPtr<EventTarget> source;
MessagePortArray ports;
};
@@ -54,11 +53,11 @@
{
return adoptRef(new MessageEvent);
}
- static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, const String& origin = "", const String& lastEventId = "", PassRefPtr<DOMWindow> source = 0)
+ static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, const String& origin = "", const String& lastEventId = "", PassRefPtr<EventTarget> source = 0)
{
return adoptRef(new MessageEvent(origin, lastEventId, source, ports));
}
- static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, PassRefPtr<SerializedScriptValue> data, const String& origin = "", const String& lastEventId = "", PassRefPtr<DOMWindow> source = 0)
+ static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, PassRefPtr<SerializedScriptValue> data, const String& origin = "", const String& lastEventId = "", PassRefPtr<EventTarget> source = 0)
{
return adoptRef(new MessageEvent(data, origin, lastEventId, source, ports));
}
@@ -85,7 +84,7 @@
const String& origin() const { return m_origin; }
const String& lastEventId() const { return m_lastEventId; }
- DOMWindow* source() const { return m_source.get(); }
+ EventTarget* source() const { return m_source.get(); }
MessagePortArray ports() const { return m_ports ? *m_ports : MessagePortArray(); }
virtual const AtomicString& interfaceName() const;
@@ -112,8 +111,8 @@
private:
MessageEvent();
MessageEvent(const AtomicString&, const MessageEventInit&);
- MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray>);
- MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray>);
+ MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray>);
+ MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray>);
explicit MessageEvent(const String& data, const String& origin);
explicit MessageEvent(PassRefPtr<Blob> data, const String& origin);
@@ -126,7 +125,7 @@
RefPtr<ArrayBuffer> m_dataAsArrayBuffer;
String m_origin;
String m_lastEventId;
- RefPtr<DOMWindow> m_source;
+ RefPtr<EventTarget> m_source;
OwnPtr<MessagePortArray> m_ports;
};
diff --git a/Source/core/dom/MessageEvent.idl b/Source/core/dom/MessageEvent.idl
index 3bc8866..33d1c33 100644
--- a/Source/core/dom/MessageEvent.idl
+++ b/Source/core/dom/MessageEvent.idl
@@ -31,7 +31,7 @@
] interface MessageEvent : Event {
[InitializedByEventConstructor] readonly attribute DOMString origin;
[InitializedByEventConstructor] readonly attribute DOMString lastEventId;
- [InitializedByEventConstructor] readonly attribute Window source;
+ [InitializedByEventConstructor] readonly attribute EventTarget source; // May be a Window or a MessagePort
[InitializedByEventConstructor, CustomGetter] readonly attribute any data;
[InitializedByEventConstructor] readonly attribute MessagePort[] ports;
diff --git a/Source/core/dom/MessagePort.h b/Source/core/dom/MessagePort.h
index 337e225..34773c9 100644
--- a/Source/core/dom/MessagePort.h
+++ b/Source/core/dom/MessagePort.h
@@ -75,6 +75,7 @@
virtual const AtomicString& interfaceName() const OVERRIDE;
virtual ScriptExecutionContext* scriptExecutionContext() const OVERRIDE;
+ MessagePort* toMessagePort() OVERRIDE { return this; }
void dispatchMessages();
diff --git a/Source/core/dom/MessagePort.idl b/Source/core/dom/MessagePort.idl
index 4324172..17ae449 100644
--- a/Source/core/dom/MessagePort.idl
+++ b/Source/core/dom/MessagePort.idl
@@ -28,8 +28,6 @@
[
ActiveDOMObject
] interface MessagePort : EventTarget {
-// We need to have something as an ObjC binding, because MessagePort is used in MessageEvent, which already has one,
-// but we don't want to actually expose the API while it is in flux.
[Custom, RaisesException] void postMessage(any message, optional Array messagePorts);
void start();
diff --git a/Source/core/dom/Node.cpp b/Source/core/dom/Node.cpp
index 3936024..c4eebe4 100644
--- a/Source/core/dom/Node.cpp
+++ b/Source/core/dom/Node.cpp
@@ -71,6 +71,7 @@
#include "core/dom/shadow/InsertionPoint.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/editing/htmlediting.h"
+#include "core/html/HTMLAnchorElement.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/html/HTMLStyleElement.h"
#include "core/html/RadioNodeList.h"
@@ -83,6 +84,7 @@
#include "core/platform/Partitions.h"
#include "core/rendering/FlowThreadController.h"
#include "core/rendering/RenderBox.h"
+#include "core/svg/graphics/SVGImage.h"
#include "wtf/HashSet.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/RefCountedLeakCounter.h"
@@ -782,6 +784,11 @@
clearChildNeedsDistributionRecalc();
}
+void Node::setIsLink(bool isLink)
+{
+ setFlag(isLink && !SVGImage::isInSVGImage(toElement(this)), IsLinkFlag);
+}
+
void Node::markAncestorsWithChildNeedsDistributionRecalc()
{
for (Node* node = this; node && !node->childNeedsDistributionRecalc(); node = node->parentOrShadowHostNode())
@@ -833,25 +840,14 @@
void Node::lazyAttach(ShouldSetAttached shouldSetAttached)
{
- // It's safe to synchronously attach here because we're in the middle of style recalc
- // while it's not safe to mark nodes as needing style recalc except in the loop in
- // Element::recalcStyle because we may mark an ancestor as not needing recalc and
- // then the node would never get updated. One place this currently happens is
- // HTMLObjectElement::renderFallbackContent which may call lazyAttach from inside
- // attach which was triggered by a recalcStyle.
- if (document()->inStyleRecalc()) {
- attach();
- return;
- }
markAncestorsWithChildNeedsStyleRecalc();
for (Node* node = this; node; node = NodeTraversal::next(node, this)) {
node->setStyleChange(LazyAttachStyleChange);
- node->setChildNeedsStyleRecalc();
+ if (node->isContainerNode())
+ node->setChildNeedsStyleRecalc();
// FIXME: This flag is only used by HTMLFrameElementBase and doesn't look needed.
if (shouldSetAttached == SetAttached)
node->setAttached();
- if (isActiveInsertionPoint(node))
- toInsertionPoint(node)->lazyAttachDistribution(shouldSetAttached);
for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot())
root->lazyAttach(shouldSetAttached);
}
@@ -868,6 +864,14 @@
return true;
}
+bool Node::isInert() const
+{
+ const Element* dialog = document()->activeModalDialog();
+ if (dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this))
+ return true;
+ return document()->ownerElement() && document()->ownerElement()->isInert();
+}
+
unsigned Node::nodeIndex() const
{
Node *_tempNode = previousSibling();
@@ -1030,6 +1034,33 @@
return false;
}
+inline void Node::detachNode(Node* root, const AttachContext& context)
+{
+ Node* node = root;
+ while (node) {
+ if (node->styleChangeType() == LazyAttachStyleChange) {
+ // FIXME: This is needed because Node::lazyAttach marks nodes as being attached even
+ // though they've never been through attach(). This allows us to avoid doing all the
+ // virtual calls to detach() and other associated work.
+ node->clearAttached();
+ node->clearChildNeedsStyleRecalc();
+
+ for (ShadowRoot* shadowRoot = node->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot())
+ detachNode(shadowRoot, context);
+
+ node = NodeTraversal::next(node, root);
+ continue;
+ }
+ // Handle normal reattaches from style recalc (ex. display type changes)
+ // or descendants of lazy attached nodes that got actually attached, for example,
+ // by innerHTML or editing.
+ // FIXME: innerHTML and editing should also lazyAttach.
+ if (node->attached())
+ node->detach(context);
+ node = NodeTraversal::nextSkippingChildren(node, root);
+ }
+}
+
void Node::reattach(const AttachContext& context)
{
// FIXME: Text::updateTextRenderer calls reattach outside a style recalc.
@@ -1037,8 +1068,7 @@
AttachContext reattachContext(context);
reattachContext.performingReattach = true;
- if (attached())
- detach(reattachContext);
+ detachNode(this, reattachContext);
attach(reattachContext);
}
@@ -1110,7 +1140,7 @@
}
}
- clearFlag(IsAttachedFlag);
+ clearAttached();
#ifndef NDEBUG
detachingNode = 0;
@@ -1681,7 +1711,7 @@
ChildListMutationScope mutation(this);
container->removeChildren();
if (!text.isEmpty())
- container->appendChild(document()->createTextNode(text), es, AttachLazily);
+ container->appendChild(document()->createTextNode(text), es);
return;
}
case DOCUMENT_NODE:
@@ -1867,8 +1897,6 @@
return p;
}
-#ifndef NDEBUG
-
String Node::debugName() const
{
StringBuilder name;
@@ -1893,6 +1921,8 @@
return name.toString();
}
+#ifndef NDEBUG
+
static void appendAttributeDesc(const Node* node, StringBuilder& stringBuilder, const QualifiedName& name, const char* attrDesc)
{
if (!node->isElementNode())
@@ -2125,7 +2155,13 @@
if (AXObjectCache* cache = oldDocument->existingAXObjectCache())
cache->remove(this);
- const EventListenerVector& wheelListeners = getEventListeners(eventNames().mousewheelEvent);
+ const EventListenerVector& mousewheelListeners = getEventListeners(eventNames().mousewheelEvent);
+ for (size_t i = 0; i < mousewheelListeners.size(); ++i) {
+ oldDocument->didRemoveWheelEventHandler();
+ document()->didAddWheelEventHandler();
+ }
+
+ const EventListenerVector& wheelListeners = getEventListeners(eventNames().wheelEvent);
for (size_t i = 0; i < wheelListeners.size(); ++i) {
oldDocument->didRemoveWheelEventHandler();
document()->didAddWheelEventHandler();
@@ -2158,7 +2194,7 @@
if (Document* document = targetNode->document()) {
document->addListenerTypeIfNeeded(eventType);
- if (eventType == eventNames().mousewheelEvent)
+ if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
document->didAddWheelEventHandler();
else if (eventNames().isTouchEventType(eventType))
document->didAddTouchEventHandler(targetNode);
@@ -2180,7 +2216,7 @@
// FIXME: Notify Document that the listener has vanished. We need to keep track of a number of
// listeners for each type, not just a bool - see https://bugs.webkit.org/show_bug.cgi?id=33861
if (Document* document = targetNode->document()) {
- if (eventType == eventNames().mousewheelEvent)
+ if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
document->didRemoveWheelEventHandler();
else if (eventNames().isTouchEventType(eventType))
document->didRemoveTouchEventHandler(targetNode);
@@ -2464,9 +2500,8 @@
if (dispatchDOMActivateEvent(detail, event))
event->setDefaultHandled();
} else if (eventType == eventNames().contextmenuEvent) {
- if (Frame* frame = document()->frame())
- if (Page* page = frame->page())
- page->contextMenuController()->handleContextMenuEvent(event);
+ if (Page* page = document()->page())
+ page->contextMenuController().handleContextMenuEvent(event);
} else if (eventType == eventNames().textInputEvent) {
if (event->hasInterface(eventNames().interfaceForTextEvent))
if (Frame* frame = document()->frame())
@@ -2488,7 +2523,7 @@
}
}
#endif
- } else if (eventType == eventNames().mousewheelEvent && event->hasInterface(eventNames().interfaceForWheelEvent)) {
+ } else if ((eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent) && event->hasInterface(eventNames().interfaceForWheelEvent)) {
WheelEvent* wheelEvent = static_cast<WheelEvent*>(event);
// If we don't have a renderer, send the wheel event to the first node we find with a renderer.
@@ -2623,15 +2658,14 @@
document()->updateDistributionForNodeIfNeeded(this);
Vector<InsertionPoint*, 8> insertionPoints;
collectInsertionPointsWhereNodeIsDistributed(this, insertionPoints);
+ Vector<RefPtr<Node> > filteredInsertionPoints;
for (size_t i = 0; i < insertionPoints.size(); ++i) {
InsertionPoint* insertionPoint = insertionPoints[i];
ASSERT(insertionPoint->containingShadowRoot());
- if (insertionPoint->containingShadowRoot()->type() == ShadowRoot::UserAgentShadowRoot)
- return StaticNodeList::createEmpty();
+ if (insertionPoint->containingShadowRoot()->type() != ShadowRoot::UserAgentShadowRoot)
+ filteredInsertionPoints.append(insertionPoint);
}
- Vector<RefPtr<Node> > asNodes;
- asNodes.appendRange(insertionPoints.begin(), insertionPoints.end());
- return StaticNodeList::adopt(asNodes);
+ return StaticNodeList::adopt(filteredInsertionPoints);
}
void Node::registerScopedHTMLStyleChild()
@@ -2707,22 +2741,22 @@
ASSERT_NOT_REACHED(); // Everything starts in this state
return;
- case UpgradeCandidate:
+ case WaitingForParser:
ASSERT(NotCustomElement == oldState);
break;
- case Defined:
- ASSERT(UpgradeCandidate == oldState || NotCustomElement == oldState);
+ case WaitingForUpgrade:
+ ASSERT(NotCustomElement == oldState || WaitingForParser == oldState);
break;
case Upgraded:
- ASSERT(Defined == oldState);
+ ASSERT(WaitingForParser == oldState || WaitingForUpgrade == oldState);
break;
}
ASSERT(isHTMLElement() || isSVGElement());
- setFlag(newState & 1, CustomElementIsUpgradeCandidateOrUpgraded);
- setFlag(newState & 2, CustomElementHasDefinitionOrIsUpgraded);
+ setFlag(newState & 1, CustomElementWaitingForParserOrIsUpgraded);
+ setFlag(newState & 2, CustomElementWaitingForUpgradeOrIsUpgraded);
if (oldState == NotCustomElement || newState == Upgraded)
setNeedsStyleRecalc(); // :unresolved has changed
diff --git a/Source/core/dom/Node.h b/Source/core/dom/Node.h
index a651d06..bdfdb4c 100644
--- a/Source/core/dom/Node.h
+++ b/Source/core/dom/Node.h
@@ -25,6 +25,7 @@
#ifndef Node_h
#define Node_h
+#include "bindings/v8/ExceptionStatePlaceholder.h"
#include "bindings/v8/ScriptWrappable.h"
#include "core/dom/EventTarget.h"
#include "core/dom/MutationObserver.h"
@@ -114,7 +115,7 @@
};
enum AttachBehavior {
- AttachNow,
+ DeprecatedAttachNow,
AttachLazily,
};
@@ -204,10 +205,10 @@
// These should all actually return a node, but this is only important for language bindings,
// which will already know and hold a ref on the right node to return. Returning bool allows
// these methods to be more efficient since they don't need to return a ref
- void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState&, AttachBehavior = AttachNow);
- void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState&, AttachBehavior = AttachNow);
+ void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
+ void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
void removeChild(Node* child, ExceptionState&);
- void appendChild(PassRefPtr<Node> newChild, ExceptionState&, AttachBehavior = AttachNow);
+ void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
bool hasChildNodes() const { return firstChild(); }
virtual PassRefPtr<Node> cloneNode(bool deep = true) = 0;
@@ -245,12 +246,12 @@
enum CustomElementState {
NotCustomElement,
- UpgradeCandidate,
- Defined,
+ WaitingForParser,
+ WaitingForUpgrade,
Upgraded
};
bool isCustomElement() const { return customElementState() != NotCustomElement; }
- CustomElementState customElementState() const { return CustomElementState((getFlag(CustomElementHasDefinitionOrIsUpgraded) ? 2 : 0) | (getFlag(CustomElementIsUpgradeCandidateOrUpgraded) ? 1 : 0)); }
+ CustomElementState customElementState() const { return CustomElementState((getFlag(CustomElementWaitingForParserOrIsUpgraded) ? 1 : 0) | (getFlag(CustomElementWaitingForUpgradeOrIsUpgraded) ? 2 : 0)); }
void setCustomElementState(CustomElementState newState);
virtual bool isMediaControlElement() const { return false; }
@@ -400,9 +401,7 @@
bool shouldNotifyRendererWithIdenticalStyles() const { return getFlag(NotifyRendererWithIdenticalStyles); }
- void setIsLink(bool f) { setFlag(f, IsLinkFlag); }
- void setIsLink() { setFlag(IsLinkFlag); }
- void clearIsLink() { clearFlag(IsLinkFlag); }
+ void setIsLink(bool f);
void setInNamedFlow() { setFlag(InNamedFlowFlag); }
void clearInNamedFlow() { clearFlag(InNamedFlowFlag); }
@@ -433,6 +432,10 @@
// This is called only when the node is focused.
virtual bool shouldHaveFocusAppearance() const;
+ // Whether the node is inert. This can't be in Element because text nodes
+ // must be recognized as inert to prevent text selection.
+ bool isInert() const;
+
enum UserSelectAllTreatment {
UserSelectAllDoesNotAffectEditability,
UserSelectAllIsAlwaysNonEditable
@@ -608,9 +611,9 @@
//
virtual void removedFrom(ContainerNode* insertionPoint);
-#ifndef NDEBUG
String debugName() const;
+#ifndef NDEBUG
virtual void formatForDebugger(char* buffer, unsigned length) const;
void showNode(const char* prefix = "") const;
@@ -713,6 +716,9 @@
PassRefPtr<NodeList> getDestinationInsertionPoints();
+ void setAlreadySpellChecked(bool flag) { setFlag(flag, AlreadySpellCheckedFlag); }
+ bool isAlreadySpellChecked() { return getFlag(AlreadySpellCheckedFlag); }
+
private:
enum NodeFlags {
IsTextFlag = 1,
@@ -750,10 +756,11 @@
NotifyRendererWithIdenticalStyles = 1 << 26,
- CustomElementIsUpgradeCandidateOrUpgraded = 1 << 27,
- CustomElementHasDefinitionOrIsUpgraded = 1 << 28,
+ CustomElementWaitingForParserOrIsUpgraded = 1 << 27,
+ CustomElementWaitingForUpgradeOrIsUpgraded = 1 << 28,
ChildNeedsDistributionRecalc = 1 << 29,
+ AlreadySpellCheckedFlag = 1 << 30,
DefaultNodeFlags = IsParsingChildrenFinishedFlag
};
@@ -839,6 +846,9 @@
void setStyleChange(StyleChangeType);
+ void detachNode(Node*, const AttachContext&);
+ void clearAttached() { clearFlag(IsAttachedFlag); }
+
// Used to share code between lazyAttach and setNeedsStyleRecalc.
void markAncestorsWithChildNeedsStyleRecalc();
diff --git a/Source/core/dom/Node.idl b/Source/core/dom/Node.idl
index 0c7c5a1..3d774a2 100644
--- a/Source/core/dom/Node.idl
+++ b/Source/core/dom/Node.idl
@@ -61,12 +61,12 @@
[CustomElementCallbacks=Enable] void normalize();
// Introduced in DOM Level 2:
- boolean isSupported([Default=Undefined] optional DOMString feature,
- [TreatNullAs=NullString,Default=Undefined] optional DOMString version);
+ [MeasureAs=NodeIsSupported] boolean isSupported([Default=Undefined] optional DOMString feature,
+ [TreatNullAs=NullString,Default=Undefined] optional DOMString version); // Removed in DOM4.
- [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString namespaceURI;
- [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString prefix;
- [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
+ [TreatReturnedNullStringAs=Null, PerWorldBindings, MeasureAs=NodeNamespaceURI] readonly attribute DOMString namespaceURI; // Moved to Element and Attr in DOM4.
+ [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException, MeasureAs=NodePrefix] attribute DOMString prefix; // Moved to Element and Attr in DOM4.
+ [TreatReturnedNullStringAs=Null, PerWorldBindings, MeasureAs=NodeLocalName] readonly attribute DOMString localName; // Moved to Element and Attr in DOM4.
// Introduced in DOM Level 3:
[TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString baseURI;
@@ -74,7 +74,7 @@
// FIXME: the spec says this can also raise on retrieval.
[TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException, CustomElementCallbacks=Enable] attribute DOMString textContent;
- boolean isSameNode([Default=Undefined] optional Node other);
+ [MeasureAs=NodeIsSameNode] boolean isSameNode([Default=Undefined] optional Node other); // Removed in DOM4.
boolean isEqualNode([Default=Undefined] optional Node other);
[TreatReturnedNullStringAs=Null] DOMString lookupPrefix([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI);
boolean isDefaultNamespace([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI);
diff --git a/Source/core/dom/NodeTraversal.h b/Source/core/dom/NodeTraversal.h
index c9d5208..c6966a6 100644
--- a/Source/core/dom/NodeTraversal.h
+++ b/Source/core/dom/NodeTraversal.h
@@ -25,38 +25,10 @@
#ifndef NodeTraversal_h
#define NodeTraversal_h
-#include "core/dom/Element.h"
+#include "core/dom/Node.h"
namespace WebCore {
-namespace ElementTraversal {
-
-// First element child of the node.
-Element* firstWithin(const Node*);
-Element* firstWithin(const ContainerNode*);
-
-// Pre-order traversal skipping non-element nodes.
-Element* next(const Node*);
-Element* next(const Node*, const Node* stayWithin);
-Element* next(const ContainerNode*);
-Element* next(const ContainerNode*, const Node* stayWithin);
-
-// Like next, but skips children.
-Element* nextSkippingChildren(const Node*);
-Element* nextSkippingChildren(const Node*, const Node* stayWithin);
-Element* nextSkippingChildren(const ContainerNode*);
-Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
-
-// Pre-order traversal including the pseudo-elements.
-Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
-Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
-Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
-
-// Utility function to traverse only the element and pseudo-element siblings of a node.
-Element* pseudoAwarePreviousSibling(const Node*);
-
-}
-
namespace NodeTraversal {
// Does a pre-order traversal of the tree to find the next node after this one.
@@ -92,101 +64,6 @@
Node* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
Node* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
-}
-
-namespace ElementTraversal {
-template <class NodeType>
-inline Element* firstElementWithinTemplate(NodeType* current)
-{
- // Except for the root containers, only elements can have element children.
- Node* node = current->firstChild();
- while (node && !node->isElementNode())
- node = node->nextSibling();
- return toElement(node);
-}
-inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
-inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementTemplate(NodeType* current)
-{
- Node* node = NodeTraversal::next(current);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextSkippingChildren(node);
- return toElement(node);
-}
-inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
-inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementTemplate(NodeType* current, const Node* stayWithin)
-{
- Node* node = NodeTraversal::next(current, stayWithin);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextSkippingChildren(node, stayWithin);
- return toElement(node);
-}
-inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
-inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
-
-template <class NodeType>
-inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current)
-{
- Node* node = NodeTraversal::nextSkippingChildren(current);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextSkippingChildren(node);
- return toElement(node);
-}
-inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
-inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
-{
- Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextSkippingChildren(node, stayWithin);
- return toElement(node);
-}
-inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
-inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
-
-inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
-{
- Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
- while (node && !node->isElementNode())
- node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
- return toElement(node);
-}
-
-inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
-{
- Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
- return toElement(node);
-}
-
-inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
-{
- Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
- while (node && !node->isElementNode())
- node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
- return toElement(node);
-}
-
-inline Element* pseudoAwarePreviousSibling(const Node* current)
-{
- Node* node = current->pseudoAwarePreviousSibling();
- while (node && !node->isElementNode())
- node = node->pseudoAwarePreviousSibling();
- return toElement(node);
-}
-
-}
-
-namespace NodeTraversal {
-
Node* nextAncestorSibling(const Node*);
Node* nextAncestorSibling(const Node*, const Node* stayWithin);
diff --git a/Source/core/dom/ParentNode.h b/Source/core/dom/ParentNode.h
new file mode 100644
index 0000000..9fb949a
--- /dev/null
+++ b/Source/core/dom/ParentNode.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParentNode_h
+#define ParentNode_h
+
+#include "core/dom/ContainerNode.h"
+
+namespace WebCore {
+
+class ParentNode {
+public:
+ static PassRefPtr<HTMLCollection> children(ContainerNode* node)
+ {
+ return node->children();
+ }
+
+ static Element* firstElementChild(ContainerNode* node)
+ {
+ return node->firstElementChild();
+ }
+
+ static Element* lastElementChild(ContainerNode* node)
+ {
+ return node->lastElementChild();
+ }
+
+ static unsigned childElementCount(ContainerNode* node)
+ {
+ return node->childElementCount();
+ }
+};
+
+} // namespace WebCore
+
+#endif // ParentNode_h
diff --git a/Source/core/dom/ParentNode.idl b/Source/core/dom/ParentNode.idl
index 358271b..8de54f8 100644
--- a/Source/core/dom/ParentNode.idl
+++ b/Source/core/dom/ParentNode.idl
@@ -1,6 +1,5 @@
[
NoInterfaceObject,
- LegacyImplementedInBaseClass
] interface ParentNode {
[PerWorldBindings] readonly attribute HTMLCollection children;
[PerWorldBindings] readonly attribute Element firstElementChild;
diff --git a/Source/core/dom/PendingScript.cpp b/Source/core/dom/PendingScript.cpp
index aab3343..6ad05cf 100644
--- a/Source/core/dom/PendingScript.cpp
+++ b/Source/core/dom/PendingScript.cpp
@@ -27,7 +27,7 @@
#include "core/dom/PendingScript.h"
#include "core/dom/Element.h"
-#include "core/loader/cache/ScriptResource.h"
+#include "core/fetch/ScriptResource.h"
namespace WebCore {
diff --git a/Source/core/dom/PendingScript.h b/Source/core/dom/PendingScript.h
index bf902b2..0f169a9 100644
--- a/Source/core/dom/PendingScript.h
+++ b/Source/core/dom/PendingScript.h
@@ -26,8 +26,8 @@
#ifndef PendingScript_h
#define PendingScript_h
-#include "core/loader/cache/ResourceClient.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourceClient.h"
+#include "core/fetch/ResourcePtr.h"
#include "wtf/PassRefPtr.h"
#include "wtf/RefPtr.h"
#include "wtf/text/TextPosition.h"
diff --git a/Source/core/dom/Position.cpp b/Source/core/dom/Position.cpp
index c71c102..02f46bc 100644
--- a/Source/core/dom/Position.cpp
+++ b/Source/core/dom/Position.cpp
@@ -844,7 +844,7 @@
bool Position::nodeIsUserSelectNone(Node* node)
{
- return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE && node->renderer()->style()->userModify() == READ_ONLY;
+ return node && node->renderer() && !node->renderer()->isSelectable();
}
ContainerNode* Position::findParent(const Node* node)
diff --git a/Source/core/dom/ProcessingInstruction.cpp b/Source/core/dom/ProcessingInstruction.cpp
index def6f8e..033c043 100644
--- a/Source/core/dom/ProcessingInstruction.cpp
+++ b/Source/core/dom/ProcessingInstruction.cpp
@@ -27,19 +27,18 @@
#include "core/css/StyleSheetContents.h"
#include "core/dom/Document.h"
#include "core/dom/DocumentStyleSheetCollection.h"
-#include "core/loader/cache/CSSStyleSheetResource.h"
-#include "core/loader/cache/FetchRequest.h"
-#include "core/loader/cache/ResourceFetcher.h"
-#include "core/loader/cache/XSLStyleSheetResource.h"
+#include "core/fetch/CSSStyleSheetResource.h"
+#include "core/fetch/FetchRequest.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/fetch/XSLStyleSheetResource.h"
#include "core/xml/XSLStyleSheet.h"
#include "core/xml/parser/XMLDocumentParser.h" // for parseAttributes()
namespace WebCore {
inline ProcessingInstruction::ProcessingInstruction(Document* document, const String& target, const String& data)
- : Node(document, CreateOther)
+ : CharacterData(document, data, CreateOther)
, m_target(target)
- , m_data(data)
, m_resource(0)
, m_loading(false)
, m_alternate(false)
@@ -67,14 +66,6 @@
document()->styleSheetCollection()->removeStyleSheetCandidateNode(this);
}
-void ProcessingInstruction::setData(const String& data)
-{
- int oldLength = m_data.length();
- m_data = data;
- document()->textRemoved(this, 0, oldLength);
- checkStyleSheet();
-}
-
String ProcessingInstruction::nodeName() const
{
return m_target;
@@ -85,16 +76,6 @@
return PROCESSING_INSTRUCTION_NODE;
}
-String ProcessingInstruction::nodeValue() const
-{
- return m_data;
-}
-
-void ProcessingInstruction::setNodeValue(const String& nodeValue)
-{
- setData(nodeValue);
-}
-
PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
{
// FIXME: Is it a problem that this does not copy m_localHref?
@@ -170,7 +151,7 @@
else {
// The request may have been denied if (for example) the stylesheet is local and the document is remote.
m_loading = false;
- document()->styleSheetCollection()->removePendingSheet();
+ document()->styleSheetCollection()->removePendingSheet(this);
}
}
}
@@ -188,7 +169,7 @@
bool ProcessingInstruction::sheetLoaded()
{
if (!isLoading()) {
- document()->styleSheetCollection()->removePendingSheet();
+ document()->styleSheetCollection()->removePendingSheet(this);
return true;
}
return false;
@@ -254,16 +235,6 @@
sheet->setDisabled(m_alternate);
}
-bool ProcessingInstruction::offsetInCharacters() const
-{
- return true;
-}
-
-int ProcessingInstruction::maxCharacterOffset() const
-{
- return static_cast<int>(m_data.length());
-}
-
void ProcessingInstruction::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
{
if (!sheet())
@@ -274,7 +245,7 @@
Node::InsertionNotificationRequest ProcessingInstruction::insertedInto(ContainerNode* insertionPoint)
{
- Node::insertedInto(insertionPoint);
+ CharacterData::insertedInto(insertionPoint);
if (!insertionPoint->inDocument())
return InsertionDone;
document()->styleSheetCollection()->addStyleSheetCandidateNode(this, m_createdByParser);
@@ -284,7 +255,7 @@
void ProcessingInstruction::removedFrom(ContainerNode* insertionPoint)
{
- Node::removedFrom(insertionPoint);
+ CharacterData::removedFrom(insertionPoint);
if (!insertionPoint->inDocument())
return;
@@ -306,7 +277,7 @@
void ProcessingInstruction::finishParsingChildren()
{
m_createdByParser = false;
- Node::finishParsingChildren();
+ CharacterData::finishParsingChildren();
}
} // namespace
diff --git a/Source/core/dom/ProcessingInstruction.h b/Source/core/dom/ProcessingInstruction.h
index 1ae7976..7b216f0 100644
--- a/Source/core/dom/ProcessingInstruction.h
+++ b/Source/core/dom/ProcessingInstruction.h
@@ -22,23 +22,21 @@
#ifndef ProcessingInstruction_h
#define ProcessingInstruction_h
-#include "core/dom/Node.h"
-#include "core/loader/cache/ResourcePtr.h"
-#include "core/loader/cache/StyleSheetResourceClient.h"
+#include "core/dom/CharacterData.h"
+#include "core/fetch/ResourcePtr.h"
+#include "core/fetch/StyleSheetResourceClient.h"
namespace WebCore {
class StyleSheet;
class CSSStyleSheet;
-class ProcessingInstruction FINAL : public Node, private StyleSheetResourceClient {
+class ProcessingInstruction FINAL : public CharacterData, private StyleSheetResourceClient {
public:
static PassRefPtr<ProcessingInstruction> create(Document*, const String& target, const String& data);
virtual ~ProcessingInstruction();
const String& target() const { return m_target; }
- const String& data() const { return m_data; }
- void setData(const String&);
void setCreatedByParser(bool createdByParser) { m_createdByParser = createdByParser; }
@@ -54,15 +52,12 @@
bool isLoading() const;
private:
+ friend class CharacterData;
ProcessingInstruction(Document*, const String& target, const String& data);
virtual String nodeName() const;
virtual NodeType nodeType() const;
- virtual String nodeValue() const;
- virtual void setNodeValue(const String&);
virtual PassRefPtr<Node> cloneNode(bool deep = true);
- virtual bool offsetInCharacters() const;
- virtual int maxCharacterOffset() const;
virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
virtual void removedFrom(ContainerNode*) OVERRIDE;
@@ -78,7 +73,6 @@
void parseStyleSheet(const String& sheet);
String m_target;
- String m_data;
String m_localHref;
String m_title;
String m_media;
@@ -91,6 +85,12 @@
bool m_isXSL;
};
+inline ProcessingInstruction* toProcessingInstruction(Node* node)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!node || node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE);
+ return static_cast<ProcessingInstruction*>(node);
+}
+
} //namespace
#endif
diff --git a/Source/core/dom/ProcessingInstruction.idl b/Source/core/dom/ProcessingInstruction.idl
index 1767ee5..80aace5 100644
--- a/Source/core/dom/ProcessingInstruction.idl
+++ b/Source/core/dom/ProcessingInstruction.idl
@@ -18,12 +18,11 @@
* Boston, MA 02110-1301, USA.
*/
-interface ProcessingInstruction : Node {
+interface ProcessingInstruction : CharacterData {
// DOM Level 1
[TreatReturnedNullStringAs=Null] readonly attribute DOMString target;
- [TreatReturnedNullStringAs=Null, TreatNullAs=NullString] attribute DOMString data;
// interface LinkStyle from DOM Level 2 Style Sheets
readonly attribute StyleSheet sheet;
diff --git a/Source/core/dom/Promise.idl b/Source/core/dom/Promise.idl
index 2550866..d2fa864 100644
--- a/Source/core/dom/Promise.idl
+++ b/Source/core/dom/Promise.idl
@@ -28,6 +28,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// FIXME: |PromiseValue| should be changed to |Promise|. http://crbug.com/266700
+// IDLs using |Promise| should be written with "typedef any PromiseValue;" and |PromiseValue|.
+
callback PromiseInit = void (PromiseResolver resolver);
callback AnyCallback = any (optional any value);
[
diff --git a/Source/core/dom/QualifiedName.h b/Source/core/dom/QualifiedName.h
index 355ceeb..b42f9e4 100644
--- a/Source/core/dom/QualifiedName.h
+++ b/Source/core/dom/QualifiedName.h
@@ -82,6 +82,8 @@
bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); }
+ bool matchesPossiblyIgnoringCase(const QualifiedName& other, bool shouldIgnoreCase) const { return m_impl == other.m_impl || (equalPossiblyIgnoringCase(localName(), other.localName(), shouldIgnoreCase) && namespaceURI() == other.namespaceURI()); }
+
bool hasPrefix() const { return m_impl->m_prefix != nullAtom; }
void setPrefix(const AtomicString& prefix) { *this = QualifiedName(prefix, localName(), namespaceURI()); }
diff --git a/Source/core/dom/ScriptExecutionContext.cpp b/Source/core/dom/ScriptExecutionContext.cpp
index 13191d8..2cc9e4b 100644
--- a/Source/core/dom/ScriptExecutionContext.cpp
+++ b/Source/core/dom/ScriptExecutionContext.cpp
@@ -205,13 +205,13 @@
if (m_inDispatchErrorEvent) {
if (!m_pendingExceptions)
m_pendingExceptions = adoptPtr(new Vector<OwnPtr<PendingException> >());
- m_pendingExceptions->append(adoptPtr(new PendingException(errorEvent->message(), errorEvent->lineno(), errorEvent->colno(), errorEvent->filename(), callStack)));
+ m_pendingExceptions->append(adoptPtr(new PendingException(errorEvent->messageForConsole(), errorEvent->lineno(), errorEvent->colno(), errorEvent->filename(), callStack)));
return;
}
// First report the original exception and only then all the nested ones.
if (!dispatchErrorEvent(errorEvent, corsStatus))
- logExceptionToConsole(errorEvent->message(), errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack);
+ logExceptionToConsole(errorEvent->messageForConsole(), errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack);
if (!m_pendingExceptions)
return;
@@ -223,9 +223,14 @@
m_pendingExceptions.clear();
}
-void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state, unsigned long requestIdentifier)
+void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber)
{
- addMessage(source, level, message, sourceURL, lineNumber, 0, state, requestIdentifier);
+ addMessage(source, level, message, sourceURL, lineNumber, 0);
+}
+
+void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, ScriptState* state)
+{
+ addMessage(source, level, message, String(), 0, state);
}
bool ScriptExecutionContext::dispatchErrorEvent(PassRefPtr<ErrorEvent> event, AccessControlStatus corsStatus)
diff --git a/Source/core/dom/ScriptExecutionContext.h b/Source/core/dom/ScriptExecutionContext.h
index ee4a312..1bcf0ab 100644
--- a/Source/core/dom/ScriptExecutionContext.h
+++ b/Source/core/dom/ScriptExecutionContext.h
@@ -77,8 +77,8 @@
bool shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus);
void reportException(PassRefPtr<ErrorEvent>, PassRefPtr<ScriptCallStack>, AccessControlStatus);
- void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* = 0, unsigned long requestIdentifier = 0);
- virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
+ void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber);
+ void addConsoleMessage(MessageSource, MessageLevel, const String& message, ScriptState* = 0);
PublicURLManager& publicURLManager();
@@ -159,7 +159,7 @@
virtual const KURL& virtualURL() const = 0;
virtual KURL virtualCompleteURL(const String&) const = 0;
- virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0) = 0;
+ virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState*) = 0;
virtual EventTarget* errorEventTarget() = 0;
virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) = 0;
bool dispatchErrorEvent(PassRefPtr<ErrorEvent>, AccessControlStatus);
diff --git a/Source/core/dom/ScriptLoader.cpp b/Source/core/dom/ScriptLoader.cpp
index 6d1c06b..55d6844 100644
--- a/Source/core/dom/ScriptLoader.cpp
+++ b/Source/core/dom/ScriptLoader.cpp
@@ -35,12 +35,12 @@
#include "core/dom/ScriptRunner.h"
#include "core/dom/ScriptableDocumentParser.h"
#include "core/dom/Text.h"
+#include "core/fetch/FetchRequest.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/fetch/ScriptResource.h"
#include "core/html/HTMLImport.h"
#include "core/html/HTMLScriptElement.h"
#include "core/html/parser/HTMLParserIdioms.h"
-#include "core/loader/cache/FetchRequest.h"
-#include "core/loader/cache/ResourceFetcher.h"
-#include "core/loader/cache/ScriptResource.h"
#include "core/page/ContentSecurityPolicy.h"
#include "core/page/Frame.h"
#include "core/platform/MIMETypeRegistry.h"
diff --git a/Source/core/dom/ScriptLoader.h b/Source/core/dom/ScriptLoader.h
index 390d83a..dfa8818 100644
--- a/Source/core/dom/ScriptLoader.h
+++ b/Source/core/dom/ScriptLoader.h
@@ -21,8 +21,8 @@
#ifndef ScriptLoader_h
#define ScriptLoader_h
-#include "core/loader/cache/ResourceClient.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourceClient.h"
+#include "core/fetch/ResourcePtr.h"
#include "wtf/text/TextPosition.h"
#include "wtf/text/WTFString.h"
diff --git a/Source/core/dom/ScriptRunner.cpp b/Source/core/dom/ScriptRunner.cpp
index d25001e..f63ab50 100644
--- a/Source/core/dom/ScriptRunner.cpp
+++ b/Source/core/dom/ScriptRunner.cpp
@@ -30,7 +30,7 @@
#include "core/dom/Element.h"
#include "core/dom/PendingScript.h"
#include "core/dom/ScriptLoader.h"
-#include "core/loader/cache/ScriptResource.h"
+#include "core/fetch/ScriptResource.h"
namespace WebCore {
diff --git a/Source/core/dom/ScriptRunner.h b/Source/core/dom/ScriptRunner.h
index ef9e270..b793589 100644
--- a/Source/core/dom/ScriptRunner.h
+++ b/Source/core/dom/ScriptRunner.h
@@ -26,7 +26,7 @@
#ifndef ScriptRunner_h
#define ScriptRunner_h
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourcePtr.h"
#include "core/platform/Timer.h"
#include "wtf/HashMap.h"
#include "wtf/Noncopyable.h"
diff --git a/Source/core/dom/SelectorQuery.cpp b/Source/core/dom/SelectorQuery.cpp
index 9e99139..db7afdf 100644
--- a/Source/core/dom/SelectorQuery.cpp
+++ b/Source/core/dom/SelectorQuery.cpp
@@ -33,7 +33,7 @@
#include "core/css/SelectorCheckerFastPath.h"
#include "core/css/SiblingTraversalStrategies.h"
#include "core/dom/Document.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/StaticNodeList.h"
namespace WebCore {
@@ -490,7 +490,7 @@
CSSSelectorList selectorList;
parser.parseSelector(selectors, selectorList);
- if (!selectorList.first() || selectorList.hasInvalidSelector()) {
+ if (!selectorList.first()) {
es.throwDOMException(SyntaxError);
return 0;
}
diff --git a/Source/core/dom/ShadowTreeStyleSheetCollection.cpp b/Source/core/dom/ShadowTreeStyleSheetCollection.cpp
new file mode 100644
index 0000000..2c53a05
--- /dev/null
+++ b/Source/core/dom/ShadowTreeStyleSheetCollection.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/dom/ShadowTreeStyleSheetCollection.h"
+
+#include "HTMLNames.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/resolver/StyleResolver.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
+#include "core/dom/Element.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/HTMLStyleElement.h"
+#include "core/page/Settings.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ShadowTreeStyleSheetCollection::ShadowTreeStyleSheetCollection(ShadowRoot* shadowRoot)
+ : StyleSheetCollection(shadowRoot)
+{
+}
+
+void ShadowTreeStyleSheetCollection::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
+{
+ if (document()->settings() && !document()->settings()->authorAndUserStylesEnabled())
+ return;
+
+ DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin();
+ DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end();
+ for (DocumentOrderedList::iterator it = begin; it != end; ++it) {
+ Node* node = *it;
+ StyleSheet* sheet = 0;
+ CSSStyleSheet* activeSheet = 0;
+
+ if (!node->isHTMLElement() || !node->hasTagName(styleTag))
+ continue;
+
+ Element* element = toElement(node);
+ AtomicString title = element->getAttribute(titleAttr);
+ bool enabledViaScript = false;
+
+ sheet = static_cast<HTMLStyleElement*>(node)->sheet();
+ if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet())
+ activeSheet = static_cast<CSSStyleSheet*>(sheet);
+
+ // FIXME: clarify how PREFERRED or ALTERNATE works in shadow trees.
+ // Should we set preferred/selected stylesheets name in shadow trees and
+ // use the name in document?
+ AtomicString rel = element->getAttribute(relAttr);
+ if (!enabledViaScript && sheet && !title.isEmpty()) {
+ if (collections->preferredStylesheetSetName().isEmpty()) {
+ if (element->hasLocalName(styleTag) || !rel.contains("alternate")) {
+ collections->setPreferredStylesheetSetName(title);
+ collections->setSelectedStylesheetSetName(title);
+ }
+ }
+ if (title != collections->preferredStylesheetSetName())
+ activeSheet = 0;
+ }
+
+ if (rel.contains("alternate") && title.isEmpty())
+ activeSheet = 0;
+
+ if (sheet)
+ styleSheets.append(sheet);
+ if (activeSheet)
+ activeSheets.append(activeSheet);
+ }
+}
+
+bool ShadowTreeStyleSheetCollection::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode)
+{
+ Vector<RefPtr<StyleSheet> > styleSheets;
+ Vector<RefPtr<CSSStyleSheet> > activeCSSStyleSheets;
+ collectStyleSheets(collections, styleSheets, activeCSSStyleSheets);
+
+ bool requiresFullStyleRecalc = true;
+
+ // If we have already decided to destroy StyleResolver, we don't need to analyze. Reconstruction will take care.
+ if (StyleResolver* styleResolver = document()->styleResolverIfExists()) {
+ StyleResolverUpdateType styleResolverUpdateType;
+
+ analyzeStyleSheetChange(updateMode, activeAuthorStyleSheets(), activeCSSStyleSheets, styleResolverUpdateType, requiresFullStyleRecalc);
+
+ // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
+ // Need to change "false" to some valid condition.
+ styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
+ if (styleResolverUpdateType == Reset || styleResolverUpdateType == Reconstruct) {
+ // We should not destroy StyleResolver when we find any stylesheet update in a shadow tree.
+ // In this case, we will reset rulesets created from style elements in the shadow tree.
+ resetAllRuleSetsInTreeScope(styleResolver);
+ styleResolver->appendAuthorStyleSheets(0, activeCSSStyleSheets);
+ } else {
+ ASSERT(styleResolverUpdateType == Additive);
+ styleResolver->appendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), activeCSSStyleSheets);
+ }
+ }
+ m_scopingNodesForStyleScoped.didRemoveScopingNodes();
+ m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
+ m_styleSheetsForStyleSheetList.swap(styleSheets);
+ updateUsesRemUnits();
+
+ return requiresFullStyleRecalc;
+}
+
+}
diff --git a/Source/core/dom/ShadowTreeStyleSheetCollection.h b/Source/core/dom/ShadowTreeStyleSheetCollection.h
new file mode 100644
index 0000000..e398440
--- /dev/null
+++ b/Source/core/dom/ShadowTreeStyleSheetCollection.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ShadowTreeStyleSheetCollection_h
+#define ShadowTreeStyleSheetCollection_h
+
+#include "core/dom/StyleSheetCollection.h"
+
+namespace WebCore {
+
+class CSSStyleSheet;
+class DocumentStyleSheetCollection;
+class ShadowRoot;
+class StyleSheet;
+class StyleSheetCollection;
+
+class ShadowTreeStyleSheetCollection FINAL : public StyleSheetCollection {
+ WTF_MAKE_NONCOPYABLE(ShadowTreeStyleSheetCollection); WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit ShadowTreeStyleSheetCollection(ShadowRoot*);
+
+ bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode);
+
+private:
+ void collectStyleSheets(DocumentStyleSheetCollection*, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
+};
+
+}
+
+#endif
+
diff --git a/Source/core/dom/StyleElement.cpp b/Source/core/dom/StyleElement.cpp
index 0320d16..8f31ee4 100644
--- a/Source/core/dom/StyleElement.cpp
+++ b/Source/core/dom/StyleElement.cpp
@@ -127,7 +127,7 @@
Document* document = e->document();
if (m_sheet) {
if (m_sheet->isLoading())
- document->styleSheetCollection()->removePendingSheet();
+ document->styleSheetCollection()->removePendingSheet(e);
clearSheet();
}
@@ -169,7 +169,7 @@
if (isLoading())
return false;
- document->styleSheetCollection()->removePendingSheet();
+ document->styleSheetCollection()->removePendingSheet(m_sheet->ownerNode());
return true;
}
diff --git a/Source/core/dom/StyleSheetCollection.cpp b/Source/core/dom/StyleSheetCollection.cpp
index 80ca3d2..a665b80 100644
--- a/Source/core/dom/StyleSheetCollection.cpp
+++ b/Source/core/dom/StyleSheetCollection.cpp
@@ -37,13 +37,11 @@
#include "core/dom/DocumentStyleSheetCollection.h"
#include "core/dom/Element.h"
#include "core/dom/ProcessingInstruction.h"
+#include "core/dom/shadow/ShadowRoot.h"
#include "core/html/HTMLIFrameElement.h"
#include "core/html/HTMLLinkElement.h"
#include "core/html/HTMLStyleElement.h"
-#include "core/page/Page.h"
-#include "core/page/PageGroup.h"
#include "core/page/Settings.h"
-#include "core/page/UserContentURLPattern.h"
#include "core/svg/SVGStyleElement.h"
namespace WebCore {
@@ -86,7 +84,115 @@
m_scopingNodesForStyleScoped.remove(scopingNode);
}
-void StyleSheetCollection::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
+StyleSheetCollection::StyleResolverUpdateType StyleSheetCollection::compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets)
+{
+ // Find out which stylesheets are new.
+ unsigned newStylesheetCount = newStylesheets.size();
+ unsigned oldStylesheetCount = oldStyleSheets.size();
+ if (newStylesheetCount < oldStylesheetCount)
+ return Reconstruct;
+
+ unsigned newIndex = 0;
+ for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
+ if (newIndex >= newStylesheetCount)
+ return Reconstruct;
+ while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
+ addedSheets.append(newStylesheets[newIndex]->contents());
+ ++newIndex;
+ if (newIndex == newStylesheetCount)
+ return Reconstruct;
+ }
+ ++newIndex;
+ }
+ bool hasInsertions = !addedSheets.isEmpty();
+ while (newIndex < newStylesheetCount) {
+ addedSheets.append(newStylesheets[newIndex]->contents());
+ ++newIndex;
+ }
+ // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
+ // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
+ return hasInsertions ? Reset : Additive;
+}
+
+bool StyleSheetCollection::activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets)
+{
+ // StyleSheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
+ bool hasActiveLoadingStylesheet = false;
+ unsigned newStylesheetCount = newStyleSheets.size();
+ for (unsigned i = 0; i < newStylesheetCount; ++i) {
+ if (newStyleSheets[i]->isLoading())
+ hasActiveLoadingStylesheet = true;
+ }
+ if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
+ m_hadActiveLoadingStylesheet = false;
+ return true;
+ }
+ m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
+ return false;
+}
+
+void StyleSheetCollection::analyzeStyleSheetChange(StyleResolverUpdateMode updateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets, StyleResolverUpdateType& styleResolverUpdateType, bool& requiresFullStyleRecalc)
+{
+ styleResolverUpdateType = Reconstruct;
+ requiresFullStyleRecalc = true;
+
+ if (activeLoadingStyleSheetLoaded(newStyleSheets))
+ return;
+
+ if (updateMode != AnalyzedStyleUpdate)
+ return;
+ if (!document()->styleResolverIfExists())
+ return;
+
+ // Find out which stylesheets are new.
+ Vector<StyleSheetContents*> addedSheets;
+ styleResolverUpdateType = compareStyleSheets(oldStyleSheets, newStyleSheets, addedSheets);
+
+ // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
+ if (!document()->body() || document()->hasNodesWithPlaceholderStyle())
+ return;
+ StyleInvalidationAnalysis invalidationAnalysis(addedSheets);
+ if (invalidationAnalysis.dirtiesAllStyle())
+ return;
+ invalidationAnalysis.invalidateStyle(document());
+ requiresFullStyleRecalc = false;
+}
+
+void StyleSheetCollection::resetAllRuleSetsInTreeScope(StyleResolver* styleResolver)
+{
+ // FIXME: If many web developers use style scoped, implement reset RuleSets in per-scoping node manner.
+ if (DocumentOrderedList* styleScopedScopingNodes = scopingNodesForStyleScoped()) {
+ for (DocumentOrderedList::iterator it = styleScopedScopingNodes->begin(); it != styleScopedScopingNodes->end(); ++it)
+ styleResolver->resetAuthorStyle(toContainerNode(*it));
+ }
+ if (ListHashSet<Node*, 4>* removedNodes = scopingNodesRemoved()) {
+ for (ListHashSet<Node*, 4>::iterator it = removedNodes->begin(); it != removedNodes->end(); ++it)
+ styleResolver->resetAuthorStyle(toContainerNode(*it));
+ }
+ styleResolver->resetAuthorStyle(toContainerNode(m_treeScope->rootNode()));
+}
+
+static bool styleSheetsUseRemUnits(const Vector<RefPtr<CSSStyleSheet> >& sheets)
+{
+ for (unsigned i = 0; i < sheets.size(); ++i) {
+ if (sheets[i]->contents()->usesRemUnits())
+ return true;
+ }
+ return false;
+}
+
+void StyleSheetCollection::updateUsesRemUnits()
+{
+ m_usesRemUnits = styleSheetsUseRemUnits(m_activeAuthorStyleSheets);
+}
+
+StyleSheetCollectionForDocument::StyleSheetCollectionForDocument(TreeScope* treeScope)
+ : StyleSheetCollection(treeScope)
+{
+ ASSERT(treeScope->rootNode() == treeScope->rootNode()->document());
+}
+
+void StyleSheetCollectionForDocument::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
{
if (document()->settings() && !document()->settings()->authorAndUserStylesEnabled())
return;
@@ -173,80 +279,6 @@
}
}
-StyleSheetCollection::StyleResolverUpdateType StyleSheetCollection::compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets)
-{
- // Find out which stylesheets are new.
- unsigned newStylesheetCount = newStylesheets.size();
- unsigned oldStylesheetCount = oldStyleSheets.size();
- if (newStylesheetCount < oldStylesheetCount)
- return Reconstruct;
-
- unsigned newIndex = 0;
- for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
- if (newIndex >= newStylesheetCount)
- return Reconstruct;
- while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
- addedSheets.append(newStylesheets[newIndex]->contents());
- ++newIndex;
- if (newIndex == newStylesheetCount)
- return Reconstruct;
- }
- ++newIndex;
- }
- bool hasInsertions = !addedSheets.isEmpty();
- while (newIndex < newStylesheetCount) {
- addedSheets.append(newStylesheets[newIndex]->contents());
- ++newIndex;
- }
- // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
- // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
- return hasInsertions ? Reset : Additive;
-}
-
-bool StyleSheetCollection::activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets)
-{
- // StyleSheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
- bool hasActiveLoadingStylesheet = false;
- unsigned newStylesheetCount = newStyleSheets.size();
- for (unsigned i = 0; i < newStylesheetCount; ++i) {
- if (newStyleSheets[i]->isLoading())
- hasActiveLoadingStylesheet = true;
- }
- if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
- m_hadActiveLoadingStylesheet = false;
- return true;
- }
- m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
- return false;
-}
-
-void StyleSheetCollection::analyzeStyleSheetChange(StyleResolverUpdateMode updateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets, StyleResolverUpdateType& styleResolverUpdateType, bool& requiresFullStyleRecalc)
-{
- styleResolverUpdateType = Reconstruct;
- requiresFullStyleRecalc = true;
-
- if (activeLoadingStyleSheetLoaded(newStyleSheets))
- return;
-
- if (updateMode != AnalyzedStyleUpdate)
- return;
- if (!document()->styleResolverIfExists())
- return;
-
- // Find out which stylesheets are new.
- Vector<StyleSheetContents*> addedSheets;
- styleResolverUpdateType = compareStyleSheets(oldStyleSheets, newStyleSheets, addedSheets);
-
- // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
- if (!document()->body() || document()->hasNodesWithPlaceholderStyle())
- return;
- StyleInvalidationAnalysis invalidationAnalysis(addedSheets);
- if (invalidationAnalysis.dirtiesAllStyle())
- return;
- invalidationAnalysis.invalidateStyle(document());
- requiresFullStyleRecalc = false;
-}
-
static void collectActiveCSSStyleSheetsFromSeamlessParents(Vector<RefPtr<CSSStyleSheet> >& sheets, Document* document)
{
HTMLIFrameElement* seamlessParentIFrame = document->seamlessParentIFrame();
@@ -255,7 +287,7 @@
sheets.append(seamlessParentIFrame->document()->styleSheetCollection()->activeAuthorStyleSheets());
}
-bool StyleSheetCollection::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode, StyleResolverUpdateType& styleResolverUpdateType)
+bool StyleSheetCollectionForDocument::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode)
{
Vector<RefPtr<StyleSheet> > styleSheets;
Vector<RefPtr<CSSStyleSheet> > activeCSSStyleSheets;
@@ -264,25 +296,20 @@
collectActiveCSSStyleSheetsFromSeamlessParents(activeCSSStyleSheets, document());
collectStyleSheets(collections, styleSheets, activeCSSStyleSheets);
+ StyleResolverUpdateType styleResolverUpdateType;
bool requiresFullStyleRecalc;
analyzeStyleSheetChange(updateMode, activeAuthorStyleSheets(), activeCSSStyleSheets, styleResolverUpdateType, requiresFullStyleRecalc);
if (styleResolverUpdateType == Reconstruct) {
document()->clearStyleResolver();
} else {
- StyleResolver* styleResolver = document()->styleResolver();
- styleResolver->setBuildScopedStyleTreeInDocumentOrder(!scopingNodesForStyleScoped());
+ StyleResolver* styleResolver = document()->styleResolverIfExists();
+ ASSERT(styleResolver);
+ // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
+ // Need to change "false" to some valid condition.
+ styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
if (styleResolverUpdateType == Reset) {
- if (DocumentOrderedList* styleScopedScopingNodes = scopingNodesForStyleScoped()) {
- for (DocumentOrderedList::iterator it = styleScopedScopingNodes->begin(); it != styleScopedScopingNodes->end(); ++it)
- styleResolver->resetAuthorStyle(toContainerNode(*it));
- }
- if (ListHashSet<Node*, 4>* removedNodes = scopingNodesRemoved()) {
- for (ListHashSet<Node*, 4>::iterator it = removedNodes->begin(); it != removedNodes->end(); ++it)
- styleResolver->resetAuthorStyle(toContainerNode(*it));
- }
- ASSERT(m_treeScope->rootNode() == document());
- styleResolver->resetAuthorStyle(toContainerNode(m_treeScope->rootNode()));
+ resetAllRuleSetsInTreeScope(styleResolver);
styleResolver->appendAuthorStyleSheets(0, activeCSSStyleSheets);
} else {
ASSERT(styleResolverUpdateType == Additive);
@@ -292,6 +319,7 @@
m_scopingNodesForStyleScoped.didRemoveScopingNodes();
m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
m_styleSheetsForStyleSheetList.swap(styleSheets);
+ updateUsesRemUnits();
return requiresFullStyleRecalc;
}
diff --git a/Source/core/dom/StyleSheetCollection.h b/Source/core/dom/StyleSheetCollection.h
index 91da785..ce41034 100644
--- a/Source/core/dom/StyleSheetCollection.h
+++ b/Source/core/dom/StyleSheetCollection.h
@@ -52,47 +52,63 @@
class StyleSheetCollection {
WTF_MAKE_NONCOPYABLE(StyleSheetCollection); WTF_MAKE_FAST_ALLOCATED;
public:
- explicit StyleSheetCollection(TreeScope*);
-
void addStyleSheetCandidateNode(Node*, bool createdByParser);
void removeStyleSheetCandidateNode(Node*, ContainerNode* scopingNode);
+ bool hasStyleSheetCandidateNodes() const { return !m_styleSheetCandidateNodes.isEmpty(); }
Vector<RefPtr<CSSStyleSheet> >& activeAuthorStyleSheets() { return m_activeAuthorStyleSheets; }
Vector<RefPtr<StyleSheet> >& styleSheetsForStyleSheetList() { return m_styleSheetsForStyleSheetList; }
const Vector<RefPtr<CSSStyleSheet> >& activeAuthorStyleSheets() const { return m_activeAuthorStyleSheets; }
const Vector<RefPtr<StyleSheet> >& styleSheetsForStyleSheetList() const { return m_styleSheetsForStyleSheetList; }
+ bool usesRemUnits() const { return m_usesRemUnits; }
+
DocumentOrderedList& styleSheetCandidateNodes() { return m_styleSheetCandidateNodes; }
DocumentOrderedList* scopingNodesForStyleScoped() { return m_scopingNodesForStyleScoped.scopingNodes(); }
ListHashSet<Node*, 4>* scopingNodesRemoved() { return m_scopingNodesForStyleScoped.scopingNodesRemoved(); }
+protected:
+ explicit StyleSheetCollection(TreeScope*);
+
+ Document* document() { return m_treeScope->documentScope(); }
+
enum StyleResolverUpdateType {
Reconstruct,
Reset,
Additive
};
- bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode, StyleResolverUpdateType&);
+ void analyzeStyleSheetChange(StyleResolverUpdateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, StyleResolverUpdateType&, bool& requiresFullStyleRecalc);
+ void resetAllRuleSetsInTreeScope(StyleResolver*);
+ void updateUsesRemUnits();
private:
- Document* document() { return m_treeScope->documentScope(); }
-
- void collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
-
StyleResolverUpdateType compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets);
bool activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets);
- void analyzeStyleSheetChange(StyleResolverUpdateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, StyleResolverUpdateType&, bool& requiresFullStyleRecalc);
-
+protected:
Vector<RefPtr<StyleSheet> > m_styleSheetsForStyleSheetList;
Vector<RefPtr<CSSStyleSheet> > m_activeAuthorStyleSheets;
TreeScope* m_treeScope;
bool m_hadActiveLoadingStylesheet;
+ bool m_usesRemUnits;
DocumentOrderedList m_styleSheetCandidateNodes;
StyleSheetScopingNodeList m_scopingNodesForStyleScoped;
};
+// FIXME: rename this class to DocumentStyleSheetCollection.
+class StyleSheetCollectionForDocument FINAL : public StyleSheetCollection {
+ WTF_MAKE_NONCOPYABLE(StyleSheetCollectionForDocument); WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit StyleSheetCollectionForDocument(TreeScope*);
+
+ bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode);
+
+private:
+ void collectStyleSheets(DocumentStyleSheetCollection*, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
+};
+
}
#endif
diff --git a/Source/core/dom/Text.cpp b/Source/core/dom/Text.cpp
index 6a7878e..425aabd 100644
--- a/Source/core/dom/Text.cpp
+++ b/Source/core/dom/Text.cpp
@@ -292,13 +292,16 @@
return false;
}
-void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
+void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, AttachBehavior attachBehavior)
{
if (!attached())
return;
RenderText* textRenderer = toRenderText(renderer());
if (!textRenderer || !textRendererIsNeeded(NodeRenderingContext(this, textRenderer->style()))) {
- reattach();
+ if (attachBehavior == DeprecatedAttachNow)
+ reattach();
+ else
+ lazyReattach();
return;
}
textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
diff --git a/Source/core/dom/Text.h b/Source/core/dom/Text.h
index 1001eff..33a459a 100644
--- a/Source/core/dom/Text.h
+++ b/Source/core/dom/Text.h
@@ -49,7 +49,7 @@
bool recalcTextStyle(StyleChange);
bool textRendererIsNeeded(const NodeRenderingContext&);
virtual RenderText* createTextRenderer(RenderStyle*);
- void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData);
+ void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, AttachBehavior = AttachLazily);
virtual void attach(const AttachContext& = AttachContext()) OVERRIDE FINAL;
diff --git a/Source/core/dom/TreeScope.cpp b/Source/core/dom/TreeScope.cpp
index e54c9be..2a4ae34 100644
--- a/Source/core/dom/TreeScope.cpp
+++ b/Source/core/dom/TreeScope.cpp
@@ -31,9 +31,9 @@
#include "core/dom/ContainerNode.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
+#include "core/dom/ElementTraversal.h"
#include "core/dom/EventPathWalker.h"
#include "core/dom/IdTargetObserverRegistry.h"
-#include "core/dom/NodeTraversal.h"
#include "core/dom/TreeScopeAdopter.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/ShadowRoot.h"
diff --git a/Source/core/dom/ViewportArguments.cpp b/Source/core/dom/ViewportArguments.cpp
index 92ae2cf..0a2708d 100644
--- a/Source/core/dom/ViewportArguments.cpp
+++ b/Source/core/dom/ViewportArguments.cpp
@@ -68,7 +68,7 @@
return value;
}
-PageScaleConstraints ViewportArguments::resolve(const FloatSize& initialViewportSize, const FloatSize& deviceSize, int defaultWidth) const
+PageScaleConstraints ViewportArguments::resolve(const FloatSize& initialViewportSize, int defaultWidth) const
{
float resultWidth = width;
float resultMaxWidth = maxWidth;
@@ -168,19 +168,19 @@
switch (static_cast<int>(resultWidth)) {
case ViewportArguments::ValueDeviceWidth:
- resultWidth = deviceSize.width();
+ resultWidth = initialViewportSize.width();
break;
case ViewportArguments::ValueDeviceHeight:
- resultWidth = deviceSize.height();
+ resultWidth = initialViewportSize.height();
break;
}
switch (static_cast<int>(resultHeight)) {
case ViewportArguments::ValueDeviceWidth:
- resultHeight = deviceSize.width();
+ resultHeight = initialViewportSize.width();
break;
case ViewportArguments::ValueDeviceHeight:
- resultHeight = deviceSize.height();
+ resultHeight = initialViewportSize.height();
break;
}
@@ -396,11 +396,12 @@
static const char* viewportErrorMessageTemplate(ViewportErrorCode errorCode)
{
static const char* const errors[] = {
- "Viewport argument key \"%replacement1\" not recognized and ignored.",
- "Viewport argument value \"%replacement1\" for key \"%replacement2\" is invalid, and has been ignored.",
- "Viewport argument value \"%replacement1\" for key \"%replacement2\" was truncated to its numeric prefix.",
- "Viewport maximum-scale cannot be larger than 10.0. The maximum-scale will be set to 10.0.",
- "Viewport target-densitydpi is not supported.",
+ "Note that ';' is not a key-value pair separator. The list should be comma-separated.",
+ "The key \"%replacement1\" is not recognized and ignored.",
+ "The value \"%replacement1\" for key \"%replacement2\" is invalid, and has been ignored.",
+ "The value \"%replacement1\" for key \"%replacement2\" was truncated to its numeric prefix.",
+ "The value for key \"maximum-scale\" is out of bounds and the value has been clamped.",
+ "The key \"target-densitydpi\" is not supported.",
};
return errors[errorCode];
@@ -409,6 +410,7 @@
static MessageLevel viewportErrorMessageLevel(ViewportErrorCode errorCode)
{
switch (errorCode) {
+ case InvalidKeyValuePairSeparatorError:
case TruncatedViewportArgumentValueError:
case TargetDensityDpiUnsupported:
return WarningMessageLevel;
@@ -434,9 +436,6 @@
if (!replacement2.isNull())
message.replace("%replacement2", replacement2);
- if ((errorCode == UnrecognizedViewportArgumentValueError || errorCode == TruncatedViewportArgumentValueError) && replacement1.find(';') != WTF::notFound)
- message.append(" Note that ';' is not a separator in viewport values. The list should be comma-separated.");
-
// FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
document->addConsoleMessage(RenderingMessageSource, viewportErrorMessageLevel(errorCode), message);
}
diff --git a/Source/core/dom/ViewportArguments.h b/Source/core/dom/ViewportArguments.h
index 5afacfe..6533441 100644
--- a/Source/core/dom/ViewportArguments.h
+++ b/Source/core/dom/ViewportArguments.h
@@ -37,6 +37,7 @@
class Document;
enum ViewportErrorCode {
+ InvalidKeyValuePairSeparatorError,
UnrecognizedViewportArgumentKeyError,
UnrecognizedViewportArgumentValueError,
TruncatedViewportArgumentValueError,
@@ -87,7 +88,7 @@
}
// All arguments are in CSS units.
- PageScaleConstraints resolve(const FloatSize& initialViewportSize, const FloatSize& deviceSize, int defaultWidth) const;
+ PageScaleConstraints resolve(const FloatSize& initialViewportSize, int defaultWidth) const;
float width;
float minWidth;
diff --git a/Source/core/dom/VisitedLinkState.cpp b/Source/core/dom/VisitedLinkState.cpp
index 77e8fd1..cf1d417 100644
--- a/Source/core/dom/VisitedLinkState.cpp
+++ b/Source/core/dom/VisitedLinkState.cpp
@@ -30,7 +30,7 @@
#include "core/dom/VisitedLinkState.h"
#include "HTMLNames.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
#include "core/html/HTMLAnchorElement.h"
#include "core/page/Page.h"
#include "public/platform/Platform.h"
diff --git a/Source/core/dom/WheelEvent.cpp b/Source/core/dom/WheelEvent.cpp
index c7bdf0d..bcb3d69 100644
--- a/Source/core/dom/WheelEvent.cpp
+++ b/Source/core/dom/WheelEvent.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
* Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
* Copyright (C) 2003, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -29,15 +30,29 @@
namespace WebCore {
+static inline double wheelTicksToPixels(double ticks)
+{
+ // Make sure we use +0 for all zeros.
+ if (!ticks)
+ return 0;
+ return -ticks * WheelEvent::TickMultiplier;
+}
+
WheelEventInit::WheelEventInit()
- : wheelDeltaX(0)
+ : deltaX(0)
+ , deltaY(0)
+ , deltaZ(0)
+ , wheelDeltaX(0)
, wheelDeltaY(0)
, deltaMode(WheelEvent::DOM_DELTA_PIXEL)
{
}
WheelEvent::WheelEvent()
- : m_deltaMode(DOM_DELTA_PIXEL)
+ : m_deltaX(0)
+ , m_deltaY(0)
+ , m_deltaZ(0)
+ , m_deltaMode(DOM_DELTA_PIXEL)
, m_directionInvertedFromDevice(false)
{
ScriptWrappable::init(this);
@@ -45,7 +60,9 @@
WheelEvent::WheelEvent(const AtomicString& type, const WheelEventInit& initializer)
: MouseEvent(type, initializer)
- , m_wheelDelta(IntPoint(initializer.wheelDeltaX, initializer.wheelDeltaY))
+ , m_deltaX(initializer.deltaX ? initializer.deltaX : -initializer.wheelDeltaX)
+ , m_deltaY(initializer.deltaY ? initializer.deltaY : -initializer.wheelDeltaY)
+ , m_deltaZ(initializer.deltaZ)
, m_deltaMode(initializer.deltaMode)
{
ScriptWrappable::init(this);
@@ -54,12 +71,14 @@
WheelEvent::WheelEvent(const FloatPoint& wheelTicks, const FloatPoint& rawDelta, unsigned deltaMode,
PassRefPtr<AbstractView> view, const IntPoint& screenLocation, const IntPoint& pageLocation,
bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool directionInvertedFromDevice)
- : MouseEvent(eventNames().mousewheelEvent,
+ : MouseEvent(eventNames().wheelEvent,
true, true, view, 0, screenLocation.x(), screenLocation.y(),
pageLocation.x(), pageLocation.y(),
0, 0,
ctrlKey, altKey, shiftKey, metaKey, 0, 0, 0, false)
- , m_wheelDelta(IntPoint(static_cast<int>(wheelTicks.x() * TickMultiplier), static_cast<int>(wheelTicks.y() * TickMultiplier)))
+ , m_deltaX(wheelTicksToPixels(wheelTicks.x()))
+ , m_deltaY(wheelTicksToPixels(wheelTicks.y()))
+ , m_deltaZ(0) // FIXME: Not supported.
, m_rawDelta(roundedIntPoint(rawDelta))
, m_deltaMode(deltaMode)
, m_directionInvertedFromDevice(directionInvertedFromDevice)
@@ -74,7 +93,7 @@
if (dispatched())
return;
- initUIEvent(eventNames().mousewheelEvent, true, true, view, 0);
+ initUIEvent(eventNames().wheelEvent, true, true, view, 0);
m_screenLocation = IntPoint(screenX, screenY);
m_ctrlKey = ctrlKey;
@@ -82,9 +101,8 @@
m_shiftKey = shiftKey;
m_metaKey = metaKey;
- // Normalize to the Windows 120 multiple
- m_wheelDelta = IntPoint(rawDeltaX * TickMultiplier, rawDeltaY * TickMultiplier);
-
+ m_deltaX = wheelTicksToPixels(rawDeltaX);
+ m_deltaY = wheelTicksToPixels(rawDeltaY);
m_rawDelta = IntPoint(rawDeltaX, rawDeltaY);
m_deltaMode = DOM_DELTA_PIXEL;
m_directionInvertedFromDevice = false;
diff --git a/Source/core/dom/WheelEvent.h b/Source/core/dom/WheelEvent.h
index ba17ab4..870c9b6 100644
--- a/Source/core/dom/WheelEvent.h
+++ b/Source/core/dom/WheelEvent.h
@@ -3,6 +3,7 @@
* Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
* Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -35,8 +36,11 @@
struct WheelEventInit : public MouseEventInit {
WheelEventInit();
- int wheelDeltaX;
- int wheelDeltaY;
+ double deltaX;
+ double deltaY;
+ double deltaZ;
+ int wheelDeltaX; // Deprecated.
+ int wheelDeltaY; // Deprecated.
unsigned deltaMode;
};
@@ -77,9 +81,12 @@
int screenX, int screenY, int pageX, int pageY,
bool ctrlKey, bool altKey, bool shiftKey, bool metaKey);
- int wheelDelta() const { return m_wheelDelta.y() ? m_wheelDelta.y() : m_wheelDelta.x(); }
- int wheelDeltaX() const { return m_wheelDelta.x(); }
- int wheelDeltaY() const { return m_wheelDelta.y(); }
+ double deltaX() const { return m_deltaX; } // Positive when scrolling right.
+ double deltaY() const { return m_deltaY; } // Positive when scrolling down.
+ double deltaZ() const { return m_deltaZ; }
+ int wheelDelta() const { return wheelDeltaY() ? wheelDeltaY() : wheelDeltaX(); } // Deprecated.
+ int wheelDeltaX() const { return -m_deltaX; } // Deprecated, negative when scrolling right.
+ int wheelDeltaY() const { return -m_deltaY; } // Deprecated, negative when scrolling down.
int rawDeltaX() const { return m_rawDelta.x(); }
int rawDeltaY() const { return m_rawDelta.y(); }
unsigned deltaMode() const { return m_deltaMode; }
@@ -96,7 +103,9 @@
unsigned, PassRefPtr<AbstractView>, const IntPoint& screenLocation, const IntPoint& pageLocation,
bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool directionInvertedFromDevice);
- IntPoint m_wheelDelta;
+ double m_deltaX;
+ double m_deltaY;
+ double m_deltaZ;
IntPoint m_rawDelta;
unsigned m_deltaMode;
bool m_directionInvertedFromDevice;
diff --git a/Source/core/dom/WheelEvent.idl b/Source/core/dom/WheelEvent.idl
index 9dc0e4a..8ee63ae 100644
--- a/Source/core/dom/WheelEvent.idl
+++ b/Source/core/dom/WheelEvent.idl
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -18,17 +19,23 @@
* Boston, MA 02110-1301, USA.
*/
+// Introduced in DOM Level 3:
[
ConstructorTemplate=Event
] interface WheelEvent : MouseEvent {
+ // DeltaModeCode
const unsigned long DOM_DELTA_PIXEL = 0x00;
const unsigned long DOM_DELTA_LINE = 0x01;
const unsigned long DOM_DELTA_PAGE = 0x02;
- [InitializedByEventConstructor] readonly attribute long wheelDeltaX;
- [InitializedByEventConstructor] readonly attribute long wheelDeltaY;
+ [InitializedByEventConstructor] readonly attribute double deltaX;
+ [InitializedByEventConstructor] readonly attribute double deltaY;
+ [InitializedByEventConstructor] readonly attribute double deltaZ;
[InitializedByEventConstructor] readonly attribute unsigned long deltaMode;
+ // Non standard API.
+ [InitializedByEventConstructor] readonly attribute long wheelDeltaX;
+ [InitializedByEventConstructor] readonly attribute long wheelDeltaY;
readonly attribute long wheelDelta;
// WebKit Extension
diff --git a/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp b/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
index c5a64fa..80ff995 100644
--- a/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
+++ b/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
@@ -29,7 +29,6 @@
#include "core/dom/shadow/ComposedShadowTreeWalker.h"
#include "core/dom/Element.h"
-#include "core/dom/shadow/ContentDistributor.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
diff --git a/Source/core/dom/shadow/ContentDistribution.cpp b/Source/core/dom/shadow/ContentDistribution.cpp
new file mode 100644
index 0000000..405ce56
--- /dev/null
+++ b/Source/core/dom/shadow/ContentDistribution.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/dom/shadow/ContentDistribution.h"
+
+namespace WebCore {
+
+void ContentDistribution::swap(ContentDistribution& other)
+{
+ m_nodes.swap(other.m_nodes);
+ m_indices.swap(other.m_indices);
+}
+
+void ContentDistribution::append(PassRefPtr<Node> node)
+{
+ size_t size = m_nodes.size();
+ m_indices.set(node.get(), size);
+ m_nodes.append(node);
+}
+
+size_t ContentDistribution::find(const Node* node) const
+{
+ HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
+ if (it == m_indices.end())
+ return notFound;
+
+ return it.get()->value;
+}
+
+Node* ContentDistribution::nextTo(const Node* node) const
+{
+ size_t index = find(node);
+ if (index == notFound || index + 1 == size())
+ return 0;
+ return at(index + 1).get();
+}
+
+Node* ContentDistribution::previousTo(const Node* node) const
+{
+ size_t index = find(node);
+ if (index == notFound || !index)
+ return 0;
+ return at(index - 1).get();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/shadow/ContentDistribution.h b/Source/core/dom/shadow/ContentDistribution.h
new file mode 100644
index 0000000..2fd8fc1
--- /dev/null
+++ b/Source/core/dom/shadow/ContentDistribution.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ContentDistribution_h
+#define ContentDistribution_h
+
+#include "core/dom/Node.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class ContentDistribution {
+public:
+ PassRefPtr<Node> first() const { return m_nodes.first(); }
+ PassRefPtr<Node> last() const { return m_nodes.last(); }
+ PassRefPtr<Node> at(size_t index) const { return m_nodes.at(index); }
+
+ size_t size() const { return m_nodes.size(); }
+ bool isEmpty() const { return m_nodes.isEmpty(); }
+
+ void append(PassRefPtr<Node>);
+ void clear() { m_nodes.clear(); m_indices.clear(); }
+
+ bool contains(const Node* node) const { return m_indices.contains(node); }
+ size_t find(const Node*) const;
+ Node* nextTo(const Node*) const;
+ Node* previousTo(const Node*) const;
+
+ void swap(ContentDistribution& other);
+
+ const Vector<RefPtr<Node> >& nodes() const { return m_nodes; }
+
+private:
+ Vector<RefPtr<Node> > m_nodes;
+ HashMap<const Node*, size_t> m_indices;
+};
+
+}
+
+#endif
diff --git a/Source/core/dom/shadow/ContentDistributor.cpp b/Source/core/dom/shadow/ContentDistributor.cpp
deleted file mode 100644
index 9bbccdc..0000000
--- a/Source/core/dom/shadow/ContentDistributor.cpp
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "core/dom/shadow/ContentDistributor.h"
-
-#include "core/dom/NodeTraversal.h"
-#include "core/dom/shadow/ElementShadow.h"
-#include "core/dom/shadow/ShadowRoot.h"
-#include "core/html/shadow/HTMLContentElement.h"
-#include "core/html/shadow/HTMLShadowElement.h"
-
-
-namespace WebCore {
-
-void ContentDistribution::swap(ContentDistribution& other)
-{
- m_nodes.swap(other.m_nodes);
- m_indices.swap(other.m_indices);
-}
-
-void ContentDistribution::append(PassRefPtr<Node> node)
-{
- size_t size = m_nodes.size();
- m_indices.set(node.get(), size);
- m_nodes.append(node);
-}
-
-size_t ContentDistribution::find(const Node* node) const
-{
- HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
- if (it == m_indices.end())
- return notFound;
-
- return it.get()->value;
-}
-
-Node* ContentDistribution::nextTo(const Node* node) const
-{
- size_t index = find(node);
- if (index == notFound || index + 1 == size())
- return 0;
- return at(index + 1).get();
-}
-
-Node* ContentDistribution::previousTo(const Node* node) const
-{
- size_t index = find(node);
- if (index == notFound || !index)
- return 0;
- return at(index - 1).get();
-}
-
-
-ScopeContentDistribution::ScopeContentDistribution()
- : m_insertionPointAssignedTo(0)
- , m_numberOfShadowElementChildren(0)
- , m_numberOfContentElementChildren(0)
- , m_numberOfElementShadowChildren(0)
- , m_insertionPointListIsValid(false)
-{
-}
-
-void ScopeContentDistribution::setInsertionPointAssignedTo(PassRefPtr<InsertionPoint> insertionPoint)
-{
- m_insertionPointAssignedTo = insertionPoint;
-}
-
-void ScopeContentDistribution::invalidateInsertionPointList()
-{
- m_insertionPointListIsValid = false;
- m_insertionPointList.clear();
-}
-
-const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertionPointList(ShadowRoot* shadowRoot)
-{
- if (m_insertionPointListIsValid)
- return m_insertionPointList;
-
- m_insertionPointListIsValid = true;
- ASSERT(m_insertionPointList.isEmpty());
-
- if (!shadowRoot->containsInsertionPoints())
- return m_insertionPointList;
-
- for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
- if (element->isInsertionPoint())
- m_insertionPointList.append(toInsertionPoint(element));
- }
-
- return m_insertionPointList;
-}
-
-void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point)
-{
- if (isHTMLShadowElement(point))
- ++m_numberOfShadowElementChildren;
- else if (isHTMLContentElement(point))
- ++m_numberOfContentElementChildren;
- else
- ASSERT_NOT_REACHED();
-
- invalidateInsertionPointList();
-}
-
-void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point)
-{
- if (isHTMLShadowElement(point))
- --m_numberOfShadowElementChildren;
- else if (isHTMLContentElement(point))
- --m_numberOfContentElementChildren;
- else
- ASSERT_NOT_REACHED();
-
- ASSERT(m_numberOfContentElementChildren >= 0);
- ASSERT(m_numberOfShadowElementChildren >= 0);
-
- invalidateInsertionPointList();
-}
-
-ContentDistributor::ContentDistributor()
- : m_needsSelectFeatureSet(false)
-{
-}
-
-ContentDistributor::~ContentDistributor()
-{
-}
-
-InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
-{
- return m_nodeToInsertionPoint.get(key);
-}
-
-void ContentDistributor::populate(Node* node, Vector<Node*>& pool)
-{
- node->lazyReattachIfAttached();
-
- if (!isActiveInsertionPoint(node)) {
- pool.append(node);
- return;
- }
-
- InsertionPoint* insertionPoint = toInsertionPoint(node);
- if (insertionPoint->hasDistribution()) {
- for (size_t i = 0; i < insertionPoint->size(); ++i)
- populate(insertionPoint->at(i), pool);
- } else {
- for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
- pool.append(fallbackNode);
- }
-}
-
-void ContentDistributor::distribute(Element* host)
-{
- Vector<Node*> pool;
- for (Node* node = host->firstChild(); node; node = node->nextSibling())
- populate(node, pool);
-
- host->setNeedsStyleRecalc();
-
- Vector<bool> distributed(pool.size());
- distributed.fill(false);
-
- Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
- for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
- HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
-
- if (ScopeContentDistribution* scope = root->scopeDistribution()) {
- const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
- for (size_t i = 0; i < insertionPoints.size(); ++i) {
- InsertionPoint* point = insertionPoints[i].get();
- if (!point->isActive())
- continue;
-
- if (isHTMLShadowElement(point)) {
- if (!firstActiveShadowInsertionPoint)
- firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
- } else {
- distributeSelectionsTo(point, pool, distributed);
- if (ElementShadow* shadow = shadowOfParentForDistribution(point))
- shadow->setNeedsDistributionRecalc();
- }
- }
- }
-
- if (firstActiveShadowInsertionPoint)
- activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
- }
-
- for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
- HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
- ShadowRoot* root = shadowElement->containingShadowRoot();
- ASSERT(root);
- if (!shadowElement->shouldSelect()) {
- if (root->olderShadowRoot())
- root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
- } else if (root->olderShadowRoot()) {
- distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
- root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
- } else {
- distributeSelectionsTo(shadowElement, pool, distributed);
- }
- if (ElementShadow* shadow = shadowOfParentForDistribution(shadowElement))
- shadow->setNeedsDistributionRecalc();
- }
-}
-
-void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const Vector<Node*>& pool, Vector<bool>& distributed)
-{
- ContentDistribution distribution;
-
- for (size_t i = 0; i < pool.size(); ++i) {
- if (distributed[i])
- continue;
-
- if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(pool, i))
- continue;
-
- Node* child = pool[i];
- distribution.append(child);
- m_nodeToInsertionPoint.add(child, insertionPoint);
- distributed[i] = true;
- }
-
- insertionPoint->lazyReattachIfAttached();
- insertionPoint->setDistribution(distribution);
-}
-
-void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
-{
- ContentDistribution distribution;
- for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
- node->lazyReattachIfAttached();
- if (isActiveInsertionPoint(node)) {
- InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
- if (innerInsertionPoint->hasDistribution()) {
- for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
- distribution.append(innerInsertionPoint->at(i));
- m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
- }
- } else {
- for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
- distribution.append(child);
- m_nodeToInsertionPoint.add(child, insertionPoint);
- }
- }
- } else {
- distribution.append(node);
- m_nodeToInsertionPoint.add(node, insertionPoint);
- }
- }
-
- insertionPoint->lazyReattachIfAttached();
- insertionPoint->setDistribution(distribution);
-}
-
-const SelectRuleFeatureSet& ContentDistributor::ensureSelectFeatureSet(ElementShadow* shadow)
-{
- if (!m_needsSelectFeatureSet)
- return m_selectFeatures;
-
- m_selectFeatures.clear();
- for (ShadowRoot* root = shadow->oldestShadowRoot(); root; root = root->youngerShadowRoot())
- collectSelectFeatureSetFrom(root);
- m_needsSelectFeatureSet = false;
- return m_selectFeatures;
-}
-
-void ContentDistributor::collectSelectFeatureSetFrom(ShadowRoot* root)
-{
- if (!root->containsShadowRoots() && !root->containsContentElements())
- return;
-
- for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element, root)) {
- if (ElementShadow* shadow = element->shadow())
- m_selectFeatures.add(shadow->ensureSelectFeatureSet());
- if (!isHTMLContentElement(element))
- continue;
- const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
- for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
- for (const CSSSelector* component = selector; component; component = component->tagHistory())
- m_selectFeatures.collectFeaturesFromSelector(component);
- }
- }
-}
-
-void ContentDistributor::didAffectSelector(Element* host, AffectedSelectorMask mask)
-{
- if (ensureSelectFeatureSet(host->shadow()).hasSelectorFor(mask))
- host->shadow()->setNeedsDistributionRecalc();
-}
-
-void ContentDistributor::willAffectSelector(Element* host)
-{
- for (ElementShadow* shadow = host->shadow(); shadow; shadow = shadow->containingShadow()) {
- if (shadow->distributor().needsSelectFeatureSet())
- break;
- shadow->distributor().setNeedsSelectFeatureSet();
- }
- host->shadow()->setNeedsDistributionRecalc();
-}
-
-void ContentDistributor::clearDistribution(Element* host)
-{
- m_nodeToInsertionPoint.clear();
-
- for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
- if (ScopeContentDistribution* scope = root->scopeDistribution())
- scope->setInsertionPointAssignedTo(0);
- }
-}
-
-}
diff --git a/Source/core/dom/shadow/ContentDistributor.h b/Source/core/dom/shadow/ContentDistributor.h
deleted file mode 100644
index e98b40b..0000000
--- a/Source/core/dom/shadow/ContentDistributor.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ContentDistributor_h
-#define ContentDistributor_h
-
-#include "core/dom/shadow/SelectRuleFeatureSet.h"
-#include "wtf/Forward.h"
-#include "wtf/HashMap.h"
-#include "wtf/Vector.h"
-
-namespace WebCore {
-
-class ContainerNode;
-class Element;
-class InsertionPoint;
-class Node;
-class ShadowRoot;
-
-class ContentDistribution {
-public:
- PassRefPtr<Node> first() const { return m_nodes.first(); }
- PassRefPtr<Node> last() const { return m_nodes.last(); }
- PassRefPtr<Node> at(size_t index) const { return m_nodes.at(index); }
-
- size_t size() const { return m_nodes.size(); }
- bool isEmpty() const { return m_nodes.isEmpty(); }
-
- void append(PassRefPtr<Node>);
- void clear() { m_nodes.clear(); m_indices.clear(); }
-
- bool contains(const Node* node) const { return m_indices.contains(node); }
- size_t find(const Node*) const;
- Node* nextTo(const Node*) const;
- Node* previousTo(const Node*) const;
-
- void swap(ContentDistribution& other);
-
- const Vector<RefPtr<Node> >& nodes() const { return m_nodes; }
-
-private:
- Vector<RefPtr<Node> > m_nodes;
- HashMap<const Node*, size_t> m_indices;
-};
-
-class ScopeContentDistribution {
-public:
- ScopeContentDistribution();
-
- InsertionPoint* insertionPointAssignedTo() const { return m_insertionPointAssignedTo.get(); }
- void setInsertionPointAssignedTo(PassRefPtr<InsertionPoint>);
-
- void registerInsertionPoint(InsertionPoint*);
- void unregisterInsertionPoint(InsertionPoint*);
- bool hasShadowElementChildren() const { return m_numberOfShadowElementChildren > 0; }
- bool hasContentElementChildren() const { return m_numberOfContentElementChildren > 0; }
-
- void registerElementShadow() { ++m_numberOfElementShadowChildren; }
- void unregisterElementShadow() { ASSERT(m_numberOfElementShadowChildren > 0); --m_numberOfElementShadowChildren; }
- unsigned numberOfElementShadowChildren() const { return m_numberOfElementShadowChildren; }
- bool hasElementShadowChildren() const { return m_numberOfElementShadowChildren > 0; }
-
- void invalidateInsertionPointList();
- const Vector<RefPtr<InsertionPoint> >& ensureInsertionPointList(ShadowRoot*);
-
-private:
- RefPtr<InsertionPoint> m_insertionPointAssignedTo;
- unsigned m_numberOfShadowElementChildren;
- unsigned m_numberOfContentElementChildren;
- unsigned m_numberOfElementShadowChildren;
- bool m_insertionPointListIsValid;
- Vector<RefPtr<InsertionPoint> > m_insertionPointList;
-};
-
-class ContentDistributor {
- WTF_MAKE_NONCOPYABLE(ContentDistributor);
-public:
- ContentDistributor();
- ~ContentDistributor();
-
- InsertionPoint* findInsertionPointFor(const Node* key) const;
- const SelectRuleFeatureSet& ensureSelectFeatureSet(ElementShadow*);
-
- void distributeSelectionsTo(InsertionPoint*, const Vector<Node*>& pool, Vector<bool>& distributed);
- void distributeNodeChildrenTo(InsertionPoint*, ContainerNode*);
-
- void didAffectSelector(Element* host, AffectedSelectorMask);
- void willAffectSelector(Element* host);
-
- void distribute(Element* host);
- void clearDistribution(Element* host);
-
-private:
- void populate(Node*, Vector<Node*>&);
-
- void collectSelectFeatureSetFrom(ShadowRoot*);
- bool needsSelectFeatureSet() const { return m_needsSelectFeatureSet; }
- void setNeedsSelectFeatureSet() { m_needsSelectFeatureSet = true; }
-
- typedef HashMap<const Node*, RefPtr<InsertionPoint> > NodeInsertionPointMap;
- NodeInsertionPointMap m_nodeToInsertionPoint;
- SelectRuleFeatureSet m_selectFeatures;
- bool m_needsSelectFeatureSet;
-};
-
-}
-
-#endif
diff --git a/Source/core/dom/shadow/ElementShadow.cpp b/Source/core/dom/shadow/ElementShadow.cpp
index 380a5f7..b6eef01 100644
--- a/Source/core/dom/shadow/ElementShadow.cpp
+++ b/Source/core/dom/shadow/ElementShadow.cpp
@@ -28,9 +28,34 @@
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/ContainerNodeAlgorithms.h"
+#include "core/dom/ElementTraversal.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/shadow/ContentDistribution.h"
+#include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
namespace WebCore {
+PassOwnPtr<ElementShadow> ElementShadow::create()
+{
+ return adoptPtr(new ElementShadow());
+}
+
+ElementShadow::ElementShadow()
+ : m_needsDistributionRecalc(false)
+ , m_applyAuthorStyles(false)
+ , m_needsSelectFeatureSet(false)
+{
+}
+
+ElementShadow::~ElementShadow()
+{
+ removeAllShadowRoots();
+}
+
ShadowRoot* ElementShadow::addShadowRoot(Element* shadowHost, ShadowRoot::ShadowRootType type)
{
RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(shadowHost->document(), type);
@@ -146,4 +171,191 @@
return false;
}
+InsertionPoint* ElementShadow::findInsertionPointFor(const Node* key) const
+{
+ return m_nodeToInsertionPoint.get(key);
+}
+
+void ElementShadow::populate(Node* node, Vector<Node*>& pool)
+{
+ if (!isActiveInsertionPoint(node)) {
+ pool.append(node);
+ return;
+ }
+
+ InsertionPoint* insertionPoint = toInsertionPoint(node);
+ if (insertionPoint->hasDistribution()) {
+ for (size_t i = 0; i < insertionPoint->size(); ++i)
+ populate(insertionPoint->at(i), pool);
+ } else {
+ for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
+ pool.append(fallbackNode);
+ }
+}
+
+void ElementShadow::distribute()
+{
+ Vector<Node*> pool;
+ for (Node* node = host()->firstChild(); node; node = node->nextSibling())
+ populate(node, pool);
+
+ host()->setNeedsStyleRecalc();
+
+ Vector<bool> distributed(pool.size());
+ distributed.fill(false);
+
+ Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
+
+ if (ScopeContentDistribution* scope = root->scopeDistribution()) {
+ const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
+ for (size_t i = 0; i < insertionPoints.size(); ++i) {
+ InsertionPoint* point = insertionPoints[i].get();
+ if (!point->isActive())
+ continue;
+
+ if (isHTMLShadowElement(point)) {
+ if (!firstActiveShadowInsertionPoint)
+ firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
+ } else {
+ distributeSelectionsTo(point, pool, distributed);
+ if (ElementShadow* shadow = shadowOfParentForDistribution(point))
+ shadow->setNeedsDistributionRecalc();
+ }
+ }
+ }
+
+ if (firstActiveShadowInsertionPoint)
+ activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
+ }
+
+ for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
+ HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
+ ShadowRoot* root = shadowElement->containingShadowRoot();
+ ASSERT(root);
+ if (!shadowElement->shouldSelect()) {
+ if (root->olderShadowRoot())
+ root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
+ } else if (root->olderShadowRoot()) {
+ distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
+ root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
+ } else {
+ distributeSelectionsTo(shadowElement, pool, distributed);
+ }
+ if (ElementShadow* shadow = shadowOfParentForDistribution(shadowElement))
+ shadow->setNeedsDistributionRecalc();
+ }
+
+ // Detach all nodes that were not distributed and have a renderer.
+ for (size_t i = 0; i < pool.size(); ++i) {
+ if (distributed[i])
+ continue;
+ if (pool[i]->renderer())
+ pool[i]->lazyReattachIfAttached();
+ }
+}
+
+void ElementShadow::distributeSelectionsTo(InsertionPoint* insertionPoint, const Vector<Node*>& pool, Vector<bool>& distributed)
+{
+ ContentDistribution distribution;
+
+ for (size_t i = 0; i < pool.size(); ++i) {
+ if (distributed[i])
+ continue;
+
+ if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(pool, i))
+ continue;
+
+ Node* child = pool[i];
+ distribution.append(child);
+ m_nodeToInsertionPoint.add(child, insertionPoint);
+ distributed[i] = true;
+ }
+
+ insertionPoint->setDistribution(distribution);
+}
+
+void ElementShadow::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
+{
+ ContentDistribution distribution;
+ for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
+ if (isActiveInsertionPoint(node)) {
+ InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
+ if (innerInsertionPoint->hasDistribution()) {
+ for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
+ distribution.append(innerInsertionPoint->at(i));
+ m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
+ }
+ } else {
+ for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
+ distribution.append(child);
+ m_nodeToInsertionPoint.add(child, insertionPoint);
+ }
+ }
+ } else {
+ distribution.append(node);
+ m_nodeToInsertionPoint.add(node, insertionPoint);
+ }
+ }
+
+ insertionPoint->setDistribution(distribution);
+}
+
+const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
+{
+ if (!m_needsSelectFeatureSet)
+ return m_selectFeatures;
+
+ m_selectFeatures.clear();
+ for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
+ collectSelectFeatureSetFrom(root);
+ m_needsSelectFeatureSet = false;
+ return m_selectFeatures;
+}
+
+void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot* root)
+{
+ if (!root->containsShadowRoots() && !root->containsContentElements())
+ return;
+
+ for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element, root)) {
+ if (ElementShadow* shadow = element->shadow())
+ m_selectFeatures.add(shadow->ensureSelectFeatureSet());
+ if (!isHTMLContentElement(element))
+ continue;
+ const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
+ for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
+ for (const CSSSelector* component = selector; component; component = component->tagHistory())
+ m_selectFeatures.collectFeaturesFromSelector(component);
+ }
+ }
+}
+
+void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
+{
+ if (ensureSelectFeatureSet().hasSelectorFor(mask))
+ setNeedsDistributionRecalc();
+}
+
+void ElementShadow::willAffectSelector()
+{
+ for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
+ if (shadow->needsSelectFeatureSet())
+ break;
+ shadow->setNeedsSelectFeatureSet();
+ }
+ setNeedsDistributionRecalc();
+}
+
+void ElementShadow::clearDistribution()
+{
+ m_nodeToInsertionPoint.clear();
+
+ for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+ if (ScopeContentDistribution* scope = root->scopeDistribution())
+ scope->setInsertionPointAssignedTo(0);
+ }
+}
+
} // namespace
diff --git a/Source/core/dom/shadow/ElementShadow.h b/Source/core/dom/shadow/ElementShadow.h
index 3f16157..8ac38e9 100644
--- a/Source/core/dom/shadow/ElementShadow.h
+++ b/Source/core/dom/shadow/ElementShadow.h
@@ -27,27 +27,24 @@
#ifndef ElementShadow_h
#define ElementShadow_h
-#include "core/dom/shadow/ContentDistributor.h"
+#include "core/dom/shadow/SelectRuleFeatureSet.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "wtf/DoublyLinkedList.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
#include "wtf/Noncopyable.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/Vector.h"
namespace WebCore {
+class InsertionPoint;
+
class ElementShadow {
WTF_MAKE_NONCOPYABLE(ElementShadow); WTF_MAKE_FAST_ALLOCATED;
public:
- static PassOwnPtr<ElementShadow> create()
- {
- return adoptPtr(new ElementShadow());
- }
-
- ~ElementShadow()
- {
- removeAllShadowRoots();
- }
+ static PassOwnPtr<ElementShadow> create();
+ ~ElementShadow();
Element* host() const;
ShadowRoot* youngestShadowRoot() const { return m_shadowRoots.head(); }
@@ -55,47 +52,47 @@
ElementShadow* containingShadow() const;
ShadowRoot* addShadowRoot(Element* shadowHost, ShadowRoot::ShadowRootType);
+
bool applyAuthorStyles() const { return m_applyAuthorStyles; }
+ bool didAffectApplyAuthorStyles();
+ bool containsActiveStyles() const;
void attach(const Node::AttachContext&);
void detach(const Node::AttachContext&);
void removeAllEventListeners();
- void didAffectSelector(AffectedSelectorMask mask) { m_distributor.didAffectSelector(host(), mask); }
- void willAffectSelector() { m_distributor.willAffectSelector(host()); }
- const SelectRuleFeatureSet& ensureSelectFeatureSet() { return m_distributor.ensureSelectFeatureSet(this); }
+ void didAffectSelector(AffectedSelectorMask);
+ void willAffectSelector();
+ const SelectRuleFeatureSet& ensureSelectFeatureSet();
- // FIXME: Move all callers of this to APIs on ElementShadow and remove it.
- ContentDistributor& distributor() { return m_distributor; }
- const ContentDistributor& distributor() const { return m_distributor; }
-
- void distributeIfNeeded()
- {
- if (m_needsDistributionRecalc)
- m_distributor.distribute(host());
- m_needsDistributionRecalc = false;
- }
- void clearDistribution() { m_distributor.clearDistribution(host()); }
-
+ void distributeIfNeeded();
void setNeedsDistributionRecalc();
- bool didAffectApplyAuthorStyles();
- bool containsActiveStyles() const;
+ InsertionPoint* findInsertionPointFor(const Node*) const;
private:
- ElementShadow()
- : m_needsDistributionRecalc(false)
- , m_applyAuthorStyles(false)
- { }
+ ElementShadow();
void removeAllShadowRoots();
bool resolveApplyAuthorStyles() const;
+ void distribute();
+ void clearDistribution();
+ void populate(Node*, Vector<Node*>&);
+ void collectSelectFeatureSetFrom(ShadowRoot*);
+ void distributeSelectionsTo(InsertionPoint*, const Vector<Node*>& pool, Vector<bool>& distributed);
+ void distributeNodeChildrenTo(InsertionPoint*, ContainerNode*);
+
+ bool needsSelectFeatureSet() const { return m_needsSelectFeatureSet; }
+ void setNeedsSelectFeatureSet() { m_needsSelectFeatureSet = true; }
+
+ HashMap<const Node*, RefPtr<InsertionPoint> > m_nodeToInsertionPoint;
+ SelectRuleFeatureSet m_selectFeatures;
DoublyLinkedList<ShadowRoot> m_shadowRoots;
- ContentDistributor m_distributor;
bool m_needsDistributionRecalc;
bool m_applyAuthorStyles;
+ bool m_needsSelectFeatureSet;
};
inline Element* ElementShadow::host() const
@@ -120,14 +117,12 @@
return 0;
}
-class ShadowRootVector : public Vector<RefPtr<ShadowRoot> > {
-public:
- explicit ShadowRootVector(ElementShadow* tree)
- {
- for (ShadowRoot* root = tree->youngestShadowRoot(); root; root = root->olderShadowRoot())
- append(root);
- }
-};
+inline void ElementShadow::distributeIfNeeded()
+{
+ if (m_needsDistributionRecalc)
+ distribute();
+ m_needsDistributionRecalc = false;
+}
inline ElementShadow* shadowOfParent(const Node* node)
{
@@ -139,7 +134,6 @@
return 0;
}
-
} // namespace
#endif
diff --git a/Source/core/dom/shadow/InsertionPoint.cpp b/Source/core/dom/shadow/InsertionPoint.cpp
index b4626d7..f2447c4 100644
--- a/Source/core/dom/shadow/InsertionPoint.cpp
+++ b/Source/core/dom/shadow/InsertionPoint.cpp
@@ -35,6 +35,7 @@
#include "core/dom/QualifiedName.h"
#include "core/dom/StaticNodeList.h"
#include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
#include "core/dom/shadow/ShadowRoot.h"
namespace WebCore {
@@ -52,8 +53,52 @@
{
}
+void InsertionPoint::setDistribution(ContentDistribution& distribution)
+{
+ if (shouldUseFallbackElements()) {
+ for (Node* child = firstChild(); child; child = child->nextSibling())
+ child->lazyReattachIfAttached();
+ }
+
+ // Attempt not to reattach nodes that would be distributed to the exact same
+ // location by comparing the old and new distributions.
+
+ size_t i = 0;
+ size_t j = 0;
+
+ for ( ; i < m_distribution.size() && j < distribution.size(); ++i, ++j) {
+ if (m_distribution.size() < distribution.size()) {
+ // If the new distribution is larger than the old one, reattach all nodes in
+ // the new distribution that were inserted.
+ for ( ; j < distribution.size() && m_distribution.at(i) != distribution.at(j); ++j)
+ distribution.at(j)->lazyReattachIfAttached();
+ } else if (m_distribution.size() > distribution.size()) {
+ // If the old distribution is larger than the new one, reattach all nodes in
+ // the old distribution that were removed.
+ for ( ; i < m_distribution.size() && m_distribution.at(i) != distribution.at(j); ++i)
+ m_distribution.at(i)->lazyReattachIfAttached();
+ } else if (m_distribution.at(i) != distribution.at(j)) {
+ // If both distributions are the same length reattach both old and new.
+ m_distribution.at(i)->lazyReattachIfAttached();
+ distribution.at(j)->lazyReattachIfAttached();
+ }
+ }
+
+ // If we hit the end of either list above we need to reattach all remaining nodes.
+
+ for ( ; i < m_distribution.size(); ++i)
+ m_distribution.at(i)->lazyReattachIfAttached();
+
+ for ( ; j < distribution.size(); ++j)
+ distribution.at(j)->lazyReattachIfAttached();
+
+ m_distribution.swap(distribution);
+}
+
void InsertionPoint::attach(const AttachContext& context)
{
+ // FIXME: This loop shouldn't be needed since the distributed nodes should
+ // never be detached, we can probably remove it.
for (size_t i = 0; i < m_distribution.size(); ++i) {
if (!m_distribution.at(i)->attached())
m_distribution.at(i)->attach(context);
@@ -64,20 +109,12 @@
void InsertionPoint::detach(const AttachContext& context)
{
- for (size_t i = 0; i < m_distribution.size(); ++i) {
- if (m_distribution.at(i)->attached())
- m_distribution.at(i)->detach(context);
- }
+ for (size_t i = 0; i < m_distribution.size(); ++i)
+ m_distribution.at(i)->lazyReattachIfAttached();
HTMLElement::detach(context);
}
-void InsertionPoint::lazyAttachDistribution(ShouldSetAttached shouldSetAttached)
-{
- for (size_t i = 0; i < m_distribution.size(); ++i)
- m_distribution.at(i)->lazyAttach(shouldSetAttached);
-}
-
void InsertionPoint::willRecalcStyle(StyleChange change)
{
if (change < Inherit)
@@ -208,7 +245,7 @@
while (current) {
if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
- if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(projectedNode)) {
+ if (InsertionPoint* insertedTo = shadow->findInsertionPointFor(projectedNode)) {
current = insertedTo;
insertionPoint = insertedTo;
continue;
@@ -234,7 +271,7 @@
const Node* current = node;
while (true) {
if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
- if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(node)) {
+ if (InsertionPoint* insertedTo = shadow->findInsertionPointFor(node)) {
current = insertedTo;
results.append(insertedTo);
continue;
diff --git a/Source/core/dom/shadow/InsertionPoint.h b/Source/core/dom/shadow/InsertionPoint.h
index 993ea34..aeb3243 100644
--- a/Source/core/dom/shadow/InsertionPoint.h
+++ b/Source/core/dom/shadow/InsertionPoint.h
@@ -32,8 +32,7 @@
#define InsertionPoint_h
#include "core/css/CSSSelectorList.h"
-#include "core/dom/shadow/ContentDistributor.h"
-#include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ContentDistribution.h"
#include "core/html/HTMLElement.h"
#include "wtf/Forward.h"
@@ -44,7 +43,7 @@
virtual ~InsertionPoint();
bool hasDistribution() const { return !m_distribution.isEmpty(); }
- void setDistribution(ContentDistribution& distribution) { m_distribution.swap(distribution); }
+ void setDistribution(ContentDistribution&);
void clearDistribution() { m_distribution.clear(); }
bool isActive() const;
@@ -67,8 +66,6 @@
Node* nextTo(const Node* node) const { return m_distribution.nextTo(node); }
Node* previousTo(const Node* node) const { return m_distribution.previousTo(node); }
- void lazyAttachDistribution(ShouldSetAttached);
-
protected:
InsertionPoint(const QualifiedName&, Document*);
virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
diff --git a/Source/core/dom/shadow/ScopeContentDistribution.cpp b/Source/core/dom/shadow/ScopeContentDistribution.cpp
new file mode 100644
index 0000000..b20ee65
--- /dev/null
+++ b/Source/core/dom/shadow/ScopeContentDistribution.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
+
+#include "core/dom/ElementTraversal.h"
+#include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+
+namespace WebCore {
+
+ScopeContentDistribution::ScopeContentDistribution()
+ : m_insertionPointAssignedTo(0)
+ , m_numberOfShadowElementChildren(0)
+ , m_numberOfContentElementChildren(0)
+ , m_numberOfElementShadowChildren(0)
+ , m_insertionPointListIsValid(false)
+{
+}
+
+void ScopeContentDistribution::setInsertionPointAssignedTo(PassRefPtr<InsertionPoint> insertionPoint)
+{
+ m_insertionPointAssignedTo = insertionPoint;
+}
+
+void ScopeContentDistribution::invalidateInsertionPointList()
+{
+ m_insertionPointListIsValid = false;
+ m_insertionPointList.clear();
+}
+
+const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertionPointList(ShadowRoot* shadowRoot)
+{
+ if (m_insertionPointListIsValid)
+ return m_insertionPointList;
+
+ m_insertionPointListIsValid = true;
+ ASSERT(m_insertionPointList.isEmpty());
+
+ if (!shadowRoot->containsInsertionPoints())
+ return m_insertionPointList;
+
+ for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
+ if (element->isInsertionPoint())
+ m_insertionPointList.append(toInsertionPoint(element));
+ }
+
+ return m_insertionPointList;
+}
+
+void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point)
+{
+ if (isHTMLShadowElement(point))
+ ++m_numberOfShadowElementChildren;
+ else if (isHTMLContentElement(point))
+ ++m_numberOfContentElementChildren;
+ else
+ ASSERT_NOT_REACHED();
+
+ invalidateInsertionPointList();
+}
+
+void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point)
+{
+ if (isHTMLShadowElement(point))
+ --m_numberOfShadowElementChildren;
+ else if (isHTMLContentElement(point))
+ --m_numberOfContentElementChildren;
+ else
+ ASSERT_NOT_REACHED();
+
+ ASSERT(m_numberOfContentElementChildren >= 0);
+ ASSERT(m_numberOfShadowElementChildren >= 0);
+
+ invalidateInsertionPointList();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/shadow/ScopeContentDistribution.h b/Source/core/dom/shadow/ScopeContentDistribution.h
new file mode 100644
index 0000000..43ed09f
--- /dev/null
+++ b/Source/core/dom/shadow/ScopeContentDistribution.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ScopeContentDistribution_h
+#define ScopeContentDistribution_h
+
+#include "wtf/Forward.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class InsertionPoint;
+class ShadowRoot;
+
+class ScopeContentDistribution {
+public:
+ ScopeContentDistribution();
+
+ InsertionPoint* insertionPointAssignedTo() const { return m_insertionPointAssignedTo.get(); }
+ void setInsertionPointAssignedTo(PassRefPtr<InsertionPoint>);
+
+ void registerInsertionPoint(InsertionPoint*);
+ void unregisterInsertionPoint(InsertionPoint*);
+ bool hasShadowElementChildren() const { return m_numberOfShadowElementChildren > 0; }
+ bool hasContentElementChildren() const { return m_numberOfContentElementChildren > 0; }
+
+ void registerElementShadow() { ++m_numberOfElementShadowChildren; }
+ void unregisterElementShadow() { ASSERT(m_numberOfElementShadowChildren > 0); --m_numberOfElementShadowChildren; }
+ unsigned numberOfElementShadowChildren() const { return m_numberOfElementShadowChildren; }
+ bool hasElementShadowChildren() const { return m_numberOfElementShadowChildren > 0; }
+
+ void invalidateInsertionPointList();
+ const Vector<RefPtr<InsertionPoint> >& ensureInsertionPointList(ShadowRoot*);
+
+private:
+ RefPtr<InsertionPoint> m_insertionPointAssignedTo;
+ unsigned m_numberOfShadowElementChildren;
+ unsigned m_numberOfContentElementChildren;
+ unsigned m_numberOfElementShadowChildren;
+ bool m_insertionPointListIsValid;
+ Vector<RefPtr<InsertionPoint> > m_insertionPointList;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/dom/shadow/ShadowRoot.cpp b/Source/core/dom/shadow/ShadowRoot.cpp
index a218b17..b9f9ce1 100644
--- a/Source/core/dom/shadow/ShadowRoot.cpp
+++ b/Source/core/dom/shadow/ShadowRoot.cpp
@@ -29,10 +29,11 @@
#include "bindings/v8/ExceptionState.h"
#include "core/css/resolver/StyleResolver.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
#include "core/dom/Text.h"
-#include "core/dom/shadow/ContentDistributor.h"
#include "core/dom/shadow/ElementShadow.h"
#include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
#include "core/editing/markup.h"
#include "core/platform/HistogramSupport.h"
@@ -76,6 +77,8 @@
ASSERT(!m_prev);
ASSERT(!m_next);
+ documentInternal()->styleSheetCollection()->didRemoveShadowRoot(this);
+
// We cannot let ContainerNode destructor call willBeDeletedFrom()
// for this ShadowRoot instance because TreeScope destructor
// clears Node::m_treeScope thus ContainerNode is no longer able
diff --git a/Source/core/dom/shadow/ShadowRoot.h b/Source/core/dom/shadow/ShadowRoot.h
index 3bfcc3d..993fdb2 100644
--- a/Source/core/dom/shadow/ShadowRoot.h
+++ b/Source/core/dom/shadow/ShadowRoot.h
@@ -149,6 +149,17 @@
return const_cast<ShadowRoot*>(toShadowRoot(static_cast<const Node*>(node)));
}
+inline const ShadowRoot* toShadowRoot(const TreeScope* treeScope)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(!treeScope || (treeScope->rootNode() && treeScope->rootNode()->isShadowRoot()));
+ return static_cast<const ShadowRoot*>(treeScope);
+}
+
+inline ShadowRoot* toShadowRoot(TreeScope* treeScope)
+{
+ return const_cast<ShadowRoot*>(toShadowRoot(static_cast<const TreeScope*>(treeScope)));
+}
+
} // namespace
#endif