diff options
Diffstat (limited to 'WebCore/dom/Document.cpp')
-rw-r--r-- | WebCore/dom/Document.cpp | 190 |
1 files changed, 122 insertions, 68 deletions
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()) { |