diff options
author | Teng-Hui Zhu <ztenghui@google.com> | 2010-11-10 15:31:59 -0800 |
---|---|---|
committer | Teng-Hui Zhu <ztenghui@google.com> | 2010-11-17 13:35:59 -0800 |
commit | 28040489d744e0c5d475a88663056c9040ed5320 (patch) | |
tree | c463676791e4a63e452a95f0a12b2a8519730693 /WebCore/dom | |
parent | eff9be92c41913c92fb1d3b7983c071f3e718678 (diff) | |
download | external_webkit-28040489d744e0c5d475a88663056c9040ed5320.zip external_webkit-28040489d744e0c5d475a88663056c9040ed5320.tar.gz external_webkit-28040489d744e0c5d475a88663056c9040ed5320.tar.bz2 |
Merge WebKit at r71558: Initial merge by git.
Change-Id: Ib345578fa29df7e4bc72b4f00e4a6fddcb754c4c
Diffstat (limited to 'WebCore/dom')
-rw-r--r-- | WebCore/dom/ContainerNode.cpp | 2 | ||||
-rw-r--r-- | WebCore/dom/Document.cpp | 190 | ||||
-rw-r--r-- | WebCore/dom/Document.h | 57 | ||||
-rw-r--r-- | WebCore/dom/DocumentTiming.h | 48 | ||||
-rw-r--r-- | WebCore/dom/Element.h | 2 | ||||
-rw-r--r-- | WebCore/dom/EventNames.h | 6 | ||||
-rw-r--r-- | WebCore/dom/NodeFilter.h | 1 | ||||
-rw-r--r-- | WebCore/dom/SelectElement.cpp | 18 | ||||
-rw-r--r-- | WebCore/dom/XMLDocumentParserLibxml2.cpp | 2 |
9 files changed, 239 insertions, 87 deletions
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp index fc33519..79d233a 100644 --- a/WebCore/dom/ContainerNode.cpp +++ b/WebCore/dom/ContainerNode.cpp @@ -24,7 +24,7 @@ #include "ContainerNode.h" #include "BeforeLoadEvent.h" -#include "Cache.h" +#include "MemoryCache.h" #include "ContainerNodeAlgorithms.h" #include "DeleteButtonController.h" #include "EventNames.h" diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp index 272387d..978ca44 100644 --- a/WebCore/dom/Document.cpp +++ b/WebCore/dom/Document.cpp @@ -226,8 +226,10 @@ using namespace HTMLNames; // for dual G5s. :) static const int cLayoutScheduleThreshold = 250; -// Use 1 to represent the document's default form. -static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1); +// These functions can't have internal linkage because they are used as template arguments. +bool keyMatchesId(AtomicStringImpl*, Element*); +bool keyMatchesMapName(AtomicStringImpl*, Element*); +bool keyMatchesLowercasedMapName(AtomicStringImpl*, Element*); // DOM Level 2 says (letters added): // @@ -500,6 +502,12 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML, con #endif } +inline void Document::DocumentOrderedMap::clear() +{ + m_map.clear(); + m_duplicateCounts.clear(); +} + void Document::removedLastRef() { ASSERT(!m_deletionHasBegun); @@ -967,34 +975,89 @@ PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const return createElement(qName, false); } -Element* Document::getElementById(const AtomicString& elementId) const +inline void Document::DocumentOrderedMap::add(AtomicStringImpl* key, Element* element) { - if (elementId.isEmpty()) - return 0; + ASSERT(key); + ASSERT(element); + + if (!m_duplicateCounts.contains(key)) { + // Fast path. The key is not already in m_duplicateCounts, so we assume that it's + // also not already in m_map and try to add it. If that add succeeds, we're done. + pair<Map::iterator, bool> addResult = m_map.add(key, element); + if (addResult.second) + return; + + // The add failed, so this key was already cached in m_map. + // There are multiple elements with this key. Remove the m_map + // cache for this key so get searches for it next time it is called. + m_map.remove(addResult.first); + m_duplicateCounts.add(key); + } else { + // There are multiple elements with this key. Remove the m_map + // cache for this key so get will search for it next time it is called. + Map::iterator cachedItem = m_map.find(key); + if (cachedItem != m_map.end()) { + m_map.remove(cachedItem); + m_duplicateCounts.add(key); + } + } - m_elementsById.checkConsistency(); + m_duplicateCounts.add(key); +} - Element* element = m_elementsById.get(elementId.impl()); +inline void Document::DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element) +{ + ASSERT(key); + ASSERT(element); + + m_map.checkConsistency(); + Map::iterator cachedItem = m_map.find(key); + if (cachedItem != m_map.end() && cachedItem->second == element) + m_map.remove(cachedItem); + else + m_duplicateCounts.remove(key); +} + +template<bool keyMatches(AtomicStringImpl*, Element*)> inline Element* Document::DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const +{ + ASSERT(key); + + m_map.checkConsistency(); + + Element* element = m_map.get(key); if (element) return element; - if (m_duplicateIds.contains(elementId.impl())) { - // We know there's at least one node with this id, but we don't know what the first one is. - for (Node* n = traverseNextNode(); n; n = n->traverseNextNode()) { - if (n->isElementNode()) { - element = static_cast<Element*>(n); - if (element->hasID() && element->getIdAttribute() == elementId) { - m_duplicateIds.remove(elementId.impl()); - m_elementsById.set(elementId.impl(), element); - return element; - } - } + if (m_duplicateCounts.contains(key)) { + // We know there's at least one node that matches; iterate to find the first one. + for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) { + if (!node->isElementNode()) + continue; + element = static_cast<Element*>(node); + if (!keyMatches(key, element)) + continue; + m_duplicateCounts.remove(key); + m_map.set(key, element); + return element; } ASSERT_NOT_REACHED(); } + return 0; } +inline bool keyMatchesId(AtomicStringImpl* key, Element* element) +{ + return element->hasID() && element->getIdAttribute().impl() == key; +} + +Element* Document::getElementById(const AtomicString& elementId) const +{ + if (elementId.isEmpty()) + return 0; + return m_elementsById.get<keyMatchesId>(elementId.impl(), this); +} + String Document::readyState() const { DEFINE_STATIC_LOCAL(const String, loading, ("loading")); @@ -1018,6 +1081,22 @@ void Document::setReadyState(ReadyState readyState) { if (readyState == m_readyState) return; + + switch (readyState) { + case Loading: + if (!m_documentTiming.domLoading) + m_documentTiming.domLoading = currentTime(); + break; + case Interactive: + if (!m_documentTiming.domInteractive) + m_documentTiming.domInteractive = currentTime(); + break; + case Complete: + if (!m_documentTiming.domComplete) + m_documentTiming.domComplete = currentTime(); + break; + } + m_readyState = readyState; dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false)); } @@ -1211,40 +1290,12 @@ PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y) void Document::addElementById(const AtomicString& elementId, Element* element) { - typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator; - if (!m_duplicateIds.contains(elementId.impl())) { - // Fast path. The ID is not already in m_duplicateIds, so we assume that it's - // also not already in m_elementsById and do an add. If that add succeeds, we're done. - pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), element); - if (addResult.second) - return; - // The add failed, so this ID was already cached in m_elementsById. - // There are multiple elements with this ID. Remove the m_elementsById - // cache for this ID so getElementById searches for it next time it is called. - m_elementsById.remove(addResult.first); - m_duplicateIds.add(elementId.impl()); - } else { - // There are multiple elements with this ID. If it exists, remove the m_elementsById - // cache for this ID so getElementById searches for it next time it is called. - iterator cachedItem = m_elementsById.find(elementId.impl()); - if (cachedItem != m_elementsById.end()) { - m_elementsById.remove(cachedItem); - m_duplicateIds.add(elementId.impl()); - } - } - m_duplicateIds.add(elementId.impl()); + m_elementsById.add(elementId.impl(), element); } void Document::removeElementById(const AtomicString& elementId, Element* element) { - m_elementsById.checkConsistency(); - - if (m_elementsById.get(elementId.impl()) == element) - m_elementsById.remove(elementId.impl()); - else { - ASSERT(m_inRemovedLastRefFunction || m_duplicateIds.contains(elementId.impl())); - m_duplicateIds.remove(elementId.impl()); - } + m_elementsById.remove(elementId.impl(), element); } Element* Document::getElementByAccessKey(const String& key) const @@ -1562,6 +1613,7 @@ bail_out: void Document::updateStyleIfNeeded() { + ASSERT(isMainThread()); ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting())); if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache()) @@ -1579,6 +1631,7 @@ void Document::updateStyleIfNeeded() void Document::updateStyleForAllDocuments() { + ASSERT(isMainThread()); if (!documentsThatNeedStyleRecalc) return; @@ -1592,6 +1645,7 @@ void Document::updateStyleForAllDocuments() void Document::updateLayout() { + ASSERT(isMainThread()); if (Element* oe = ownerElement()) oe->document()->updateLayout(); @@ -2066,7 +2120,7 @@ void Document::implicitClose() // Resume the animations (or start them) if (f) - f->animation()->resumeAnimations(this); + f->animation()->resumeAnimationsForDocument(this); ImageLoader::dispatchPendingBeforeLoadEvents(); ImageLoader::dispatchPendingLoadEvents(); @@ -3822,30 +3876,28 @@ bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, S void Document::addImageMap(HTMLMapElement* imageMap) { - const AtomicString& name = imageMap->getName(); - if (!name.impl()) + AtomicStringImpl* name = imageMap->getName().impl(); + if (!name) return; - - // Add the image map, unless there's already another with that name. - // "First map wins" is the rule other browsers seem to implement. - m_imageMapsByName.add(name.impl(), imageMap); + m_imageMapsByName.add(name, imageMap); } void Document::removeImageMap(HTMLMapElement* imageMap) { - // Remove the image map by name. - // But don't remove some other image map that just happens to have the same name. - // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map - // once a map has been removed. - const AtomicString& name = imageMap->getName(); - if (!name.impl()) + AtomicStringImpl* name = imageMap->getName().impl(); + if (!name) return; + m_imageMapsByName.remove(name, imageMap); +} - m_imageMapsByName.checkConsistency(); +inline bool keyMatchesMapName(AtomicStringImpl* key, Element* element) +{ + return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().impl() == key; +} - ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl()); - if (it != m_imageMapsByName.end() && it->second == imageMap) - m_imageMapsByName.remove(it); +inline bool keyMatchesLowercasedMapName(AtomicStringImpl* key, Element* element) +{ + return element->hasTagName(mapTag) && static_cast<HTMLMapElement*>(element)->getName().lower().impl() == key; } HTMLMapElement* Document::getImageMap(const String& url) const @@ -3854,9 +3906,9 @@ HTMLMapElement* Document::getImageMap(const String& url) const return 0; size_t hashPos = url.find('#'); String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl(); - AtomicString mapName = isHTMLDocument() ? name.lower() : name; - m_imageMapsByName.checkConsistency(); - return m_imageMapsByName.get(mapName.impl()); + if (isHTMLDocument()) + return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesLowercasedMapName>(AtomicString(name.lower()).impl(), this)); + return static_cast<HTMLMapElement*>(m_imageMapsByName.get<keyMatchesMapName>(AtomicString(name).impl(), this)); } void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder) @@ -4201,6 +4253,8 @@ void Document::finishedParsing() ASSERT(!scriptableDocumentParser() || !m_parser->isParsing()); ASSERT(!scriptableDocumentParser() || m_readyState != Loading); setParsing(false); + if (!m_documentTiming.domContentLoaded) + m_documentTiming.domContentLoaded = currentTime(); dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false)); if (Frame* f = frame()) { diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h index 2d169e7..b4af55d 100644 --- a/WebCore/dom/Document.h +++ b/WebCore/dom/Document.h @@ -33,6 +33,7 @@ #include "Color.h" #include "ContainerNode.h" #include "DocumentMarkerController.h" +#include "DocumentTiming.h" #include "QualifiedName.h" #include "ScriptExecutionContext.h" #include "Timer.h" @@ -310,7 +311,7 @@ public: PassRefPtr<Element> createElement(const QualifiedName&, bool createdByParser); Element* getElementById(const AtomicString&) const; bool hasElementWithId(AtomicStringImpl* id) const; - bool containsMultipleElementsWithId(const AtomicString& elementId) { return m_duplicateIds.contains(elementId.impl()); } + bool containsMultipleElementsWithId(const AtomicString& id) const; /** * Retrieve all nodes that intersect a rect in the window's document, until it is fully enclosed by @@ -1058,6 +1059,8 @@ public: PassRefPtr<TouchList> createTouchList(ExceptionCode&) const; #endif + const DocumentTiming* timing() const { return &m_documentTiming; } + protected: Document(Frame*, const KURL& url, bool isXHTML, bool isHTML, const KURL& baseURL = KURL()); @@ -1065,6 +1068,28 @@ protected: private: + class DocumentOrderedMap { + public: + void add(AtomicStringImpl*, Element*); + void remove(AtomicStringImpl*, Element*); + void clear(); + + bool contains(AtomicStringImpl*) const; + bool containsMultiple(AtomicStringImpl*) const; + template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const Document*) const; + + void checkConsistency() const; + + private: + typedef HashMap<AtomicStringImpl*, Element*> Map; + + // We maintain the invariant that m_duplicateCounts is the count of all elements with a given key + // excluding the one referenced in m_map, if any. This means it one less than the total count + // when the first node with a given key is cached, otherwise the same as the total count. + mutable Map m_map; + mutable HashCountedSet<AtomicStringImpl*> m_duplicateCounts; + }; + friend class IgnoreDestructiveWriteCountIncrementer; void detachParser(); @@ -1259,8 +1284,7 @@ private: RefPtr<Document> m_transformSourceDocument; #endif - typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName; - ImageMapsByName m_imageMapsByName; + DocumentOrderedMap m_imageMapsByName; int m_docID; // A unique document identifier used for things like document-specific mapped attributes. @@ -1278,11 +1302,7 @@ private: RefPtr<TextResourceDecoder> m_decoder; - // We maintain the invariant that m_duplicateIds is the count of all elements with a given ID - // excluding the one referenced in m_elementsById, if any. This means it one less than the total count - // when the first node with a given ID is cached, otherwise the same as the total count. - mutable HashMap<AtomicStringImpl*, Element*> m_elementsById; - mutable HashCountedSet<AtomicStringImpl*> m_duplicateIds; + DocumentOrderedMap m_elementsById; mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey; @@ -1357,15 +1377,32 @@ private: Timer<Document> m_loadEventDelayTimer; ViewportArguments m_viewportArguments; - + bool m_directionSetOnDocumentElement; bool m_writingModeSetOnDocumentElement; + + DocumentTiming m_documentTiming; }; +inline bool Document::DocumentOrderedMap::contains(AtomicStringImpl* id) const +{ + return m_map.contains(id) || m_duplicateCounts.contains(id); +} + +inline bool Document::DocumentOrderedMap::containsMultiple(AtomicStringImpl* id) const +{ + return m_duplicateCounts.contains(id); +} + inline bool Document::hasElementWithId(AtomicStringImpl* id) const { ASSERT(id); - return m_elementsById.contains(id) || m_duplicateIds.contains(id); + return m_elementsById.contains(id); +} + +inline bool Document::containsMultipleElementsWithId(const AtomicString& id) const +{ + return m_elementsById.containsMultiple(id.impl()); } inline bool Node::isDocumentNode() const diff --git a/WebCore/dom/DocumentTiming.h b/WebCore/dom/DocumentTiming.h new file mode 100644 index 0000000..a0bbb8c --- /dev/null +++ b/WebCore/dom/DocumentTiming.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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 GOOGLE 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 GOOGLE 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 DocumentTiming_h +#define DocumentTiming_h + +namespace WebCore { + +struct DocumentTiming { + DocumentTiming() + : domLoading(0.0) + , domInteractive(0.0) + , domContentLoaded(0.0) + , domComplete(0.0) + { + } + + double domLoading; + double domInteractive; + double domContentLoaded; + double domComplete; +}; + +} + +#endif diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h index 67887cc..1a85650 100644 --- a/WebCore/dom/Element.h +++ b/WebCore/dom/Element.h @@ -326,7 +326,7 @@ public: void webkitRequestFullScreen(unsigned short flags); #endif - bool isSpellCheckingEnabled() const; + virtual bool isSpellCheckingEnabled() const; protected: Element(const QualifiedName& tagName, Document* document, ConstructionType type) diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h index c91c136..4d39acf 100644 --- a/WebCore/dom/EventNames.h +++ b/WebCore/dom/EventNames.h @@ -172,7 +172,11 @@ namespace WebCore { \ macro(webkitfullscreenchange) \ \ - macro(webkitspeechchange) + macro(webkitspeechchange) \ + \ + macro(webglcontextlost) \ + macro(webglcontextrestored) \ + macro(webglcontextcreationerror) \ \ // end of DOM_EVENT_NAMES_FOR_EACH diff --git a/WebCore/dom/NodeFilter.h b/WebCore/dom/NodeFilter.h index d2022bc..5ce2866 100644 --- a/WebCore/dom/NodeFilter.h +++ b/WebCore/dom/NodeFilter.h @@ -25,6 +25,7 @@ #ifndef NodeFilter_h #define NodeFilter_h +#include "DOMWrapperWorld.h" #include "NodeFilterCondition.h" #include <wtf/RefPtr.h> diff --git a/WebCore/dom/SelectElement.cpp b/WebCore/dom/SelectElement.cpp index 57fb277..886eee7 100644 --- a/WebCore/dom/SelectElement.cpp +++ b/WebCore/dom/SelectElement.cpp @@ -41,7 +41,7 @@ #include "Page.h" #include "RenderListBox.h" #include "RenderMenuList.h" -#include "Settings.h" +#include "SpatialNavigation.h" #include <wtf/Assertions.h> #if ENABLE(WML) @@ -561,10 +561,9 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element #else // When using spatial navigation, we want to be able to navigate away from the select element // when the user hits any of the arrow keys, instead of changing the selection. - if (Frame* frame = element->document()->frame()) { - if (frame->settings() && frame->settings()->isSpatialNavigationEnabled()) + if (isSpatialNavigationEnabled(element->document()->frame())) + if (!data.activeSelectionState()) return; - } UNUSED_PARAM(htmlForm); const Vector<Element*>& listItems = data.listItems(element); @@ -645,6 +644,10 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element // listIndex should already be selected, but this will fire the onchange handler. setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex), true, true); handled = true; + } else if (keyCode == ' ' && isSpatialNavigationEnabled(element->document()->frame())) { + // Use space to trigger arrow key handling for selection change or spatial navigation. + data.setActiveSelectionState(!data.activeSelectionState()); + handled = true; } #endif if (handled) @@ -762,7 +765,12 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element* else if (keyIdentifier == "Up") endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex()); } - + + if (isSpatialNavigationEnabled(element->document()->frame())) + // Check if the selection moves to the boundary. + if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == data.activeSelectionEndIndex())) + return; + if (keyIdentifier == "Down" || keyIdentifier == "Up") { // 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); diff --git a/WebCore/dom/XMLDocumentParserLibxml2.cpp b/WebCore/dom/XMLDocumentParserLibxml2.cpp index 5b5ac89..77b0af6 100644 --- a/WebCore/dom/XMLDocumentParserLibxml2.cpp +++ b/WebCore/dom/XMLDocumentParserLibxml2.cpp @@ -403,7 +403,7 @@ static bool shouldAllowExternalLoad(const KURL& url) // retrieved content. If we had more context, we could potentially allow // the parser to load a DTD. As things stand, we take the conservative // route and allow same-origin requests only. - if (!XMLDocumentParserScope::currentCachedResourceLoader->doc()->securityOrigin()->canRequest(url)) { + if (!XMLDocumentParserScope::currentCachedResourceLoader->document()->securityOrigin()->canRequest(url)) { XMLDocumentParserScope::currentCachedResourceLoader->printAccessDeniedMessage(url); return false; } |