diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/dom | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/dom')
72 files changed, 1524 insertions, 819 deletions
diff --git a/Source/WebCore/dom/Attr.cpp b/Source/WebCore/dom/Attr.cpp index 6500a97..e3ae348 100644 --- a/Source/WebCore/dom/Attr.cpp +++ b/Source/WebCore/dom/Attr.cpp @@ -152,7 +152,7 @@ PassRefPtr<Node> Attr::cloneNode(bool /*deep*/) } // DOM Section 1.1.1 -bool Attr::childTypeAllowed(NodeType type) +bool Attr::childTypeAllowed(NodeType type) const { switch (type) { case TEXT_NODE: diff --git a/Source/WebCore/dom/Attr.h b/Source/WebCore/dom/Attr.h index e76d2fa..217a0c3 100644 --- a/Source/WebCore/dom/Attr.h +++ b/Source/WebCore/dom/Attr.h @@ -79,7 +79,7 @@ private: virtual PassRefPtr<Node> cloneNode(bool deep); virtual bool isAttributeNode() const { return true; } - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); diff --git a/Source/WebCore/dom/CDATASection.cpp b/Source/WebCore/dom/CDATASection.cpp index d73054e..33a3acc 100644 --- a/Source/WebCore/dom/CDATASection.cpp +++ b/Source/WebCore/dom/CDATASection.cpp @@ -51,7 +51,7 @@ PassRefPtr<Node> CDATASection::cloneNode(bool /*deep*/) return create(document(), data()); } -bool CDATASection::childTypeAllowed(NodeType) +bool CDATASection::childTypeAllowed(NodeType) const { return false; } diff --git a/Source/WebCore/dom/CDATASection.h b/Source/WebCore/dom/CDATASection.h index 5cf07e1..d7aca9d 100644 --- a/Source/WebCore/dom/CDATASection.h +++ b/Source/WebCore/dom/CDATASection.h @@ -37,7 +37,7 @@ private: virtual String nodeName() const; virtual NodeType nodeType() const; virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual PassRefPtr<Text> virtualCreate(const String&); }; diff --git a/Source/WebCore/dom/Comment.cpp b/Source/WebCore/dom/Comment.cpp index 00f1724..92cffed 100644 --- a/Source/WebCore/dom/Comment.cpp +++ b/Source/WebCore/dom/Comment.cpp @@ -51,7 +51,7 @@ PassRefPtr<Node> Comment::cloneNode(bool /*deep*/) return create(document(), data()); } -bool Comment::childTypeAllowed(NodeType) +bool Comment::childTypeAllowed(NodeType) const { return false; } diff --git a/Source/WebCore/dom/Comment.h b/Source/WebCore/dom/Comment.h index a0210c4..9db1f31 100644 --- a/Source/WebCore/dom/Comment.h +++ b/Source/WebCore/dom/Comment.h @@ -37,7 +37,7 @@ private: virtual String nodeName() const; virtual NodeType nodeType() const; virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; }; } // namespace WebCore diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp index 4014cca..276df56 100644 --- a/Source/WebCore/dom/ContainerNode.cpp +++ b/Source/WebCore/dom/ContainerNode.cpp @@ -56,15 +56,19 @@ static NodeCallbackQueue* s_postAttachCallbackQueue; static size_t s_attachDepth; static bool s_shouldReEnableMemoryCacheCallsAfterAttach; +static inline void collectNodes(Node* node, NodeVector& nodes) +{ + for (Node* child = node->firstChild(); child; child = child->nextSibling()) + nodes.append(child); +} + static void collectTargetNodes(Node* node, NodeVector& nodes) { if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) { nodes.append(node); return; } - - for (Node* child = node->firstChild(); child; child = child->nextSibling()) - nodes.append(child); + collectNodes(node, nodes); } void ContainerNode::removeAllChildren() @@ -75,8 +79,7 @@ void ContainerNode::removeAllChildren() void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) { NodeVector children; - for (Node* child = oldParent->firstChild(); child; child = child->nextSibling()) - children.append(child); + collectNodes(oldParent, children); oldParent->removeAllChildren(); for (unsigned i = 0; i < children.size(); ++i) { @@ -101,7 +104,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentNode()); + ASSERT(refCount() || parentOrHostNode()); ec = 0; @@ -158,7 +161,8 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce InspectorInstrumentation::willInsertDOMNode(document(), child, this); #endif - child->setDocumentRecursively(document()); + child->setTreeScopeRecursively(treeScope()); + insertBeforeCommon(next.get(), child); // Send notification about the children change. @@ -241,7 +245,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentNode()); + ASSERT(refCount() || parentOrHostNode()); ec = 0; @@ -307,7 +311,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce InspectorInstrumentation::willInsertDOMNode(document(), child.get(), this); #endif - child->setDocumentRecursively(document()); + child->setTreeScopeRecursively(treeScope()); // Add child after "prev". forbidEventDispatch(); @@ -384,8 +388,7 @@ static void willRemoveChildren(ContainerNode* container) container->document()->incDOMTreeVersion(); NodeVector children; - for (Node* n = container->firstChild(); n; n = n->nextSibling()) - children.append(n); + collectNodes(container, children); for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) { Node* child = it->get(); @@ -399,7 +402,7 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentNode()); + ASSERT(refCount() || parentOrHostNode()); ec = 0; @@ -559,7 +562,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo { // Check that this node is not "floating". // If it is, it can be deleted as a side effect of sending mutation events. - ASSERT(refCount() || parentNode()); + ASSERT(refCount() || parentOrHostNode()); ec = 0; @@ -597,7 +600,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo InspectorInstrumentation::willInsertDOMNode(document(), child, this); #endif - child->setDocumentRecursively(document()); + child->setTreeScopeRecursively(treeScope()); // Append child to the end of the list forbidEventDispatch(); @@ -735,8 +738,16 @@ void ContainerNode::insertedIntoDocument() { Node::insertedIntoDocument(); insertedIntoTree(false); - for (Node* child = m_firstChild; child && inDocument(); child = child->nextSibling()) + + // Determine set of children before operating on any of them. + NodeVector children; + collectNodes(this, children); + + NodeVector::iterator it; + for (it = children.begin(); it != children.end() && inDocument(); ++it) { + Node* child = it->get(); child->insertedIntoDocument(); + } } void ContainerNode::removedFromDocument() @@ -778,9 +789,16 @@ void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, No void ContainerNode::cloneChildNodes(ContainerNode *clone) { // disable the delete button so it's elements are not serialized into the markup - bool isEditorEnabled = document()->frame() && document()->frame()->editor()->canEdit(); - if (isEditorEnabled) - document()->frame()->editor()->deleteButtonController()->disable(); + bool isEditorEnabled = false; + if (document()->frame() && document()->frame()->editor()->canEdit()) { + SelectionController* selection = document()->frame()->selection(); + Element* root = selection ? selection->rootEditableElement() : 0; + isEditorEnabled = root && isDescendantOf(root); + + if (isEditorEnabled) + document()->frame()->editor()->deleteButtonController()->disable(); + } + ExceptionCode ec = 0; for (Node* n = firstChild(); n && !ec; n = n->nextSibling()) clone->appendChild(n->cloneNode(true), ec); diff --git a/Source/WebCore/dom/DOMAllInOne.cpp b/Source/WebCore/dom/DOMAllInOne.cpp index cc4888f..4a51d90 100644 --- a/Source/WebCore/dom/DOMAllInOne.cpp +++ b/Source/WebCore/dom/DOMAllInOne.cpp @@ -108,6 +108,7 @@ #include "ScriptableDocumentParser.cpp" #include "SelectElement.cpp" #include "SelectorNodeList.cpp" +#include "ShadowRoot.cpp" #include "SpaceSplitString.cpp" #include "StaticHashSetNodeList.cpp" #include "StaticNodeList.cpp" @@ -121,6 +122,7 @@ #include "TouchList.cpp" #include "TransformSourceLibxslt.cpp" #include "Traversal.cpp" +#include "TreeScope.cpp" #include "TreeWalker.cpp" #include "UIEvent.cpp" #include "UIEventWithKeyState.cpp" diff --git a/Source/WebCore/dom/DataTransferItem.h b/Source/WebCore/dom/DataTransferItem.h index 7b5886a..d648c56 100644 --- a/Source/WebCore/dom/DataTransferItem.h +++ b/Source/WebCore/dom/DataTransferItem.h @@ -38,6 +38,7 @@ namespace WebCore { +class Blob; class StringCallback; class DataTransferItem : public RefCounted<DataTransferItem> { @@ -51,6 +52,7 @@ public: virtual String type() const = 0; virtual void getAsString(PassRefPtr<StringCallback>) = 0; + virtual PassRefPtr<Blob> getAsFile() = 0; }; } // namespace WebCore diff --git a/Source/WebCore/dom/DataTransferItem.idl b/Source/WebCore/dom/DataTransferItem.idl index a2c9942..accaf50 100644 --- a/Source/WebCore/dom/DataTransferItem.idl +++ b/Source/WebCore/dom/DataTransferItem.idl @@ -37,6 +37,7 @@ module core { readonly attribute DOMString type; void getAsString(in [Callback] StringCallback callback); + Blob getAsFile(); }; } diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index a0ddede..b85bdfb 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -123,7 +123,7 @@ #include "RenderTextControl.h" #include "RenderView.h" #include "RenderWidget.h" -#include "ScopedEventQueue.h" +#include "ScopedEventQueue.h" #include "ScriptCallStack.h" #include "ScriptController.h" #include "ScriptElement.h" @@ -391,7 +391,8 @@ private: uint64_t Document::s_globalTreeVersion = 0; Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) - : ContainerNode(0) + : TreeScope(this) + , m_guardRefCount(0) , m_compatibilityMode(NoQuirksMode) , m_compatibilityModeLocked(false) , m_domTreeVersion(++s_globalTreeVersion) @@ -406,8 +407,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_containsValidityStyleRules(false) , m_updateFocusAppearanceRestoresSelection(false) , m_ignoreDestructiveWriteCount(0) - , m_title("") - , m_rawTitle("") , m_titleSetExplicitly(false) , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired) , m_startTime(currentTime()) @@ -418,7 +417,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_xmlStandalone(false) , m_savedRenderer(0) , m_designMode(inherit) - , m_selfOnlyRefCount(0) #if ENABLE(SVG) , m_svgExtensions(0) #endif @@ -426,7 +424,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_hasDashboardRegions(false) , m_dashboardRegionsDirty(false) #endif - , m_accessKeyMapValid(false) , m_createRenderers(true) , m_inPageCache(false) , m_useSecureKeyboardEntryWhenActive(false) @@ -434,10 +431,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_isHTML(isHTML) , m_usesViewSourceStyles(false) , m_sawElementsInKnownNamespaces(false) - , m_numNodeListCaches(0) -#if USE(JSC) - , m_normalWorldWrapperCache(0) -#endif , m_usingGeolocation(false) , m_eventQueue(EventQueue::create(this)) #if ENABLE(WML) @@ -446,7 +439,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_weakReference(DocumentWeakReference::create(this)) , m_idAttributeName(idAttr) #if ENABLE(FULLSCREEN_API) - , m_isFullScreen(0) , m_areKeysEnabledInFullScreen(0) , m_fullScreenRenderer(0) , m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired) @@ -506,7 +498,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) m_usesLinkRules = false; m_gotoAnchorNeededAfterStylesheetsLoad = false; - + m_didCalculateStyleSelector = false; m_hasDirtyStyleSelector = false; m_pendingStylesheets = 0; @@ -532,57 +524,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) #endif } -void Document::removedLastRef() -{ - ASSERT(!m_deletionHasBegun); - if (m_selfOnlyRefCount) { - // If removing a child removes the last self-only ref, we don't - // want the document to be destructed until after - // removeAllChildren returns, so we guard ourselves with an - // extra self-only ref. - selfOnlyRef(); - - // We must make sure not to be retaining any of our children through - // these extra pointers or we will create a reference cycle. - m_docType = 0; - m_focusedNode = 0; - m_hoverNode = 0; - m_activeNode = 0; - m_titleElement = 0; - m_documentElement = 0; -#if ENABLE(FULLSCREEN_API) - m_fullScreenElement = 0; -#endif - - // removeAllChildren() doesn't always unregister IDs, do it upfront to avoid having stale references in the map. - m_elementsById.clear(); - - removeAllChildren(); - - m_markers->detach(); - - detachParser(); - - m_cssCanvasElements.clear(); - -#if ENABLE(REQUEST_ANIMATION_FRAME) - // FIXME: consider using ActiveDOMObject. - m_scriptedAnimationController = 0; -#endif - -#ifndef NDEBUG - m_inRemovedLastRefFunction = false; -#endif - - selfOnlyDeref(); - } else { -#ifndef NDEBUG - m_deletionHasBegun = true; -#endif - delete this; - } -} - Document::~Document() { ASSERT(!renderer()); @@ -590,15 +531,12 @@ Document::~Document() ASSERT(!m_savedRenderer); ASSERT(m_ranges.isEmpty()); ASSERT(!m_styleRecalcTimer.isActive()); + ASSERT(!m_parentTreeScope); m_scriptRunner.clear(); removeAllEventListeners(); -#if USE(JSC) - destroyAllWrapperCaches(); -#endif - // Currently we believe that Document can never outlive the parser. // Although the Document may be replaced synchronously, DocumentParsers // generally keep at least one reference to an Element which would in turn @@ -642,41 +580,74 @@ Document::~Document() m_implementation->ownerDocumentDestroyed(); } -MediaQueryMatcher* Document::mediaQueryMatcher() +void Document::removedLastRef() { - if (!m_mediaQueryMatcher) - m_mediaQueryMatcher = MediaQueryMatcher::create(this); - return m_mediaQueryMatcher.get(); -} + ASSERT(!m_deletionHasBegun); + if (m_guardRefCount) { + // If removing a child removes the last self-only ref, we don't + // want the scope to be destructed until after + // removeAllChildren returns, so we guard ourselves with an + // extra self-only ref. + guardRef(); -#if USE(JSC) -Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world) -{ - JSWrapperCache* wrapperCache = new JSWrapperCache; - m_wrapperCacheMap.set(world, wrapperCache); - if (world->isNormal()) { - ASSERT(!m_normalWorldWrapperCache); - m_normalWorldWrapperCache = wrapperCache; + // We must make sure not to be retaining any of our children through + // these extra pointers or we will create a reference cycle. + m_docType = 0; + m_focusedNode = 0; + m_hoverNode = 0; + m_activeNode = 0; + m_titleElement = 0; + m_documentElement = 0; +#if ENABLE(FULLSCREEN_API) + m_fullScreenElement = 0; +#endif + m_styleSelector.clear(); + m_styleSheets.clear(); + m_elemSheet.clear(); + m_mappedElementSheet.clear(); + m_pageUserSheet.clear(); + m_pageGroupUserSheets.clear(); + + // removeAllChildren() doesn't always unregister IDs, + // so tear down scope information upfront to avoid having stale references in the map. + destroyTreeScopeData(); + removeAllChildren(); + + m_markers->detach(); + + detachParser(); + + m_cssCanvasElements.clear(); + +#if ENABLE(REQUEST_ANIMATION_FRAME) + // FIXME: consider using ActiveDOMObject. + m_scriptedAnimationController = 0; +#endif + +#ifndef NDEBUG + m_inRemovedLastRefFunction = false; +#endif + + guardDeref(); + } else { +#ifndef NDEBUG + m_deletionHasBegun = true; +#endif + delete this; } - world->didCreateWrapperCache(this); - return wrapperCache; } -void Document::destroyWrapperCache(DOMWrapperWorld* world) +Element* Document::getElementById(const AtomicString& id) const { - Document::JSWrapperCache* wrappers = wrapperCacheMap().take(world); - ASSERT(wrappers); - delete wrappers; - world->didDestroyWrapperCache(this); + return TreeScope::getElementById(id); } -void Document::destroyAllWrapperCaches() +MediaQueryMatcher* Document::mediaQueryMatcher() { - JSWrapperCacheMap& wrapperCacheMap = this->wrapperCacheMap(); - while (!wrapperCacheMap.isEmpty()) - destroyWrapperCache(wrapperCacheMap.begin()->first); + if (!m_mediaQueryMatcher) + m_mediaQueryMatcher = MediaQueryMatcher::create(this); + return m_mediaQueryMatcher.get(); } -#endif void Document::setCompatibilityMode(CompatibilityMode mode) { @@ -718,6 +689,7 @@ void Document::setDocType(PassRefPtr<DocumentType> docType) ASSERT(!m_docType || !docType); m_docType = docType; if (m_docType) +<<<<<<< HEAD m_docType->setDocument(this); #ifdef ANDROID_META_SUPPORT if (m_docType && !ownerElement() @@ -729,6 +701,9 @@ void Document::setDocType(PassRefPtr<DocumentType> docType) PlatformBridge::updateViewport(frameView); } #endif +======= + m_docType->setTreeScope(this); +>>>>>>> WebKit.org at r84325 } DOMImplementation* Document::implementation() @@ -740,7 +715,7 @@ DOMImplementation* Document::implementation() void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) { - ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); + TreeScope::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); // Invalidate the document element we have cached in case it was replaced. m_documentElement = 0; @@ -958,7 +933,7 @@ PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec) source->parentNode()->removeChild(source.get(), ec); } - source->setDocumentRecursively(this); + source->setTreeScopeRecursively(this); return source; } @@ -1033,13 +1008,6 @@ PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const return createElement(qName, false); } -Element* Document::getElementById(const AtomicString& elementId) const -{ - if (elementId.isEmpty()) - return 0; - return m_elementsById.getElementById(elementId.impl(), this); -} - String Document::readyState() const { DEFINE_STATIC_LOCAL(const String, loading, ("loading")); @@ -1266,42 +1234,15 @@ PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) return Range::create(this, rangeCompliantPosition, rangeCompliantPosition); } -void Document::addElementById(const AtomicString& elementId, Element* element) -{ - m_elementsById.add(elementId.impl(), element); -} - -void Document::removeElementById(const AtomicString& elementId, Element* element) -{ - m_elementsById.remove(elementId.impl(), element); -} - -Element* Document::getElementByAccessKey(const String& key) const -{ - if (key.isEmpty()) - return 0; - if (!m_accessKeyMapValid) { - for (Node* n = firstChild(); n; n = n->traverseNextNode()) { - if (!n->isElementNode()) - continue; - Element* element = static_cast<Element*>(n); - const AtomicString& accessKey = element->getAttribute(accesskeyAttr); - if (!accessKey.isEmpty()) - m_elementsByAccessKey.set(accessKey.impl(), element); - } - m_accessKeyMapValid = true; - } - return m_elementsByAccessKey.get(key.impl()); -} - /* * Performs three operations: * 1. Convert control characters to spaces * 2. Trim leading and trailing spaces * 3. Collapse internal whitespace. */ -static inline String canonicalizedTitle(Document* document, const String& title) +static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection) { + const String& title = titleWithDirection.string(); const UChar* characters = title.characters(); unsigned length = title.length(); unsigned i; @@ -1317,7 +1258,7 @@ static inline String canonicalizedTitle(Document* document, const String& title) } if (i == length) - return ""; + return StringWithDirection(); // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace. bool previousCharWasWS = false; @@ -1342,17 +1283,17 @@ static inline String canonicalizedTitle(Document* document, const String& title) } if (!builderIndex && buffer[builderIndex] == ' ') - return ""; + return StringWithDirection(); buffer.shrink(builderIndex + 1); // Replace the backslashes with currency symbols if the encoding requires it. document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length()); - return String::adopt(buffer); + return StringWithDirection(String::adopt(buffer), titleWithDirection.direction()); } -void Document::updateTitle(const String& title) +void Document::updateTitle(const StringWithDirection& title) { if (m_rawTitle == title) return; @@ -1378,16 +1319,17 @@ void Document::setTitle(const String& title) } } - updateTitle(title); + // The DOM API has no method of specifying direction, so assume LTR. + updateTitle(StringWithDirection(title, LTR)); if (m_titleElement) { ASSERT(m_titleElement->hasTagName(titleTag)); if (m_titleElement->hasTagName(titleTag)) - static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title); + static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(title); } } -void Document::setTitleElement(const String& title, Element* titleElement) +void Document::setTitleElement(const StringWithDirection& title, Element* titleElement) { if (titleElement != m_titleElement) { if (m_titleElement || m_titleSetExplicitly) @@ -1412,13 +1354,13 @@ void Document::removeTitle(Element* titleElement) for (Node* e = headElement->firstChild(); e; e = e->nextSibling()) if (e->hasTagName(titleTag)) { HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e); - setTitleElement(titleElement->text(), titleElement); + setTitleElement(titleElement->textWithDirection(), titleElement); break; } } if (!m_titleElement) - updateTitle(""); + updateTitle(StringWithDirection()); } String Document::nodeName() const @@ -1489,10 +1431,7 @@ void Document::scheduleStyleRecalc() documentsThatNeedStyleRecalc->add(this); // FIXME: Why on earth is this here? This is clearly misplaced. - if (m_accessKeyMapValid) { - m_accessKeyMapValid = false; - m_elementsByAccessKey.clear(); - } + invalidateAccessKeyMap(); m_styleRecalcTimer.startOneShot(0); } @@ -1542,17 +1481,24 @@ void Document::recalcStyle(StyleChange change) m_inStyleRecalc = true; suspendPostAttachCallbacks(); RenderWidget::suspendWidgetHierarchyUpdates(); - if (view()) - view()->pauseScheduledEvents(); +<<<<<<< HEAD #ifdef ANDROID_INSTRUMENT android::TimeCounter::start(android::TimeCounter::CalculateStyleTimeCounter); #endif +======= + RefPtr<FrameView> frameView = view(); + if (frameView) { + frameView->pauseScheduledEvents(); + frameView->beginDeferredRepaints(); + } + +>>>>>>> WebKit.org at r84325 ASSERT(!renderer() || renderArena()); if (!renderer() || !renderArena()) goto bail_out; - + if (m_pendingStyleRecalcShouldForce) change = Force; @@ -1596,8 +1542,10 @@ bail_out: m_usesLinkRules = m_styleSelector->usesLinkRules(); } - if (view()) - view()->resumeScheduledEvents(); + if (frameView) { + frameView->resumeScheduledEvents(); + frameView->endDeferredRepaints(); + } RenderWidget::resumeWidgetHierarchyUpdates(); resumePostAttachCallbacks(); m_inStyleRecalc = false; @@ -1794,7 +1742,7 @@ void Document::attach() RenderObject* render = renderer(); setRenderer(0); - ContainerNode::attach(); + TreeScope::attach(); setRenderer(render); } @@ -1806,6 +1754,7 @@ void Document::detach() clearAXObjectCache(); stopActiveDOMObjects(); + m_eventQueue->cancelQueuedEvents(); #if ENABLE(REQUEST_ANIMATION_FRAME) // FIXME: consider using ActiveDOMObject. @@ -1840,7 +1789,7 @@ void Document::detach() m_focusedNode = 0; m_activeNode = 0; - ContainerNode::detach(); + TreeScope::detach(); unscheduleStyleRecalc(); @@ -2725,7 +2674,8 @@ void Document::processHttpEquiv(const String& equiv, const String& content) frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String()); } } - } + } else if (equalIgnoringCase(equiv, "x-webkit-csp")) + contentSecurityPolicy()->didReceiveHeader(content); } // Though isspace() considers \t and \v to be whitespace, Win IE doesn't. @@ -2821,7 +2771,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r } // DOM Section 1.1.1 -bool Document::childTypeAllowed(NodeType type) +bool Document::childTypeAllowed(NodeType type) const { switch (type) { case ATTRIBUTE_NODE: @@ -3957,33 +3907,6 @@ bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, S return true; } -void Document::addImageMap(HTMLMapElement* imageMap) -{ - AtomicStringImpl* name = imageMap->getName().impl(); - if (!name) - return; - m_imageMapsByName.add(name, imageMap); -} - -void Document::removeImageMap(HTMLMapElement* imageMap) -{ - AtomicStringImpl* name = imageMap->getName().impl(); - if (!name) - return; - m_imageMapsByName.remove(name, imageMap); -} - -HTMLMapElement* Document::getImageMap(const String& url) const -{ - if (url.isNull()) - return 0; - size_t hashPos = url.find('#'); - String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl(); - if (isHTMLDocument()) - return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this)); - return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this)); -} - void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) { m_decoder = decoder; @@ -4832,29 +4755,6 @@ void Document::resumeScriptedAnimationControllerCallbacks() #endif } -Element* Document::findAnchor(const String& name) -{ - if (name.isEmpty()) - return 0; - if (Element* element = getElementById(name)) - return element; - for (Node* node = this; node; node = node->traverseNextNode()) { - if (node->hasTagName(aTag)) { - HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); - if (inQuirksMode()) { - // Quirks mode, case insensitive comparison of names. - if (equalIgnoringCase(anchor->name(), name)) - return anchor; - } else { - // Strict mode, names need to match exactly. - if (anchor->name() == name) - return anchor; - } - } - } - return 0; -} - String Document::displayStringModifiedByEncoding(const String& str) const { if (m_decoder) @@ -4977,7 +4877,6 @@ void Document::webkitWillEnterFullScreenForElement(Element* element) ASSERT(page() && page()->settings()->fullScreenEnabled()); m_fullScreenElement = element; - m_isFullScreen = true; if (m_fullScreenElement != documentElement()) m_fullScreenElement->detach(); @@ -4988,8 +4887,8 @@ void Document::webkitWillEnterFullScreenForElement(Element* element) m_fullScreenRenderer->setAnimating(true); #if USE(ACCELERATED_COMPOSITING) view()->updateCompositingLayers(); - ASSERT(m_fullScreenRenderer->layer()->backing()); - page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); + if (m_fullScreenRenderer->layer()->isComposited()) + page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); #endif } } @@ -5000,7 +4899,6 @@ void Document::webkitDidEnterFullScreenForElement(Element*) m_fullScreenRenderer->setAnimating(false); #if USE(ACCELERATED_COMPOSITING) view()->updateCompositingLayers(); - ASSERT(!m_fullScreenRenderer->layer()->backing()); page()->chrome()->client()->setRootFullScreenLayer(0); #endif } @@ -5011,18 +4909,16 @@ void Document::webkitWillExitFullScreenForElement(Element*) { if (m_fullScreenRenderer) { m_fullScreenRenderer->setAnimating(true); - m_fullScreenRenderer->setAnimating(true); #if USE(ACCELERATED_COMPOSITING) view()->updateCompositingLayers(); - ASSERT(m_fullScreenRenderer->layer()->backing()); - page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); + if (m_fullScreenRenderer->layer()->isComposited()) + page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer()); #endif } } void Document::webkitDidExitFullScreenForElement(Element*) { - m_isFullScreen = false; m_areKeysEnabledInFullScreen = false; if (m_fullScreenRenderer) @@ -5030,7 +4926,8 @@ void Document::webkitDidExitFullScreenForElement(Element*) if (m_fullScreenElement != documentElement()) m_fullScreenElement->detach(); - + + m_fullScreenElement = 0; setFullScreenRenderer(0); #if USE(ACCELERATED_COMPOSITING) page()->chrome()->client()->setRootFullScreenLayer(0); @@ -5149,34 +5046,4 @@ PassRefPtr<TouchList> Document::createTouchList(ExceptionCode&) const } #endif -static bool hasHeadSibling(const Document* document) -{ - Node* de = document->documentElement(); - if (!de) - return false; - - for (Node* i = de->firstChild(); i; i = i->nextSibling()) { - // A child of the document element which is rather than <head> is - // typically visible and FOUC safe. So we return true here. - if (!i->hasTagName(headTag)) - return true; - } - - return false; -} - -bool Document::mayCauseFlashOfUnstyledContent() const -{ - // Some kind of FOUC is caused by a repaint request before page's <body> arrival - // because page authors often give background styles to <body>, not to <html>. - // (And these styles are unavailable before <style> or <link> is given.) - // This functions is used for checking such possibility of FOUCs. - // Note that the implementation considers only empty or <head> only contents as a FOUC cause - // rather than missing <body>, because non-HTML document like SVG and arbitrary XML from foreign namespace - // should be painted even if there is no <body>. - if (didLayoutWithPendingStylesheets()) - return true; - return !hasHeadSibling(this); -} - } // namespace WebCore diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index 11c595a..5ab6d77 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -31,23 +31,19 @@ #include "CollectionCache.h" #include "CollectionType.h" #include "Color.h" -#include "ContainerNode.h" #include "DOMTimeStamp.h" -#include "DocumentOrderedMap.h" #include "DocumentTiming.h" #include "QualifiedName.h" #include "ScriptExecutionContext.h" +#include "StringWithDirection.h" #include "Timer.h" +#include "TreeScope.h" #include "ViewportArguments.h" #include <wtf/FixedArray.h> #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> -#if USE(JSC) -#include <runtime/WeakGCMap.h> -#endif - namespace WebCore { class AXObjectCache; @@ -205,7 +201,7 @@ enum PageshowEventPersistence { enum StyleSelectorUpdateFlag { RecalcStyleImmediately, DeferRecalcStyle }; -class Document : public ContainerNode, public ScriptExecutionContext { +class Document : public TreeScope, public ScriptExecutionContext { public: static PassRefPtr<Document> create(Frame* frame, const KURL& url) { @@ -219,25 +215,25 @@ public: MediaQueryMatcher* mediaQueryMatcher(); - using ContainerNode::ref; - using ContainerNode::deref; + using TreeScope::ref; + using TreeScope::deref; - // Nodes belonging to this document hold "self-only" references - + // Nodes belonging to this document hold guard references - // these are enough to keep the document from being destroyed, but // not enough to keep it from removing its children. This allows a // node that outlives its document to still have a valid document - // pointer without introducing reference cycles - - void selfOnlyRef() + // pointer without introducing reference cycles. + void guardRef() { ASSERT(!m_deletionHasBegun); - ++m_selfOnlyRefCount; + ++m_guardRefCount; } - void selfOnlyDeref() + + void guardDeref() { ASSERT(!m_deletionHasBegun); - --m_selfOnlyRefCount; - if (!m_selfOnlyRefCount && !refCount()) { + --m_guardRefCount; + if (!m_guardRefCount && !refCount()) { #ifndef NDEBUG m_deletionHasBegun = true; #endif @@ -245,6 +241,10 @@ public: } } + virtual void removedLastRef(); + + Element* getElementById(const AtomicString& id) const; + // DOM methods & attributes for Document DEFINE_ATTRIBUTE_EVENT_LISTENER(abort); @@ -259,8 +259,6 @@ public: DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart); DEFINE_ATTRIBUTE_EVENT_LISTENER(drag); DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend); - DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange); - DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput); DEFINE_ATTRIBUTE_EVENT_LISTENER(input); DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid); DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown); @@ -328,9 +326,6 @@ public: PassRefPtr<Node> importNode(Node* importedNode, bool deep, ExceptionCode&); virtual PassRefPtr<Element> createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode&); PassRefPtr<Element> createElement(const QualifiedName&, bool createdByParser); - Element* getElementById(const AtomicString&) const; - bool hasElementWithId(AtomicStringImpl* id) const; - bool containsMultipleElementsWithId(const AtomicString& id) const; /** * Retrieve all nodes that intersect a rect in the window's document, until it is fully enclosed by @@ -394,13 +389,6 @@ public: PassRefPtr<HTMLAllCollection> all(); - // Find first anchor with the given name. - // First searches for an element with the given ID, but if that fails, then looks - // for an anchor with the given name. ID matching is always case sensitive, but - // Anchor name matching is case sensitive in strict mode and not case sensitive in - // quirks mode for historical compatibility reasons. - Element* findAnchor(const String& name); - CollectionCache* collectionInfo(CollectionType type) { ASSERT(type >= FirstUnnamedDocumentCachedType); @@ -451,8 +439,6 @@ public: return m_styleSelector.get(); } - Element* getElementByAccessKey(const String& key) const; - /** * Updates the pending sheet count and then calls updateStyleSelector. */ @@ -819,9 +805,11 @@ public: // Returns 0 if this is the top level document. HTMLFrameOwnerElement* ownerElement() const; - String title() const { return m_title; } + // Used by DOM bindings; no direction known. + String title() const { return m_title.string(); } void setTitle(const String&); - void setTitleElement(const String& title, Element* titleElement); + + void setTitleElement(const StringWithDirection&, Element* titleElement); void removeTitle(Element* titleElement); String cookie(ExceptionCode&) const; @@ -872,13 +860,6 @@ public: // Checks to make sure prefix and namespace do not conflict (per DOM Core 3) static bool hasPrefixNamespaceMismatch(const QualifiedName&); - void addElementById(const AtomicString& elementId, Element *element); - void removeElementById(const AtomicString& elementId, Element *element); - - void addImageMap(HTMLMapElement*); - void removeImageMap(HTMLMapElement*); - HTMLMapElement* getImageMap(const String& url) const; - HTMLElement* body() const; void setBody(PassRefPtr<HTMLElement>, ExceptionCode&); @@ -956,10 +937,6 @@ public: void setUseSecureKeyboardEntryWhenActive(bool); bool useSecureKeyboardEntryWhenActive() const; - void addNodeListCache() { ++m_numNodeListCaches; } - void removeNodeListCache() { ASSERT(m_numNodeListCaches > 0); --m_numNodeListCaches; } - bool hasNodeListCaches() const { return m_numNodeListCaches; } - void updateFocusAppearanceSoon(bool restorePreviousSelection); void cancelFocusAppearanceUpdate(); @@ -979,16 +956,6 @@ public: virtual void suspendScriptedAnimationControllerCallbacks(); virtual void resumeScriptedAnimationControllerCallbacks(); -#if USE(JSC) - typedef JSC::WeakGCMap<WebCore::Node*, JSNode> JSWrapperCache; - typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap; - JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; } - JSWrapperCache* getWrapperCache(DOMWrapperWorld* world); - JSWrapperCache* createWrapperCache(DOMWrapperWorld*); - void destroyWrapperCache(DOMWrapperWorld*); - void destroyAllWrapperCaches(); -#endif - virtual void finishedParsing(); bool inPageCache() const { return m_inPageCache; } @@ -1059,7 +1026,7 @@ public: #endif virtual bool isContextThread() const; - virtual bool isJSExecutionTerminated() const { return false; } + virtual bool isJSExecutionForbidden() const { return false; } void setUsingGeolocation(bool f) { m_usingGeolocation = f; } bool usingGeolocation() const { return m_usingGeolocation; }; @@ -1089,8 +1056,8 @@ public: const QualifiedName& idAttributeName() const { return m_idAttributeName; } #if ENABLE(FULLSCREEN_API) - bool webkitIsFullScreen() const { return m_isFullScreen; } - bool webkitFullScreenKeyboardInputAllowed() const { return m_isFullScreen && m_areKeysEnabledInFullScreen; } + bool webkitIsFullScreen() const { return m_fullScreenElement.get(); } + bool webkitFullScreenKeyboardInputAllowed() const { return m_fullScreenElement.get() && m_areKeysEnabledInFullScreen; } Element* webkitCurrentFullScreenElement() const { return m_fullScreenElement.get(); } void webkitRequestFullScreenForElement(Element*, unsigned short flags); void webkitCancelFullScreen(); @@ -1128,8 +1095,6 @@ public: void serviceScriptedAnimations(DOMTimeStamp); #endif - bool mayCauseFlashOfUnstyledContent() const; - virtual EventTarget* errorEventTarget(); virtual void logExceptionToConsole(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>); @@ -1152,13 +1117,12 @@ private: void processArguments(const String& features, void* data, ArgumentsCallback); virtual bool isDocument() const { return true; } - virtual void removedLastRef(); virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); virtual String nodeName() const; virtual NodeType nodeType() const; - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual PassRefPtr<Node> cloneNode(bool deep); virtual bool canReplaceChild(Node* newChild, Node* oldChild); @@ -1172,7 +1136,7 @@ private: String encoding() const; - void updateTitle(const String& title); + void updateTitle(const StringWithDirection&); void updateFocusAppearanceTimerFired(Timer<Document>*); void updateBaseURL(); @@ -1184,6 +1148,8 @@ private: void loadEventDelayTimerFired(Timer<Document>*); + int m_guardRefCount; + OwnPtr<CSSStyleSelector> m_styleSelector; bool m_didCalculateStyleSelector; bool m_hasDirtyStyleSelector; @@ -1312,8 +1278,8 @@ private: // http://www.whatwg.org/specs/web-apps/current-work/#ignore-destructive-writes-counter unsigned m_ignoreDestructiveWriteCount; - String m_title; - String m_rawTitle; + StringWithDirection m_title; + StringWithDirection m_rawTitle; bool m_titleSetExplicitly; RefPtr<Element> m_titleElement; @@ -1344,8 +1310,6 @@ private: RefPtr<Document> m_transformSourceDocument; #endif - DocumentOrderedMap m_imageMapsByName; - int m_docID; // A unique document identifier used for things like document-specific mapped attributes. String m_xmlEncoding; @@ -1362,14 +1326,8 @@ private: RefPtr<TextResourceDecoder> m_decoder; - DocumentOrderedMap m_elementsById; - - mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey; - InheritedBool m_designMode; - int m_selfOnlyRefCount; - CheckedRadioButtons m_checkedRadioButtons; typedef HashMap<AtomicStringImpl*, CollectionCache*> NamedCollectionMap; @@ -1392,7 +1350,6 @@ private: HashMap<String, RefPtr<HTMLCanvasElement> > m_cssCanvasElements; - mutable bool m_accessKeyMapValid; bool m_createRenderers; bool m_inPageCache; String m_iconURL; @@ -1409,13 +1366,6 @@ private: bool m_usesViewSourceStyles; bool m_sawElementsInKnownNamespaces; - unsigned m_numNodeListCaches; - -#if USE(JSC) - JSWrapperCacheMap m_wrapperCacheMap; - JSWrapperCache* m_normalWorldWrapperCache; -#endif - bool m_usingGeolocation; RefPtr<EventQueue> m_eventQueue; @@ -1431,7 +1381,6 @@ private: QualifiedName m_idAttributeName; #if ENABLE(FULLSCREEN_API) - bool m_isFullScreen; bool m_areKeysEnabledInFullScreen; RefPtr<Element> m_fullScreenElement; RenderFullScreen* m_fullScreenRenderer; @@ -1458,23 +1407,13 @@ private: RefPtr<ContentSecurityPolicy> m_contentSecurityPolicy; }; -inline bool Document::hasElementWithId(AtomicStringImpl* id) const -{ - ASSERT(id); - return m_elementsById.contains(id); -} +// Put these methods here, because they require the Document definition, but we really want to inline them. -inline bool Document::containsMultipleElementsWithId(const AtomicString& id) const -{ - return m_elementsById.containsMultiple(id.impl()); -} - inline bool Node::isDocumentNode() const { return this == m_document; } -// here because it uses a Document method but we really want to inline it inline Node::Node(Document* document, ConstructionType type) : m_document(document) , m_previous(0) @@ -1483,7 +1422,7 @@ inline Node::Node(Document* document, ConstructionType type) , m_nodeFlags(type) { if (m_document) - m_document->selfOnlyRef(); + m_document->guardRef(); #if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS) trackForDebugging(); #endif diff --git a/Source/WebCore/dom/Document.idl b/Source/WebCore/dom/Document.idl index 11d6678..cf820ba 100644 --- a/Source/WebCore/dom/Document.idl +++ b/Source/WebCore/dom/Document.idl @@ -29,7 +29,7 @@ module core { // DOM Level 1 Core readonly attribute DocumentType doctype; - readonly attribute [V8Custom] DOMImplementation implementation; + readonly attribute DOMImplementation implementation; readonly attribute Element documentElement; [ReturnsNew] Element createElement(in [ConvertNullToNullString] DOMString tagName) @@ -266,8 +266,6 @@ module core { attribute [DontEnum] EventListener ondrop; attribute [DontEnum] EventListener onerror; attribute [DontEnum] EventListener onfocus; - attribute [DontEnum] EventListener onformchange; - attribute [DontEnum] EventListener onforminput; attribute [DontEnum] EventListener oninput; attribute [DontEnum] EventListener oninvalid; attribute [DontEnum] EventListener onkeydown; diff --git a/Source/WebCore/dom/DocumentFragment.cpp b/Source/WebCore/dom/DocumentFragment.cpp index c9c3020..3882c4d 100644 --- a/Source/WebCore/dom/DocumentFragment.cpp +++ b/Source/WebCore/dom/DocumentFragment.cpp @@ -31,7 +31,7 @@ namespace WebCore { -inline DocumentFragment::DocumentFragment(Document* document) +DocumentFragment::DocumentFragment(Document* document) : ContainerNode(document) { ASSERT(document); @@ -52,7 +52,7 @@ Node::NodeType DocumentFragment::nodeType() const return DOCUMENT_FRAGMENT_NODE; } -bool DocumentFragment::childTypeAllowed(NodeType type) +bool DocumentFragment::childTypeAllowed(NodeType type) const { switch (type) { case ELEMENT_NODE: diff --git a/Source/WebCore/dom/DocumentFragment.h b/Source/WebCore/dom/DocumentFragment.h index d588b4e..b035a64 100644 --- a/Source/WebCore/dom/DocumentFragment.h +++ b/Source/WebCore/dom/DocumentFragment.h @@ -36,13 +36,14 @@ public: void parseHTML(const String&, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed); bool parseXML(const String&, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed); -private: +protected: DocumentFragment(Document*); - virtual String nodeName() const; + +private: virtual NodeType nodeType() const; virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; }; } //namespace diff --git a/Source/WebCore/dom/DocumentMarker.h b/Source/WebCore/dom/DocumentMarker.h index 81112bf..1711a96 100644 --- a/Source/WebCore/dom/DocumentMarker.h +++ b/Source/WebCore/dom/DocumentMarker.h @@ -37,9 +37,9 @@ struct DocumentMarker { Spelling = 1 << 0, Grammar = 1 << 1, TextMatch = 1 << 2, - // Text has been modified by spell correction. On some platforms, this prevents the text - // to be autocorrected again. On post Snow Leopard Mac OS X, if a Replacement marker contains - // non-empty description, a reversion UI will be shown. + // Text has been modified by spell correction, reversion of spell correction or other type of substitution. + // On some platforms, this prevents the text from being autocorrected again. On post Snow Leopard Mac OS X, + // if a Replacement marker contains non-empty description, a reversion UI will be shown. Replacement = 1 << 3, // Renderer needs to add underline indicating that the text has been modified by spell // correction. Text with Replacement marker doesn't necessarily has CorrectionIndicator @@ -49,12 +49,37 @@ struct DocumentMarker { CorrectionIndicator = 1 << 4, // Correction suggestion has been offered, but got rejected by user. RejectedCorrection = 1 << 5, - // On some platforms, this prevents the text to be spellchecked again. - SpellCheckingExemption = 1 << 6, - AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | SpellCheckingExemption + // Text has been modified by autocorrection. The description of this marker is the original text before autocorrection. + Autocorrected = 1 << 6, + // On some platforms, this prevents the text from being spellchecked again. + SpellCheckingExemption = 1 << 7, }; + + class MarkerTypes { + public: + // The constructor is intentionally implicit to allow conversion from the bit-wise sum of above types + MarkerTypes(unsigned mask) : m_mask(mask) { } + + bool contains(MarkerType type) const { return m_mask & type; } + bool intersects(const MarkerTypes& types) const { return (m_mask & types.m_mask); } + bool operator==(const MarkerTypes& other) const { return m_mask == other.m_mask; } + + void add(const MarkerTypes& types) { m_mask |= types.m_mask; } + void remove(const MarkerTypes& types) { m_mask &= ~types.m_mask; } + + private: + unsigned m_mask; + }; + + class AllMarkers : public MarkerTypes { + public: + AllMarkers() + : MarkerTypes(Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | Autocorrected | SpellCheckingExemption) + { + } + }; + MarkerType type; - typedef unsigned MarkerTypes; unsigned startOffset; unsigned endOffset; String description; diff --git a/Source/WebCore/dom/DocumentMarkerController.cpp b/Source/WebCore/dom/DocumentMarkerController.cpp index f646f3c..d97f2af 100644 --- a/Source/WebCore/dom/DocumentMarkerController.cpp +++ b/Source/WebCore/dom/DocumentMarkerController.cpp @@ -40,7 +40,7 @@ static IntRect placeholderRectForMarker() inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types) { - return m_possiblyExistingMarkerTypes & types; + return m_possiblyExistingMarkerTypes.intersects(types); } DocumentMarkerController::DocumentMarkerController() @@ -91,7 +91,7 @@ void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker) if (newMarker.endOffset == newMarker.startOffset) return; - m_possiblyExistingMarkerTypes |= newMarker.type; + m_possiblyExistingMarkerTypes.add(newMarker.type); MarkerMapVectorPair* vectorPair = m_markers.get(node); @@ -152,12 +152,12 @@ void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker) // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode. -void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta) { if (length <= 0) return; - if (!possiblyHasMarkers(markerType)) + if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) return; ASSERT(!m_markers.isEmpty()); @@ -178,7 +178,7 @@ void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, break; // skip marker that is before the specified range or is the wrong type - if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) + if (marker.endOffset < startOffset) continue; // pin the marker to the specified range and apply the shift delta @@ -224,7 +224,7 @@ void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, i break; // skip marker that is wrong type or before target - if (marker.endOffset <= startOffset || !(marker.type & markerTypes)) { + if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) { i++; continue; } @@ -292,7 +292,7 @@ DocumentMarker* DocumentMarkerController::markerContainingPoint(const IntPoint& DocumentMarker& marker = markers[markerIndex]; // skip marker that is wrong type - if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) + if (marker.type != markerType) continue; IntRect& r = rects[markerIndex]; @@ -317,6 +317,35 @@ Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node) return Vector<DocumentMarker>(); } +Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType) +{ + if (!possiblyHasMarkers(markerType)) + return Vector<DocumentMarker>(); + + Vector<DocumentMarker> foundMarkers; + + Node* startContainer = range->startContainer(); + ASSERT(startContainer); + Node* endContainer = range->endContainer(); + ASSERT(endContainer); + + Node* pastLastNode = range->pastLastNode(); + for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) { + Vector<DocumentMarker> markers = markersForNode(node); + Vector<DocumentMarker>::const_iterator end = markers.end(); + for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) { + if (markerType != it->type) + continue; + if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) + continue; + if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) + continue; + foundMarkers.append(*it); + } + } + return foundMarkers; +} + Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType) { Vector<IntRect> result; @@ -338,7 +367,7 @@ Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker DocumentMarker marker = markers[markerIndex]; // skip marker that is wrong type - if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) + if (marker.type != markerType) continue; IntRect r = rects[markerIndex]; @@ -379,13 +408,13 @@ void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerT removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerTypes); } - m_possiblyExistingMarkerTypes &= ~markerTypes; + m_possiblyExistingMarkerTypes.remove(markerTypes); } // This function may release node and vectorPair. void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerTypes markerTypes) { - if (!~(markerTypes & DocumentMarker::AllMarkers)) { + if (markerTypes == DocumentMarker::AllMarkers()) { delete vectorPair; m_markers.remove(node); if (RenderObject* renderer = node->renderer()) @@ -399,7 +428,7 @@ void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, DocumentMarker marker = markers[i]; // skip nodes that are not of the specified type - if (!(marker.type & markerTypes)) { + if (!markerTypes.contains(marker.type)) { ++i; continue; } @@ -430,9 +459,9 @@ void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, m_possiblyExistingMarkerTypes = 0; } -void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerType markerType) +void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes) { - if (!possiblyHasMarkers(markerType)) + if (!possiblyHasMarkers(markerTypes)) return; ASSERT(!m_markers.isEmpty()); @@ -449,7 +478,7 @@ void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerType markerT DocumentMarker marker = markers[i]; // skip nodes that are not of the specified type - if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) { + if (markerTypes.contains(marker.type)) { nodeNeedsRepaint = true; break; } @@ -503,9 +532,9 @@ void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const Int } } -void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType) +void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta) { - if (!possiblyHasMarkers(markerType)) + if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) return; ASSERT(!m_markers.isEmpty()); @@ -520,7 +549,7 @@ void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, in bool docDirty = false; for (size_t i = 0; i != markers.size(); ++i) { DocumentMarker& marker = markers[i]; - if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) { + if (marker.startOffset >= startOffset) { ASSERT((int)marker.startOffset + delta >= 0); marker.startOffset += delta; marker.endOffset += delta; @@ -538,7 +567,7 @@ void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, in void DocumentMarkerController::setMarkersActive(Range* range, bool active) { - if (!possiblyHasMarkers(DocumentMarker::AllMarkers)) + if (!possiblyHasMarkers(DocumentMarker::AllMarkers())) return; ASSERT(!m_markers.isEmpty()); @@ -600,22 +629,13 @@ bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTy Vector<DocumentMarker> markers = markersForNode(node); Vector<DocumentMarker>::const_iterator end = markers.end(); for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) { - if (!(markerTypes & it->type)) + if (!markerTypes.contains(it->type)) continue; - if (node == startContainer && node == endContainer) { - // The range spans only one node. - if (it->endOffset > static_cast<unsigned>(range->startOffset()) && it->startOffset < static_cast<unsigned>(range->endOffset())) - return true; - } else { - if (node == startContainer) { - if (it->endOffset > static_cast<unsigned>(range->startOffset())) - return true; - } else if (node == endContainer) { - if (it->startOffset < static_cast<unsigned>(range->endOffset())) - return true; - } else - return true; - } + if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset())) + continue; + if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset())) + continue; + return true; } } return false; @@ -647,7 +667,7 @@ void DocumentMarkerController::clearDescriptionOnMarkersIntersectingRange(Range* break; // skip marker that is wrong type or before target - if (marker.endOffset <= startOffset || !(marker.type & markerTypes)) { + if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) { i++; continue; } diff --git a/Source/WebCore/dom/DocumentMarkerController.h b/Source/WebCore/dom/DocumentMarkerController.h index 6fa060a..0f34c9f 100644 --- a/Source/WebCore/dom/DocumentMarkerController.h +++ b/Source/WebCore/dom/DocumentMarkerController.h @@ -47,28 +47,29 @@ public: void detach(); void addMarker(Range*, DocumentMarker::MarkerType, String description = String()); void addMarker(Node*, DocumentMarker); - void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); - bool hasMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); + void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta); + bool hasMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers()); // When a marker partially overlaps with range, if removePartiallyOverlappingMarkers is true, we completely // remove the marker. If the argument is false, we will adjust the span of the marker so that it retains // the portion that is outside of the range. enum RemovePartiallyOverlappingMarkerOrNot { DoNotRemovePartiallyOverlappingMarker, RemovePartiallyOverlappingMarker }; - void removeMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); - void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); + void removeMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers(), RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); + void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers(), RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker); - void removeMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); - void removeMarkers(Node*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers); - void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); + void removeMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers()); + void removeMarkers(Node*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers()); + void repaintMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers()); void setRenderedRectForMarker(Node*, const DocumentMarker&, const IntRect&); void invalidateRenderedRectsForMarkersInRect(const IntRect&); - void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); + void shiftMarkers(Node*, unsigned startOffset, int delta); void setMarkersActive(Range*, bool); void setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool); - DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers); + DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType); Vector<DocumentMarker> markersForNode(Node*); - Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers); + Vector<DocumentMarker> markersInRange(Range*, DocumentMarker::MarkerType); + Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType); void clearDescriptionOnMarkersIntersectingRange(Range*, DocumentMarker::MarkerTypes); #ifndef NDEBUG diff --git a/Source/WebCore/dom/DocumentOrderedMap.cpp b/Source/WebCore/dom/DocumentOrderedMap.cpp index 787fcf4..47268c4 100644 --- a/Source/WebCore/dom/DocumentOrderedMap.cpp +++ b/Source/WebCore/dom/DocumentOrderedMap.cpp @@ -34,6 +34,7 @@ #include "Element.h" #include "HTMLMapElement.h" #include "HTMLNames.h" +#include "TreeScope.h" namespace WebCore { @@ -104,7 +105,7 @@ void DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element) } template<bool keyMatches(AtomicStringImpl*, Element*)> -inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const +inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const TreeScope* scope) const { ASSERT(key); @@ -116,7 +117,7 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* d if (m_duplicateCounts.contains(key)) { // We know there's at least one node that matches; iterate to find the first one. - for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) { + for (Node* node = scope->firstChild(); node; node = node->traverseNextNode()) { if (!node->isElementNode()) continue; element = static_cast<Element*>(node); @@ -132,19 +133,19 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* d return 0; } -Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const Document* document) const +Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const TreeScope* scope) const { - return get<keyMatchesId>(key, document); + return get<keyMatchesId>(key, scope); } -Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const Document* document) const +Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const TreeScope* scope) const { - return get<keyMatchesMapName>(key, document); + return get<keyMatchesMapName>(key, scope); } -Element* DocumentOrderedMap::getElementByLowercasedMapName(AtomicStringImpl* key, const Document* document) const +Element* DocumentOrderedMap::getElementByLowercasedMapName(AtomicStringImpl* key, const TreeScope* scope) const { - return get<keyMatchesLowercasedMapName>(key, document); + return get<keyMatchesLowercasedMapName>(key, scope); } } // namespace WebCore diff --git a/Source/WebCore/dom/DocumentOrderedMap.h b/Source/WebCore/dom/DocumentOrderedMap.h index 58767c6..7d12686 100644 --- a/Source/WebCore/dom/DocumentOrderedMap.h +++ b/Source/WebCore/dom/DocumentOrderedMap.h @@ -37,8 +37,8 @@ namespace WebCore { -class Document; class Element; +class TreeScope; class DocumentOrderedMap { public: @@ -49,14 +49,14 @@ public: bool contains(AtomicStringImpl*) const; bool containsMultiple(AtomicStringImpl*) const; // concrete instantiations of the get<>() method template - Element* getElementById(AtomicStringImpl*, const Document*) const; - Element* getElementByMapName(AtomicStringImpl*, const Document*) const; - Element* getElementByLowercasedMapName(AtomicStringImpl*, const Document*) const; + Element* getElementById(AtomicStringImpl*, const TreeScope*) const; + Element* getElementByMapName(AtomicStringImpl*, const TreeScope*) const; + Element* getElementByLowercasedMapName(AtomicStringImpl*, const TreeScope*) const; void checkConsistency() const; private: - template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const Document*) const; + template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const TreeScope*) const; typedef HashMap<AtomicStringImpl*, Element*> Map; diff --git a/Source/WebCore/dom/DynamicNodeList.cpp b/Source/WebCore/dom/DynamicNodeList.cpp index 3538b60..23664e8 100644 --- a/Source/WebCore/dom/DynamicNodeList.cpp +++ b/Source/WebCore/dom/DynamicNodeList.cpp @@ -145,6 +145,11 @@ Node* DynamicNodeList::itemWithName(const AtomicString& elementId) const return 0; } +bool DynamicNodeList::isDynamicNodeList() const +{ + return true; +} + void DynamicNodeList::invalidateCache() { // This should only be called for node lists that own their own caches. diff --git a/Source/WebCore/dom/DynamicNodeList.h b/Source/WebCore/dom/DynamicNodeList.h index db133b7..9c8f3cc 100644 --- a/Source/WebCore/dom/DynamicNodeList.h +++ b/Source/WebCore/dom/DynamicNodeList.h @@ -60,6 +60,7 @@ namespace WebCore { // Other methods (not part of DOM) void invalidateCache(); + Node* rootNode() const { return m_rootNode.get(); } protected: DynamicNodeList(PassRefPtr<Node> rootNode); @@ -72,6 +73,7 @@ namespace WebCore { bool m_ownsCaches; private: + virtual bool isDynamicNodeList() const; Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const; Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const; }; diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp index 81668cf..50431aa 100644 --- a/Source/WebCore/dom/Element.cpp +++ b/Source/WebCore/dom/Element.cpp @@ -54,6 +54,7 @@ #include "RenderView.h" #include "RenderWidget.h" #include "Settings.h" +#include "ShadowRoot.h" #include "TextIterator.h" #include "WebKitAnimationList.h" #include "XMLNames.h" @@ -543,11 +544,19 @@ PassRefPtr<ClientRectList> Element::getClientRects() const Vector<FloatQuad> quads; renderBoxModelObject->absoluteQuads(quads); + float pageScale = 1; + if (Page* page = document()->page()) { + if (Frame* frame = page->mainFrame()) + pageScale = frame->pageScaleFactor(); + } + if (FrameView* view = document()->view()) { IntRect visibleContentRect = view->visibleContentRect(); for (size_t i = 0; i < quads.size(); ++i) { quads[i].move(-visibleContentRect.x(), -visibleContentRect.y()); adjustFloatQuadForAbsoluteZoom(quads[i], renderBoxModelObject); + if (pageScale != 1) + adjustFloatQuadForPageScale(quads[i], pageScale); } } @@ -587,6 +596,11 @@ PassRefPtr<ClientRect> Element::getBoundingClientRect() const } adjustFloatRectForAbsoluteZoom(result, renderer()); + if (Page* page = document()->page()) { + if (Frame* frame = page->mainFrame()) + adjustFloatRectForPageScale(result, frame->pageScaleFactor()); + } + return ClientRect::create(result); } @@ -643,22 +657,20 @@ void Element::setAttribute(const AtomicString& name, const AtomicString& value, #endif const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; - + QualifiedName attributeName(nullAtom, localName, nullAtom); + // Allocate attribute map if necessary. Attribute* old = attributes(false)->getAttributeItem(localName, false); document()->incDOMTreeVersion(); - // FIXME: This check is probably not correct for the case where the document has an id attribute - // with a non-null namespace, because it will return true if the local name happens to match - // but the namespace does not. - if (localName == document()->idAttributeName().localName()) + if (isIdAttributeName(old ? old->name() : attributeName)) updateId(old ? old->value() : nullAtom, value); if (old && value.isNull()) m_attributeMap->removeAttribute(old->name()); else if (!old && !value.isNull()) - m_attributeMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value)); + m_attributeMap->addAttribute(createAttribute(attributeName, value)); else if (old && !value.isNull()) { if (Attr* attrNode = old->attr()) attrNode->setValue(value); @@ -713,6 +725,8 @@ PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const void Element::attributeChanged(Attribute* attr, bool) { + if (isIdAttributeName(attr->name())) + idAttributeChanged(attr); recalcStyleIfNeededAfterAttributeChanged(attr); updateAfterAttributeChanged(attr); } @@ -751,6 +765,20 @@ void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr) setNeedsStyleRecalc(); } +void Element::idAttributeChanged(Attribute* attr) +{ + setHasID(!attr->isNull()); + if (attributeMap()) { + if (attr->isNull()) + attributeMap()->setIdForStyleResolution(nullAtom); + else if (document()->inQuirksMode()) + attributeMap()->setIdForStyleResolution(attr->value().lower()); + else + attributeMap()->setIdForStyleResolution(attr->value()); + } + setNeedsStyleRecalc(); +} + // Returns true is the given attribute is an event handler. // We consider an event handler any attribute that begins with "on". // It is a simple solution that has the advantage of not requiring any @@ -957,13 +985,16 @@ void Element::attach() createRendererIfNeeded(); StyleSelectorParentPusher parentPusher(this); - if (firstChild()) - parentPusher.push(); - ContainerNode::attach(); + if (Node* shadow = shadowRoot()) { parentPusher.push(); shadow->attach(); } + + if (firstChild()) + parentPusher.push(); + ContainerNode::attach(); + if (hasRareData()) { ElementRareData* data = rareData(); if (data->needsFocusAppearanceUpdateSoonAfterAttach()) { @@ -1047,7 +1078,7 @@ void Element::recalcStyle(StyleChange change) { // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called. RefPtr<RenderStyle> currentStyle(renderStyle()); - bool hasParentStyle = parentOrHostNode() ? parentOrHostNode()->renderStyle() : false; + bool hasParentStyle = parentNodeForRenderingAndStyle() ? parentNodeForRenderingAndStyle()->renderStyle() : false; bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules(); if ((change > NoChange || needsStyleRecalc())) { @@ -1134,7 +1165,7 @@ void Element::recalcStyle(StyleChange change) } // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world. if (Node* shadow = shadowRoot()) { - if (change >= Inherit || shadow->isTextNode() || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) { + if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) { parentPusher.push(); shadow->recalcStyle(change); } @@ -1144,28 +1175,24 @@ void Element::recalcStyle(StyleChange change) clearChildNeedsStyleRecalc(); } -Node* Element::shadowRoot() +ContainerNode* Element::shadowRoot() const { return hasRareData() ? rareData()->m_shadowRoot : 0; } -void Element::setShadowRoot(PassRefPtr<Node> node) +ContainerNode* Element::ensureShadowRoot() { - // FIXME: Because today this is never called from script directly, we don't have to worry - // about compromising DOM tree integrity (eg. node being a parent of this). However, - // once we implement XBL2, we will have to add integrity checks here. - removeShadowRoot(); - - RefPtr<Node> newRoot = node; - if (!newRoot) - return; + if (ContainerNode* existingRoot = shadowRoot()) + return existingRoot; + RefPtr<ShadowRoot> newRoot = ShadowRoot::create(document()); ensureRareData()->m_shadowRoot = newRoot.get(); newRoot->setShadowHost(this); if (inDocument()) newRoot->insertedIntoDocument(); - if (attached() && !newRoot->attached()) + if (attached()) newRoot->lazyAttach(); + return newRoot.get(); } void Element::removeShadowRoot() @@ -1185,7 +1212,7 @@ void Element::removeShadowRoot() } } -bool Element::childTypeAllowed(NodeType type) +bool Element::childTypeAllowed(NodeType type) const { switch (type) { case ELEMENT_NODE: diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h index ba0870c..d269dbe 100644 --- a/Source/WebCore/dom/Element.h +++ b/Source/WebCore/dom/Element.h @@ -64,8 +64,6 @@ public: DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart); DEFINE_ATTRIBUTE_EVENT_LISTENER(drag); DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend); - DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange); - DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput); DEFINE_ATTRIBUTE_EVENT_LISTENER(input); DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid); DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown); @@ -231,8 +229,10 @@ public: virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void recalcStyle(StyleChange = NoChange); - Node* shadowRoot(); - void setShadowRoot(PassRefPtr<Node>); + ContainerNode* shadowRoot() const; + ContainerNode* ensureShadowRoot(); + void removeShadowRoot(); + virtual const AtomicString& shadowPseudoId() const; RenderStyle* computedStyle(PseudoId = NOPSEUDO); @@ -303,6 +303,10 @@ public: static bool isMathMLElement() { return false; } #endif +#if ENABLE(INPUT_SPEECH) + virtual bool isInputFieldSpeechButtonElement() const { return false; } +#endif + virtual bool isFormControlElement() const { return false; } virtual bool isEnabledFormControl() const { return true; } virtual bool isReadOnlyFormControl() const { return false; } @@ -364,13 +368,15 @@ protected: // They are separated to allow a different flow of control in StyledElement::attributeChanged(). void recalcStyleIfNeededAfterAttributeChanged(Attribute*); void updateAfterAttributeChanged(Attribute*); + + void idAttributeChanged(Attribute*); private: void scrollByUnits(int units, ScrollGranularity); virtual void setPrefix(const AtomicString&, ExceptionCode&); virtual NodeType nodeType() const; - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual PassRefPtr<Attribute> createAttribute(const QualifiedName&, const AtomicString& value); @@ -407,7 +413,6 @@ private: ElementRareData* ensureRareData(); SpellcheckAttributeState spellcheckAttributeState() const; - void removeShadowRoot(); private: mutable RefPtr<NamedNodeMap> m_attributeMap; diff --git a/Source/WebCore/dom/Element.idl b/Source/WebCore/dom/Element.idl index fc28642..0e91811 100644 --- a/Source/WebCore/dom/Element.idl +++ b/Source/WebCore/dom/Element.idl @@ -155,8 +155,6 @@ module core { attribute [DontEnum] EventListener ondrop; attribute [DontEnum] EventListener onerror; attribute [DontEnum] EventListener onfocus; - attribute [DontEnum] EventListener onformchange; - attribute [DontEnum] EventListener onforminput; attribute [DontEnum] EventListener oninput; attribute [DontEnum] EventListener oninvalid; attribute [DontEnum] EventListener onkeydown; diff --git a/Source/WebCore/dom/ElementRareData.h b/Source/WebCore/dom/ElementRareData.h index 818a2c2..14ceef2 100644 --- a/Source/WebCore/dom/ElementRareData.h +++ b/Source/WebCore/dom/ElementRareData.h @@ -30,6 +30,8 @@ namespace WebCore { +class ShadowRoot; + class ElementRareData : public NodeRareData { public: ElementRareData(); @@ -42,7 +44,7 @@ public: IntSize m_minimumSizeForResizing; RefPtr<RenderStyle> m_computedStyle; - Node* m_shadowRoot; + ShadowRoot* m_shadowRoot; OwnPtr<DatasetDOMStringMap> m_datasetDOMStringMap; OwnPtr<ClassList> m_classList; diff --git a/Source/WebCore/dom/Event.cpp b/Source/WebCore/dom/Event.cpp index a1352dc..9cb2778 100644 --- a/Source/WebCore/dom/Event.cpp +++ b/Source/WebCore/dom/Event.cpp @@ -229,6 +229,11 @@ bool Event::isAudioProcessingEvent() const { return false; } + +bool Event::isOfflineAudioCompletionEvent() const +{ + return false; +} #endif #if ENABLE(INPUT_SPEECH) @@ -259,7 +264,7 @@ bool Event::fromUserGesture() // other accepted events || type == eventNames().selectEvent || type == eventNames().changeEvent || type == eventNames().focusEvent || type == eventNames().blurEvent - || type == eventNames().submitEvent || type == eventNames().formchangeEvent; + || type == eventNames().submitEvent; } bool Event::storesResultAsString() const @@ -271,11 +276,6 @@ void Event::storeResult(const String&) { } -bool Event::dispatch(EventDispatcher* dispatcher) -{ - return dispatcher->dispatchEvent(this); -} - void Event::setTarget(PassRefPtr<EventTarget> target) { if (m_target == target) @@ -299,4 +299,18 @@ void Event::setUnderlyingEvent(PassRefPtr<Event> ue) m_underlyingEvent = ue; } +EventDispatchMediator::EventDispatchMediator(PassRefPtr<Event> event) + : m_event(event) +{ +} + +EventDispatchMediator::~EventDispatchMediator() +{ +} + +bool EventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const +{ + return dispatcher->dispatchEvent(m_event.get()); +} + } // namespace WebCore diff --git a/Source/WebCore/dom/Event.h b/Source/WebCore/dom/Event.h index d4d7e06..f6e5586 100644 --- a/Source/WebCore/dom/Event.h +++ b/Source/WebCore/dom/Event.h @@ -131,6 +131,7 @@ namespace WebCore { #endif #if ENABLE(WEB_AUDIO) virtual bool isAudioProcessingEvent() const; + virtual bool isOfflineAudioCompletionEvent() const; #endif virtual bool isErrorEvent() const; #if ENABLE(TOUCH_EVENTS) @@ -166,7 +167,6 @@ namespace WebCore { virtual Clipboard* clipboard() const { return 0; } - virtual bool dispatch(EventDispatcher*); protected: Event(); @@ -194,6 +194,37 @@ namespace WebCore { RefPtr<Event> m_underlyingEvent; }; +class EventDispatchMediator { +public: + explicit EventDispatchMediator(PassRefPtr<Event>); + virtual ~EventDispatchMediator(); + + virtual bool dispatchEvent(EventDispatcher*) const; + +protected: + EventDispatchMediator(); + + Event* event() const; + void setEvent(PassRefPtr<Event>); + +private: + RefPtr<Event> m_event; +}; + +inline EventDispatchMediator::EventDispatchMediator() +{ +} + +inline Event* EventDispatchMediator::event() const +{ + return m_event.get(); +} + +inline void EventDispatchMediator::setEvent(PassRefPtr<Event> event) +{ + m_event = event; +} + } // namespace WebCore #endif // Event_h diff --git a/Source/WebCore/dom/EventDispatcher.cpp b/Source/WebCore/dom/EventDispatcher.cpp index c8b330d..ca2ed30 100644 --- a/Source/WebCore/dom/EventDispatcher.cpp +++ b/Source/WebCore/dom/EventDispatcher.cpp @@ -33,7 +33,6 @@ #include "InspectorInstrumentation.h" #include "MouseEvent.h" #include "Node.h" -#include "PlatformWheelEvent.h" #include "ScopedEventQueue.h" #if ENABLE(SVG) @@ -44,7 +43,6 @@ #include "UIEvent.h" #include "UIEventWithKeyState.h" -#include "WheelEvent.h" #include "WindowEventContext.h" #include <wtf/RefPtr.h> @@ -53,12 +51,12 @@ namespace WebCore { static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0; -bool EventDispatcher::dispatchEvent(Node* node, PassRefPtr<Event> prpEvent) +bool EventDispatcher::dispatchEvent(Node* node, const EventDispatchMediator& mediator) { - RefPtr<Event> event = prpEvent; + ASSERT(!eventDispatchForbidden()); EventDispatcher dispatcher(node); - return event->dispatch(&dispatcher); + return mediator.dispatchEvent(&dispatcher); } static EventTarget* findElementInstance(Node* referenceNode) @@ -67,10 +65,10 @@ static EventTarget* findElementInstance(Node* referenceNode) // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects for (Node* n = referenceNode; n; n = n->parentNode()) { - if (!n->isShadowRoot() || !n->isSVGElement()) + if (!n->isSVGShadowRoot() || !n->isSVGElement()) continue; - Element* shadowTreeParentElement = n->shadowHost(); + Element* shadowTreeParentElement = n->svgShadowHost(); ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag)); if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode)) @@ -124,80 +122,138 @@ void EventDispatcher::dispatchSimulatedClick(Node* node, PassRefPtr<Event> under gNodesDispatchingSimulatedClicks->remove(node); } -inline static WheelEvent::Granularity granularity(const PlatformWheelEvent& event) +static inline bool isShadowRootOrSVGShadowRoot(const Node* node) { - return event.granularity() == ScrollByPageWheelEvent ? WheelEvent::Page : WheelEvent::Pixel; + return node->isShadowRoot() || node->isSVGShadowRoot(); } -void EventDispatcher::dispatchWheelEvent(Node* node, PlatformWheelEvent& event) +PassRefPtr<EventTarget> EventDispatcher::adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors) { - ASSERT(!eventDispatchForbidden()); - if (!(event.deltaX() || event.deltaY())) - return; + Vector<EventContext>::const_iterator lowestCommonBoundary = m_ancestors.end(); + // Assume divergent boundary is the relatedTarget itself (in other words, related target ancestor chain does not cross any shadow DOM boundaries). + Vector<Node*>::const_iterator firstDivergentBoundary = relatedTargetAncestors.begin(); + + Vector<EventContext>::const_iterator targetAncestor = m_ancestors.end(); + // Walk down from the top, looking for lowest common ancestor, also monitoring shadow DOM boundaries. + bool diverged = false; + for (Vector<Node*>::const_iterator i = relatedTargetAncestors.end() - 1; i >= relatedTargetAncestors.begin(); --i) { + if (diverged) { + if (isShadowRootOrSVGShadowRoot(*i)) { + firstDivergentBoundary = i + 1; + break; + } + continue; + } - EventDispatcher dispatcher(node); + if (targetAncestor == m_ancestors.begin()) { + diverged = true; + continue; + } - if (!dispatcher.m_view) - return; + targetAncestor--; - IntPoint position = dispatcher.m_view->windowToContents(event.pos()); + if (isShadowRootOrSVGShadowRoot(*i)) + lowestCommonBoundary = targetAncestor; - int adjustedPageX = position.x(); - int adjustedPageY = position.y(); - if (Frame* frame = node->document()->frame()) { - float pageZoom = frame->pageZoomFactor(); - if (pageZoom != 1.0f) { - adjustedPageX = lroundf(position.x() / pageZoom); - adjustedPageY = lroundf(position.y() / pageZoom); - } + if ((*i) != (*targetAncestor).node()) + diverged = true; } - RefPtr<WheelEvent> wheelEvent = WheelEvent::create(event.wheelTicksX(), event.wheelTicksY(), event.deltaX(), event.deltaY(), granularity(event), - node->document()->defaultView(), event.globalX(), event.globalY(), adjustedPageX, adjustedPageY, - event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey()); - - wheelEvent->setAbsoluteLocation(position); + if (!diverged) { + // The relatedTarget is a parent or shadowHost of the target. + if (isShadowRootOrSVGShadowRoot(m_node.get())) + lowestCommonBoundary = m_ancestors.begin(); + } else if ((*firstDivergentBoundary) == m_node.get()) { + // Since ancestors does not contain target itself, we must account + // for the possibility that target is a shadowHost of relatedTarget + // and thus serves as the lowestCommonBoundary. + // Luckily, in this case the firstDivergentBoundary is target. + lowestCommonBoundary = m_ancestors.begin(); + } - if (!dispatcher.dispatchEvent(wheelEvent) || wheelEvent->defaultHandled()) - event.accept(); + // Trim ancestors to lowestCommonBoundary to keep events inside of the common shadow DOM subtree. + if (lowestCommonBoundary != m_ancestors.end()) + m_ancestors.shrink(lowestCommonBoundary - m_ancestors.begin()); + // Set event's related target to the first encountered shadow DOM boundary in the divergent subtree. + return firstDivergentBoundary != relatedTargetAncestors.begin() ? *firstDivergentBoundary : relatedTarget; +} +inline static bool ancestorsCrossShadowBoundaries(const Vector<EventContext>& ancestors) +{ + return ancestors.isEmpty() || ancestors.first().node() == ancestors.last().node(); } // FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should // be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025. -static Node* pullOutOfShadow(Node* node) +PassRefPtr<EventTarget> EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget) { - Node* outermostShadowBoundary = node; - for (Node* n = node; n; n = n->parentOrHostNode()) { - if (n->isShadowRoot()) + if (!prpRelatedTarget) + return 0; + + RefPtr<Node> relatedTarget = prpRelatedTarget->toNode(); + if (!relatedTarget) + return 0; + + Node* target = m_node.get(); + if (!target) + return prpRelatedTarget; + + ensureEventAncestors(event); + + // Calculate early if the common boundary is even possible by looking at + // ancestors size and if the retargeting has occured (indicating the presence of shadow DOM boundaries). + // If there are no boundaries detected, the target and related target can't have a common boundary. + bool noCommonBoundary = ancestorsCrossShadowBoundaries(m_ancestors); + + Vector<Node*> relatedTargetAncestors; + Node* outermostShadowBoundary = relatedTarget.get(); + for (Node* n = outermostShadowBoundary; n; n = n->parentOrHostNode()) { + if (isShadowRootOrSVGShadowRoot(n)) outermostShadowBoundary = n->parentOrHostNode(); + if (!noCommonBoundary) + relatedTargetAncestors.append(n); } - return outermostShadowBoundary; + + // Short-circuit the fast case when we know there is no need to calculate a common boundary. + if (noCommonBoundary) + return outermostShadowBoundary; + + return adjustToShadowBoundaries(relatedTarget.release(), relatedTargetAncestors); } EventDispatcher::EventDispatcher(Node* node) : m_node(node) + , m_ancestorsInitialized(false) { ASSERT(node); m_view = node->document()->view(); } -void EventDispatcher::getEventAncestors(EventTarget* originalTarget, EventDispatchBehavior behavior) +void EventDispatcher::ensureEventAncestors(Event* event) { + EventDispatchBehavior behavior = determineDispatchBehavior(event); + if (!m_node->inDocument()) return; - if (ancestorsInitialized()) + if (m_ancestorsInitialized) return; - EventTarget* target = originalTarget; + m_ancestorsInitialized = true; + Node* ancestor = m_node.get(); + EventTarget* target = eventTargetRespectingSVGTargetRules(ancestor); bool shouldSkipNextAncestor = false; while (true) { - if (ancestor->isShadowRoot()) { + bool isSVGShadowRoot = ancestor->isSVGShadowRoot(); + if (isSVGShadowRoot || ancestor->isShadowRoot()) { if (behavior == StayInsideShadowDOM) return; +#if ENABLE(SVG) + ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost(); +#else ancestor = ancestor->shadowHost(); +#endif if (!shouldSkipNextAncestor) target = ancestor; } else @@ -208,7 +264,7 @@ void EventDispatcher::getEventAncestors(EventTarget* originalTarget, EventDispat #if ENABLE(SVG) // Skip SVGShadowTreeRootElement. - shouldSkipNextAncestor = ancestor->isSVGElement() && ancestor->isShadowRoot(); + shouldSkipNextAncestor = ancestor->isSVGShadowRoot(); if (shouldSkipNextAncestor) continue; #endif @@ -226,7 +282,7 @@ bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event) ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. RefPtr<EventTarget> originalTarget = event->target(); - getEventAncestors(originalTarget.get(), determineDispatchBehavior(event.get())); + ensureEventAncestors(event.get()); WindowEventContext windowContext(event.get(), m_node.get(), topEventContext()); @@ -309,73 +365,12 @@ doneWithDefault: return !event->defaultPrevented(); } -bool EventDispatcher::dispatchMouseEvent(Node* node, const PlatformMouseEvent& event, const AtomicString& eventType, - int detail, Node* relatedTargetArg) -{ - ASSERT(!eventDispatchForbidden()); - ASSERT(event.eventType() == MouseEventMoved || event.button() != NoButton); - - if (node->disabled()) // Don't even send DOM events for disabled controls.. - return true; - - if (eventType.isEmpty()) - return false; // Shouldn't happen. - - EventDispatcher dispatcher(node); - - // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored. - RefPtr<Node> relatedTarget = pullOutOfShadow(relatedTargetArg); - - IntPoint contentsPosition; - if (FrameView* view = node->document()->view()) - contentsPosition = view->windowToContents(event.pos()); - - IntPoint adjustedPagePosition = contentsPosition; - if (Frame* frame = node->document()->frame()) { - float pageZoom = frame->pageZoomFactor(); - if (pageZoom != 1.0f) { - // Adjust our pageX and pageY to account for the page zoom. - adjustedPagePosition.setX(lroundf(contentsPosition.x() / pageZoom)); - adjustedPagePosition.setY(lroundf(contentsPosition.y() / pageZoom)); - } - } - - RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventType, node->document()->defaultView(), event, adjustedPagePosition, detail, relatedTarget); - mouseEvent->setAbsoluteLocation(contentsPosition); - - bool swallowEvent = false; - - dispatcher.dispatchEvent(mouseEvent); - bool defaultHandled = mouseEvent->defaultHandled(); - bool defaultPrevented = mouseEvent->defaultPrevented(); - if (defaultHandled || defaultPrevented) - swallowEvent = true; - - // Special case: If it's a double click event, we also send the dblclick event. This is not part - // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated - // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same. - if (eventType == eventNames().clickEvent && detail == 2) { - RefPtr<Event> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent, node->document()->defaultView(), event, adjustedPagePosition, detail, relatedTarget); - if (defaultHandled) - doubleClickEvent->setDefaultHandled(); - dispatcher.dispatchEvent(doubleClickEvent); - if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented()) - swallowEvent = true; - } - - return swallowEvent; -} const EventContext* EventDispatcher::topEventContext() { return m_ancestors.isEmpty() ? 0 : &m_ancestors.last(); } -bool EventDispatcher::ancestorsInitialized() const -{ - return m_ancestors.size(); -} - EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event) { // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary: diff --git a/Source/WebCore/dom/EventDispatcher.h b/Source/WebCore/dom/EventDispatcher.h index d43127f..88e9756 100644 --- a/Source/WebCore/dom/EventDispatcher.h +++ b/Source/WebCore/dom/EventDispatcher.h @@ -33,6 +33,7 @@ namespace WebCore { class Event; class EventContext; +class EventDispatchMediator; class EventTarget; class FrameView; class Node; @@ -47,32 +48,35 @@ enum EventDispatchBehavior { class EventDispatcher { public: - static bool dispatchEvent(Node*, PassRefPtr<Event>); + static bool dispatchEvent(Node*, const EventDispatchMediator&); static void dispatchScopedEvent(Node*, PassRefPtr<Event>); - static bool dispatchMouseEvent(Node*, const PlatformMouseEvent&, const AtomicString& eventType, int clickCount = 0, Node* relatedTarget = 0); static void dispatchSimulatedClick(Node*, PassRefPtr<Event> underlyingEvent, bool sendMouseEvents, bool showPressedLook); - static void dispatchWheelEvent(Node*, PlatformWheelEvent&); bool dispatchEvent(PassRefPtr<Event>); + PassRefPtr<EventTarget> adjustRelatedTarget(Event*, PassRefPtr<EventTarget>); + Node* node() const; + private: EventDispatcher(Node*); + PassRefPtr<EventTarget> adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors); EventDispatchBehavior determineDispatchBehavior(Event*); - void getEventAncestors(EventTarget* originalTarget, EventDispatchBehavior); + void ensureEventAncestors(Event*); const EventContext* topEventContext(); - bool ancestorsInitialized() const; - - bool dispatchMouseEvent(const AtomicString& eventType, int button, int detail, - int pageX, int pageY, int screenX, int screenY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, - bool isSimulated, Node* relatedTargetArg, PassRefPtr<Event> underlyingEvent); Vector<EventContext> m_ancestors; RefPtr<Node> m_node; RefPtr<EventTarget> m_originalTarget; RefPtr<FrameView> m_view; + bool m_ancestorsInitialized; }; +inline Node* EventDispatcher::node() const +{ + return m_node.get(); +} + } #endif diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h index 12afbc4..c445a7d 100644 --- a/Source/WebCore/dom/EventNames.h +++ b/Source/WebCore/dom/EventNames.h @@ -67,8 +67,6 @@ namespace WebCore { macro(focus) \ macro(focusin) \ macro(focusout) \ - macro(formchange) \ - macro(forminput) \ macro(hashchange) \ macro(input) \ macro(invalid) \ diff --git a/Source/WebCore/dom/EventQueue.cpp b/Source/WebCore/dom/EventQueue.cpp index 8e544c1..90f3e5d 100644 --- a/Source/WebCore/dom/EventQueue.cpp +++ b/Source/WebCore/dom/EventQueue.cpp @@ -28,12 +28,20 @@ #include "EventQueue.h" #include "DOMWindow.h" +#include "Document.h" #include "Event.h" #include "EventNames.h" +#include "RuntimeApplicationChecks.h" #include "ScriptExecutionContext.h" #include "SuspendableTimer.h" namespace WebCore { + +static inline bool shouldDispatchScrollEventSynchronously(Document* document) +{ + ASSERT_ARG(document, document); + return applicationIsSafari() && (document->url().protocolIs("feed") || document->url().protocolIs("feeds")); +} class EventQueueTimer : public SuspendableTimer { WTF_MAKE_NONCOPYABLE(EventQueueTimer); @@ -71,14 +79,20 @@ void EventQueue::enqueueEvent(PassRefPtr<Event> event) m_pendingEventTimer->startOneShot(0); } -void EventQueue::enqueueScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType) +void EventQueue::enqueueOrDispatchScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType) { - if (!m_nodesWithQueuedScrollEvents.add(target.get()).second) - return; - // Per the W3C CSSOM View Module, scroll events fired at the document should bubble, others should not. bool canBubble = targetType == ScrollEventDocumentTarget; RefPtr<Event> scrollEvent = Event::create(eventNames().scrollEvent, canBubble, false /* non cancelleable */); + + if (shouldDispatchScrollEventSynchronously(target->document())) { + target->dispatchEvent(scrollEvent.release()); + return; + } + + if (!m_nodesWithQueuedScrollEvents.add(target.get()).second) + return; + scrollEvent->setTarget(target); enqueueEvent(scrollEvent.release()); } @@ -92,6 +106,12 @@ bool EventQueue::cancelEvent(Event* event) return found; } +void EventQueue::cancelQueuedEvents() +{ + m_pendingEventTimer->stop(); + m_queuedEvents.clear(); +} + void EventQueue::pendingEventTimerFired() { ASSERT(!m_pendingEventTimer->isActive()); diff --git a/Source/WebCore/dom/EventQueue.h b/Source/WebCore/dom/EventQueue.h index 94b6eaf..2cb38f4 100644 --- a/Source/WebCore/dom/EventQueue.h +++ b/Source/WebCore/dom/EventQueue.h @@ -51,8 +51,9 @@ public: ~EventQueue(); void enqueueEvent(PassRefPtr<Event>); - void enqueueScrollEvent(PassRefPtr<Node>, ScrollEventTargetType); + void enqueueOrDispatchScrollEvent(PassRefPtr<Node>, ScrollEventTargetType); bool cancelEvent(Event*); + void cancelQueuedEvents(); private: explicit EventQueue(ScriptExecutionContext*); diff --git a/Source/WebCore/dom/EventTarget.cpp b/Source/WebCore/dom/EventTarget.cpp index 7bd5cd6..d84d66b 100644 --- a/Source/WebCore/dom/EventTarget.cpp +++ b/Source/WebCore/dom/EventTarget.cpp @@ -119,6 +119,11 @@ SVGElementInstance* EventTarget::toSVGElementInstance() #endif #if ENABLE(WEB_AUDIO) +AudioContext* EventTarget::toAudioContext() +{ + return 0; +} + JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode() { return 0; diff --git a/Source/WebCore/dom/EventTarget.h b/Source/WebCore/dom/EventTarget.h index 31644b7..3544ce6 100644 --- a/Source/WebCore/dom/EventTarget.h +++ b/Source/WebCore/dom/EventTarget.h @@ -40,6 +40,7 @@ namespace WebCore { + class AudioContext; class AbstractWorker; class DedicatedWorkerContext; class DOMApplicationCache; @@ -122,6 +123,7 @@ namespace WebCore { #endif #if ENABLE(WEB_AUDIO) + virtual AudioContext* toAudioContext(); virtual JavaScriptAudioNode* toJavaScriptAudioNode(); #endif diff --git a/Source/WebCore/dom/InputElement.cpp b/Source/WebCore/dom/InputElement.cpp index b467df3..bbdf2f4 100644 --- a/Source/WebCore/dom/InputElement.cpp +++ b/Source/WebCore/dom/InputElement.cpp @@ -131,7 +131,7 @@ void InputElement::setValueFromRenderer(InputElementData& data, InputElement* in // Input event is fired by the Node::defaultEventHandler for editable controls. if (!inputElement->isTextField()) - element->dispatchInputEvents(); + element->dispatchInputEvent(); notifyFormStateChanged(element); } diff --git a/Source/WebCore/dom/KeyboardEvent.cpp b/Source/WebCore/dom/KeyboardEvent.cpp index 109135d..e244fd2 100644 --- a/Source/WebCore/dom/KeyboardEvent.cpp +++ b/Source/WebCore/dom/KeyboardEvent.cpp @@ -161,10 +161,15 @@ KeyboardEvent* findKeyboardEvent(Event* event) return 0; } -bool KeyboardEvent::dispatch(EventDispatcher* dispatcher) +KeyboardEventDispatchMediator::KeyboardEventDispatchMediator(PassRefPtr<KeyboardEvent> event) + : EventDispatchMediator(event) +{ +} + +bool KeyboardEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const { // Make sure not to return true if we already took default action while handling the event. - return dispatcher->dispatchEvent(this) && !defaultHandled(); + return EventDispatchMediator::dispatchEvent(dispatcher) && !event()->defaultHandled(); } } // namespace WebCore diff --git a/Source/WebCore/dom/KeyboardEvent.h b/Source/WebCore/dom/KeyboardEvent.h index ebdb9c8..68910b5 100644 --- a/Source/WebCore/dom/KeyboardEvent.h +++ b/Source/WebCore/dom/KeyboardEvent.h @@ -36,10 +36,10 @@ namespace WebCore { #if PLATFORM(MAC) struct KeypressCommand { KeypressCommand() { } - KeypressCommand(const String& commandName) : commandName(commandName) { } - KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { } + KeypressCommand(const String& commandName) : commandName(commandName) { ASSERT(isASCIILower(commandName[0U])); } + KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:"); } - String commandName; + String commandName; // Actually, a selector name - it may have a trailing colon, and a name that can be different from an editor command name. String text; }; #endif @@ -101,20 +101,28 @@ namespace WebCore { KeyboardEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*, const String& keyIdentifier, unsigned keyLocation, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey); - virtual bool dispatch(EventDispatcher*); OwnPtr<PlatformKeyboardEvent> m_keyEvent; String m_keyIdentifier; unsigned m_keyLocation; bool m_altGraphKey : 1; -#if PLATFORM(MAC) +#if PLATFORM(MAC) + // Commands that were sent by AppKit when interpreting the event. Doesn't include input method commands. Vector<KeypressCommand> m_keypressCommands; #endif }; KeyboardEvent* findKeyboardEvent(Event*); +class KeyboardEventDispatchMediator : public EventDispatchMediator { +public: + explicit KeyboardEventDispatchMediator(PassRefPtr<KeyboardEvent>); + +private: + virtual bool dispatchEvent(EventDispatcher*) const; +}; + } // namespace WebCore #endif // KeyboardEvent_h diff --git a/Source/WebCore/dom/MessagePort.cpp b/Source/WebCore/dom/MessagePort.cpp index 1b7aea7..5edc36c 100644 --- a/Source/WebCore/dom/MessagePort.cpp +++ b/Source/WebCore/dom/MessagePort.cpp @@ -34,6 +34,7 @@ #include "MessageEvent.h" #include "SecurityOrigin.h" #include "Timer.h" +#include "WorkerContext.h" #include <wtf/text/AtomicString.h> namespace WebCore { @@ -171,6 +172,13 @@ void MessagePort::dispatchMessages() OwnPtr<MessagePortChannel::EventData> eventData; while (m_entangledChannel && m_entangledChannel->tryGetMessageFromRemote(eventData)) { + +#if ENABLE(WORKERS) + // close() in Worker onmessage handler should prevent next message from dispatching. + if (m_scriptExecutionContext->isWorkerContext() && static_cast<WorkerContext*>(m_scriptExecutionContext)->isClosing()) + return; +#endif + OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*m_scriptExecutionContext, eventData->channels()); RefPtr<Event> evt = MessageEvent::create(ports.release(), eventData->message()); diff --git a/Source/WebCore/dom/MouseEvent.cpp b/Source/WebCore/dom/MouseEvent.cpp index 0acbd74..134e5f6 100644 --- a/Source/WebCore/dom/MouseEvent.cpp +++ b/Source/WebCore/dom/MouseEvent.cpp @@ -23,19 +23,22 @@ #include "config.h" #include "MouseEvent.h" +#include "EventDispatcher.h" +#include "EventNames.h" #include "Frame.h" #include "FrameView.h" -#include "EventNames.h" #include "PlatformMouseEvent.h" namespace WebCore { -PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, const PlatformMouseEvent& event, const IntPoint& position, int detail, PassRefPtr<Node> relatedTarget) +PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtr<Node> relatedTarget) { + ASSERT(event.eventType() == MouseEventMoved || event.button() != NoButton); + bool isCancelable = eventType != eventNames().mousemoveEvent; return MouseEvent::create(eventType, true, isCancelable, view, - detail, event.globalX(), event.globalY(), position.x(), position.y(), + detail, event.globalX(), event.globalY(), event.x(), event.y(), event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(), relatedTarget, 0, false); } @@ -149,4 +152,47 @@ SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefP setUnderlyingEvent(underlyingEvent); } +MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtr<MouseEvent> mouseEvent) + : EventDispatchMediator(mouseEvent) +{ +} + +MouseEvent* MouseEventDispatchMediator::event() const +{ + return static_cast<MouseEvent*>(EventDispatchMediator::event()); +} + +bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const +{ + if (dispatcher->node()->disabled()) // Don't even send DOM events for disabled controls.. + return true; + + if (event()->type().isEmpty()) + return false; // Shouldn't happen. + + RefPtr<EventTarget> relatedTarget = dispatcher->adjustRelatedTarget(event(), event()->relatedTarget()); + event()->setRelatedTarget(relatedTarget); + + dispatcher->dispatchEvent(event()); + bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented(); + + // Special case: If it's a double click event, we also send the dblclick event. This is not part + // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated + // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same. + if (event()->type() == eventNames().clickEvent && event()->detail() == 2) { + RefPtr<MouseEvent> doubleClickEvent = MouseEvent::create(); + doubleClickEvent->initMouseEvent(eventNames().dblclickEvent, event()->bubbles(), event()->cancelable(), event()->view(), + event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(), + event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(), + event()->button(), relatedTarget); + if (event()->defaultHandled()) + doubleClickEvent->setDefaultHandled(); + dispatcher->dispatchEvent(doubleClickEvent); + if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented()) + swallowEvent = true; + } + + return swallowEvent; +} + } // namespace WebCore diff --git a/Source/WebCore/dom/MouseEvent.h b/Source/WebCore/dom/MouseEvent.h index 06e6218..bab2b42 100644 --- a/Source/WebCore/dom/MouseEvent.h +++ b/Source/WebCore/dom/MouseEvent.h @@ -29,6 +29,7 @@ namespace WebCore { +class EventDispatcher; class PlatformMouseEvent; // Introduced in DOM Level 2 @@ -46,7 +47,7 @@ class PlatformMouseEvent; return adoptRef(new MouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, pageX, pageY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, clipboard, isSimulated)); } - static PassRefPtr<MouseEvent> create(const AtomicString& eventType, PassRefPtr<AbstractView>, const PlatformMouseEvent&, const IntPoint&, int detail, PassRefPtr<Node> relatedTarget); + static PassRefPtr<MouseEvent> create(const AtomicString& eventType, PassRefPtr<AbstractView>, const PlatformMouseEvent&, int detail, PassRefPtr<Node> relatedTarget); virtual ~MouseEvent(); @@ -60,6 +61,7 @@ class PlatformMouseEvent; unsigned short button() const { return m_button; } bool buttonDown() const { return m_buttonDown; } EventTarget* relatedTarget() const { return m_relatedTarget.get(); } + void setRelatedTarget(PassRefPtr<EventTarget> relatedTarget) { m_relatedTarget = relatedTarget; } Clipboard* clipboard() const { return m_clipboard.get(); } @@ -96,6 +98,16 @@ private: SimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<AbstractView>, PassRefPtr<Event> underlyingEvent); }; +class MouseEventDispatchMediator : public EventDispatchMediator { +public: + explicit MouseEventDispatchMediator(PassRefPtr<MouseEvent>); + +private: + MouseEvent* event() const; + + virtual bool dispatchEvent(EventDispatcher*) const; +}; + } // namespace WebCore #endif // MouseEvent_h diff --git a/Source/WebCore/dom/MouseRelatedEvent.cpp b/Source/WebCore/dom/MouseRelatedEvent.cpp index f752670..01e2d19 100644 --- a/Source/WebCore/dom/MouseRelatedEvent.cpp +++ b/Source/WebCore/dom/MouseRelatedEvent.cpp @@ -74,18 +74,43 @@ static int contentsY(AbstractView* abstractView) return frameView->scrollY() / frame->pageZoomFactor(); } -MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> viewArg, - int detail, int screenX, int screenY, int pageX, int pageY, +MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> abstractView, + int detail, int screenX, int screenY, int windowX, int windowY, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated) - : UIEventWithKeyState(eventType, canBubble, cancelable, viewArg, detail, ctrlKey, altKey, shiftKey, metaKey) + : UIEventWithKeyState(eventType, canBubble, cancelable, abstractView, detail, ctrlKey, altKey, shiftKey, metaKey) , m_screenX(screenX) , m_screenY(screenY) - , m_clientX(pageX - contentsX(view())) - , m_clientY(pageY - contentsY(view())) - , m_pageX(pageX) - , m_pageY(pageY) + , m_clientX(0) + , m_clientY(0) + , m_pageX(0) + , m_pageY(0) , m_isSimulated(isSimulated) { + IntPoint adjustedPageLocation; + IntPoint scrollPosition; + + Frame* frame = view() ? view()->frame() : 0; + if (frame && !isSimulated) { + if (FrameView* frameView = frame->view()) { + scrollPosition = frameView->scrollPosition(); + adjustedPageLocation = frameView->windowToContents(IntPoint(windowX, windowY)); + float pageZoom = frame->pageZoomFactor(); + if (pageZoom != 1.0f) { + // Adjust our pageX and pageY to account for the page zoom. + adjustedPageLocation.setX(lroundf(adjustedPageLocation.x() / pageZoom)); + adjustedPageLocation.setY(lroundf(adjustedPageLocation.y() / pageZoom)); + scrollPosition.setX(scrollPosition.x() / pageZoom); + scrollPosition.setY(scrollPosition.y() / pageZoom); + } + } + } + + IntPoint clientLocation(adjustedPageLocation - scrollPosition); + m_clientX = clientLocation.x(); + m_clientY = clientLocation.y(); + m_pageX = adjustedPageLocation.x(); + m_pageY = adjustedPageLocation.y(); + initCoordinates(); } diff --git a/Source/WebCore/dom/NamedNodeMap.idl b/Source/WebCore/dom/NamedNodeMap.idl index 4d36577..3350d2f 100644 --- a/Source/WebCore/dom/NamedNodeMap.idl +++ b/Source/WebCore/dom/NamedNodeMap.idl @@ -21,6 +21,7 @@ module core { interface [ + CustomToJS, CustomMarkFunction, HasIndexGetter, HasNameGetter diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp index 4def034..1fd4b92 100644 --- a/Source/WebCore/dom/Node.cpp +++ b/Source/WebCore/dom/Node.cpp @@ -411,7 +411,7 @@ Node::~Node() m_next->setPreviousSibling(0); if (m_document) - m_document->selfOnlyDeref(); + m_document->guardDeref(); } #ifdef NDEBUG @@ -447,16 +447,12 @@ void Node::setDocument(Document* document) if (inDocument() || m_document == document) return; - document->selfOnlyRef(); + document->guardRef(); setWillMoveToNewOwnerDocumentWasCalled(false); willMoveToNewOwnerDocument(); ASSERT(willMoveToNewOwnerDocumentWasCalled); -#if USE(JSC) - updateDOMNodeDocument(this, m_document, document); -#endif - if (hasRareData() && rareData()->nodeLists()) { if (m_document) m_document->removeNodeListCache(); @@ -465,7 +461,7 @@ void Node::setDocument(Document* document) if (m_document) { m_document->moveNodeIteratorsToNewDocument(this, document); - m_document->selfOnlyDeref(); + m_document->guardDeref(); } m_document = document; @@ -475,6 +471,58 @@ void Node::setDocument(Document* document) ASSERT(didMoveToNewOwnerDocumentWasCalled); } +TreeScope* Node::treeScope() const +{ + if (!hasRareData()) + return document(); + TreeScope* scope = rareData()->treeScope(); + // FIXME: Until we land shadow scopes, there should be no non-document scopes. + ASSERT(!scope); + return scope ? scope : document(); +} + +void Node::setTreeScope(TreeScope* newTreeScope) +{ + ASSERT(!isDocumentNode()); + ASSERT(newTreeScope); + ASSERT(!inDocument() || treeScope() == newTreeScope); + + if (newTreeScope->isDocumentNode()) { + if (hasRareData()) + rareData()->setTreeScope(0); + // Setting the new document scope will be handled implicitly + // by setDocument() below. + } else { + // FIXME: Until we land shadow scopes, this branch should be inert. + ASSERT_NOT_REACHED(); + ensureRareData()->setTreeScope(newTreeScope); + } + + setDocument(newTreeScope->document()); +} + +void Node::setTreeScopeRecursively(TreeScope* newTreeScope) +{ + ASSERT(!isDocumentNode()); + ASSERT(newTreeScope); + if (treeScope() == newTreeScope) + return; + + Document* currentDocument = document(); + Document* newDocument = newTreeScope->document(); + // If an element is moved from a document and then eventually back again the collection cache for + // that element may contain stale data as changes made to it will have updated the DOMTreeVersion + // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here + // we ensure that the collection cache will be invalidated as needed when the element is moved back. + if (currentDocument && currentDocument != newDocument) + currentDocument->incDOMTreeVersion(); + + for (Node* node = this; node; node = node->traverseNextNode(this)) { + node->setTreeScope(newTreeScope); + // FIXME: Once shadow scopes are landed, update parent scope, etc. + } +} + NodeRareData* Node::rareData() const { ASSERT(hasRareData()); @@ -505,7 +553,7 @@ Element* Node::shadowHost() const void Node::setShadowHost(Element* host) { - ASSERT(!parentNode()); + ASSERT(!parentNode() && !isSVGShadowRoot()); if (host) setFlag(IsShadowRootFlag); else @@ -714,6 +762,12 @@ void Node::deprecatedParserAddChild(PassRefPtr<Node>) { } +bool Node::isContentEditable() const +{ + document()->updateLayoutIgnorePendingStylesheets(); + return rendererIsEditable(Editable); +} + bool Node::rendererIsEditable(EditableLevel editableLevel) const { if (document()->inDesignMode() || (document()->frame() && document()->frame()->page() && document()->frame()->page()->isEditable())) @@ -743,7 +797,7 @@ bool Node::rendererIsEditable(EditableLevel editableLevel) const bool Node::shouldUseInputMethod() const { - return rendererIsEditable(); + return isContentEditable(); } RenderBox* Node::renderBox() const @@ -799,24 +853,21 @@ bool Node::hasNonEmptyBoundingBox() const return false; } -void Node::setDocumentRecursively(Document* document) +inline static ContainerNode* shadowRoot(Node* node) { - if (this->document() == document) - return; + return node->isElementNode() ? toElement(node)->shadowRoot() : 0; +} - // If an element is moved from a document and then eventually back again the collection cache for - // that element may contain stale data as changes made to it will have updated the DOMTreeVersion - // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here - // we ensure that the collection cache will be invalidated as needed when the element is moved back. - if (this->document()) - this->document()->incDOMTreeVersion(); +void Node::setDocumentRecursively(Document* newDocument) +{ + ASSERT(document() != newDocument); for (Node* node = this; node; node = node->traverseNextNode(this)) { - node->setDocument(document); + node->setDocument(newDocument); if (!node->isElementNode()) continue; - if (Node* shadow = toElement(node)->shadowRoot()) - shadow->setDocumentRecursively(document); + if (Node* shadow = shadowRoot(node)) + shadow->setDocumentRecursively(newDocument); } } @@ -1401,18 +1452,44 @@ Node *Node::nextLeafNode() const return 0; } +ContainerNode* Node::parentNodeForRenderingAndStyle() const +{ + ContainerNode* parent = parentOrHostNode(); + return parent && parent->isShadowBoundary() ? parent->shadowHost() : parent; +} + +static bool shouldCreateRendererFor(Node* node, ContainerNode* parentForRenderingAndStyle) +{ + RenderObject* parentRenderer = parentForRenderingAndStyle->renderer(); + if (!parentRenderer) + return false; + + bool atShadowBoundary = node->parentOrHostNode()->isShadowBoundary(); + + // FIXME: Ignoring canHaveChildren() in a case of isShadowRoot() might be wrong. + // See https://bugs.webkit.org/show_bug.cgi?id=52423 + if (!parentRenderer->canHaveChildren() && !(node->isShadowRoot() || atShadowBoundary)) + return false; + + if (shadowRoot(parentForRenderingAndStyle) && !atShadowBoundary + && !parentForRenderingAndStyle->canHaveLightChildRendererWithShadow()) + return false; + + if (!parentForRenderingAndStyle->childShouldCreateRenderer(node)) + return false; + + return true; +} + RenderObject* Node::createRendererAndStyle() { ASSERT(!renderer()); ASSERT(document()->shouldCreateRenderers()); - ContainerNode* parent = parentOrHostNode(); + ContainerNode* parent = parentNodeForRenderingAndStyle(); ASSERT(parent); - RenderObject* parentRenderer = parent->renderer(); - // FIXME: Ignoring canHaveChildren() in a case of isShadowRoot() might be wrong. - // See https://bugs.webkit.org/show_bug.cgi?id=52423 - if (!parentRenderer || (!parentRenderer->canHaveChildren() && !isShadowRoot()) || !parent->childShouldCreateRenderer(this)) + if (!shouldCreateRendererFor(this, parent)) return 0; RefPtr<RenderStyle> style = styleForRenderer(); @@ -1423,7 +1500,7 @@ RenderObject* Node::createRendererAndStyle() if (!newRenderer) return 0; - if (!parentRenderer->isChildAllowed(newRenderer, style.get())) { + if (!parent->renderer()->isChildAllowed(newRenderer, style.get())) { newRenderer->destroy(); return 0; } @@ -1464,7 +1541,7 @@ void Node::createRendererIfNeeded() return; // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer. - parentOrHostNode()->renderer()->addChild(newRenderer, nextRenderer()); + parentNodeForRenderingAndStyle()->renderer()->addChild(newRenderer, nextRenderer()); } PassRefPtr<RenderStyle> Node::styleForRenderer() @@ -1530,6 +1607,13 @@ bool Node::canStartSelection() const return parentOrHostNode() ? parentOrHostNode()->canStartSelection() : true; } +#if ENABLE(SVG) +SVGUseElement* Node::svgShadowHost() const +{ + return isSVGShadowRoot() ? static_cast<SVGUseElement*>(parent()) : 0; +} +#endif + Node* Node::shadowAncestorNode() { #if ENABLE(SVG) @@ -1551,7 +1635,7 @@ Node* Node::shadowTreeRootNode() { Node* root = this; while (root) { - if (root->isShadowRoot()) + if (root->isShadowRoot() || root->isSVGShadowRoot()) return root; root = root->parentNodeGuaranteedHostFree(); } @@ -2641,28 +2725,6 @@ EventTargetData* Node::ensureEventTargetData() return ensureRareData()->ensureEventTargetData(); } -#if USE(JSC) - -template <class NodeListMap> -void markNodeLists(const NodeListMap& map, JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) -{ - for (typename NodeListMap::const_iterator it = map.begin(); it != map.end(); ++it) - markDOMObjectWrapper(markStack, globalData, it->second); -} - -void Node::markCachedNodeListsSlow(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) -{ - NodeListsNodeData* nodeLists = rareData()->nodeLists(); - if (!nodeLists) - return; - - markNodeLists(nodeLists->m_classNodeListCache, markStack, globalData); - markNodeLists(nodeLists->m_nameNodeListCache, markStack, globalData); - markNodeLists(nodeLists->m_tagNodeListCache, markStack, globalData); -} - -#endif - void Node::handleLocalEvents(Event* event) { if (!hasRareData() || !rareData()->eventTargetData()) @@ -2681,7 +2743,7 @@ void Node::dispatchScopedEvent(PassRefPtr<Event> event) bool Node::dispatchEvent(PassRefPtr<Event> event) { - return EventDispatcher::dispatchEvent(this, event); + return EventDispatcher::dispatchEvent(this, EventDispatchMediator(event)); } void Node::dispatchSubtreeModifiedEvent() @@ -2713,13 +2775,13 @@ void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr bool Node::dispatchKeyEvent(const PlatformKeyboardEvent& event) { - return EventDispatcher::dispatchEvent(this, KeyboardEvent::create(event, document()->defaultView())); + return EventDispatcher::dispatchEvent(this, KeyboardEventDispatchMediator(KeyboardEvent::create(event, document()->defaultView()))); } bool Node::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType, int detail, Node* relatedTarget) { - return EventDispatcher::dispatchMouseEvent(this, event, eventType, detail, relatedTarget); + return EventDispatcher::dispatchEvent(this, MouseEventDispatchMediator(MouseEvent::create(eventType, document()->defaultView(), event, detail, relatedTarget))); } void Node::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook) @@ -2727,9 +2789,9 @@ void Node::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, EventDispatcher::dispatchSimulatedClick(this, event, sendMouseEvents, showPressedLook); } -void Node::dispatchWheelEvent(PlatformWheelEvent& e) +bool Node::dispatchWheelEvent(const PlatformWheelEvent& event) { - EventDispatcher::dispatchWheelEvent(this, e); + return EventDispatcher::dispatchEvent(this, WheelEventDispatchMediator(event, document()->defaultView())); } void Node::dispatchFocusEvent() @@ -2742,12 +2804,12 @@ void Node::dispatchBlurEvent() dispatchEvent(Event::create(eventNames().blurEvent, false, false)); } -void Node::dispatchChangeEvents() +void Node::dispatchChangeEvent() { dispatchEvent(Event::create(eventNames().changeEvent, true, false)); } -void Node::dispatchInputEvents() +void Node::dispatchInputEvent() { dispatchEvent(Event::create(eventNames().inputEvent, true, false)); } @@ -2809,7 +2871,7 @@ void Node::defaultEventHandler(Event* event) if (Frame* frame = document()->frame()) frame->eventHandler()->defaultWheelEventHandler(startNode, wheelEvent); } else if (event->type() == eventNames().webkitEditableContentChangedEvent) { - dispatchInputEvents(); + dispatchInputEvent(); } } diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h index 31f6ae8..c7bf90d 100644 --- a/Source/WebCore/dom/Node.h +++ b/Source/WebCore/dom/Node.h @@ -71,7 +71,11 @@ class RenderBox; class RenderBoxModelObject; class RenderObject; class RenderStyle; +#if ENABLE(SVG) +class SVGUseElement; +#endif class TagNodeList; +class TreeScope; typedef int ExceptionCode; @@ -89,6 +93,8 @@ enum StyleChangeType { class Node : public EventTarget, public TreeShared<ContainerNode>, public ScriptWrappable { friend class Document; + friend class TreeScope; + public: enum NodeType { ELEMENT_NODE = 1, @@ -188,6 +194,10 @@ public: bool isHTMLElement() const { return getFlag(IsHTMLFlag); } bool isSVGElement() const { return getFlag(IsSVGFlag); } + virtual bool isSVGShadowRoot() const { return false; } +#if ENABLE(SVG) + SVGUseElement* svgShadowHost() const; +#endif #if ENABLE(WML) virtual bool isWMLElement() const { return false; } @@ -203,12 +213,16 @@ public: virtual bool isCharacterDataNode() const { return false; } bool isDocumentNode() const; bool isShadowRoot() const { return getFlag(IsShadowRootFlag); } + // FIXME: Remove this when all shadow roots are ShadowRoots. + virtual bool isShadowBoundary() const { return false; } + virtual bool canHaveLightChildRendererWithShadow() const { return false; } + Node* shadowAncestorNode(); Node* shadowTreeRootNode(); bool isInShadowTree(); - // Node's parent or shadow tree host. + // Node's parent, shadow tree host, or SVG use. ContainerNode* parentOrHostNode() const; - // Use when it's guaranteed to that shadowHost is 0. + // Use when it's guaranteed to that shadowHost is 0 and svgShadowHost is 0. ContainerNode* parentNodeGuaranteedHostFree() const; Element* shadowHost() const; @@ -319,10 +333,8 @@ public: virtual bool isKeyboardFocusable(KeyboardEvent*) const; virtual bool isMouseFocusable() const; -#if PLATFORM(MAC) - // Objective-C extensions - bool isContentEditable() const { return rendererIsEditable(Editable); } -#endif + bool isContentEditable() const; + bool rendererIsEditable() const { return rendererIsEditable(Editable); } bool rendererIsRichlyEditable() const { return rendererIsEditable(RichlyEditable); } virtual bool shouldUseInputMethod() const; @@ -351,12 +363,14 @@ public: return m_document; } - // Do not use this method to change the document of a node until after the node has been - // removed from its previous document. - void setDocument(Document*); + TreeScope* treeScope() const; + + // Do not use this method to change the scope of a node until after the node has been + // removed from its previous scope. Do not use to change documents. + void setTreeScope(TreeScope*); // Used by the basic DOM methods (e.g., appendChild()). - void setDocumentRecursively(Document*); + void setTreeScopeRecursively(TreeScope*); // Returns true if this node is associated with a document and is in its associated document's // node tree, false otherwise. @@ -367,7 +381,7 @@ public: } bool isReadOnlyNode() const { return nodeType() == ENTITY_REFERENCE_NODE; } - virtual bool childTypeAllowed(NodeType) { return false; } + virtual bool childTypeAllowed(NodeType) const { return false; } unsigned childNodeCount() const; Node* childNode(unsigned index) const; @@ -446,6 +460,7 @@ public: virtual bool rendererIsNeeded(RenderStyle*); virtual bool childShouldCreateRenderer(Node*) const { return true; } virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); + ContainerNode* parentNodeForRenderingAndStyle() const; // Wrapper for nodes that don't have a renderer, but still cache the style (like HTMLOptionElement). RenderStyle* renderStyle() const; @@ -547,14 +562,14 @@ public: void dispatchSubtreeModifiedEvent(); void dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent); bool dispatchKeyEvent(const PlatformKeyboardEvent&); - void dispatchWheelEvent(PlatformWheelEvent&); + bool dispatchWheelEvent(const PlatformWheelEvent&); bool dispatchMouseEvent(const PlatformMouseEvent&, const AtomicString& eventType, int clickCount = 0, Node* relatedTarget = 0); void dispatchSimulatedClick(PassRefPtr<Event> underlyingEvent, bool sendMouseEvents = false, bool showPressedLook = true); virtual void dispatchFocusEvent(); virtual void dispatchBlurEvent(); - virtual void dispatchChangeEvents(); - virtual void dispatchInputEvents(); + virtual void dispatchChangeEvent(); + virtual void dispatchInputEvent(); // Perform the default action for an event. virtual void defaultEventHandler(Event*); @@ -569,17 +584,6 @@ public: virtual EventTargetData* eventTargetData(); virtual EventTargetData* ensureEventTargetData(); -#if USE(JSC) - void markCachedNodeLists(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData) - { - // NodeLists may be present. If so, they need to be marked. - if (!hasRareData()) - return; - - markCachedNodeListsSlow(markStack, globalData); - } -#endif - private: enum NodeFlags { IsTextFlag = 1, @@ -644,6 +648,11 @@ protected: }; Node(Document*, ConstructionType); + // Do not use this method to change the document of a node until after the node has been + // removed from its previous document. + void setDocument(Document*); + void setDocumentRecursively(Document*); + virtual void willMoveToNewOwnerDocument(); virtual void didMoveToNewOwnerDocument(); @@ -657,10 +666,6 @@ protected: NodeRareData* ensureRareData(); private: -#if USE(JSC) - void markCachedNodeListsSlow(JSC::MarkStack&, JSC::JSGlobalData&); -#endif - enum EditableLevel { Editable, RichlyEditable }; bool rendererIsEditable(EditableLevel) const; @@ -734,7 +739,7 @@ inline void addSubresourceURL(ListHashSet<KURL>& urls, const KURL& url) inline ContainerNode* Node::parentNode() const { - return getFlag(IsShadowRootFlag) ? 0 : parent(); + return getFlag(IsShadowRootFlag) || isSVGShadowRoot() ? 0 : parent(); } inline ContainerNode* Node::parentOrHostNode() const @@ -744,7 +749,7 @@ inline ContainerNode* Node::parentOrHostNode() const inline ContainerNode* Node::parentNodeGuaranteedHostFree() const { - ASSERT(!getFlag(IsShadowRootFlag)); + ASSERT(!getFlag(IsShadowRootFlag) && !isSVGShadowRoot()); return parentOrHostNode(); } diff --git a/Source/WebCore/dom/NodeFilter.h b/Source/WebCore/dom/NodeFilter.h index 5ce2866..d6e47fb 100644 --- a/Source/WebCore/dom/NodeFilter.h +++ b/Source/WebCore/dom/NodeFilter.h @@ -70,15 +70,22 @@ namespace WebCore { return adoptRef(new NodeFilter(condition)); } + static PassRefPtr<NodeFilter> create() + { + return adoptRef(new NodeFilter()); + } + short acceptNode(ScriptState*, Node*) const; - void markAggregate(JSC::MarkStack& markStack) { m_condition->markAggregate(markStack); }; // Do not call these functions. They are just scaffolding to support the Objective-C bindings. // They operate in the main thread normal world, and they swallow JS exceptions. short acceptNode(Node* node) const { return acceptNode(scriptStateFromNode(mainThreadNormalWorld(), node), node); } + + void setCondition(PassRefPtr<NodeFilterCondition> condition) { ASSERT(!m_condition); m_condition = condition; } private: NodeFilter(PassRefPtr<NodeFilterCondition> condition) : m_condition(condition) { } + NodeFilter() {} RefPtr<NodeFilterCondition> m_condition; }; diff --git a/Source/WebCore/dom/NodeList.h b/Source/WebCore/dom/NodeList.h index d4e18aa..7639d37 100644 --- a/Source/WebCore/dom/NodeList.h +++ b/Source/WebCore/dom/NodeList.h @@ -39,6 +39,9 @@ namespace WebCore { virtual unsigned length() const = 0; virtual Node* item(unsigned index) const = 0; virtual Node* itemWithName(const AtomicString&) const = 0; + + // Other methods (not part of DOM) + virtual bool isDynamicNodeList() const { return false; } }; } // namespace WebCore diff --git a/Source/WebCore/dom/NodeList.idl b/Source/WebCore/dom/NodeList.idl index edb2dc7..b751f66 100644 --- a/Source/WebCore/dom/NodeList.idl +++ b/Source/WebCore/dom/NodeList.idl @@ -21,6 +21,7 @@ module core { interface [ + CustomToJS, HasIndexGetter, HasNameGetter, CustomCall diff --git a/Source/WebCore/dom/NodeRareData.h b/Source/WebCore/dom/NodeRareData.h index badc4e1..ac05d3e 100644 --- a/Source/WebCore/dom/NodeRareData.h +++ b/Source/WebCore/dom/NodeRareData.h @@ -34,6 +34,8 @@ namespace WebCore { +class TreeScope; + struct NodeListsNodeData { WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED; public: @@ -73,7 +75,8 @@ class NodeRareData { WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED; public: NodeRareData() - : m_tabIndex(0) + : m_treeScope(0) + , m_tabIndex(0) , m_tabIndexWasSetExplicitly(false) , m_isFocused(false) , m_needsFocusAppearanceUpdateSoonAfterAttach(false) @@ -96,11 +99,14 @@ public: { return rareDataMap().get(node); } + + TreeScope* treeScope() const { return m_treeScope; } + void setTreeScope(TreeScope* treeScope) { m_treeScope = treeScope; } void clearNodeLists() { m_nodeLists.clear(); } void setNodeLists(PassOwnPtr<NodeListsNodeData> lists) { m_nodeLists = lists; } NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); } - + short tabIndex() const { return m_tabIndex; } void setTabIndexExplicitly(short index) { m_tabIndex = index; m_tabIndexWasSetExplicitly = true; } bool tabIndexSetExplicitly() const { return m_tabIndexWasSetExplicitly; } @@ -123,6 +129,7 @@ protected: void setNeedsFocusAppearanceUpdateSoonAfterAttach(bool needs) { m_needsFocusAppearanceUpdateSoonAfterAttach = needs; } private: + TreeScope* m_treeScope; OwnPtr<NodeListsNodeData> m_nodeLists; OwnPtr<EventTargetData> m_eventTargetData; short m_tabIndex; diff --git a/Source/WebCore/dom/NodeRenderStyle.h b/Source/WebCore/dom/NodeRenderStyle.h index 3a67e02..1a2d2c3 100644 --- a/Source/WebCore/dom/NodeRenderStyle.h +++ b/Source/WebCore/dom/NodeRenderStyle.h @@ -33,7 +33,11 @@ namespace WebCore { inline RenderStyle* Node::renderStyle() const { - return m_renderer ? m_renderer->style() : nonRendererRenderStyle(); + // Using a ternary here confuses the Solaris Studio 12/12.1/12.2 compilers: + // Bug is CR 6569194, "Problem with question operator binding in inline function" + if (m_renderer) + return m_renderer->style(); + return nonRendererRenderStyle(); } } diff --git a/Source/WebCore/dom/Notation.cpp b/Source/WebCore/dom/Notation.cpp index 4b3ab28..f62e630 100644 --- a/Source/WebCore/dom/Notation.cpp +++ b/Source/WebCore/dom/Notation.cpp @@ -49,7 +49,7 @@ PassRefPtr<Node> Notation::cloneNode(bool /*deep*/) return 0; } -bool Notation::childTypeAllowed(NodeType) +bool Notation::childTypeAllowed(NodeType) const { return false; } diff --git a/Source/WebCore/dom/Notation.h b/Source/WebCore/dom/Notation.h index 547c9e7..b2155ba 100644 --- a/Source/WebCore/dom/Notation.h +++ b/Source/WebCore/dom/Notation.h @@ -39,7 +39,7 @@ private: virtual String nodeName() const; virtual NodeType nodeType() const; virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; String m_name; String m_publicId; diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp index ae0e40d..7135644 100644 --- a/Source/WebCore/dom/ProcessingInstruction.cpp +++ b/Source/WebCore/dom/ProcessingInstruction.cpp @@ -101,7 +101,7 @@ PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/) } // DOM Section 1.1.1 -bool ProcessingInstruction::childTypeAllowed(NodeType) +bool ProcessingInstruction::childTypeAllowed(NodeType) const { return false; } diff --git a/Source/WebCore/dom/ProcessingInstruction.h b/Source/WebCore/dom/ProcessingInstruction.h index 8619070..fd98566 100644 --- a/Source/WebCore/dom/ProcessingInstruction.h +++ b/Source/WebCore/dom/ProcessingInstruction.h @@ -69,7 +69,7 @@ private: virtual String nodeValue() const; virtual void setNodeValue(const String&, ExceptionCode&); virtual PassRefPtr<Node> cloneNode(bool deep); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual bool offsetInCharacters() const; virtual int maxCharacterOffset() const; diff --git a/Source/WebCore/dom/QualifiedName.h b/Source/WebCore/dom/QualifiedName.h index 192e7bc..01eaebb 100644 --- a/Source/WebCore/dom/QualifiedName.h +++ b/Source/WebCore/dom/QualifiedName.h @@ -141,11 +141,9 @@ namespace WTF { typedef WebCore::QualifiedNameHash Hash; }; - template<> struct HashTraits<WebCore::QualifiedName> : GenericHashTraits<WebCore::QualifiedName> { + template<> struct HashTraits<WebCore::QualifiedName> : SimpleClassHashTraits<WebCore::QualifiedName> { static const bool emptyValueIsZero = false; static WebCore::QualifiedName emptyValue() { return WebCore::QualifiedName(nullAtom, nullAtom, nullAtom); } - static void constructDeletedValue(WebCore::QualifiedName& slot) { new (&slot) WebCore::QualifiedName(WTF::HashTableDeletedValue); } - static bool isDeletedValue(const WebCore::QualifiedName& slot) { return slot.isHashTableDeletedValue(); } }; } diff --git a/Source/WebCore/dom/Range.cpp b/Source/WebCore/dom/Range.cpp index 423d43f..469a94a 100644 --- a/Source/WebCore/dom/Range.cpp +++ b/Source/WebCore/dom/Range.cpp @@ -224,8 +224,10 @@ void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec) if (startRootContainer != endRootContainer) collapse(true, ec); // check if new start after end - else if (compareBoundaryPoints(m_start, m_end) > 0) + else if (compareBoundaryPoints(m_start, m_end, ec) > 0) { + ASSERT(!ec); collapse(true, ec); + } } void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec) @@ -262,8 +264,10 @@ void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec) if (startRootContainer != endRootContainer) collapse(false, ec); // check if new end before start - if (compareBoundaryPoints(m_start, m_end) > 0) + if (compareBoundaryPoints(m_start, m_end, ec) > 0) { + ASSERT(!ec); collapse(false, ec); + } } void Range::collapse(bool toStart, ExceptionCode& ec) @@ -306,8 +310,8 @@ bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec) if (ec) return false; - return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) >= 0 - && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) <= 0; + return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) >= 0 && !ec + && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) <= 0 && !ec; } short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const @@ -337,11 +341,14 @@ short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const return 0; // compare to start, and point comes before - if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) < 0) + if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) < 0) return -1; + if (ec) + return 0; + // compare to end, and point comes after - if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) > 0) + if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) > 0 && !ec) return 1; // point is in the middle of this range, or on the boundary points @@ -433,20 +440,20 @@ short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, Exc switch (how) { case START_TO_START: - return compareBoundaryPoints(m_start, sourceRange->m_start); + return compareBoundaryPoints(m_start, sourceRange->m_start, ec); case START_TO_END: - return compareBoundaryPoints(m_end, sourceRange->m_start); + return compareBoundaryPoints(m_end, sourceRange->m_start, ec); case END_TO_END: - return compareBoundaryPoints(m_end, sourceRange->m_end); + return compareBoundaryPoints(m_end, sourceRange->m_end, ec); case END_TO_START: - return compareBoundaryPoints(m_start, sourceRange->m_end); + return compareBoundaryPoints(m_start, sourceRange->m_end, ec); } ec = SYNTAX_ERR; return 0; } -short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB) +short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode& ec) { ASSERT(containerA); ASSERT(containerB); @@ -507,8 +514,10 @@ short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containe // case 4: containers A & B are siblings, or children of siblings // ### we need to do a traversal here instead Node* commonAncestor = commonAncestorContainer(containerA, containerB); - if (!commonAncestor) + if (!commonAncestor) { + ec = WRONG_DOCUMENT_ERR; return 0; + } Node* childA = containerA; while (childA && childA->parentNode() != commonAncestor) childA = childA->parentNode(); @@ -537,14 +546,15 @@ short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containe return 0; } -short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB) +short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode& ec) { - return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset()); + return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), ec); } bool Range::boundaryPointsValid() const { - return m_start.container() && compareBoundaryPoints(m_start, m_end) <= 0; + ExceptionCode ec = 0; + return m_start.container() && compareBoundaryPoints(m_start, m_end, ec) <= 0 && !ec; } void Range::deleteContents(ExceptionCode& ec) @@ -1620,7 +1630,7 @@ void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight) } } -void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight) +void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight) const { Node* startContainer = m_start.container(); Node* endContainer = m_end.container(); @@ -1893,16 +1903,24 @@ PassRefPtr<ClientRect> Range::getBoundingClientRect() const return rect.isEmpty() ? 0 : ClientRect::create(rect); } -static void adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>& quads, Document* document, RenderObject* renderer) +static void adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(Vector<FloatQuad>& quads, Document* document, RenderObject* renderer) { FrameView* view = document->view(); if (!view) return; + float pageScale = 1; + if (Page* page = document->page()) { + if (Frame* frame = page->mainFrame()) + pageScale = frame->pageScaleFactor(); + } + IntRect visibleContentRect = view->visibleContentRect(); for (size_t i = 0; i < quads.size(); ++i) { quads[i].move(-visibleContentRect.x(), -visibleContentRect.y()); adjustFloatQuadForAbsoluteZoom(quads[i], renderer); + if (pageScale != 1) + adjustFloatQuadForPageScale(quads[i], pageScale); } } @@ -1924,7 +1942,7 @@ void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const if (RenderBoxModelObject* renderBoxModelObject = static_cast<Element*>(node)->renderBoxModelObject()) { Vector<FloatQuad> elementQuads; renderBoxModelObject->absoluteQuads(elementQuads); - adjustFloatQuadsForScrollAndAbsoluteZoom(elementQuads, m_ownerDocument.get(), renderBoxModelObject); + adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(elementQuads, m_ownerDocument.get(), renderBoxModelObject); quads.append(elementQuads); } @@ -1937,7 +1955,7 @@ void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const Vector<FloatQuad> textQuads; renderText->absoluteQuadsForRange(textQuads, startOffset, endOffset); - adjustFloatQuadsForScrollAndAbsoluteZoom(textQuads, m_ownerDocument.get(), renderText); + adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(textQuads, m_ownerDocument.get(), renderText); quads.append(textQuads); } diff --git a/Source/WebCore/dom/Range.h b/Source/WebCore/dom/Range.h index 5637b77..062ad67 100644 --- a/Source/WebCore/dom/Range.h +++ b/Source/WebCore/dom/Range.h @@ -69,8 +69,8 @@ public: CompareResults compareNode(Node* refNode, ExceptionCode&) const; enum CompareHow { START_TO_START, START_TO_END, END_TO_END, END_TO_START }; short compareBoundaryPoints(CompareHow, const Range* sourceRange, ExceptionCode&) const; - static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB); - static short compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB); + static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode&); + static short compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode&); bool boundaryPointsValid() const; bool intersectsNode(Node* refNode, ExceptionCode&); void deleteContents(ExceptionCode&); @@ -109,7 +109,7 @@ public: // Not transform-friendly void textRects(Vector<IntRect>&, bool useSelectionHeight = false); // Transform-friendly - void textQuads(Vector<FloatQuad>&, bool useSelectionHeight = false); + void textQuads(Vector<FloatQuad>&, bool useSelectionHeight = false) const; void getBorderAndTextQuads(Vector<FloatQuad>&) const; FloatRect boundingRect() const; diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp index 9a07bb8..5dd6b7d 100644 --- a/Source/WebCore/dom/ScriptElement.cpp +++ b/Source/WebCore/dom/ScriptElement.cpp @@ -257,6 +257,9 @@ void ScriptElement::executeScript(const ScriptSourceCode& sourceCode) if (sourceCode.isEmpty()) return; + if (!m_isExternalScript && !m_element->document()->contentSecurityPolicy()->allowInlineScript()) + return; + RefPtr<Document> document = m_element->document(); ASSERT(document); if (Frame* frame = document->frame()) { diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h index 3b37f0c..8407699 100644 --- a/Source/WebCore/dom/ScriptExecutionContext.h +++ b/Source/WebCore/dom/ScriptExecutionContext.h @@ -82,7 +82,7 @@ namespace WebCore { void stopDatabases(DatabaseTaskSynchronizer*); #endif virtual bool isContextThread() const = 0; - virtual bool isJSExecutionTerminated() const = 0; + virtual bool isJSExecutionForbidden() const = 0; const KURL& url() const { return virtualURL(); } KURL completeURL(const String& url) const { return virtualCompleteURL(url); } diff --git a/Source/WebCore/dom/SelectElement.cpp b/Source/WebCore/dom/SelectElement.cpp index 15c69ad..545f271 100644 --- a/Source/WebCore/dom/SelectElement.cpp +++ b/Source/WebCore/dom/SelectElement.cpp @@ -70,6 +70,74 @@ namespace WebCore { static const DOMTimeStamp typeAheadTimeout = 1000; +enum SkipDirection { + SkipBackwards = -1, + SkipForwards = 1 +}; + +// Returns the 1st valid item |skip| items from |listIndex| in direction |direction| if there is one. +// Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one. +// Otherwise, it returns |listIndex|. +// Valid means that it is enabled and an option element. +static int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip) +{ + ASSERT(direction == -1 || direction == 1); + int lastGoodIndex = listIndex; + int size = listItems.size(); + for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) { + --skip; + if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) { + lastGoodIndex = listIndex; + if (skip <= 0) + break; + } + } + return lastGoodIndex; +} + +static int nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex) +{ + return nextValidIndex(data.listItems(element), startIndex, SkipForwards, 1); +} + +static int previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex) +{ + if (startIndex == -1) + startIndex = data.listItems(element).size(); + return nextValidIndex(data.listItems(element), startIndex, SkipBackwards, 1); +} + +static int firstSelectableListIndex(SelectElementData& data, Element* element) +{ + const Vector<Element*>& items = data.listItems(element); + int index = nextValidIndex(items, items.size(), SkipBackwards, INT_MAX); + if (static_cast<unsigned>(index) == items.size()) + return -1; + return index; +} + +static int lastSelectableListIndex(SelectElementData& data, Element* element) +{ + return nextValidIndex(data.listItems(element), -1, SkipForwards, INT_MAX); +} + +// Returns the index of the next valid item one page away from |startIndex| in direction |direction|. +static int nextSelectableListIndexPageAway(SelectElementData& data, Element* element, int startIndex, SkipDirection direction) +{ + const Vector<Element*>& items = data.listItems(element); + // Can't use data->size() because renderer forces a minimum size. + int pageSize = 0; + if (element->renderer()->isListBox()) + pageSize = toRenderListBox(element->renderer())->size() - 1; // -1 so we still show context + + // One page away, but not outside valid bounds. + // If there is a valid option item one page away, the index is chosen. + // If there is no exact one page away valid option, returns startIndex or the most far index. + int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1); + int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex)); + return nextValidIndex(items, edgeIndex, direction, skipAmount); +} + void SelectElement::selectAll(SelectElementData& data, Element* element) { ASSERT(!data.usesMenuList()); @@ -104,30 +172,6 @@ void SelectElement::saveLastSelection(SelectElementData& data, Element* element) } } -int SelectElement::nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex) -{ - const Vector<Element*>& items = data.listItems(element); - int index = startIndex + 1; - while (index >= 0 && (unsigned) index < items.size() && (!isOptionElement(items[index]) || items[index]->disabled())) - ++index; - if ((unsigned) index == items.size()) - return startIndex; - return index; -} - -int SelectElement::previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex) -{ - const Vector<Element*>& items = data.listItems(element); - if (startIndex == -1) - startIndex = items.size(); - int index = startIndex - 1; - while (index >= 0 && (unsigned) index < items.size() && (!isOptionElement(items[index]) || items[index]->disabled())) - --index; - if (index == -1) - return startIndex; - return index; -} - void SelectElement::setActiveSelectionAnchorIndex(SelectElementData& data, Element* element, int index) { data.setActiveSelectionAnchorIndex(index); @@ -515,27 +559,6 @@ void SelectElement::reset(SelectElementData& data, Element* element) setOptionsChangedOnRenderer(data, element); element->setNeedsStyleRecalc(); } - -enum SkipDirection { - SkipBackwards = -1, - SkipForwards = 1 -}; - -// Returns the index of the next valid list item |skip| items past |listIndex| in direction |direction|. -static int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip) -{ - int lastGoodIndex = listIndex; - int size = listItems.size(); - for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) { - --skip; - if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) { - lastGoodIndex = listIndex; - if (skip <= 0) - break; - } - } - return lastGoodIndex; -} void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm) { @@ -594,8 +617,8 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element listIndex = nextValidIndex(listItems, listItems.size(), SkipBackwards, 1); handled = true; } - - if (handled && listIndex >= 0 && (unsigned)listIndex < listItems.size()) + + if (handled && listIndex >= 0 && static_cast<unsigned>(listIndex) < listItems.size()) setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex)); if (handled) @@ -760,19 +783,47 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* return; const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier(); - int endIndex = 0; + bool handled = false; + int endIndex = 0; if (data.activeSelectionEndIndex() < 0) { // Initialize the end index - if (keyIdentifier == "Down") - endIndex = nextSelectableListIndex(data, element, lastSelectedListIndex(data, element)); - else if (keyIdentifier == "Up") - endIndex = previousSelectableListIndex(data, element, optionToListIndex(data, element, selectedIndex(data, element))); + if (keyIdentifier == "Down" || keyIdentifier == "PageDown") { + int startIndex = lastSelectedListIndex(data, element); + handled = true; + if (keyIdentifier == "Down") + endIndex = nextSelectableListIndex(data, element, startIndex); + else + endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipForwards); + } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") { + int startIndex = optionToListIndex(data, element, selectedIndex(data, element)); + handled = true; + if (keyIdentifier == "Up") + endIndex = previousSelectableListIndex(data, element, startIndex); + else + endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipBackwards); + } } else { // Set the end index based on the current end index - if (keyIdentifier == "Down") + if (keyIdentifier == "Down") { endIndex = nextSelectableListIndex(data, element, data.activeSelectionEndIndex()); - else if (keyIdentifier == "Up") - endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex()); + handled = true; + } else if (keyIdentifier == "Up") { + endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex()); + handled = true; + } else if (keyIdentifier == "PageDown") { + endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipForwards); + handled = true; + } else if (keyIdentifier == "PageUp") { + endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipBackwards); + handled = true; + } + } + if (keyIdentifier == "Home") { + endIndex = firstSelectableListIndex(data, element); + handled = true; + } else if (keyIdentifier == "End") { + endIndex = lastSelectableListIndex(data, element); + handled = true; } if (isSpatialNavigationEnabled(element->document()->frame())) @@ -780,13 +831,13 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == data.activeSelectionEndIndex())) return; - if (keyIdentifier == "Down" || keyIdentifier == "Up") { + if (endIndex >= 0 && handled) { // Save the selection so it can be compared to the new selection when dispatching change events immediately after making the new selection. saveLastSelection(data, element); - ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && (unsigned) endIndex < listItems.size())); + ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && static_cast<unsigned>(endIndex) < listItems.size())); setActiveSelectionEndIndex(data, endIndex); - + bool selectNewItem = !data.multiple() || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(element->document()->frame()); if (selectNewItem) data.setActiveSelectionState(true); diff --git a/Source/WebCore/dom/SelectElement.h b/Source/WebCore/dom/SelectElement.h index 222a1bb..dd073a2 100644 --- a/Source/WebCore/dom/SelectElement.h +++ b/Source/WebCore/dom/SelectElement.h @@ -72,8 +72,6 @@ protected: static void selectAll(SelectElementData&, Element*); static void saveLastSelection(SelectElementData&, Element*); - static int nextSelectableListIndex(SelectElementData&, Element*, int startIndex); - static int previousSelectableListIndex(SelectElementData&, Element*, int startIndex); static void setActiveSelectionAnchorIndex(SelectElementData&, Element*, int index); static void setActiveSelectionEndIndex(SelectElementData&, int index); static void updateListBoxSelection(SelectElementData&, Element*, bool deselectOtherOptions); diff --git a/Source/WebCore/dom/ShadowRoot.cpp b/Source/WebCore/dom/ShadowRoot.cpp new file mode 100644 index 0000000..8fe56b5 --- /dev/null +++ b/Source/WebCore/dom/ShadowRoot.cpp @@ -0,0 +1,52 @@ +/* + * 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 "ShadowRoot.h" + +namespace WebCore { + +ShadowRoot::ShadowRoot(Document* document) + : DocumentFragment(document) +{ + ASSERT(document); +} + +String ShadowRoot::nodeName() const +{ + return "#shadow-root"; +} + +void ShadowRoot::recalcStyle(StyleChange change) +{ + for (Node* n = firstChild(); n; n = n->nextSibling()) + n->recalcStyle(change); + + clearNeedsStyleRecalc(); + clearChildNeedsStyleRecalc(); +} + +} diff --git a/Source/WebCore/dom/ShadowRoot.h b/Source/WebCore/dom/ShadowRoot.h new file mode 100644 index 0000000..aeccd8a --- /dev/null +++ b/Source/WebCore/dom/ShadowRoot.h @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef ShadowRoot_h +#define ShadowRoot_h + +#include "DocumentFragment.h" + +namespace WebCore { + +class Document; + +class ShadowRoot : public DocumentFragment { +public: + static PassRefPtr<ShadowRoot> create(Document*); + + virtual bool isShadowBoundary() const { return true; } + virtual void recalcStyle(StyleChange = NoChange); + +private: + ShadowRoot(Document*); + virtual String nodeName() const; +}; + +inline PassRefPtr<ShadowRoot> ShadowRoot::create(Document* document) +{ + return adoptRef(new ShadowRoot(document)); +} + +} // namespace + +#endif diff --git a/Source/WebCore/dom/StyledElement.cpp b/Source/WebCore/dom/StyledElement.cpp index 3c55591..6781ed5 100644 --- a/Source/WebCore/dom/StyledElement.cpp +++ b/Source/WebCore/dom/StyledElement.cpp @@ -233,18 +233,9 @@ void StyledElement::classAttributeChanged(const AtomicString& newClassString) void StyledElement::parseMappedAttribute(Attribute* attr) { - if (isIdAttributeName(attr->name())) { - setHasID(!attr->isNull()); - if (attributeMap()) { - if (attr->isNull()) - attributeMap()->setIdForStyleResolution(nullAtom); - else if (document()->inQuirksMode()) - attributeMap()->setIdForStyleResolution(attr->value().lower()); - else - attributeMap()->setIdForStyleResolution(attr->value()); - } - setNeedsStyleRecalc(); - } else if (attr->name() == classAttr) + if (isIdAttributeName(attr->name())) + idAttributeChanged(attr); + else if (attr->name() == classAttr) classAttributeChanged(attr->value()); else if (attr->name() == styleAttr) { if (attr->isNull()) diff --git a/Source/WebCore/dom/Text.cpp b/Source/WebCore/dom/Text.cpp index 5a28e37..906e421 100644 --- a/Source/WebCore/dom/Text.cpp +++ b/Source/WebCore/dom/Text.cpp @@ -292,7 +292,7 @@ void Text::recalcStyle(StyleChange change) clearNeedsStyleRecalc(); } -bool Text::childTypeAllowed(NodeType) +bool Text::childTypeAllowed(NodeType) const { return false; } diff --git a/Source/WebCore/dom/Text.h b/Source/WebCore/dom/Text.h index f693f3b..5995f1f 100644 --- a/Source/WebCore/dom/Text.h +++ b/Source/WebCore/dom/Text.h @@ -56,7 +56,7 @@ private: virtual bool rendererIsNeeded(RenderStyle*); virtual RenderObject* createRenderer(RenderArena*, RenderStyle*); virtual void recalcStyle(StyleChange = NoChange); - virtual bool childTypeAllowed(NodeType); + virtual bool childTypeAllowed(NodeType) const; virtual PassRefPtr<Text> virtualCreate(const String&); diff --git a/Source/WebCore/dom/TreeScope.cpp b/Source/WebCore/dom/TreeScope.cpp new file mode 100644 index 0000000..a995a2d --- /dev/null +++ b/Source/WebCore/dom/TreeScope.cpp @@ -0,0 +1,170 @@ +/* + * 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: + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 "TreeScope.h" + +#include "Element.h" +#include "HTMLAnchorElement.h" +#include "HTMLMapElement.h" +#include "HTMLNames.h" +#include "NodeRareData.h" + +namespace WebCore { + +using namespace HTMLNames; + +TreeScope::TreeScope(Document* document, ConstructionType constructionType) + : ContainerNode(0, constructionType) + , m_parentTreeScope(0) + , m_accessKeyMapValid(false) + , m_numNodeListCaches(0) +{ + m_document = document; + if (document != this) { + // Assume document as parent scope + m_parentTreeScope = document; + // FIXME: This branch should be inert until shadow scopes are landed. + ASSERT_NOT_REACHED(); + } +} + +TreeScope::~TreeScope() +{ + if (hasRareData()) + rareData()->setTreeScope(0); +} + +void TreeScope::destroyTreeScopeData() +{ + m_elementsById.clear(); + m_imageMapsByName.clear(); + m_elementsByAccessKey.clear(); +} + +void TreeScope::setParentTreeScope(TreeScope* newParentScope) +{ + // A document node cannot be re-parented. + ASSERT(!isDocumentNode()); + // Every scope other than document needs a parent scope. + ASSERT(m_parentTreeScope); + ASSERT(newParentScope); + + m_parentTreeScope = newParentScope; +} + +Element* TreeScope::getElementById(const AtomicString& elementId) const +{ + if (elementId.isEmpty()) + return 0; + return m_elementsById.getElementById(elementId.impl(), this); +} + +void TreeScope::addElementById(const AtomicString& elementId, Element* element) +{ + m_elementsById.add(elementId.impl(), element); +} + +void TreeScope::removeElementById(const AtomicString& elementId, Element* element) +{ + m_elementsById.remove(elementId.impl(), element); +} + +Element* TreeScope::getElementByAccessKey(const String& key) const +{ + if (key.isEmpty()) + return 0; + if (!m_accessKeyMapValid) { + for (Node* n = firstChild(); n; n = n->traverseNextNode()) { + if (!n->isElementNode()) + continue; + Element* element = static_cast<Element*>(n); + const AtomicString& accessKey = element->getAttribute(accesskeyAttr); + if (!accessKey.isEmpty()) + m_elementsByAccessKey.set(accessKey.impl(), element); + } + m_accessKeyMapValid = true; + } + return m_elementsByAccessKey.get(key.impl()); +} + +void TreeScope::invalidateAccessKeyMap() +{ + m_accessKeyMapValid = false; + m_elementsByAccessKey.clear(); +} + +void TreeScope::addImageMap(HTMLMapElement* imageMap) +{ + AtomicStringImpl* name = imageMap->getName().impl(); + if (!name) + return; + m_imageMapsByName.add(name, imageMap); +} + +void TreeScope::removeImageMap(HTMLMapElement* imageMap) +{ + AtomicStringImpl* name = imageMap->getName().impl(); + if (!name) + return; + m_imageMapsByName.remove(name, imageMap); +} + +HTMLMapElement* TreeScope::getImageMap(const String& url) const +{ + if (url.isNull()) + return 0; + size_t hashPos = url.find('#'); + String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl(); + if (document()->isHTMLDocument()) + return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this)); + return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this)); +} + +Element* TreeScope::findAnchor(const String& name) +{ + if (name.isEmpty()) + return 0; + if (Element* element = getElementById(name)) + return element; + for (Node* node = this; node; node = node->traverseNextNode()) { + if (node->hasTagName(aTag)) { + HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); + if (document()->inQuirksMode()) { + // Quirks mode, case insensitive comparison of names. + if (equalIgnoringCase(anchor->name(), name)) + return anchor; + } else { + // Strict mode, names need to match exactly. + if (anchor->name() == name) + return anchor; + } + } + } + return 0; +} + +} // namespace WebCore + diff --git a/Source/WebCore/dom/TreeScope.h b/Source/WebCore/dom/TreeScope.h new file mode 100644 index 0000000..6271541 --- /dev/null +++ b/Source/WebCore/dom/TreeScope.h @@ -0,0 +1,102 @@ +/* + * 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: + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 TreeScope_h +#define TreeScope_h + +#include "ContainerNode.h" +#include "DocumentOrderedMap.h" + +namespace WebCore { + +class Element; +class HTMLMapElement; + +class TreeScope : public ContainerNode { + friend class Document; + +public: + TreeScope* parentTreeScope() const { return m_parentTreeScope; } + + Element* getElementById(const AtomicString&) const; + bool hasElementWithId(AtomicStringImpl* id) const; + bool containsMultipleElementsWithId(const AtomicString& id) const; + void addElementById(const AtomicString& elementId, Element*); + void removeElementById(const AtomicString& elementId, Element*); + + void addImageMap(HTMLMapElement*); + void removeImageMap(HTMLMapElement*); + HTMLMapElement* getImageMap(const String& url) const; + + Element* getElementByAccessKey(const String& key) const; + void invalidateAccessKeyMap(); + + void addNodeListCache() { ++m_numNodeListCaches; } + void removeNodeListCache() { ASSERT(m_numNodeListCaches > 0); --m_numNodeListCaches; } + bool hasNodeListCaches() const { return m_numNodeListCaches; } + + // Find first anchor with the given name. + // First searches for an element with the given ID, but if that fails, then looks + // for an anchor with the given name. ID matching is always case sensitive, but + // Anchor name matching is case sensitive in strict mode and not case sensitive in + // quirks mode for historical compatibility reasons. + Element* findAnchor(const String& name); + +protected: + TreeScope(Document*, ConstructionType = CreateContainer); + + virtual ~TreeScope(); + + void destroyTreeScopeData(); + + void setParentTreeScope(TreeScope*); + +private: + TreeScope* m_parentTreeScope; + + DocumentOrderedMap m_elementsById; + DocumentOrderedMap m_imageMapsByName; + + mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey; + mutable bool m_accessKeyMapValid; + + unsigned m_numNodeListCaches; +}; + +inline bool TreeScope::hasElementWithId(AtomicStringImpl* id) const +{ + ASSERT(id); + return m_elementsById.contains(id); +} + +inline bool TreeScope::containsMultipleElementsWithId(const AtomicString& id) const +{ + return m_elementsById.containsMultiple(id.impl()); +} + +} // namespace WebCore + +#endif // TreeScope_h + diff --git a/Source/WebCore/dom/WheelEvent.cpp b/Source/WebCore/dom/WheelEvent.cpp index 0981a57..a673c93 100644 --- a/Source/WebCore/dom/WheelEvent.cpp +++ b/Source/WebCore/dom/WheelEvent.cpp @@ -23,7 +23,10 @@ #include "config.h" #include "WheelEvent.h" +#include "EventDispatcher.h" #include "EventNames.h" +#include "PlatformWheelEvent.h" + #include <wtf/MathExtras.h> namespace WebCore { @@ -92,4 +95,32 @@ bool WheelEvent::isWheelEvent() const return true; } +inline static WheelEvent::Granularity granularity(const PlatformWheelEvent& event) +{ + return event.granularity() == ScrollByPageWheelEvent ? WheelEvent::Page : WheelEvent::Pixel; +} + +WheelEventDispatchMediator::WheelEventDispatchMediator(const PlatformWheelEvent& event, PassRefPtr<AbstractView> view) +{ + if (!(event.deltaX() || event.deltaY())) + return; + + setEvent(WheelEvent::create(event.wheelTicksX(), event.wheelTicksY(), event.deltaX(), event.deltaY(), granularity(event), + view, event.globalX(), event.globalY(), event.x(), event.y(), event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey())); + +} + +WheelEvent* WheelEventDispatchMediator::event() const +{ + return static_cast<WheelEvent*>(EventDispatchMediator::event()); +} + +bool WheelEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const +{ + if (!event()) + return true; + + return EventDispatchMediator::dispatchEvent(dispatcher) && !event()->defaultHandled(); +} + } // namespace WebCore diff --git a/Source/WebCore/dom/WheelEvent.h b/Source/WebCore/dom/WheelEvent.h index b085e86..5f0d569 100644 --- a/Source/WebCore/dom/WheelEvent.h +++ b/Source/WebCore/dom/WheelEvent.h @@ -82,6 +82,15 @@ namespace WebCore { Granularity m_granularity; }; +class WheelEventDispatchMediator : public EventDispatchMediator { +public: + WheelEventDispatchMediator(const PlatformWheelEvent&, PassRefPtr<AbstractView>); + +private: + WheelEvent* event() const; + virtual bool dispatchEvent(EventDispatcher*) const; +}; + } // namespace WebCore #endif // WheelEvent_h diff --git a/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp b/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp index 9214391..85cf285 100644 --- a/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp +++ b/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp @@ -1341,25 +1341,21 @@ void XMLDocumentParser::doEnd() #if ENABLE(XSLT) XMLTreeViewer xmlTreeViewer(document()); - bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && xmlTreeViewer.hasNoStyleInformation(); + if (xmlViewerMode) + xmlTreeViewer.transformDocumentToTreeView(); - if (xmlViewerMode || m_sawXSLTransform) { + if (m_sawXSLTransform) { void* doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform, document()->url().string()); document()->setTransformSource(new TransformSource(doc)); - if (xmlViewerMode) - xmlTreeViewer.transformDocumentToTreeView(); - else { - document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets. - document()->styleSelectorChanged(RecalcStyleImmediately); - document()->setParsing(true); - } + document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets. + document()->styleSelectorChanged(RecalcStyleImmediately); + document()->setParsing(true); DocumentParser::stopParsing(); } #endif - } #if ENABLE(XSLT) diff --git a/Source/WebCore/dom/make_names.pl b/Source/WebCore/dom/make_names.pl index 836137e..674831c 100755 --- a/Source/WebCore/dom/make_names.pl +++ b/Source/WebCore/dom/make_names.pl @@ -3,6 +3,7 @@ # Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved. # Copyright (C) 2009, Julien Chaffraix <jchaffraix@webkit.org> # Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) +# Copyright (C) 2011 Ericsson AB. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -65,7 +66,7 @@ if ($ENV{CC}) { } else { $gccLocation = "/usr/bin/gcc"; } -my $preprocessor = $gccLocation . " -E -P -x c++"; +my $preprocessor = $gccLocation . " -E -x c++"; GetOptions( 'tags=s' => \$tagsFile, @@ -596,6 +597,10 @@ sub printJSElementIncludes for my $tagName (sort keys %enabledTags) { my $JSInterfaceName = $enabledTags{$tagName}{JSInterfaceName}; next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName); + if ($enabledTags{$tagName}{conditional}) { + # We skip feature-define-specific #includes here since we handle them separately. + next; + } $tagsSeen{$JSInterfaceName} = 1; print F "#include \"${wrapperFactoryType}${JSInterfaceName}.h\"\n"; @@ -610,12 +615,54 @@ sub printElementIncludes for my $tagName (sort keys %enabledTags) { my $interfaceName = $enabledTags{$tagName}{interfaceName}; next if defined($tagsSeen{$interfaceName}); + if ($enabledTags{$tagName}{conditional}) { + # We skip feature-define-specific #includes here since we handle them separately. + next; + } $tagsSeen{$interfaceName} = 1; print F "#include \"${interfaceName}.h\"\n"; } } +sub printConditionalElementIncludes +{ + my ($F, $wrapperFactoryType) = @_; + + my %conditionals; + my %unconditionalElementIncludes; + my %unconditionalJSElementIncludes; + + for my $tagName (keys %enabledTags) { + my $conditional = $enabledTags{$tagName}{conditional}; + my $interfaceName = $enabledTags{$tagName}{interfaceName}; + my $JSInterfaceName = $enabledTags{$tagName}{JSInterfaceName}; + + if ($conditional) { + $conditionals{$conditional}{interfaceNames}{$interfaceName} = 1; + $conditionals{$conditional}{JSInterfaceNames}{$JSInterfaceName} = 1; + } else { + $unconditionalElementIncludes{$interfaceName} = 1; + $unconditionalJSElementIncludes{$JSInterfaceName} = 1; + } + } + + for my $conditional (sort keys %conditionals) { + print F "\n#if ENABLE($conditional)\n"; + for my $interfaceName (sort keys %{$conditionals{$conditional}{interfaceNames}}) { + next if $unconditionalElementIncludes{$interfaceName}; + print F "#include \"$interfaceName.h\"\n"; + } + if ($wrapperFactoryType) { + for my $JSInterfaceName (sort keys %{$conditionals{$conditional}{JSInterfaceNames}}) { + next if $unconditionalJSElementIncludes{$JSInterfaceName}; + print F "#include \"$wrapperFactoryType$JSInterfaceName.h\"\n"; + } + } + print F "#endif\n"; + } +} + sub printDefinitions { my ($F, $namesRef, $type, $namespaceURI) = @_; @@ -661,8 +708,11 @@ END printElementIncludes($F); +print F "\n#include <wtf/HashMap.h>\n"; + +printConditionalElementIncludes($F); + print F <<END -#include <wtf/HashMap.h> #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(VIDEO) #include "Document.h" @@ -922,8 +972,11 @@ sub printWrapperFactoryCppFile printElementIncludes($F); + print F "\n#include <wtf/StdLibExtras.h>\n"; + + printConditionalElementIncludes($F, $wrapperFactoryType); + print F <<END -#include <wtf/StdLibExtras.h> #if ENABLE(VIDEO) #include "Document.h" |