diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (patch) | |
tree | d49911209b132da58d838efa852daf28d516df21 /WebCore/dom | |
parent | 87eb0cb35bad8784770ebc807e6c982432e47107 (diff) | |
download | external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.zip external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.tar.gz external_webkit-9364f22aed35e1a1e9d07c121510f80be3ab0502.tar.bz2 |
Initial Contribution
Diffstat (limited to 'WebCore/dom')
59 files changed, 2051 insertions, 1120 deletions
diff --git a/WebCore/dom/Attr.cpp b/WebCore/dom/Attr.cpp index 52a2581..24ea6b9 100644 --- a/WebCore/dom/Attr.cpp +++ b/WebCore/dom/Attr.cpp @@ -30,7 +30,7 @@ namespace WebCore { -Attr::Attr(Element* element, Document* docPtr, PassRefPtr<Attribute> a) +Attr::Attr(Element* element, Document* docPtr, Attribute* a) : ContainerNode(docPtr), m_element(element), m_attribute(a), @@ -51,7 +51,7 @@ void Attr::createTextChild() { ASSERT(refCount()); if (!m_attribute->value().isEmpty()) { - RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string()); + RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().domString()); // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set), // but much more efficiently. @@ -149,13 +149,13 @@ bool Attr::childTypeAllowed(NodeType type) } } -void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +void Attr::childrenChanged(bool changedByParser) { + Node::childrenChanged(changedByParser); + if (m_ignoreChildrenChanged > 0) return; - - Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); - + // FIXME: We should include entity references in the value String val = ""; diff --git a/WebCore/dom/Attr.h b/WebCore/dom/Attr.h index d71a79e..9ade207 100644 --- a/WebCore/dom/Attr.h +++ b/WebCore/dom/Attr.h @@ -46,7 +46,7 @@ class Attr : public ContainerNode { friend class NamedAttrMap; public: - Attr(Element*, Document*, PassRefPtr<Attribute>); + Attr(Element*, Document*, Attribute*); ~Attr(); // Call this after calling the constructor so the @@ -77,7 +77,7 @@ public: virtual bool isAttributeNode() const { return true; } virtual bool childTypeAllowed(NodeType); - virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual void childrenChanged(bool changedByParser = false); virtual String toString() const; Attribute* attr() const { return m_attribute.get(); } diff --git a/WebCore/dom/Attribute.h b/WebCore/dom/Attribute.h index d515ea7..266003b 100644 --- a/WebCore/dom/Attribute.h +++ b/WebCore/dom/Attribute.h @@ -48,11 +48,11 @@ class Attribute : public RefCounted<Attribute> { public: // null value is forbidden ! Attribute(const QualifiedName& name, const AtomicString& value) - : RefCounted<Attribute>(0), m_name(name), m_value(value), m_impl(0) + : m_name(name), m_value(value), m_impl(0) {} Attribute(const AtomicString& name, const AtomicString& value) - : RefCounted<Attribute>(0), m_name(nullAtom, name, nullAtom), m_value(value), m_impl(0) + : m_name(nullAtom, name, nullAtom), m_value(value), m_impl(0) {} virtual ~Attribute() { } @@ -70,7 +70,7 @@ public: bool isNull() const { return m_value.isNull(); } bool isEmpty() const { return m_value.isEmpty(); } - virtual Attribute* clone(bool preserveDecl = true) const; + virtual Attribute* clone(bool preserveDecl=true) const; // An extension to get the style information for presentational attributes. virtual CSSStyleDeclaration* style() const { return 0; } diff --git a/WebCore/dom/CharacterData.cpp b/WebCore/dom/CharacterData.cpp index 1228c98..d525650 100644 --- a/WebCore/dom/CharacterData.cpp +++ b/WebCore/dom/CharacterData.cpp @@ -26,6 +26,7 @@ #include "Document.h" #include "EventNames.h" #include "ExceptionCode.h" +#include "TextStream.h" #include "MutationEvent.h" #include "RenderText.h" @@ -258,4 +259,13 @@ bool CharacterData::offsetInCharacters() const return true; } +#ifndef NDEBUG +void CharacterData::dump(TextStream *stream, DeprecatedString ind) const +{ + *stream << " m_data=\"" << String(m_data).utf8().data() << "\""; + + EventTargetNode::dump(stream, ind); +} +#endif + } // namespace WebCore diff --git a/WebCore/dom/CharacterData.h b/WebCore/dom/CharacterData.h index da89a95..fdb65e2 100644 --- a/WebCore/dom/CharacterData.h +++ b/WebCore/dom/CharacterData.h @@ -61,6 +61,10 @@ public: virtual bool offsetInCharacters() const; virtual bool rendererIsNeeded(RenderStyle*); +#ifndef NDEBUG + virtual void dump(TextStream*, DeprecatedString indent = "") const; +#endif + protected: RefPtr<StringImpl> m_data; diff --git a/WebCore/dom/Clipboard.cpp b/WebCore/dom/Clipboard.cpp index 4c808d1..152f403 100755 --- a/WebCore/dom/Clipboard.cpp +++ b/WebCore/dom/Clipboard.cpp @@ -35,8 +35,7 @@ namespace WebCore { Clipboard::Clipboard(ClipboardAccessPolicy policy, bool isForDragging) - : RefCounted<Clipboard>(0) - , m_policy(policy) + : m_policy(policy) , m_dragStarted(false) , m_forDragging(isForDragging) , m_dragImage(0) diff --git a/WebCore/dom/Comment.cpp b/WebCore/dom/Comment.cpp index 18bd89f..96b557f 100644 --- a/WebCore/dom/Comment.cpp +++ b/WebCore/dom/Comment.cpp @@ -44,7 +44,7 @@ Comment::~Comment() String Comment::nodeName() const { - return commentAtom.string(); + return commentAtom.domString(); } Node::NodeType Comment::nodeType() const diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp index 7103d72..66bdc5c 100644 --- a/WebCore/dom/ContainerNode.cpp +++ b/WebCore/dom/ContainerNode.cpp @@ -162,9 +162,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce return true; RefPtr<Node> next = refChild; - RefPtr<Node> prev = refChild->previousSibling(); - int childCountDelta = 0; RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; while (child) { RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0; @@ -192,8 +190,6 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce ASSERT(!child->nextSibling()); ASSERT(!child->previousSibling()); - childCountDelta++; - // Add child before "next". forbidEventDispatch(); Node* prev = next->previousSibling(); @@ -223,8 +219,6 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce } document()->setDocumentChanged(true); - if (childCountDelta) - childrenChanged(false, prev.get(), next.get(), childCountDelta); dispatchSubtreeModifiedEvent(); return true; } @@ -240,6 +234,16 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce if (oldChild == newChild) // nothing to do return true; +#ifdef ANDROID_FIX + // if oldChild is null, it will cause crash in checkReplaceChild(). We + // should check null first. + // Fix Android bug, http://b/issue?id=847893 + if (!oldChild) { + ec = NOT_FOUND_ERR; + return false; + } +#endif + // Make sure replacing the old child with the new is ok checkReplaceChild(newChild.get(), oldChild, ec); if (ec) @@ -252,7 +256,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce } RefPtr<Node> prev = oldChild->previousSibling(); - RefPtr<Node> next = oldChild->nextSibling(); // Remove the node we're replacing RefPtr<Node> removedChild = oldChild; @@ -268,7 +271,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE; // Add the new child(ren) - int childCountDelta = 0; RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; while (child) { // If the new child is already in the right place, we're done. @@ -293,8 +295,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce if (child->parentNode()) break; - childCountDelta++; - ASSERT(!child->nextSibling()); ASSERT(!child->previousSibling()); @@ -334,8 +334,6 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce } document()->setDocumentChanged(true); - if (childCountDelta) - childrenChanged(false, prev.get(), next.get(), childCountDelta); dispatchSubtreeModifiedEvent(); return true; } @@ -438,7 +436,6 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec) document()->setDocumentChanged(true); // Dispatch post-removal mutation events - childrenChanged(false, prev, next, -1); dispatchSubtreeModifiedEvent(); if (child->inDocument()) @@ -467,10 +464,7 @@ bool ContainerNode::removeChildren() document()->removeFocusedNodeOfSubtree(this, true); forbidEventDispatch(); - int childCountDelta = 0; while ((n = m_firstChild) != 0) { - childCountDelta--; - Node *next = n->nextSibling(); n->ref(); @@ -495,7 +489,6 @@ bool ContainerNode::removeChildren() allowEventDispatch(); // Dispatch a single post-removal mutation event denoting a modified subtree. - childrenChanged(false, 0, 0, childCountDelta); dispatchSubtreeModifiedEvent(); return true; @@ -525,8 +518,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec) return true; // Now actually add the child(ren) - int childCountDelta = 0; - RefPtr<Node> prev = lastChild(); RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild; while (child) { // For a fragment we have more children to do. @@ -546,7 +537,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec) } // Append child to the end of the list - childCountDelta++; forbidEventDispatch(); child->setParent(this); if (m_lastChild) { @@ -568,7 +558,6 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec) } document()->setDocumentChanged(true); - childrenChanged(false, prev.get(), 0, childCountDelta); dispatchSubtreeModifiedEvent(); return true; } @@ -589,7 +578,6 @@ ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild) forbidEventDispatch(); newChild->setParent(this); - Node* last = m_lastChild; if (m_lastChild) { newChild->setPreviousSibling(m_lastChild); m_lastChild->setNextSibling(newChild.get()); @@ -601,7 +589,9 @@ ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild) document()->incDOMTreeVersion(); if (inDocument()) newChild->insertedIntoDocument(); - childrenChanged(true, last, 0, 1); + if (document()->hasNodeLists()) + notifyNodeListsChildrenChanged(); + childrenChanged(true); if (newChild->isElementNode()) return static_cast<ContainerNode*>(newChild.get()); @@ -694,13 +684,6 @@ void ContainerNode::removedFromTree(bool deep) } } -void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) -{ - Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); - if (document()->hasNodeLists()) - notifyNodeListsChildrenChanged(); -} - void ContainerNode::cloneChildNodes(ContainerNode *clone) { // disable the delete button so it's elements are not serialized into the markup diff --git a/WebCore/dom/ContainerNode.h b/WebCore/dom/ContainerNode.h index 9bc4634..9384f6a 100644 --- a/WebCore/dom/ContainerNode.h +++ b/WebCore/dom/ContainerNode.h @@ -59,7 +59,6 @@ public: virtual void removedFromDocument(); virtual void insertedIntoTree(bool deep); virtual void removedFromTree(bool deep); - virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); virtual bool removeChildren(); diff --git a/WebCore/dom/DOMImplementation.cpp b/WebCore/dom/DOMImplementation.cpp index db277d5..49f732e 100644 --- a/WebCore/dom/DOMImplementation.cpp +++ b/WebCore/dom/DOMImplementation.cpp @@ -284,8 +284,10 @@ PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceUR doc = new Document(this, 0); // now get the interesting parts of the doctype - if (doctype) - doc->addChild(doctype); + if (doctype) { + doc->setDocType(doctype); + doctype->setDocument(doc.get()); + } if (!qualifiedName.isEmpty()) doc->addChild(doc->createElementNS(namespaceURI, qualifiedName, ec)); @@ -325,8 +327,10 @@ bool DOMImplementation::isXMLMIMEType(const String& mimeType) if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl") return true; static const char* validChars = "[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]"; // per RFCs: 3023, 2045 - static RegularExpression xmlTypeRegExp(String("^") + validChars + "+/" + validChars + "+\\+xml$"); - return xmlTypeRegExp.match(mimeType) > -1; + static RegularExpression xmlTypeRegExp(DeprecatedString("^") + validChars + "+/" + validChars + "+\\+xml$"); + if (xmlTypeRegExp.match(mimeType.deprecatedString()) > -1) + return true; + return false; } bool DOMImplementation::isTextMIMEType(const String& mimeType) @@ -343,7 +347,7 @@ PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& tit { RefPtr<HTMLDocument> d = new HTMLDocument(this, 0); d->open(); - d->write("<!doctype html><html><head><title>" + title + "</title></head><body></body></html>"); + d->write("<html><head><title>" + title + "</title></head><body></body></html>"); return d.release(); } diff --git a/WebCore/dom/DOMImplementation.h b/WebCore/dom/DOMImplementation.h index 80b921c..736ca7b 100644 --- a/WebCore/dom/DOMImplementation.h +++ b/WebCore/dom/DOMImplementation.h @@ -42,8 +42,7 @@ typedef int ExceptionCode; class DOMImplementation : public RefCounted<DOMImplementation> { public: - DOMImplementation() : RefCounted<DOMImplementation>(0) { } - virtual ~DOMImplementation(); + virtual ~DOMImplementation(); // DOM methods & attributes for DOMImplementation bool hasFeature(const String& feature, const String& version) const; diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp index f6de5de..4b3e8ad 100644 --- a/WebCore/dom/Document.cpp +++ b/WebCore/dom/Document.cpp @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * (C) 2006 Alexey Proskuryakov (ap@webkit.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,7 +26,6 @@ #include "AXObjectCache.h" #include "CDATASection.h" -#include "CachedCSSStyleSheet.h" #include "CSSHelper.h" #include "CSSStyleSelector.h" #include "CSSStyleSheet.h" @@ -35,12 +34,12 @@ #include "ClassNodeList.h" #include "Comment.h" #include "CookieJar.h" +#include "Database.h" #include "DOMImplementation.h" #include "DocLoader.h" #include "DocumentFragment.h" #include "DocumentLoader.h" #include "DocumentType.h" -#include "DOMWindow.h" #include "EditingText.h" #include "Editor.h" #include "EditorClient.h" @@ -109,14 +108,9 @@ #include "kjs_proxy.h" #if ENABLE(DATABASE) -#include "Database.h" #include "DatabaseThread.h" #endif -#if ENABLE(CROSS_DOCUMENT_MESSAGING) -#include "MessageEvent.h" -#endif - #if ENABLE(XPATH) #include "XPathEvaluator.h" #include "XPathExpression.h" @@ -140,6 +134,21 @@ #include "TimeScheduler.h" #endif +#ifdef ANDROID_INSTRUMENT +#undef LOG +#include <utils/Log.h> +#endif + +#ifdef ANDROID_META_SUPPORT +#include "Settings.h" +#endif + +#ifdef ANDROID_RESET_SELECTION +#include "CacheBuilder.h" +#include "FrameAndroid.h" +#include "HTMLTextAreaElement.h" +#endif + using namespace std; using namespace WTF; using namespace Unicode; @@ -300,6 +309,9 @@ Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML) #if USE(LOW_BANDWIDTH_DISPLAY) , m_inLowBandwidthDisplay(false) #endif +#ifdef ANDROID_MOBILE + , mExtraLayoutDelay(0) +#endif { m_document.resetSkippingRef(this); @@ -319,8 +331,8 @@ Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML) m_tokenizer = 0; m_wellFormed = false; - setParseMode(Strict); - + pMode = Strict; + hMode = XHtml; m_textColor = Color::black; m_listenerTypes = 0; m_inDocument = true; @@ -331,8 +343,12 @@ Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML) m_usesFirstLineRules = false; m_usesFirstLetterRules = false; m_gotoAnchorNeededAfterStylesheetsLoad = false; - - m_styleSelector = 0; + + bool matchAuthorAndUserStyles = true; + if (Settings* settings = this->settings()) + matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled(); + m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles); + m_didCalculateStyleSelector = false; m_pendingStylesheets = 0; m_ignorePendingStylesheets = false; @@ -409,7 +425,7 @@ Document::~Document() XMLHttpRequest::detachRequests(this); { KJS::JSLock lock; - ScriptInterpreter::forgetAllDOMNodesForDocument(this); + KJS::ScriptInterpreter::forgetAllDOMNodesForDocument(this); } if (m_docChanged && changedDocuments) @@ -472,15 +488,12 @@ void Document::resetActiveLinkColor() void Document::setDocType(PassRefPtr<DocumentType> docType) { - // This should never be called more than once. - // Note: This is not a public DOM method and can only be called by the parser. - ASSERT(!m_docType || !docType); - if (m_docType && docType) - return; m_docType = docType; - if (m_docType) - m_docType->setDocument(this); - determineParseMode(); +} + +DocumentType *Document::doctype() const +{ + return m_docType.get(); } DOMImplementation* Document::implementation() const @@ -488,11 +501,9 @@ DOMImplementation* Document::implementation() const return m_implementation.get(); } -void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +void Document::childrenChanged(bool changedByParser) { - ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); - - // Invalidate the document element we have cached in case it was replaced. + // invalidate the document element we have cached in case it was replaced m_documentElement = 0; } @@ -680,12 +691,7 @@ PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec) ec = NOT_SUPPORTED_ERR; return 0; } - - if (source->isReadOnlyNode()) { - ec = NO_MODIFICATION_ALLOWED_ERR; - return 0; - } - + switch (source->nodeType()) { case ENTITY_NODE: case NOTATION_NODE: @@ -834,19 +840,19 @@ void Document::setXMLStandalone(bool standalone, ExceptionCode& ec) m_xmlStandalone = standalone; } -KURL Document::documentURI() const +String Document::documentURI() const { return m_baseURL; } -void Document::setDocumentURI(const String& uri) +void Document::setDocumentURI(const String &uri) { - m_baseURL = KURL(uri); + m_baseURL = uri.deprecatedString(); } -KURL Document::baseURI() const +String Document::baseURI() const { - return m_baseURL; + return documentURI(); } Element* Document::elementFromPoint(int x, int y) const @@ -1012,7 +1018,7 @@ PassRefPtr<Range> Document::createRange() } PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) + NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec) { if (!root) { ec = NOT_SUPPORTED_ERR; @@ -1022,7 +1028,7 @@ PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatT } PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow, - PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec) + NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec) { if (!root) { ec = NOT_SUPPORTED_ERR; @@ -1051,6 +1057,23 @@ void Document::setDocumentChanged(bool b) m_docChanged = b; } +#ifdef ANDROID_INSTRUMENT +static uint32_t sTotalTimeUsed = 0; +static uint32_t sCounter = 0; + +void Frame::resetCalculateStyleTimeCounter() +{ + sTotalTimeUsed = 0; + sCounter = 0; +} + +void Frame::reportCalculateStyleTimeCounter() +{ + LOG(LOG_DEBUG, "WebCore", "*-* Total calcStyle time: %d ms called %d times\n", + sTotalTimeUsed, sCounter); +} +#endif + void Document::recalcStyle(StyleChange change) { // we should not enter style recalc while painting @@ -1065,6 +1088,10 @@ void Document::recalcStyle(StyleChange change) m_inStyleRecalc = true; suspendPostAttachCallbacks(); +#ifdef ANDROID_INSTRUMENT + uint32_t time = get_thread_msec(); +#endif + ASSERT(!renderer() || renderArena()); if (!renderer() || !renderArena()) goto bail_out; @@ -1117,6 +1144,14 @@ void Document::recalcStyle(StyleChange change) if (change >= Inherit || n->hasChangedChild() || n->changed()) n->recalcStyle(change); +#ifdef ANDROID_INSTRUMENT + time = get_thread_msec() - time; + sTotalTimeUsed += time; + sCounter++; + if (time > 1000) + LOGW("***** Document::recalcStyle() used %d ms\n", time); +#endif + if (changed() && view()) view()->layout(); @@ -1210,14 +1245,6 @@ void Document::attach() // Create the rendering tree setRenderer(new (m_renderArena) RenderView(this, view())); - if (!m_styleSelector) { - bool matchAuthorAndUserStyles = true; - if (Settings* docSettings = settings()) - matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled(); - m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles); - m_styleSelector->setEncodedURL(m_url); - } - recalcStyle(Force); RenderObject* render = renderer(); @@ -1337,10 +1364,10 @@ void Document::open() { // This is work that we should probably do in clear(), but we can't have it // happen when implicitOpen() is called unless we reorganize Frame code. - if (Document* parent = parentDocument()) { - if (m_url.isEmpty() || m_url == blankURL()) + if (Document *parent = parentDocument()) { + if (m_url.isEmpty() || m_url == "about:blank") setURL(parent->baseURL()); - if (m_baseURL.isEmpty() || m_baseURL == blankURL()) + if (m_baseURL.isEmpty() || m_baseURL == "about:blank") setBaseURL(parent->baseURL()); } @@ -1464,6 +1491,11 @@ void Document::implicitClose() delete m_tokenizer; m_tokenizer = 0; +#ifdef ANDROID_PRELOAD_CHANGES + // Parser should have picked up all preloads by now + m_docLoader->clearPreloads(); +#endif + // Create a body element if we don't already have one. See Radar 3758785. if (!this->body() && isHTMLDocument()) { if (Node* documentElement = this->documentElement()) { @@ -1630,21 +1662,21 @@ void Document::clear() m_windowEventListeners.clear(); } -void Document::setURL(const KURL& url) +void Document::setURL(const DeprecatedString& url) { if (url == m_url) return; m_url = url; if (m_styleSelector) - m_styleSelector->setEncodedURL(url); + m_styleSelector->setEncodedURL(m_url); m_isAllowedToLoadLocalResources = shouldBeAllowedToLoadLocalResources(); } bool Document::shouldBeAllowedToLoadLocalResources() const { - if (FrameLoader::shouldTreatURLAsLocal(m_url.string())) + if (FrameLoader::shouldTreatURLAsLocal(m_url)) return true; Frame* frame = this->frame(); @@ -1655,23 +1687,23 @@ bool Document::shouldBeAllowedToLoadLocalResources() const if (!documentLoader) return false; - if (m_url == blankURL() && frame->loader()->opener() && frame->loader()->opener()->document()->isAllowedToLoadLocalResources()) + if (m_url == "about:blank" && frame->loader()->opener() && frame->loader()->opener()->document()->isAllowedToLoadLocalResources()) return true; return documentLoader->substituteData().isValid(); } -void Document::setBaseURL(const KURL& baseURL) +void Document::setBaseURL(const DeprecatedString& baseURL) { - m_baseURL = baseURL; + m_baseURL = baseURL; if (m_elemSheet) - m_elemSheet->setHref(baseURL.string()); + m_elemSheet->setHref(m_baseURL); } -void Document::setCSSStyleSheet(const String &url, const String& charset, const CachedCSSStyleSheet* sheet) +void Document::setCSSStyleSheet(const String &url, const String& charset, const String &sheet) { m_sheet = new CSSStyleSheet(this, url, charset); - m_sheet->parseString(sheet->sheetText()); + m_sheet->parseString(sheet); updateStyleSelector(); } @@ -1701,17 +1733,25 @@ String Document::userStyleSheet() const CSSStyleSheet* Document::elementSheet() { if (!m_elemSheet) - m_elemSheet = new CSSStyleSheet(this, baseURL().string()); + m_elemSheet = new CSSStyleSheet(this, baseURL()); return m_elemSheet.get(); } CSSStyleSheet* Document::mappedElementSheet() { if (!m_mappedElementSheet) - m_mappedElementSheet = new CSSStyleSheet(this, baseURL().string()); + m_mappedElementSheet = new CSSStyleSheet(this, baseURL()); return m_mappedElementSheet.get(); } +void Document::determineParseMode(const String&) +{ + // For XML documents use strict parse mode. + // HTML overrides this method to determine the parse mode. + pMode = Strict; + hMode = XHtml; +} + static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event) { // Search is inclusive of start @@ -1830,6 +1870,64 @@ Node *Document::nodeWithAbsIndex(int absIndex) return n; } +#ifdef ANDROID_META_SUPPORT +// Though isspace() considers \t and \v to be whitespace, Win IE doesn't. +static bool isSeparator(::UChar c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0'; +} + +void Document::processMetadataSettings(const String& content) +{ + ASSERT(!content.isNull()); + + int keyBegin, keyEnd, valueBegin, valueEnd; + int i = 0; + int length = content.length(); + String buffer = content.lower(); + while (i < length) { + // skip to first non-separator, but don't skip past the end of the string + while (isSeparator(buffer[i])) { + if (i >= length) + break; + i++; + } + keyBegin = i; + + // skip to first separator + while (!isSeparator(buffer[i])) + i++; + keyEnd = i; + + // skip to first '=', but don't skip past a ',' or the end of the string + while (buffer[i] != '=') { + if (buffer[i] == ',' || i >= length) + break; + i++; + } + + // skip to first non-separator, but don't skip past a ',' or the end of the string + while (isSeparator(buffer[i])) { + if (buffer[i] == ',' || i >= length) + break; + i++; + } + valueBegin = i; + + // skip to first separator + while (!isSeparator(buffer[i])) + i++; + valueEnd = i; + + ASSERT(i <= length); + + String key(buffer.substring(keyBegin, keyEnd - keyBegin)); + String value(buffer.substring(valueBegin, valueEnd - valueBegin)); + frame()->settings()->setMetadataSettings(key, value); + } +} +#endif + void Document::processHttpEquiv(const String &equiv, const String &content) { ASSERT(!equiv.isNull() && !content.isNull()); @@ -1853,7 +1951,7 @@ void Document::processHttpEquiv(const String &equiv, const String &content) if (url.isEmpty()) url = frame->loader()->url().string(); else - url = completeURL(url).string(); + url = completeURL(url); frame->loader()->scheduleHTTPRedirection(delay, url); } } else if (equalIgnoringCase(equiv, "set-cookie")) { @@ -2145,7 +2243,7 @@ void Document::recalcStyleSelector() // it is loading but we should still decide which style sheet set to use if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) { const AtomicString& rel = e->getAttribute(relAttr); - if (!rel.contains("alternate")) { + if (!rel.domString().contains("alternate")) { m_preferredStylesheetSet = title; m_selectedStylesheetSet = title; } @@ -2186,6 +2284,11 @@ void Document::recalcStyleSelector() if (title != m_preferredStylesheetSet) sheet = 0; + +#if ENABLE(SVG) + if (!n->isHTMLElement()) + title = title.deprecatedString().replace('&', "&&"); +#endif } } @@ -2287,6 +2390,20 @@ bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode) if (m_inPageCache) return false; +#ifdef ANDROID_RESET_SELECTION + WebCore::FrameAndroid* frameAndroid = static_cast<WebCore::FrameAndroid*>(frame()); + WebCore::Node* oldFocus = frameAndroid->getCacheBuilder().currentFocus(); + if (oldFocus) { + if (oldFocus->hasTagName(WebCore::HTMLNames::inputTag)) { + WebCore::HTMLInputElement* input = static_cast<WebCore::HTMLInputElement*>(oldFocus); + if (input->isTextField()) + input->setSelectionRange(-1, -1); + } else if (oldFocus->hasTagName(WebCore::HTMLNames::textareaTag)) { + WebCore::HTMLTextAreaElement* textArea = static_cast<WebCore::HTMLTextAreaElement*>(oldFocus); + textArea->setSelectionRange(-1, -1); + } + } +#endif bool focusChangeBlocked = false; RefPtr<Node> oldFocusedNode = m_focusedNode; m_focusedNode = 0; @@ -2428,7 +2545,7 @@ DOMWindow* Document::defaultView() const return frame()->domWindow(); } -PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec) +PassRefPtr<Event> Document::createEvent(const String &eventType, ExceptionCode& ec) { if (eventType == "UIEvents" || eventType == "UIEvent") return new UIEvent; @@ -2454,10 +2571,6 @@ PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& if (eventType == "SVGZoomEvents") return new SVGZoomEvent; #endif -#if ENABLE(CROSS_DOCUMENT_MESSAGING) - if (eventType == "MessageEvent") - return new MessageEvent; -#endif ec = NOT_SUPPORTED_ERR; return 0; } @@ -2548,7 +2661,7 @@ PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functi void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribute* attr) { setHTMLWindowEventListener(eventType, - createHTMLEventListener(attr->localName().string(), attr->value(), 0)); + createHTMLEventListener(attr->localName().domString(), attr->value(), 0)); } void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image) @@ -2612,7 +2725,7 @@ String Document::cookie() const void Document::setCookie(const String& value) { - setCookies(this, url(), policyBaseURL(), value); + setCookies(this, url(), policyBaseURL().deprecatedString(), value); } String Document::referrer() const @@ -2774,7 +2887,7 @@ HTMLMapElement *Document::getImageMap(const String& url) const return 0; int hashPos = url.find('#'); String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl(); - AtomicString mapName = isHTMLDocument() ? name.lower() : name; + AtomicString mapName = hMode == XHtml ? name : name.lower(); return m_imageMapsByName.get(mapName.impl()); } @@ -2790,18 +2903,27 @@ UChar Document::backslashAsCurrencySymbol() const return m_decoder->encoding().backslashAsCurrencySymbol(); } -KURL Document::completeURL(const String& url) +DeprecatedString Document::completeURL(const DeprecatedString& url) { - // Always return a null URL when passed a null string. - // FIXME: Should we change the KURL constructor to have this behavior? - if (url.isNull()) - return KURL(); - KURL base = m_baseURL; - if (base.isEmpty()) - base = m_url; + // FIXME: This treats null URLs the same as empty URLs, unlike the String function below. + + // If both the URL and base URL are empty, like they are for documents + // created using DOMImplementation::createDocument, just return the passed in URL. + // (We do this because url() returns "about:blank" for empty URLs. + if (m_url.isEmpty() && m_baseURL.isEmpty()) + return url; if (!m_decoder) - return KURL(base, url); - return KURL(base, url, m_decoder->encoding()); + return KURL(baseURL(), url).deprecatedString(); + return KURL(baseURL(), url, m_decoder->encoding()).deprecatedString(); +} + +String Document::completeURL(const String& url) +{ + // FIXME: This always returns null when passed a null URL, unlike the DeprecatedString function above. + // Code relies on this behavior, namely the href property of <a> and the data property of <object>. + if (url.isNull()) + return url; + return completeURL(url.deprecatedString()); } bool Document::inPageCache() @@ -3342,7 +3464,7 @@ void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, Documen void Document::applyXSLTransform(ProcessingInstruction* pi) { - RefPtr<XSLTProcessor> processor = XSLTProcessor::create(); + RefPtr<XSLTProcessor> processor = new XSLTProcessor; processor->setXSLStylesheet(static_cast<XSLStyleSheet*>(pi->sheet())); String resultMIMEType; @@ -3539,8 +3661,8 @@ Vector<String> Document::formElementsState() const HTMLFormControlElementWithState* e = *it; String value; if (e->saveState(value)) { - stateVector.append(e->name().string()); - stateVector.append(e->type().string()); + stateVector.append(e->name().domString()); + stateVector.append(e->type().domString()); stateVector.append(value); } } @@ -3554,14 +3676,14 @@ PassRefPtr<XPathExpression> Document::createExpression(const String& expression, ExceptionCode& ec) { if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); + m_xpathEvaluator = new XPathEvaluator; return m_xpathEvaluator->createExpression(expression, resolver, ec); } PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver) { if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); + m_xpathEvaluator = new XPathEvaluator; return m_xpathEvaluator->createNSResolver(nodeResolver); } @@ -3573,7 +3695,7 @@ PassRefPtr<XPathResult> Document::evaluate(const String& expression, ExceptionCode& ec) { if (!m_xpathEvaluator) - m_xpathEvaluator = XPathEvaluator::create(); + m_xpathEvaluator = new XPathEvaluator; return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec); } @@ -3770,12 +3892,6 @@ void Document::updateFocusAppearanceTimerFired(Timer<Document>*) element->updateFocusAppearance(false); } -// FF method for accessing the selection added for compatability. -DOMSelection* Document::getSelection() const -{ - return frame() ? frame()->domWindow()->getSelection() : 0; -} - #if ENABLE(DATABASE) void Document::addOpenDatabase(Database* database) diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h index 14277ea..a4c935b 100644 --- a/WebCore/dom/Document.h +++ b/WebCore/dom/Document.h @@ -3,7 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * (C) 2006 Alexey Proskuryakov (ap@webkit.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -32,7 +32,6 @@ #include "DocumentMarker.h" #include "HTMLCollection.h" #include "HTMLFormElement.h" -#include "KURL.h" #include "StringHash.h" #include "Timer.h" #include <wtf/HashCountedSet.h> @@ -53,14 +52,12 @@ namespace WebCore { class Attr; class Attribute; class CDATASection; - class CachedCSSStyleSheet; class CSSStyleDeclaration; class CSSStyleSelector; class CSSStyleSheet; class Comment; class Database; class DOMImplementation; - class DOMSelection; class DOMWindow; class DatabaseThread; class DocLoader; @@ -180,10 +177,11 @@ public: // DOM methods & attributes for Document - DocumentType* doctype() const { return m_docType.get(); } + virtual DocumentType* doctype() const; // May return 0 for HTML documents + DocumentType* realDocType() const { return m_docType.get(); } DOMImplementation* implementation() const; - virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual void childrenChanged(bool changedByParser = false); Element* documentElement() const; virtual PassRefPtr<Element> createElement(const String& tagName, ExceptionCode&); PassRefPtr<DocumentFragment> createDocumentFragment (); @@ -220,10 +218,10 @@ public: void setXMLVersion(const String&, ExceptionCode&); void setXMLStandalone(bool, ExceptionCode&); - KURL documentURI() const; + String documentURI() const; void setDocumentURI(const String&); - virtual KURL baseURI() const; + virtual String baseURI() const; PassRefPtr<Node> adoptNode(PassRefPtr<Node> source, ExceptionCode&); @@ -333,10 +331,10 @@ public: PassRefPtr<Range> createRange(); PassRefPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&); + NodeFilter*, bool expandEntityReferences, ExceptionCode&); PassRefPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow, - PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&); + NodeFilter*, bool expandEntityReferences, ExceptionCode&); // Special support for editing PassRefPtr<CSSStyleDeclaration> createCSSStyleDeclaration(); @@ -373,19 +371,20 @@ public: bool wellFormed() const { return m_wellFormed; } - const KURL& url() const { return m_url.isEmpty() ? blankURL() : m_url; } - void setURL(const KURL&); + DeprecatedString url() const { return m_url.isEmpty() ? "about:blank" : m_url; } + void setURL(const DeprecatedString& url); - const KURL& baseURL() const { return m_baseURL.isEmpty() ? url() : m_baseURL; } - void setBaseURL(const KURL&); + DeprecatedString baseURL() const { return m_baseURL.isEmpty() ? url() : m_baseURL; } + void setBaseURL(const DeprecatedString& baseURL); - const String& baseTarget() const { return m_baseTarget; } + String baseTarget() const { return m_baseTarget; } void setBaseTarget(const String& baseTarget) { m_baseTarget = baseTarget; } - KURL completeURL(const String&); + DeprecatedString completeURL(const DeprecatedString &); + String completeURL(const String&); // from cachedObjectClient - virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*); + virtual void setCSSStyleSheet(const String& url, const String& charset, const String& sheetStr); #if FRAME_LOADS_USER_STYLESHEET void setUserStyleSheet(const String& sheet); @@ -402,18 +401,20 @@ public: void setPrinting(bool p) { m_printing = p; } enum ParseMode { Compat, AlmostStrict, Strict }; - -private: - virtual void determineParseMode() {} -public: - void setParseMode(ParseMode m) { m_parseMode = m; } - ParseMode parseMode() const { return m_parseMode; } + virtual void determineParseMode(const String&); + void setParseMode(ParseMode m) { pMode = m; } + ParseMode parseMode() const { return pMode; } - bool inCompatMode() const { return m_parseMode == Compat; } - bool inAlmostStrictMode() const { return m_parseMode == AlmostStrict; } - bool inStrictMode() const { return m_parseMode == Strict; } + bool inCompatMode() const { return pMode == Compat; } + bool inAlmostStrictMode() const { return pMode == AlmostStrict; } + bool inStrictMode() const { return pMode == Strict; } + enum HTMLMode { Html3, Html4, XHtml }; + + void setHTMLMode(HTMLMode m) { hMode = m; } + HTMLMode htmlMode() const { return hMode; } + void setParsing(bool); bool parsing() const { return m_bParsing; } int minimumLayoutDelay(); @@ -547,6 +548,14 @@ public: */ void processHttpEquiv(const String& equiv, const String& content); +#ifdef ANDROID_META_SUPPORT + /** + * Handles viewport like <meta name = "viewport" content = "width = device-width"> + * or format-detection like <meta name = "format-detection" content = "telephone=no"> + */ + void processMetadataSettings(const String& content); +#endif + void dispatchImageLoadEventSoon(HTMLImageLoader*); void dispatchImageLoadEventsNow(); void removeImage(HTMLImageLoader*); @@ -569,8 +578,8 @@ public: String lastModified() const; - const KURL& policyBaseURL() const { return m_policyBaseURL; } - void setPolicyBaseURL(const KURL& url) { m_policyBaseURL = url; } + String policyBaseURL() const { return m_policyBaseURL; } + void setPolicyBaseURL(const String& s) { m_policyBaseURL = s; } // The following implements the rule from HTML 4 for what valid names are. // To get this right for all the XML cases, we probably have to improve this or move it @@ -691,9 +700,11 @@ public: void updateFocusAppearanceSoon(); void cancelFocusAppearanceUpdate(); - // FF method for accessing the selection added for compatability. - DOMSelection* getSelection() const; - +#ifdef ANDROID_MOBILE + void setExtraLayoutDelay(int delay) { mExtraLayoutDelay = delay; } + int extraLayoutDelay() { return mExtraLayoutDelay; } +#endif + private: CSSStyleSelector* m_styleSelector; bool m_didCalculateStyleSelector; @@ -702,8 +713,8 @@ private: DocLoader* m_docLoader; Tokenizer* m_tokenizer; bool m_wellFormed; - KURL m_url; - KURL m_baseURL; + DeprecatedString m_url; + DeprecatedString m_baseURL; String m_baseTarget; RefPtr<DocumentType> m_docType; @@ -736,7 +747,8 @@ private: bool m_printing; - ParseMode m_parseMode; + ParseMode pMode; + HTMLMode hMode; Color m_textColor; @@ -752,6 +764,7 @@ private: unsigned short m_listenerTypes; RefPtr<StyleSheetList> m_styleSheets; + typedef DeprecatedValueList<RefPtr<RegisteredEventListener> > RegisteredEventListenerList; RegisteredEventListenerList m_windowEventListeners; typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap; @@ -813,7 +826,7 @@ private: typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName; ImageMapsByName m_imageMapsByName; - KURL m_policyBaseURL; + String m_policyBaseURL; HashSet<Node*> m_disconnectedNodesWithEventListeners; @@ -953,6 +966,10 @@ private: #if USE(LOW_BANDWIDTH_DISPLAY) bool m_inLowBandwidthDisplay; #endif +#ifdef ANDROID_MOBILE + int mExtraLayoutDelay; +#endif + }; } // namespace WebCore diff --git a/WebCore/dom/Document.idl b/WebCore/dom/Document.idl index ddc25f3..e77da2e 100644 --- a/WebCore/dom/Document.idl +++ b/WebCore/dom/Document.idl @@ -193,9 +193,7 @@ module core { Element elementFromPoint(in long x, in long y); // Mozilla extensions -#if defined(LANGUAGE_JAVASCRIPT) - DOMSelection getSelection(); -#endif + readonly attribute [ConvertNullStringTo=Null] DOMString characterSet; // WebKit extensions diff --git a/WebCore/dom/DocumentType.cpp b/WebCore/dom/DocumentType.cpp index f051363..2c4f060 100644 --- a/WebCore/dom/DocumentType.cpp +++ b/WebCore/dom/DocumentType.cpp @@ -1,8 +1,10 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,30 +31,19 @@ namespace WebCore { -DocumentType::DocumentType(DOMImplementation* i, Document* document, const String& n, const String& p, const String& s) - : Node(document) - , m_implementation(i) - , m_name(n) - , m_publicId(p) - , m_systemId(s) +DocumentType::DocumentType(DOMImplementation *i, Document *doc, const String &n, const String &p, const String &s) + : Node(doc), m_implementation(i), m_name(n), m_publicId(p), m_systemId(s) { } -DocumentType::DocumentType(Document* document, const String& n, const String& p, const String& s) - : Node(document) - , m_name(n) - , m_publicId(p) - , m_systemId(s) +DocumentType::DocumentType(Document *doc, const String &n, const String &p, const String &s) + : Node(doc), m_name(n), m_publicId(p), m_systemId(s) { } -DocumentType::DocumentType(Document* document, const DocumentType &t) - : Node(document) - , m_implementation(t.m_implementation) - , m_name(t.m_name) - , m_publicId(t.m_publicId) - , m_systemId(t.m_systemId) - , m_subset(t.m_subset) +DocumentType::DocumentType(Document *doc, const DocumentType &t) + : Node(doc), m_implementation(t.m_implementation) + , m_name(t.m_name), m_publicId(t.m_publicId), m_systemId(t.m_systemId), m_subset(t.m_subset) { } @@ -66,12 +57,9 @@ String DocumentType::toString() const if (!m_publicId.isEmpty()) { result += " PUBLIC \""; result += m_publicId; + result += "\" \""; + result += m_systemId; result += "\""; - if (!m_systemId.isEmpty()) { - result += " \""; - result += m_systemId; - result += "\""; - } } else if (!m_systemId.isEmpty()) { result += " SYSTEM \""; result += m_systemId; @@ -86,9 +74,9 @@ String DocumentType::toString() const return result; } -KURL DocumentType::baseURI() const +String DocumentType::baseURI() const { - return KURL(); + return String(); } String DocumentType::nodeName() const @@ -103,26 +91,8 @@ Node::NodeType DocumentType::nodeType() const PassRefPtr<Node> DocumentType::cloneNode(bool /*deep*/) { - return new DocumentType(document(), m_name, m_publicId, m_systemId); -} - -void DocumentType::insertedIntoDocument() -{ - // Our document node can be null if we were created by a DOMImplementation. We use the parent() instead. - ASSERT(parent() && parent()->isDocumentNode()); - if (parent() && parent()->isDocumentNode()) { - Document* doc = static_cast<Document*>(parent()); - if (!doc->doctype()) - doc->setDocType(this); - } - Node::insertedIntoDocument(); -} - -void DocumentType::removedFromDocument() -{ - if (document() && document()->doctype() == this) - document()->setDocType(0); - Node::removedFromDocument(); + // The DOM Level 2 specification says cloning DocumentType nodes is "implementation dependent" so for now we do not support it. + return 0; } } diff --git a/WebCore/dom/DocumentType.h b/WebCore/dom/DocumentType.h index c348c4c..63cfc25 100644 --- a/WebCore/dom/DocumentType.h +++ b/WebCore/dom/DocumentType.h @@ -48,7 +48,7 @@ public: String systemId() const { return m_systemId; } String internalSubset() const { return m_subset; } - virtual KURL baseURI() const; + virtual String baseURI() const; // Other methods (not part of DOM) DOMImplementation *implementation() const { return m_implementation.get(); } @@ -58,9 +58,6 @@ public: virtual PassRefPtr<Node> cloneNode(bool deep); virtual String toString() const; - virtual void insertedIntoDocument(); - virtual void removedFromDocument(); - private: RefPtr<DOMImplementation> m_implementation; RefPtr<NamedNodeMap> m_entities; diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp index 8af84e2..808696a 100644 --- a/WebCore/dom/Element.cpp +++ b/WebCore/dom/Element.cpp @@ -4,7 +4,7 @@ * (C) 2001 Peter Kelly (pmk@post.com) * (C) 2001 Dirk Mueller (mueller@kde.org) * (C) 2007 David Smith (catfish.man@gmail.com) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * (C) 2007 Eric Seidel (eric@webkit.org) * * This library is free software; you can redistribute it and/or @@ -27,7 +27,6 @@ #include "Element.h" #include "CSSStyleSelector.h" -#include "CString.h" #include "ClassNames.h" #include "ClassNodeList.h" #include "Document.h" @@ -38,13 +37,14 @@ #include "FrameView.h" #include "HTMLElement.h" #include "HTMLNames.h" +#include "KURL.h" #include "NamedAttrMap.h" #include "NodeList.h" #include "Page.h" -#include "PlatformString.h" #include "RenderBlock.h" #include "SelectionController.h" #include "TextIterator.h" +#include "TextStream.h" #include "XMLNames.h" namespace WebCore { @@ -562,21 +562,18 @@ void Element::setPrefix(const AtomicString &_prefix, ExceptionCode& ec) m_tagName.setPrefix(_prefix); } -KURL Element::baseURI() const +String Element::baseURI() const { - KURL base(getAttribute(baseAttr)); - if (!base.protocol().isEmpty()) - return base; + KURL xmlbase(getAttribute(baseAttr).deprecatedString()); - Node* parent = parentNode(); - if (!parent) - return base; + if (!xmlbase.protocol().isEmpty()) + return xmlbase.string(); - KURL parentBase = parent->baseURI(); - if (parentBase.isNull()) - return base; + Node* parent = parentNode(); + if (parent) + return KURL(parent->baseURI().deprecatedString(), xmlbase.deprecatedString()).string(); - return KURL(parentBase, base.string()); + return xmlbase.string(); } Node* Element::insertAdjacentElement(const String& where, Node* newChild, int& exception) @@ -706,7 +703,8 @@ void Element::recalcStyle(StyleChange change) { RenderStyle* currentStyle = renderStyle(); bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false; - bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules(); + bool hasPositionalChildren = currentStyle && (currentStyle->childrenAffectedByFirstChildRules() || currentStyle->childrenAffectedByLastChildRules() || + currentStyle->childrenAffectedByForwardPositionalRules() || currentStyle->childrenAffectedByBackwardPositionalRules()); #if ENABLE(SVG) if (!hasParentStyle && isShadowNode() && isSVGElement()) @@ -732,7 +730,7 @@ void Element::recalcStyle(StyleChange change) return; } - if (currentStyle) { + if (currentStyle && newStyle) { // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full // style change (e.g., only inline style changed). if (currentStyle->affectedByHoverRules()) @@ -749,13 +747,12 @@ void Element::recalcStyle(StyleChange change) newStyle->setChildrenAffectedByFirstChildRules(); if (currentStyle->childrenAffectedByLastChildRules()) newStyle->setChildrenAffectedByLastChildRules(); - if (currentStyle->childrenAffectedByDirectAdjacentRules()) - newStyle->setChildrenAffectedByDirectAdjacentRules(); } - if (ch != NoChange) - setRenderStyle(newStyle); - else if (changed() && (document()->usesSiblingRules() || document()->usesDescendantRules())) { + if (ch != NoChange) { + if (newStyle) + setRenderStyle(newStyle); + } else if (changed() && newStyle && (document()->usesSiblingRules() || document()->usesDescendantRules())) { // Although no change occurred, we use the new style so that the cousin style sharing code won't get // fooled into believing this style is the same. This is only necessary if the document actually uses // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of @@ -769,7 +766,7 @@ void Element::recalcStyle(StyleChange change) newStyle->deref(document()->renderArena()); if (change != Force) { - if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() == FullStyleChange) + if ((document()->usesDescendantRules() || hasPositionalChildren) && styleChangeType() == FullStyleChange) change = Force; else change = ch; @@ -801,98 +798,81 @@ bool Element::childTypeAllowed(NodeType type) } } -static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback, - Node* beforeChange, Node* afterChange, int childCountDelta) -{ - if (!style || (e->changed() && style->childrenAffectedByPositionalRules())) - return; - - // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time. - // In the DOM case, we only need to do something if |afterChange| is not 0. - // |afterChange| is 0 in the parser case, so it works out that we'll skip this block. - if (style->childrenAffectedByFirstChildRules() && afterChange) { - // Find our new first child. - Node* newFirstChild = 0; - for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {}; - - // Find the first element node following |afterChange| - Node* firstElementAfterInsertion = 0; - for (firstElementAfterInsertion = afterChange; - firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); - firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; - - // This is the insert/append case. - if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() && - firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState()) - firstElementAfterInsertion->setChanged(); - - // We also have to handle node removal. - if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState()) - newFirstChild->setChanged(); +static void checkFirstChildRules(Element* e, RenderStyle* style) +{ + if (style->childrenAffectedByFirstChildRules()) { + // Check our first two children. They need to be true and false respectively. + bool checkingFirstChild = true; + for (Node* n = e->firstChild(); n; n = n->nextSibling()) { + if (n->isElementNode()) { + if (checkingFirstChild) { + if (n->attached() && n->renderStyle() && !n->renderStyle()->firstChildState()) + n->setChanged(); + checkingFirstChild = false; + } else { + if (n->attached() && n->renderStyle() && n->renderStyle()->firstChildState()) + n->setChanged(); + break; + } + } + } + } +} + +static void checkLastChildRules(Element* e, RenderStyle* style) +{ + if (style->childrenAffectedByLastChildRules()) { + // Check our last two children. They need to be true and false respectively. + bool checkingLastChild = true; + for (Node* n = e->lastChild(); n; n = n->previousSibling()) { + if (n->isElementNode()) { + if (checkingLastChild) { + if (n->attached() && n->renderStyle() && !n->renderStyle()->lastChildState()) + n->setChanged(); + checkingLastChild = false; + } else { + if (n->attached() && n->renderStyle() && n->renderStyle()->lastChildState()) + n->setChanged(); + break; + } + } + } } +} - // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time. - // In the DOM case, we only need to do something if |afterChange| is not 0. - if (style->childrenAffectedByLastChildRules() && beforeChange) { - // Find our new last child. - Node* newLastChild = 0; - for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {}; - - // Find the last element node going backwards from |beforeChange| - Node* lastElementBeforeInsertion = 0; - for (lastElementBeforeInsertion = beforeChange; - lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode(); - lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {}; - - if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() && - lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState()) - lastElementBeforeInsertion->setChanged(); - - // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child - // to match now. - if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState()) - newLastChild->setChanged(); - } +static bool checkEmptyRules(Element* e, RenderStyle* style) +{ + return style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()); +} - // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element - // that could be affected by this DOM change. - if (style->childrenAffectedByDirectAdjacentRules() && afterChange) { - Node* firstElementAfterInsertion = 0; - for (firstElementAfterInsertion = afterChange; - firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode(); - firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {}; - if (firstElementAfterInsertion && firstElementAfterInsertion->attached()) - firstElementAfterInsertion->setChanged(); - } +static void checkStyleRules(Element* e, RenderStyle* style, bool changedByParser) +{ + if (e->changed() || !style) + return; - // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type. - // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type. - // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the - // backward case. - // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to. - // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids - // here. recalcStyle will then force a walk of the children when it sees that this has happened. - if ((style->childrenAffectedByForwardPositionalRules() && afterChange) || - (style->childrenAffectedByBackwardPositionalRules() && beforeChange)) - e->setChanged(); - - // :empty selector. - if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes())) + if (style->childrenAffectedByBackwardPositionalRules() || + (!changedByParser && style->childrenAffectedByForwardPositionalRules()) || + checkEmptyRules(e, style)) { e->setChanged(); + return; + } + + checkFirstChildRules(e, style); + checkLastChildRules(e, style); } -void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +void Element::childrenChanged(bool changedByParser) { - ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); + ContainerNode::childrenChanged(changedByParser); if (!changedByParser) - checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta); + checkStyleRules(this, renderStyle(), false); } void Element::finishParsingChildren() { ContainerNode::finishParsingChildren(); m_parsingChildrenFinished = true; - checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0); + checkStyleRules(this, renderStyle(), true); } void Element::dispatchAttrRemovalEvent(Attribute*) @@ -981,7 +961,23 @@ void Element::updateId(const AtomicString& oldId, const AtomicString& newId) } #ifndef NDEBUG -void Element::formatForDebugger(char* buffer, unsigned length) const +void Element::dump(TextStream *stream, DeprecatedString ind) const +{ + updateStyleAttributeIfNeeded(); + if (namedAttrMap) { + for (unsigned i = 0; i < namedAttrMap->length(); i++) { + Attribute *attr = namedAttrMap->attributeItem(i); + *stream << " " << attr->name().localName().deprecatedString().ascii() + << "=\"" << attr->value().deprecatedString().ascii() << "\""; + } + } + + ContainerNode::dump(stream,ind); +} +#endif + +#ifndef NDEBUG +void Element::formatForDebugger(char *buffer, unsigned length) const { String result; String s; @@ -1007,7 +1003,7 @@ void Element::formatForDebugger(char* buffer, unsigned length) const result += s; } - strncpy(buffer, result.utf8().data(), length - 1); + strncpy(buffer, result.deprecatedString().latin1(), length - 1); } #endif @@ -1143,13 +1139,27 @@ void Element::updateFocusAppearance(bool restorePreviousSelection) frame->selectionController()->setSelection(newSelection); frame->revealSelection(); } +#ifdef ANDROID_SCROLL_FIX + // We handle the scrolling the screen with our navigation code, + // so ignore this call to put the rectangle on screen. + } +#else } else if (renderer() && !renderer()->isWidget()) renderer()->enclosingLayer()->scrollRectToVisible(getRect()); +#endif } void Element::blur() { cancelFocusAppearanceUpdate(); +#ifdef ANDROID_IGNORE_BLUR + // Since we control the focus anyway, there is no need to do blur events + // unless the element has a blur event. + NamedAttrMap* map = attributes(); + Node* blur = (map->getNamedItem(HTMLNames::onblurAttr)).get(); + if (!blur) + return; +#endif Document* doc = document(); if (doc->focusedNode() == this) { if (doc->frame()) diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h index 33727cd..e85cd1b 100644 --- a/WebCore/dom/Element.h +++ b/WebCore/dom/Element.h @@ -109,7 +109,7 @@ public: virtual void setPrefix(const AtomicString &_prefix, ExceptionCode&); virtual const AtomicString& namespaceURI() const { return m_tagName.namespaceURI(); } - virtual KURL baseURI() const; + virtual String baseURI() const; // DOM methods overridden from parent classes virtual NodeType nodeType() const; @@ -118,7 +118,7 @@ public: virtual bool isElementNode() const { return true; } virtual void insertedIntoDocument(); virtual void removedFromDocument(); - virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0); + virtual void childrenChanged(bool changedByParser = false); virtual bool isInputTypeHidden() const { return false; } @@ -161,12 +161,20 @@ public: virtual bool isURLAttribute(Attribute*) const; virtual const QualifiedName& imageSourceAttributeName() const; virtual String target() const { return String(); } - +#ifdef ANDROID_DO_NOT_RESTORE_PREVIOUS_SELECTION + // Set the default to not restore the previous selection, since + // we want the selection to cover the whole textfield. + // FIXME: Would it be a better fix to simply ignore the input + // value in the implementation? + virtual void focus(bool restorePreviousSelection = false); +#else virtual void focus(bool restorePreviousSelection = true); +#endif virtual void updateFocusAppearance(bool restorePreviousSelection); void blur(); #ifndef NDEBUG + virtual void dump(TextStream* , DeprecatedString ind = "") const; virtual void formatForDebugger(char* buffer, unsigned length) const; #endif diff --git a/WebCore/dom/Event.cpp b/WebCore/dom/Event.cpp index 543dfff..2f3313d 100644 --- a/WebCore/dom/Event.cpp +++ b/WebCore/dom/Event.cpp @@ -30,8 +30,7 @@ namespace WebCore { Event::Event() - : RefCounted<Event>(0) - , m_canBubble(false) + : m_canBubble(false) , m_cancelable(false) , m_propagationStopped(false) , m_defaultPrevented(false) @@ -44,8 +43,7 @@ Event::Event() } Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg) - : RefCounted<Event>(0) - , m_type(eventType) + : m_type(eventType) , m_canBubble(canBubbleArg) , m_cancelable(cancelableArg) , m_propagationStopped(false) diff --git a/WebCore/dom/EventListener.h b/WebCore/dom/EventListener.h index 0938041..1bc4283 100644 --- a/WebCore/dom/EventListener.h +++ b/WebCore/dom/EventListener.h @@ -29,7 +29,6 @@ namespace WebCore { class EventListener : public RefCounted<EventListener> { public: - EventListener() : RefCounted<EventListener>(0) { } virtual ~EventListener() { } virtual void handleEvent(Event*, bool isWindowEvent = false) = 0; virtual bool isHTMLEventListener() const { return false; } diff --git a/WebCore/dom/EventTargetNode.cpp b/WebCore/dom/EventTargetNode.cpp index 146ee8b..bae16f4 100644 --- a/WebCore/dom/EventTargetNode.cpp +++ b/WebCore/dom/EventTargetNode.cpp @@ -42,6 +42,7 @@ #include "ProgressEvent.h" #include "RegisteredEventListener.h" #include "TextEvent.h" +#include "TextStream.h" #include "WheelEvent.h" namespace WebCore { @@ -114,13 +115,18 @@ bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool return dispatchGenericEvent(eventTarget, evt.release(), ec, tempEvent); } -bool EventTargetNode::dispatchSubtreeModifiedEvent() +bool EventTargetNode::dispatchSubtreeModifiedEvent(bool sendChildrenChanged) { ASSERT(!eventDispatchForbidden()); document()->incDOMTreeVersion(); - notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing. + // FIXME: Pull this whole if clause out of this function. + if (sendChildrenChanged) { + notifyNodeListsChildrenChanged(); + childrenChanged(); + } else + notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing. if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER)) return false; @@ -387,6 +393,20 @@ EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventTy return 0; } +#ifdef ANDROID +EventListener *EventTargetNode::getEventListener(const AtomicString &eventType) +{ + if (!m_regdListeners) + return 0; + + RegisteredEventListenerList::Iterator end = m_regdListeners->end(); + for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it) + if ((*it)->eventType() == eventType) + return (*it)->listener(); + return 0; +} +#endif + bool EventTargetNode::disabled() const { return false; @@ -415,4 +435,16 @@ void EventTargetNode::defaultEventHandler(Event* event) } } +#ifndef NDEBUG + +void EventTargetNode::dump(TextStream* stream, DeprecatedString ind) const +{ + if (m_regdListeners) + *stream << " #regdListeners=" << m_regdListeners->count(); // ### more detail + + Node::dump(stream,ind); +} + +#endif + } // namespace WebCore diff --git a/WebCore/dom/EventTargetNode.h b/WebCore/dom/EventTargetNode.h index 9a0647b..b499b7e 100644 --- a/WebCore/dom/EventTargetNode.h +++ b/WebCore/dom/EventTargetNode.h @@ -48,8 +48,11 @@ public: void removeHTMLEventListener(const AtomicString& eventType); bool dispatchHTMLEvent(const AtomicString& eventType, bool canBubble, bool cancelable); EventListener* getHTMLEventListener(const AtomicString& eventType); +#ifdef ANDROID + EventListener* getEventListener(const AtomicString& eventType); +#endif - bool dispatchSubtreeModifiedEvent(); + bool dispatchSubtreeModifiedEvent(bool childrenChanged = true); void dispatchWindowEvent(const AtomicString& eventType, bool canBubble, bool cancelable); bool dispatchUIEvent(const AtomicString& eventType, int detail = 0, PassRefPtr<Event> underlyingEvent = 0); bool dispatchKeyEvent(const PlatformKeyboardEvent&); @@ -82,6 +85,10 @@ public: * to event listeners, and prevents DOMActivate events from being sent at all. */ virtual bool disabled() const; + +#ifndef NDEBUG + virtual void dump(TextStream*, DeprecatedString indent = "") const; +#endif RegisteredEventListenerList* localEventListeners() const { return m_regdListeners; } diff --git a/WebCore/dom/ExceptionBase.cpp b/WebCore/dom/ExceptionBase.cpp index d2526bd..92a14f5 100644 --- a/WebCore/dom/ExceptionBase.cpp +++ b/WebCore/dom/ExceptionBase.cpp @@ -32,7 +32,6 @@ namespace WebCore { ExceptionBase::ExceptionBase(const ExceptionCodeDescription& description) - : RefCounted<ExceptionBase>(0) { m_code = description.code; if (description.name) { diff --git a/WebCore/dom/NamedAttrMap.cpp b/WebCore/dom/NamedAttrMap.cpp index ee89bcc..d1a39a7 100644 --- a/WebCore/dom/NamedAttrMap.cpp +++ b/WebCore/dom/NamedAttrMap.cpp @@ -99,7 +99,11 @@ PassRefPtr<Node> NamedAttrMap::getNamedItem(const QualifiedName& name) const PassRefPtr<Node> NamedAttrMap::setNamedItem(Node* arg, ExceptionCode& ec) { +#ifdef ANDROID_FIX + if (!element || !arg) { +#else if (!element) { +#endif ec = NOT_FOUND_ERR; return 0; } @@ -282,7 +286,7 @@ void NamedAttrMap::addAttribute(PassRefPtr<Attribute> prpAttribute) // Because of our updateStyleAttributeIfNeeded() style modification events are never sent at the right time, so don't bother sending them. if (attribute->name() != styleAttr) { element->dispatchAttrAdditionEvent(attribute); - element->dispatchSubtreeModifiedEvent(); + element->dispatchSubtreeModifiedEvent(false); } } } @@ -328,7 +332,7 @@ void NamedAttrMap::removeAttribute(const QualifiedName& name) } if (element) { element->dispatchAttrRemovalEvent(attr); - element->dispatchSubtreeModifiedEvent(); + element->dispatchSubtreeModifiedEvent(false); } attr->deref(); } diff --git a/WebCore/dom/NamedAttrMap.h b/WebCore/dom/NamedAttrMap.h index dd57284..21e8ce8 100644 --- a/WebCore/dom/NamedAttrMap.h +++ b/WebCore/dom/NamedAttrMap.h @@ -68,8 +68,7 @@ public: // used during parsing: only inserts if not already there // no error checking! - void insertAttribute(PassRefPtr<Attribute> newAttribute, bool allowDuplicates) - { + void insertAttribute(PassRefPtr<Attribute> newAttribute, bool allowDuplicates) { ASSERT(!element); if (allowDuplicates || !getAttributeItem(newAttribute->name())) addAttribute(newAttribute); @@ -84,7 +83,7 @@ public: protected: // this method is internal, does no error checking at all - void addAttribute(PassRefPtr<Attribute>); + void addAttribute(PassRefPtr<Attribute> newAttribute); // this method is internal, does no error checking at all void removeAttribute(const QualifiedName& name); virtual void clearAttributes(); diff --git a/WebCore/dom/NamedNodeMap.h b/WebCore/dom/NamedNodeMap.h index cc70bea..b8d5fff 100644 --- a/WebCore/dom/NamedNodeMap.h +++ b/WebCore/dom/NamedNodeMap.h @@ -41,7 +41,7 @@ typedef int ExceptionCode; // Other classes implement this for more specific situations e.g. attributes of an element. class NamedNodeMap : public RefCounted<NamedNodeMap> { public: - NamedNodeMap() : RefCounted<NamedNodeMap>(0) { } + NamedNodeMap() { } virtual ~NamedNodeMap() { } virtual PassRefPtr<Node> getNamedItem(const String& name) const = 0; diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp index 8a52e0e..52e43e4 100644 --- a/WebCore/dom/Node.cpp +++ b/WebCore/dom/Node.cpp @@ -2,7 +2,7 @@ * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2007 Trolltech ASA * * This library is free software; you can redistribute it and/or @@ -42,6 +42,7 @@ #include "Frame.h" #include "HTMLNames.h" #include "HTMLNames.h" +#include "KURL.h" #include "Logging.h" #include "NameNodeList.h" #include "NamedAttrMap.h" @@ -49,6 +50,7 @@ #include "SelectorNodeList.h" #include "TagNodeList.h" #include "Text.h" +#include "TextStream.h" #include "XMLNames.h" #include "htmlediting.h" #include "kjs_binding.h" @@ -150,7 +152,7 @@ void Node::setDocument(Document* doc) { KJS::JSLock lock; - ScriptInterpreter::updateDOMNodeDocument(this, m_document.get(), doc); + KJS::ScriptInterpreter::updateDOMNodeDocument(this, m_document.get(), doc); } m_document = doc; @@ -484,17 +486,23 @@ Node *Node::childNode(unsigned /*index*/) const Node *Node::traverseNextNode(const Node *stayWithin) const { - if (firstChild()) + if (firstChild()) { + ASSERT(!stayWithin || firstChild()->isDescendantOf(stayWithin)); return firstChild(); + } if (this == stayWithin) return 0; - if (nextSibling()) + if (nextSibling()) { + ASSERT(!stayWithin || nextSibling()->isDescendantOf(stayWithin)); return nextSibling(); + } const Node *n = this; while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); - if (n) + if (n) { + ASSERT(!stayWithin || !n->nextSibling() || n->nextSibling()->isDescendantOf(stayWithin)); return n->nextSibling(); + } return 0; } @@ -502,13 +510,17 @@ Node *Node::traverseNextSibling(const Node *stayWithin) const { if (this == stayWithin) return 0; - if (nextSibling()) + if (nextSibling()) { + ASSERT(!stayWithin || nextSibling()->isDescendantOf(stayWithin)); return nextSibling(); + } const Node *n = this; while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); - if (n) + if (n) { + ASSERT(!stayWithin || !n->nextSibling() || n->nextSibling()->isDescendantOf(stayWithin)); return n->nextSibling(); + } return 0; } @@ -527,31 +539,23 @@ Node *Node::traversePreviousNode(const Node *stayWithin) const Node *Node::traversePreviousNodePostOrder(const Node *stayWithin) const { - if (lastChild()) + if (lastChild()) { + ASSERT(!stayWithin || lastChild()->isDescendantOf(stayWithin)); return lastChild(); + } if (this == stayWithin) return 0; - if (previousSibling()) - return previousSibling(); - const Node *n = this; - while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin)) - n = n->parentNode(); - if (n) - return n->previousSibling(); - return 0; -} - -Node* Node::traversePreviousSiblingPostOrder(const Node* stayWithin) const -{ - if (this == stayWithin) - return 0; - if (previousSibling()) + if (previousSibling()) { + ASSERT(!stayWithin || previousSibling()->isDescendantOf(stayWithin)); return previousSibling(); + } const Node *n = this; while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); - if (n) + if (n) { + ASSERT(!stayWithin || !n->previousSibling() || n->previousSibling()->isDescendantOf(stayWithin)); return n->previousSibling(); + } return 0; } @@ -735,7 +739,7 @@ bool Node::isDescendantOf(const Node *other) const return false; } -bool Node::childAllowed(Node* newChild) +bool Node::childAllowed( Node *newChild ) { return childTypeAllowed(newChild->nodeType()); } @@ -784,6 +788,24 @@ Node::StyleChange Node::diff( RenderStyle *s1, RenderStyle *s2 ) const return ch; } +#ifndef NDEBUG +void Node::dump(TextStream* stream, DeprecatedString ind) const +{ + if (m_hasId) { *stream << " hasId"; } + if (m_hasClass) { *stream << " hasClass"; } + if (m_focused) { *stream << " focused"; } + if (m_active) { *stream << " active"; } + + *stream << " tabIndex=" << m_tabIndex; + *stream << endl; + + for (Node* child = firstChild(); child; child = child->nextSibling()) { + *stream << ind << child->nodeName() << ": "; + child->dump(stream, ind + " "); + } +} +#endif + void Node::attach() { ASSERT(!attached()); @@ -1262,14 +1284,18 @@ bool Node::hasAttributes() const return false; } -NamedAttrMap* Node::attributes() const +NamedAttrMap *Node::attributes() const { return 0; } -KURL Node::baseURI() const +String Node::baseURI() const { - return parentNode() ? parentNode()->baseURI() : KURL(); + Node* parent = parentNode(); + if (parent) + return parent->baseURI(); + + return String(); } bool Node::isEqualNode(Node *other) const @@ -1522,7 +1548,7 @@ String Node::textContent(bool convertBRsToNewlines) const case DOCUMENT_TYPE_NODE: case NOTATION_NODE: default: - return String(); + return String(); } } diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h index 3abdfc0..e63ec4b 100644 --- a/WebCore/dom/Node.h +++ b/WebCore/dom/Node.h @@ -24,6 +24,7 @@ #ifndef Node_h #define Node_h +#include "DeprecatedString.h" #include "DocPtr.h" #include "PlatformString.h" #include "TreeShared.h" @@ -43,7 +44,6 @@ class Event; class EventListener; class IntRect; class KeyboardEvent; -class KURL; class NamedAttrMap; class NodeList; class PlatformKeyboardEvent; @@ -54,7 +54,7 @@ class RegisteredEventListener; class RenderArena; class RenderObject; class RenderStyle; - +class TextStream; struct NodeListsNodeData; typedef int ExceptionCode; @@ -106,7 +106,7 @@ public: virtual bool hasAttributes() const; virtual NamedAttrMap* attributes() const; - virtual KURL baseURI() const; + virtual String baseURI() const; // These should all actually return a node, but this is only important for language bindings, // which will already know and hold a ref on the right node to return. Returning bool allows @@ -329,7 +329,6 @@ public: /* Like traversePreviousNode, but visits nodes before their children. */ Node* traversePreviousNodePostOrder(const Node *stayWithin = 0) const; - Node* traversePreviousSiblingPostOrder(const Node *stayWithin = 0) const; /** * Finds previous or next editable leaf node. @@ -368,6 +367,10 @@ public: // Whether or not a selection can be started in this object virtual bool canStartSelection() const; +#ifndef NDEBUG + virtual void dump(TextStream*, DeprecatedString indent = "") const; +#endif + // ----------------------------------------------------------------------------- // Integration with rendering tree @@ -432,7 +435,7 @@ public: * Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child * node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value. */ - virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) {}; + virtual void childrenChanged(bool changedByParser = false) {}; virtual String toString() const = 0; diff --git a/WebCore/dom/NodeFilter.cpp b/WebCore/dom/NodeFilter.cpp index 1844a2d..ff5ad92 100644 --- a/WebCore/dom/NodeFilter.cpp +++ b/WebCore/dom/NodeFilter.cpp @@ -1,9 +1,11 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,14 +27,17 @@ #include "config.h" #include "NodeFilter.h" -using namespace KJS; - namespace WebCore { -short NodeFilter::acceptNode(Node* node, JSValue*& exception) const +NodeFilter::NodeFilter(NodeFilterCondition* condition) + : m_condition(condition) +{ +} + +short NodeFilter::acceptNode(Node* node) const { // cast to short silences "enumeral and non-enumeral types in return" warning - return m_condition ? m_condition->acceptNode(node, exception) : static_cast<short>(FILTER_ACCEPT); + return m_condition ? m_condition->acceptNode(node) : static_cast<short>(FILTER_ACCEPT); } } // namespace WebCore diff --git a/WebCore/dom/NodeFilter.h b/WebCore/dom/NodeFilter.h index 2f7c822..66b175d 100644 --- a/WebCore/dom/NodeFilter.h +++ b/WebCore/dom/NodeFilter.h @@ -1,9 +1,11 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,7 +28,6 @@ #define NodeFilter_h #include "NodeFilterCondition.h" -#include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> namespace WebCore { @@ -65,13 +66,10 @@ namespace WebCore { SHOW_NOTATION = 0x00000800 }; - NodeFilter(PassRefPtr<NodeFilterCondition> condition) : RefCounted<NodeFilter>(0), m_condition(condition) { } - short acceptNode(Node*, KJS::JSValue*& exception) const; + NodeFilter(NodeFilterCondition*); + short acceptNode(Node*) const; void mark() { m_condition->mark(); }; - // For non-JS bindings. Silently ignores the JavaScript exception if any. - short acceptNode(Node* node) const { KJS::JSValue* exception; return acceptNode(node, exception); } - private: RefPtr<NodeFilterCondition> m_condition; }; diff --git a/WebCore/dom/NodeFilter.idl b/WebCore/dom/NodeFilter.idl index 3cc5e86..1e0eac0 100644 --- a/WebCore/dom/NodeFilter.idl +++ b/WebCore/dom/NodeFilter.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> * * This library is free software; you can redistribute it and/or @@ -43,7 +43,7 @@ module traversal { const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x00000400; const unsigned long SHOW_NOTATION = 0x00000800; - [Custom] short acceptNode(in Node n); + short acceptNode(in Node n); }; diff --git a/WebCore/dom/NodeFilterCondition.cpp b/WebCore/dom/NodeFilterCondition.cpp index 48bdcb4..5ee81c3 100644 --- a/WebCore/dom/NodeFilterCondition.cpp +++ b/WebCore/dom/NodeFilterCondition.cpp @@ -1,9 +1,11 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,11 +29,9 @@ #include "NodeFilter.h" -using namespace KJS; - namespace WebCore { -short NodeFilterCondition::acceptNode(Node*, JSValue*&) const +short NodeFilterCondition::acceptNode(Node*) const { return NodeFilter::FILTER_ACCEPT; } diff --git a/WebCore/dom/NodeFilterCondition.h b/WebCore/dom/NodeFilterCondition.h index 7596684..74fa2fa 100644 --- a/WebCore/dom/NodeFilterCondition.h +++ b/WebCore/dom/NodeFilterCondition.h @@ -1,9 +1,11 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,19 +29,14 @@ #include <wtf/RefCounted.h> -namespace KJS { - class JSValue; -} - namespace WebCore { class Node; class NodeFilterCondition : public RefCounted<NodeFilterCondition> { public: - NodeFilterCondition() : RefCounted<NodeFilterCondition>(0) { } virtual ~NodeFilterCondition() { } - virtual short acceptNode(Node*, KJS::JSValue*& exception) const; + virtual short acceptNode(Node*) const; virtual void mark() { } }; diff --git a/WebCore/dom/NodeIterator.cpp b/WebCore/dom/NodeIterator.cpp index 502d393..47117b2 100644 --- a/WebCore/dom/NodeIterator.cpp +++ b/WebCore/dom/NodeIterator.cpp @@ -1,9 +1,11 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,197 +31,148 @@ #include "ExceptionCode.h" #include "NodeFilter.h" -using namespace KJS; - namespace WebCore { -NodeIterator::NodePointer::NodePointer() -{ -} - -NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b) - : node(n) - , isPointerBeforeNode(b) -{ -} - -void NodeIterator::NodePointer::clear() -{ - node.clear(); -} - -bool NodeIterator::NodePointer::moveToNext(Node* root) -{ - if (!node) - return false; - if (isPointerBeforeNode) { - isPointerBeforeNode = false; - return true; - } - node = node->traverseNextNode(root); - return node; -} - -bool NodeIterator::NodePointer::moveToPrevious(Node* root) -{ - if (!node) - return false; - if (!isPointerBeforeNode) { - isPointerBeforeNode = true; - return true; - } - node = node->traversePreviousNode(root); - return node; -} - -NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences) +NodeIterator::NodeIterator(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences) : Traversal(rootNode, whatToShow, filter, expandEntityReferences) - , m_referenceNode(root(), true) + , m_beforeReferenceNode(true) , m_detached(false) + , m_doc(rootNode ? rootNode->document() : 0) { - root()->document()->attachNodeIterator(this); + if (document()) + document()->attachNodeIterator(this); } NodeIterator::~NodeIterator() { - root()->document()->detachNodeIterator(this); + if (document()) + document()->detachNodeIterator(this); } -Node* NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception) +Node* NodeIterator::findNextNode(Node* node) const { - if (m_detached) { - ec = INVALID_STATE_ERR; - return 0; - } - - Node* result = 0; - - m_candidateNode = m_referenceNode; - while (m_candidateNode.moveToNext(root())) { + while ((node = node->traverseNextNode(root()))) { // NodeIterators treat the DOM tree as a flat list of nodes. // In other words, FILTER_REJECT does not pass over descendants // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP. - exception = 0; - bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT; - if (exception) - break; - if (nodeWasAccepted) { - m_referenceNode = m_candidateNode; - result = m_referenceNode.node.get(); + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) break; - } } - - m_candidateNode.clear(); - return result; + return node; } -Node* NodeIterator::previousNode(ExceptionCode& ec, JSValue*& exception) +Node* NodeIterator::nextNode(ExceptionCode& ec) { - if (m_detached) { + if (detached()) { ec = INVALID_STATE_ERR; return 0; } - Node* result = 0; + Node* node = referenceNode() ? referenceNode() : root(); + if (!pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT) + node = findNextNode(node); + if (node) + setReferenceNode(node); + setPointerBeforeReferenceNode(false); + return node; +} - m_candidateNode = m_referenceNode; - while (m_candidateNode.moveToPrevious(root())) { +Node* NodeIterator::findPreviousNode(Node* node) const +{ + while ((node = node->traversePreviousNode(root()))) { // NodeIterators treat the DOM tree as a flat list of nodes. // In other words, FILTER_REJECT does not pass over descendants // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP. - exception = 0; - bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT; - if (exception) - break; - if (nodeWasAccepted) { - m_referenceNode = m_candidateNode; - result = m_referenceNode.node.get(); + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) break; - } } + return node; +} - m_candidateNode.clear(); - return result; +Node* NodeIterator::previousNode(ExceptionCode&) +{ + Node* node = referenceNode() ? referenceNode() : root(); + if (pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT) + node = findPreviousNode(node); + if (node) + setReferenceNode(node); + setPointerBeforeReferenceNode(); + return node; } void NodeIterator::detach() { - root()->document()->detachNodeIterator(this); - m_detached = true; - m_referenceNode.node.clear(); + if (!detached() && document()) + document()->detachNodeIterator(this); + setDetached(); } -void NodeIterator::notifyBeforeNodeRemoval(Node* removedNode) +void NodeIterator::setReferenceNode(Node* node) { - updateForNodeRemoval(removedNode, m_referenceNode); + m_referenceNode = node; } -void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const +void NodeIterator::notifyBeforeNodeRemoval(Node* removedNode) { - ASSERT(!m_detached); - ASSERT(removedNode); - ASSERT(root()->document() == removedNode->document()); - // Iterator is not affected if the removed node is the reference node and is the root. // or if removed node is not the reference node, or the ancestor of the reference node. - if (!removedNode->isDescendantOf(root())) + if (!removedNode || removedNode == root() || !removedNode->isDescendantOf(root())) return; - bool willRemoveReferenceNode = removedNode == referenceNode.node; - bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode); + bool willRemoveReferenceNode = removedNode == referenceNode(); + bool willRemoveReferenceNodeAncestor = referenceNode() && referenceNode()->isDescendantOf(removedNode); if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor) return; - if (referenceNode.isPointerBeforeNode) { - Node* node = removedNode->traverseNextNode(root()); + if (pointerBeforeReferenceNode()) { + Node* node = findNextNode(removedNode); if (node) { // Move out from under the node being removed if the reference node is // a descendant of the node being removed. if (willRemoveReferenceNodeAncestor) { while (node && node->isDescendantOf(removedNode)) - node = node->traverseNextNode(root()); + node = findNextNode(node); } if (node) - referenceNode.node = node; + setReferenceNode(node); } else { - node = removedNode->traversePreviousNode(root()); + node = findPreviousNode(removedNode); if (node) { // Move out from under the node being removed if the reference node is // a descendant of the node being removed. if (willRemoveReferenceNodeAncestor) { while (node && node->isDescendantOf(removedNode)) - node = node->traversePreviousNode(root()); + node = findPreviousNode(node); } if (node) { // Removing last node. // Need to move the pointer after the node preceding the // new reference node. - referenceNode.node = node; - referenceNode.isPointerBeforeNode = false; + setReferenceNode(node); + setPointerBeforeReferenceNode(false); } } } } else { - Node* node = removedNode->traversePreviousNode(root()); + Node* node = findPreviousNode(removedNode); if (node) { // Move out from under the node being removed if the reference node is // a descendant of the node being removed. if (willRemoveReferenceNodeAncestor) { while (node && node->isDescendantOf(removedNode)) - node = node->traversePreviousNode(root()); + node = findPreviousNode(node); } if (node) - referenceNode.node = node; + setReferenceNode(node); } else { - node = removedNode->traverseNextNode(root()); + node = findNextNode(removedNode); // Move out from under the node being removed if the reference node is // a descendant of the node being removed. if (willRemoveReferenceNodeAncestor) { while (node && node->isDescendantOf(removedNode)) - node = node->traversePreviousNode(root()); + node = findPreviousNode(node); } if (node) - referenceNode.node = node; + setReferenceNode(node); } } } diff --git a/WebCore/dom/NodeIterator.h b/WebCore/dom/NodeIterator.h index b2a7c70..b737e57 100644 --- a/WebCore/dom/NodeIterator.h +++ b/WebCore/dom/NodeIterator.h @@ -1,9 +1,11 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,47 +28,45 @@ #define NodeIterator_h #include "Traversal.h" -#include <wtf/PassRefPtr.h> namespace WebCore { + class Document; + typedef int ExceptionCode; class NodeIterator : public Traversal { public: - NodeIterator(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); - virtual ~NodeIterator(); + NodeIterator(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); + ~NodeIterator(); - Node* nextNode(ExceptionCode&, KJS::JSValue*& exception); - Node* previousNode(ExceptionCode&, KJS::JSValue*& exception); + Node* nextNode(ExceptionCode&); + Node* previousNode(ExceptionCode&); void detach(); - Node* referenceNode() const { return m_referenceNode.node.get(); } - bool pointerBeforeReferenceNode() const { return m_referenceNode.isPointerBeforeNode; } + Node* referenceNode() const { return m_referenceNode.get(); } + bool pointerBeforeReferenceNode() const { return m_beforeReferenceNode; } - // This function is called before any node is removed from the document tree. - void notifyBeforeNodeRemoval(Node* nodeToBeRemoved); - - // For non-JS bindings. Silently ignores the JavaScript exception if any. - Node* nextNode(ExceptionCode& ec) { KJS::JSValue* exception; return nextNode(ec, exception); } - Node* previousNode(ExceptionCode& ec) { KJS::JSValue* exception; return previousNode(ec, exception); } + /** + * This function has to be called if you delete a node from the + * document tree and you want the Iterator to react if there + * are any changes concerning it. + */ + void notifyBeforeNodeRemoval(Node* removed); private: - struct NodePointer { - RefPtr<Node> node; - bool isPointerBeforeNode; - NodePointer(); - NodePointer(PassRefPtr<Node>, bool); - void clear(); - bool moveToNext(Node* root); - bool moveToPrevious(Node* root); - }; - - void updateForNodeRemoval(Node* nodeToBeRemoved, NodePointer&) const; + void setReferenceNode(Node*); + void setPointerBeforeReferenceNode(bool flag = true) { m_beforeReferenceNode = flag; } + bool detached() const { return m_detached; } + void setDetached(bool flag = true) { m_detached = flag; } + Document* document() const { return m_doc.get(); } + Node* findNextNode(Node*) const; + Node* findPreviousNode(Node*) const; - NodePointer m_referenceNode; - NodePointer m_candidateNode; + RefPtr<Node> m_referenceNode; + bool m_beforeReferenceNode; bool m_detached; + RefPtr<Document> m_doc; }; } // namespace WebCore diff --git a/WebCore/dom/NodeIterator.idl b/WebCore/dom/NodeIterator.idl index e129de3..4c82cc0 100644 --- a/WebCore/dom/NodeIterator.idl +++ b/WebCore/dom/NodeIterator.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Apple Computer, Inc. * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> * * This library is free software; you can redistribute it and/or @@ -29,9 +29,9 @@ module traversal { readonly attribute Node referenceNode; readonly attribute boolean pointerBeforeReferenceNode; - [Custom] Node nextNode() + Node nextNode() raises (DOMException); - [Custom] Node previousNode() + Node previousNode() raises (DOMException); void detach(); }; diff --git a/WebCore/dom/NodeList.h b/WebCore/dom/NodeList.h index 2bc1443..bbb20f4 100644 --- a/WebCore/dom/NodeList.h +++ b/WebCore/dom/NodeList.h @@ -33,7 +33,7 @@ namespace WebCore { class NodeList : public RefCounted<NodeList> { public: - NodeList() : RefCounted<NodeList>(0) { } + NodeList() { } virtual ~NodeList() { } // DOM methods & attributes for NodeList diff --git a/WebCore/dom/Position.cpp b/WebCore/dom/Position.cpp index 84ff856..ce60e68 100644 --- a/WebCore/dom/Position.cpp +++ b/WebCore/dom/Position.cpp @@ -26,20 +26,18 @@ #include "config.h" #include "Position.h" -#include "CSSComputedStyleDeclaration.h" -#include "CString.h" #include "CharacterNames.h" #include "Document.h" #include "Element.h" -#include "HTMLNames.h" #include "Logging.h" -#include "PositionIterator.h" #include "RenderBlock.h" +#include "CSSComputedStyleDeclaration.h" +#include "htmlediting.h" +#include "HTMLNames.h" +#include "PositionIterator.h" #include "Text.h" #include "TextIterator.h" -#include "htmlediting.h" #include "visible_units.h" -#include <stdio.h> namespace WebCore { @@ -296,16 +294,6 @@ static bool isStreamer(const PositionIterator& pos) return pos.atStartOfNode(); } -// enclosingBlock does some expensive editability checks, upstream and downstream -// can avoid those because they do their own editability checking. -static Node* enclosingBlockIgnoringEditability(Node* node) -{ - while (node && !isBlock(node)) - node = node->parentNode(); - - return node; -} - // p.upstream() returns the start of the range of positions that map to the same VisiblePosition as P. Position Position::upstream() const { @@ -314,27 +302,19 @@ Position Position::upstream() const return Position(); // iterate backward from there, looking for a qualified position - Node* originalBlock = enclosingBlockIgnoringEditability(startNode); + Node* block = enclosingBlock(startNode); PositionIterator lastVisible = *this; PositionIterator currentPos = lastVisible; - bool startEditable = startNode->isContentEditable(); - Node* lastNode = startNode; + Node* originalRoot = node()->rootEditableElement(); for (; !currentPos.atStart(); currentPos.decrement()) { Node* currentNode = currentPos.node(); - // Don't check for an editability change if we haven't moved to a different node, - // to avoid the expense of computing isContentEditable(). - if (currentNode != lastNode) { - // Don't change editability. - bool currentEditable = currentNode->isContentEditable(); - if (startEditable != currentEditable) - break; - lastNode = currentNode; - } + if (currentNode->rootEditableElement() != originalRoot) + break; // Don't enter a new enclosing block flow or table element. There is code below that - // terminates early if we're about to leave a block. - if (isBlock(currentNode) && currentNode != originalBlock) + // terminates early if we're about to leave an enclosing block flow or table element. + if (block != enclosingBlock(currentNode)) return lastVisible; // skip position in unrendered or invisible node @@ -347,8 +327,8 @@ Position Position::upstream() const lastVisible = currentPos; // Don't leave a block flow or table element. We could rely on code above to terminate and - // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call. - if (isBlock(currentNode) && currentPos.atStartOfNode()) + // return lastVisible on the next iteration, but we terminate early. + if (currentNode == enclosingBlock(currentNode) && currentPos.atStartOfNode()) return lastVisible; // Return position after tables and nodes which have content that can be ignored. @@ -394,36 +374,23 @@ Position Position::downstream() const return Position(); // iterate forward from there, looking for a qualified position - Node* originalBlock = enclosingBlockIgnoringEditability(startNode); + Node* block = enclosingBlock(startNode); PositionIterator lastVisible = *this; PositionIterator currentPos = lastVisible; - bool startEditable = startNode->isContentEditable(); - Node* lastNode = startNode; + Node* originalRoot = node()->rootEditableElement(); for (; !currentPos.atEnd(); currentPos.increment()) { Node* currentNode = currentPos.node(); - // Don't check for an editability change if we haven't moved to a different node, - // to avoid the expense of computing isContentEditable(). - if (currentNode != lastNode) { - // Don't change editability. - bool currentEditable = currentNode->isContentEditable(); - if (startEditable != currentEditable) - break; - lastNode = currentNode; - } + if (currentNode->rootEditableElement() != originalRoot) + break; // stop before going above the body, up into the head // return the last visible streamer position if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode()) break; - // Do not enter a new enclosing block. - if (isBlock(currentNode) && currentNode != originalBlock) - return lastVisible; - // Do not leave the original enclosing block. - // Note: The first position after the last one in the original block - // will be [originalBlock->parentNode(), originalBlock->nodeIndex() + 1]. - if (originalBlock && originalBlock->parentNode() == currentNode) + // Do not enter a new enclosing block flow or table element, and don't leave the original one. + if (block != enclosingBlock(currentNode)) return lastVisible; // skip position in unrendered or invisible node @@ -693,17 +660,17 @@ Position Position::trailingWhitespacePosition(EAffinity affinity, bool considerN return Position(); } -void Position::debugPosition(const char* msg) const +void Position::debugPosition(const char *msg) const { if (isNull()) fprintf(stderr, "Position [%s]: null\n", msg); else - fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), offset()); + fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().deprecatedString().latin1(), node(), offset()); } #ifndef NDEBUG -void Position::formatForDebugger(char* buffer, unsigned length) const +void Position::formatForDebugger(char *buffer, unsigned length) const { String result; @@ -718,7 +685,7 @@ void Position::formatForDebugger(char* buffer, unsigned length) const result += s; } - strncpy(buffer, result.utf8().data(), length - 1); + strncpy(buffer, result.deprecatedString().latin1(), length - 1); } void Position::showTreeForThis() const diff --git a/WebCore/dom/ProcessingInstruction.cpp b/WebCore/dom/ProcessingInstruction.cpp index 34b00d4..7486e9a 100644 --- a/WebCore/dom/ProcessingInstruction.cpp +++ b/WebCore/dom/ProcessingInstruction.cpp @@ -1,6 +1,8 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 2000 Peter Kelly (pmk@post.com) - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,7 +19,6 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ - #include "config.h" #include "ProcessingInstruction.h" @@ -155,7 +156,7 @@ bool ProcessingInstruction::checkStyleSheet() m_cachedSheet->deref(this); #if ENABLE(XSLT) if (m_isXSL) - m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href).string()); + m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href)); else #endif { @@ -163,7 +164,7 @@ bool ProcessingInstruction::checkStyleSheet() if (charset.isEmpty()) charset = document()->frame()->loader()->encoding(); - m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href).string(), charset); + m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href), charset); } if (m_cachedSheet) m_cachedSheet->ref(this); @@ -196,13 +197,13 @@ bool ProcessingInstruction::sheetLoaded() return false; } -void ProcessingInstruction::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet) +void ProcessingInstruction::setCSSStyleSheet(const String& url, const String& charset, const String& sheet) { #if ENABLE(XSLT) ASSERT(!m_isXSL); #endif m_sheet = new CSSStyleSheet(this, url, charset); - parseStyleSheet(sheet->sheetText()); + parseStyleSheet(sheet); } #if ENABLE(XSLT) diff --git a/WebCore/dom/ProcessingInstruction.h b/WebCore/dom/ProcessingInstruction.h index be4a63e..f4ee819 100644 --- a/WebCore/dom/ProcessingInstruction.h +++ b/WebCore/dom/ProcessingInstruction.h @@ -57,7 +57,7 @@ public: String localHref() const { return m_localHref; } StyleSheet* sheet() const { return m_sheet.get(); } bool checkStyleSheet(); - virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*); + virtual void setCSSStyleSheet(const String& url, const String& charset, const String& sheet); #if ENABLE(XSLT) virtual void setXSLStyleSheet(const String& url, const String& sheet); #endif diff --git a/WebCore/dom/QualifiedName.cpp b/WebCore/dom/QualifiedName.cpp index c9d7e28..ebc63a2 100644 --- a/WebCore/dom/QualifiedName.cpp +++ b/WebCore/dom/QualifiedName.cpp @@ -97,7 +97,7 @@ struct QNameComponentsTranslator { return c.m_prefix == name->m_prefix.impl() && c.m_localName == name->m_localName.impl() && c.m_namespace == name->m_namespace.impl(); } static void translate(QualifiedName::QualifiedNameImpl*& location, const QualifiedNameComponents& components, unsigned hash) { - location = QualifiedName::QualifiedNameImpl::create(components.m_prefix, components.m_localName, components.m_namespace).releaseRef(); + location = new QualifiedName::QualifiedNameImpl(components.m_prefix, components.m_localName, components.m_namespace); } }; @@ -109,10 +109,8 @@ QualifiedName::QualifiedName(const AtomicString& p, const AtomicString& l, const if (!gNameCache) gNameCache = new QNameSet; QualifiedNameComponents components = { p.impl(), l.impl(), n.impl() }; - pair<QNameSet::iterator, bool> addResult = gNameCache->add<QualifiedNameComponents, QNameComponentsTranslator>(components); - m_impl = *addResult.first; - if (!addResult.second) - m_impl->ref(); + m_impl = *gNameCache->add<QualifiedNameComponents, QNameComponentsTranslator>(components).first; + ref(); } QualifiedName::~QualifiedName() diff --git a/WebCore/dom/QualifiedName.h b/WebCore/dom/QualifiedName.h index 5aa8abf..60826b2 100644 --- a/WebCore/dom/QualifiedName.h +++ b/WebCore/dom/QualifiedName.h @@ -30,22 +30,11 @@ class QualifiedName { public: class QualifiedNameImpl : public RefCounted<QualifiedNameImpl> { public: - static PassRefPtr<QualifiedNameImpl> create(const AtomicString& p, const AtomicString& l, const AtomicString& n) - { - return adoptRef(new QualifiedNameImpl(p, l, n)); - } - + QualifiedNameImpl(const AtomicString& p, const AtomicString& l, const AtomicString& n) :m_prefix(p), m_localName(l), m_namespace(n) {} + AtomicString m_prefix; AtomicString m_localName; AtomicString m_namespace; - - private: - QualifiedNameImpl(const AtomicString& p, const AtomicString& l, const AtomicString& n) - : m_prefix(p) - , m_localName(l) - , m_namespace(n) - { - } }; QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI); @@ -77,7 +66,8 @@ public: static void init(); private: - void ref() { m_impl->ref(); } + + void ref() { m_impl->ref(); } void deref(); QualifiedNameImpl* m_impl; diff --git a/WebCore/dom/Range.cpp b/WebCore/dom/Range.cpp index 88292c3..176c07b 100644 --- a/WebCore/dom/Range.cpp +++ b/WebCore/dom/Range.cpp @@ -24,7 +24,6 @@ #include "config.h" #include "Range.h" -#include "CString.h" #include "Document.h" #include "DocumentFragment.h" #include "ExceptionCode.h" @@ -37,7 +36,6 @@ #include "TextIterator.h" #include "markup.h" #include "visible_units.h" -#include <stdio.h> namespace WebCore { @@ -59,8 +57,7 @@ static RangeCounter rangeCounter; #endif Range::Range(Document* ownerDocument) - : RefCounted<Range>(0) - , m_ownerDocument(ownerDocument) + : m_ownerDocument(ownerDocument) , m_startContainer(ownerDocument) , m_startOffset(0) , m_endContainer(ownerDocument) @@ -75,8 +72,7 @@ Range::Range(Document* ownerDocument) Range::Range(Document* ownerDocument, Node* startContainer, int startOffset, Node* endContainer, int endOffset) - : RefCounted<Range>(0) - , m_ownerDocument(ownerDocument) + : m_ownerDocument(ownerDocument) , m_startContainer(ownerDocument) , m_startOffset(0) , m_endContainer(ownerDocument) @@ -96,8 +92,7 @@ Range::Range(Document* ownerDocument, } Range::Range(Document* ownerDocument, const Position& start, const Position& end) - : RefCounted<Range>(0) - , m_ownerDocument(ownerDocument) + : m_ownerDocument(ownerDocument) , m_startContainer(ownerDocument) , m_startOffset(0) , m_endContainer(ownerDocument) @@ -366,11 +361,12 @@ short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) return -1; // compare to end, and point comes after - if (compareBoundaryPoints(refNode, offset, m_endContainer.get(), m_endOffset) == 1) + else if (compareBoundaryPoints(refNode, offset, m_endContainer.get(), m_endOffset) == 1) return 1; - + // point is in the middle of this range, or on the boundary points - return 0; + else + return 0; } Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec) @@ -1169,36 +1165,34 @@ bool Range::isDetached() const void Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const { + if (offset < 0) + ec = INDEX_SIZE_ERR; + // no return here + switch (n->nodeType()) { - case Node::DOCUMENT_TYPE_NODE: case Node::ENTITY_NODE: case Node::NOTATION_NODE: + case Node::DOCUMENT_TYPE_NODE: ec = RangeException::INVALID_NODE_TYPE_ERR; - return; - case Node::CDATA_SECTION_NODE: - case Node::COMMENT_NODE: + break; case Node::TEXT_NODE: - if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length()) + case Node::COMMENT_NODE: + case Node::CDATA_SECTION_NODE: + if ((unsigned)offset > static_cast<CharacterData*>(n)->length()) ec = INDEX_SIZE_ERR; - return; + break; case Node::PROCESSING_INSTRUCTION_NODE: - if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length()) + if ((unsigned)offset > static_cast<ProcessingInstruction*>(n)->data().length()) ec = INDEX_SIZE_ERR; - return; - case Node::ATTRIBUTE_NODE: - case Node::DOCUMENT_FRAGMENT_NODE: - case Node::DOCUMENT_NODE: - case Node::ELEMENT_NODE: - case Node::ENTITY_REFERENCE_NODE: - case Node::XPATH_NAMESPACE_NODE: - if (static_cast<unsigned>(offset) > n->childNodeCount()) + break; + default: + if ((unsigned)offset > n->childNodeCount()) ec = INDEX_SIZE_ERR; - return; + break; } - ASSERT_NOT_REACHED(); } -void Range::checkNodeBA(Node* n, ExceptionCode& ec) const +void Range::checkNodeBA( Node *n, ExceptionCode& ec) const { // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an // Attr, Document or DocumentFragment node or part of a shadow DOM tree @@ -1206,7 +1200,6 @@ void Range::checkNodeBA(Node* n, ExceptionCode& ec) const Node *root = n; while (root->parentNode()) root = root->parentNode(); - if (!(root->nodeType() == Node::ATTRIBUTE_NODE || root->nodeType() == Node::DOCUMENT_NODE || root->nodeType() == Node::DOCUMENT_FRAGMENT_NODE || @@ -1381,7 +1374,7 @@ void Range::selectNodeContents( Node *refNode, ExceptionCode& ec) m_startContainer = refNode; m_startOffset = 0; m_endContainer = refNode; - m_endOffset = maxEndOffset(); + m_endOffset = refNode->offsetInCharacters() ? refNode->maxCharacterOffset() : refNode->childNodeCount(); } void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec) @@ -1400,23 +1393,14 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec) // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation, // Document, or DocumentFragment node. - switch (newParent->nodeType()) { - case Node::ATTRIBUTE_NODE: - case Node::DOCUMENT_FRAGMENT_NODE: - case Node::DOCUMENT_NODE: - case Node::DOCUMENT_TYPE_NODE: - case Node::ENTITY_NODE: - case Node::NOTATION_NODE: - ec = RangeException::INVALID_NODE_TYPE_ERR; - return; - case Node::CDATA_SECTION_NODE: - case Node::COMMENT_NODE: - case Node::ELEMENT_NODE: - case Node::ENTITY_REFERENCE_NODE: - case Node::PROCESSING_INSTRUCTION_NODE: - case Node::TEXT_NODE: - case Node::XPATH_NAMESPACE_NODE: - break; + if( newParent->nodeType() == Node::ATTRIBUTE_NODE || + newParent->nodeType() == Node::ENTITY_NODE || + newParent->nodeType() == Node::NOTATION_NODE || + newParent->nodeType() == Node::DOCUMENT_TYPE_NODE || + newParent->nodeType() == Node::DOCUMENT_NODE || + newParent->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) { + ec = RangeException::INVALID_NODE_TYPE_ERR; + return; } // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of @@ -1433,20 +1417,6 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec) return; } - // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node. - if (m_startContainer->nodeType() != Node::TEXT_NODE) { - if (m_startOffset > 0 && m_startOffset < maxStartOffset()) { - ec = RangeException::BAD_BOUNDARYPOINTS_ERR; - return; - } - } - if (m_endContainer->nodeType() != Node::TEXT_NODE) { - if (m_endOffset > 0 && m_endOffset < maxEndOffset()) { - ec = RangeException::BAD_BOUNDARYPOINTS_ERR; - return; - } - } - // Raise a HIERARCHY_REQUEST_ERR if m_startContainer doesn't accept children like newParent. Node* parentOfNewParent = m_startContainer.get(); // If m_startContainer is a textNode, it will be split and it will be its parent that will @@ -1463,8 +1433,21 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec) return; } - // FIXME: Do we need a check if the node would end up with a child node of a type not - // allowed by the type of node? + // ### check if node would end up with a child node of a type not allowed by the type of node + + // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-text node. + if (!m_startContainer->offsetInCharacters()) { + if (m_startOffset > 0 && m_startOffset < m_startContainer->childNodeCount()) { + ec = RangeException::BAD_BOUNDARYPOINTS_ERR; + return; + } + } + if (!m_endContainer->offsetInCharacters()) { + if (m_endOffset > 0 && m_endOffset < m_endContainer->childNodeCount()) { + ec = RangeException::BAD_BOUNDARYPOINTS_ERR; + return; + } + } ec = 0; while (Node* n = newParent->firstChild()) { @@ -1663,7 +1646,7 @@ void Range::formatForDebugger(char *buffer, unsigned length) const result += s; } - strncpy(buffer, result.utf8().data(), length - 1); + strncpy(buffer, result.deprecatedString().latin1(), length - 1); } #undef FormatBufferSize #endif @@ -1697,22 +1680,4 @@ PassRefPtr<Range> rangeOfContents(Node* node) return range.release(); } -unsigned Range::maxStartOffset() const -{ - if (!m_startContainer) - return 0; - if (!m_startContainer->offsetInCharacters()) - return m_startContainer->childNodeCount(); - return m_startContainer->maxCharacterOffset(); -} - -unsigned Range::maxEndOffset() const -{ - if (!m_endContainer) - return 0; - if (!m_endContainer->offsetInCharacters()) - return m_endContainer->childNodeCount(); - return m_endContainer->maxCharacterOffset(); -} - } diff --git a/WebCore/dom/Range.h b/WebCore/dom/Range.h index 7568748..b3c516c 100644 --- a/WebCore/dom/Range.h +++ b/WebCore/dom/Range.h @@ -131,8 +131,6 @@ private: void checkNodeBA(Node*, ExceptionCode&) const; void checkDeleteExtract(ExceptionCode&); bool containedByReadOnly() const; - unsigned maxStartOffset() const; - unsigned maxEndOffset() const; }; PassRefPtr<Range> rangeOfContents(Node*); diff --git a/WebCore/dom/RegisteredEventListener.cpp b/WebCore/dom/RegisteredEventListener.cpp index e995bd0..927a728 100644 --- a/WebCore/dom/RegisteredEventListener.cpp +++ b/WebCore/dom/RegisteredEventListener.cpp @@ -30,8 +30,7 @@ namespace WebCore { RegisteredEventListener::RegisteredEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture) - : RefCounted<RegisteredEventListener>(0) - , m_eventType(eventType) + : m_eventType(eventType) , m_listener(listener) , m_useCapture(useCapture) , m_removed(false) diff --git a/WebCore/dom/StyleElement.cpp b/WebCore/dom/StyleElement.cpp index 8280880..322808d 100644 --- a/WebCore/dom/StyleElement.cpp +++ b/WebCore/dom/StyleElement.cpp @@ -1,6 +1,7 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 2006, 2007 Rob Buis - * Copyright (C) 2008 Apple, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,7 +18,6 @@ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ - #include "config.h" #include "StyleElement.h" @@ -56,13 +56,13 @@ void StyleElement::process(Element* e) if (!e || !e->inDocument()) return; - Vector<UChar> text; + String text = ""; for (Node* c = e->firstChild(); c; c = c->nextSibling()) if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE || c->nodeType() == Node::COMMENT_NODE) - append(text, c->nodeValue()); + text += c->nodeValue(); - createSheet(e, String::adopt(text)); + createSheet(e, text); } void StyleElement::createSheet(Element* e, const String& text) @@ -74,9 +74,8 @@ void StyleElement::createSheet(Element* e, const String& text) m_sheet = 0; } - // If type is empty or CSS, this is a CSS style sheet. - const AtomicString& type = this->type(); - if (type.isEmpty() || (e->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"))) { + String typeValue = e->isHTMLElement() ? type().deprecatedString().lower() : type(); + if (typeValue.isEmpty() || typeValue == "text/css") { // Type must be empty or CSS RefPtr<MediaList> mediaList = new MediaList((CSSStyleSheet*)0, media(), e->isHTMLElement()); MediaQueryEvaluator screenEval("screen", true); MediaQueryEvaluator printEval("print", true); diff --git a/WebCore/dom/StyledElement.cpp b/WebCore/dom/StyledElement.cpp index 6d9a7d7..8792ba8 100644 --- a/WebCore/dom/StyledElement.cpp +++ b/WebCore/dom/StyledElement.cpp @@ -172,7 +172,7 @@ void StyledElement::attributeChanged(Attribute* attr, bool preserveDecls) if (needToParse) parseMappedAttribute(mappedAttr); - if (entry == eNone && ownerDocument()->attached() && ownerDocument()->styleSelector()->hasSelectorForAttribute(attr->name().localName())) + if (entry == eNone && ownerDocument()->styleSelector()->hasSelectorForAttribute(attr->name().localName())) setChanged(); if (checkDecl && mappedAttr->decl()) { @@ -203,7 +203,7 @@ void StyledElement::parseMappedAttribute(MappedAttribute *attr) if (attr->isNull()) namedAttrMap->setID(nullAtom); else if (document()->inCompatMode() && !attr->value().impl()->isLower()) - namedAttrMap->setID(AtomicString(attr->value().string().lower())); + namedAttrMap->setID(AtomicString(attr->value().domString().lower())); else namedAttrMap->setID(attr->value()); } diff --git a/WebCore/dom/StyledElement.h b/WebCore/dom/StyledElement.h index 82df0bf..e7766b2 100644 --- a/WebCore/dom/StyledElement.h +++ b/WebCore/dom/StyledElement.h @@ -68,8 +68,8 @@ public: virtual void updateStyleAttributeIfNeeded() const; virtual const ClassNames* getClassNames() const; - virtual void attributeChanged(Attribute*, bool preserveDecls = false); - virtual void parseMappedAttribute(MappedAttribute*); + virtual void attributeChanged(Attribute* attr, bool preserveDecls = false); + virtual void parseMappedAttribute(MappedAttribute* attr); virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const; virtual void createAttributeMap() const; virtual Attribute* createAttribute(const QualifiedName& name, StringImpl* value); diff --git a/WebCore/dom/Text.cpp b/WebCore/dom/Text.cpp index d61214f..0ba7d70 100644 --- a/WebCore/dom/Text.cpp +++ b/WebCore/dom/Text.cpp @@ -22,7 +22,6 @@ #include "config.h" #include "Text.h" -#include "CString.h" #include "Document.h" #include "ExceptionCode.h" #include "RenderText.h" @@ -88,100 +87,9 @@ PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec) return newText.release(); } -static const Text* earliestLogicallyAdjacentTextNode(const Text* t) -{ - const Node* n = t; - while ((n = n->previousSibling())) { - Node::NodeType type = n->nodeType(); - if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) { - t = static_cast<const Text*>(n); - continue; - } - - // We would need to visit EntityReference child text nodes if they existed - ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes()); - break; - } - return t; -} - -static const Text* latestLogicallyAdjacentTextNode(const Text* t) -{ - const Node* n = t; - while ((n = n->nextSibling())) { - Node::NodeType type = n->nodeType(); - if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) { - t = static_cast<const Text*>(n); - continue; - } - - // We would need to visit EntityReference child text nodes if they existed - ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes()); - break; - } - return t; -} - -String Text::wholeText() const -{ - const Text* startText = earliestLogicallyAdjacentTextNode(this); - const Text* endText = latestLogicallyAdjacentTextNode(this); - - Vector<UChar> result; - Node* onePastEndText = endText->nextSibling(); - for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) { - if (!n->isTextNode()) - continue; - const Text* t = static_cast<const Text*>(n); - const String& data = t->data(); - result.append(data.characters(), data.length()); - } - - return String::adopt(result); -} - -PassRefPtr<Text> Text::replaceWholeText(const String& newText, ExceptionCode&) -{ - // We don't support "read-only" text nodes (no Entity node support) - // Thus, we remove all adjacent text nodes, and replace the contents of this one. - ASSERT(!isReadOnlyNode()); - // This method only raises exceptions when dealing with Entity nodes (which we don't support) - - // Protect startText and endText against mutation event handlers removing the last ref - RefPtr<Text> startText = const_cast<Text*>(earliestLogicallyAdjacentTextNode(this)); - RefPtr<Text> endText = const_cast<Text*>(latestLogicallyAdjacentTextNode(this)); - - RefPtr<Text> protectedThis(this); // Mutation event handlers could cause our last ref to go away - Node* parent = parentNode(); // Protect against mutation handlers moving this node during traversal - ExceptionCode ignored = 0; - for (RefPtr<Node> n = startText; n && n != this && n->isTextNode() && n->parentNode() == parent;) { - RefPtr<Node> nodeToRemove(n.release()); - n = nodeToRemove->nextSibling(); - parent->removeChild(nodeToRemove.get(), ignored); - } - - if (this != endText) { - Node* onePastEndText = endText->nextSibling(); - for (RefPtr<Node> n = nextSibling(); n && n != onePastEndText && n->isTextNode() && n->parentNode() == parent;) { - RefPtr<Node> nodeToRemove(n.release()); - n = nodeToRemove->nextSibling(); - parent->removeChild(nodeToRemove.get(), ignored); - } - } - - if (newText.isEmpty()) { - if (parent && parentNode() == parent) - parent->removeChild(this, ignored); - return 0; - } - - setData(newText, ignored); - return protectedThis.release(); -} - String Text::nodeName() const { - return textAtom.string(); + return textAtom.domString(); } Node::NodeType Text::nodeType() const @@ -323,7 +231,7 @@ void Text::formatForDebugger(char *buffer, unsigned length) const result += s; } - strncpy(buffer, result.utf8().data(), length - 1); + strncpy(buffer, result.deprecatedString().latin1(), length - 1); } #endif diff --git a/WebCore/dom/Text.h b/WebCore/dom/Text.h index e5282d5..c9b73c1 100644 --- a/WebCore/dom/Text.h +++ b/WebCore/dom/Text.h @@ -39,10 +39,6 @@ public: PassRefPtr<Text> splitText(unsigned offset, ExceptionCode&); - // DOM Level 3: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1312295772 - String wholeText() const; - PassRefPtr<Text> replaceWholeText(const String&, ExceptionCode&); - // DOM methods overridden from parent classes virtual String nodeName() const; diff --git a/WebCore/dom/Text.idl b/WebCore/dom/Text.idl index 1b0009d..c0426ea 100644 --- a/WebCore/dom/Text.idl +++ b/WebCore/dom/Text.idl @@ -30,10 +30,6 @@ module core { Text splitText(in [IsIndex] unsigned long offset) raises (DOMException); - // Introduced in DOM Level 3: - readonly attribute DOMString wholeText; - Text replaceWholeText(in DOMString content) - raises(DOMException); }; } diff --git a/WebCore/dom/Traversal.cpp b/WebCore/dom/Traversal.cpp index d9dd0a7..5e1aa03 100644 --- a/WebCore/dom/Traversal.cpp +++ b/WebCore/dom/Traversal.cpp @@ -1,9 +1,11 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,14 +29,12 @@ #include "Node.h" #include "NodeFilter.h" - -using namespace KJS; +#include <wtf/PassRefPtr.h> namespace WebCore { -Traversal::Traversal(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> nodeFilter, bool expandEntityReferences) - : RefCounted<Traversal>(0) - , m_root(rootNode) +Traversal::Traversal(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> nodeFilter, bool expandEntityReferences) + : m_root(rootNode) , m_whatToShow(whatToShow) , m_filter(nodeFilter) , m_expandEntityReferences(expandEntityReferences) @@ -45,17 +45,15 @@ Traversal::~Traversal() { } -short Traversal::acceptNode(Node* node, JSValue*& exception) const +short Traversal::acceptNode(Node* node) const { - // FIXME: To handle XML properly we would have to check m_expandEntityReferences. - + // FIXME: If XML is implemented we have to check expandEntityRerefences in this function. // The bid twiddling here is done to map DOM node types, which are given as integers from // 1 through 12, to whatToShow bit masks. - if (!(((1 << (node->nodeType() - 1)) & m_whatToShow))) - return NodeFilter::FILTER_SKIP; - if (!m_filter) - return NodeFilter::FILTER_ACCEPT; - return m_filter->acceptNode(node, exception); + if (node && ((1 << (node->nodeType()-1)) & m_whatToShow)) + // cast to short silences "enumeral and non-enumeral types in return" warning + return m_filter ? m_filter->acceptNode(node) : static_cast<short>(NodeFilter::FILTER_ACCEPT); + return NodeFilter::FILTER_SKIP; } } // namespace WebCore diff --git a/WebCore/dom/Traversal.h b/WebCore/dom/Traversal.h index 78265e0..7611145 100644 --- a/WebCore/dom/Traversal.h +++ b/WebCore/dom/Traversal.h @@ -1,9 +1,11 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,14 +27,10 @@ #ifndef Traversal_h #define Traversal_h -#include <wtf/Forward.h> #include <wtf/RefCounted.h> +#include <wtf/Forward.h> #include <wtf/RefPtr.h> -namespace KJS { - class JSValue; -} - namespace WebCore { class Node; @@ -40,7 +38,7 @@ namespace WebCore { class Traversal : public RefCounted<Traversal> { public: - Traversal(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); + Traversal(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); virtual ~Traversal(); Node* root() const { return m_root.get(); } @@ -48,8 +46,7 @@ namespace WebCore { NodeFilter* filter() const { return m_filter.get(); } bool expandEntityReferences() const { return m_expandEntityReferences; } - protected: - short acceptNode(Node*, KJS::JSValue*& jsException) const; + short acceptNode(Node*) const; private: RefPtr<Node> m_root; diff --git a/WebCore/dom/TreeWalker.cpp b/WebCore/dom/TreeWalker.cpp index 09c1c95..ffa8ae7 100644 --- a/WebCore/dom/TreeWalker.cpp +++ b/WebCore/dom/TreeWalker.cpp @@ -1,9 +1,11 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -30,17 +32,15 @@ #include "NodeFilter.h" #include <wtf/PassRefPtr.h> -using namespace KJS; - namespace WebCore { -TreeWalker::TreeWalker(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences) +TreeWalker::TreeWalker(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences) : Traversal(rootNode, whatToShow, filter, expandEntityReferences) - , m_current(root()) + , m_current(rootNode) { } -void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionCode& ec) +void TreeWalker::setCurrentNode(Node* node, ExceptionCode& ec) { if (!node) { ec = NOT_SUPPORTED_ERR; @@ -49,237 +49,97 @@ void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionCode& ec) m_current = node; } -inline Node* TreeWalker::setCurrent(PassRefPtr<Node> node) +void TreeWalker::setCurrentNode(Node* node) { - m_current = node; - return m_current.get(); + ASSERT(node); + int dummy; + setCurrentNode(node, dummy); } -Node* TreeWalker::parentNode(JSValue*& exception) +Node* TreeWalker::parentNode() { - exception = 0; - RefPtr<Node> node = m_current; - while (node != root()) { - node = node->parentNode(); - if (!node) - return 0; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return setCurrent(node.release()); + for (Node* node = currentNode()->parentNode(); node && (node == root() || node->isDescendantOf(root())); node = node->parentNode()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) { + setCurrentNode(node); + return node; + } } return 0; } -Node* TreeWalker::firstChild(JSValue*& exception) +Node* TreeWalker::firstChild() { - exception = 0; - for (RefPtr<Node> node = m_current->firstChild(); node; ) { - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - switch (acceptNodeResult) { - case NodeFilter::FILTER_ACCEPT: - m_current = node.release(); - return m_current.get(); - case NodeFilter::FILTER_SKIP: - if (node->firstChild()) { - node = node->firstChild(); - continue; - } - break; - case NodeFilter::FILTER_REJECT: - break; + for (Node* node = currentNode()->firstChild(); node && (node == root() || node->isDescendantOf(root())); node = node->nextSibling()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) { + setCurrentNode(node); + return node; } - do { - if (node->nextSibling()) { - node = node->nextSibling(); - break; - } - Node* parent = node->parentNode(); - if (!parent || parent == root() || parent == m_current) - return 0; - node = parent; - } while (node); } return 0; } -Node* TreeWalker::lastChild(JSValue*& exception) +Node* TreeWalker::lastChild() { - exception = 0; - for (RefPtr<Node> node = m_current->lastChild(); node; ) { - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - switch (acceptNodeResult) { - case NodeFilter::FILTER_ACCEPT: - m_current = node.release(); - return m_current.get(); - case NodeFilter::FILTER_SKIP: - if (node->lastChild()) { - node = node->lastChild(); - continue; - } - break; - case NodeFilter::FILTER_REJECT: - break; + for (Node* node = currentNode()->lastChild(); node && (node == root() || node->isDescendantOf(root())); node = node->previousSibling()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) { + setCurrentNode(node); + return node; } - do { - if (node->previousSibling()) { - node = node->previousSibling(); - break; - } - Node* parent = node->parentNode(); - if (!parent || parent == root() || parent == m_current) - return 0; - node = parent; - } while (node); } return 0; } -Node* TreeWalker::previousSibling(JSValue*& exception) +Node* TreeWalker::previousSibling() { - exception = 0; - RefPtr<Node> node = m_current; - if (node == root()) - return 0; - while (1) { - for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) { - short acceptNodeResult = acceptNode(sibling.get(), exception); - if (exception) - return 0; - switch (acceptNodeResult) { - case NodeFilter::FILTER_ACCEPT: - m_current = sibling.release(); - return m_current.get(); - case NodeFilter::FILTER_SKIP: - if (sibling->firstChild()) { - sibling = sibling->firstChild(); - continue; - } - break; - case NodeFilter::FILTER_REJECT: - break; - } - sibling = sibling->previousSibling(); + for (Node* node = currentNode()->previousSibling(); node && (node == root() || node->isDescendantOf(root())); node = node->previousSibling()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) { + setCurrentNode(node); + return node; } - node = node->parentNode(); - if (!node || node == root()) - return 0; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return 0; } + return 0; } -Node* TreeWalker::nextSibling(JSValue*& exception) +Node* TreeWalker::nextSibling() { - exception = 0; - RefPtr<Node> node = m_current; - if (node == root()) - return 0; - while (1) { - for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) { - short acceptNodeResult = acceptNode(sibling.get(), exception); - if (exception) - return 0; - switch (acceptNodeResult) { - case NodeFilter::FILTER_ACCEPT: - m_current = sibling.release(); - return m_current.get(); - case NodeFilter::FILTER_SKIP: - if (sibling->firstChild()) { - sibling = sibling->firstChild(); - continue; - } - break; - case NodeFilter::FILTER_REJECT: - break; - } - sibling = sibling->nextSibling(); + for (Node* node = currentNode()->nextSibling(); node && (node == root() || node->isDescendantOf(root())); node = node->nextSibling()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) { + setCurrentNode(node); + return node; } - node = node->parentNode(); - if (!node || node == root()) - return 0; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return 0; } + return 0; } -Node* TreeWalker::previousNode(JSValue*& exception) +Node* TreeWalker::previousNode() { - exception = 0; - RefPtr<Node> node = m_current; - while (node != root()) { - while (Node* previousSibling = node->previousSibling()) { - node = previousSibling; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_REJECT) - continue; - while (Node* lastChild = node->lastChild()) { - node = lastChild; - acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - continue; - } - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) { - m_current = node.release(); - return m_current.get(); - } + for (Node* node = currentNode()->traversePreviousNode(); node && (node == root() || node->isDescendantOf(root())); node = node->traversePreviousNode()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) { + setCurrentNode(node); + return node; } - if (node == root()) - return 0; - Node* parent = node->parentNode(); - if (!parent) - return 0; - node = parent; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return setCurrent(node.release()); } return 0; } -Node* TreeWalker::nextNode(JSValue*& exception) +Node* TreeWalker::nextNode() { - exception = 0; - RefPtr<Node> node = m_current; -Children: - while (Node* firstChild = node->firstChild()) { - node = firstChild; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return setCurrent(node.release()); - if (acceptNodeResult == NodeFilter::FILTER_REJECT) - break; - } - while (Node* nextSibling = node->traverseNextSibling(root())) { - node = nextSibling; - short acceptNodeResult = acceptNode(node.get(), exception); - if (exception) - return 0; - if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) - return setCurrent(node.release()); - if (acceptNodeResult == NodeFilter::FILTER_SKIP) - goto Children; + for (Node* node = currentNode()->traverseNextNode(); node && (node == root() || node->isDescendantOf(root())); node = node->traverseNextNode()) { + if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) { + setCurrentNode(node); + return node; + } } return 0; } +bool TreeWalker::ancestorRejected(const Node* node) const +{ + for (Node* a = node->parentNode(); a && a != root(); a = a->parentNode()) { + if (acceptNode(a) == NodeFilter::FILTER_REJECT) + return true; + } + return false; +} + } // namespace WebCore diff --git a/WebCore/dom/TreeWalker.h b/WebCore/dom/TreeWalker.h index 8b0ea98..206d8ac 100644 --- a/WebCore/dom/TreeWalker.h +++ b/WebCore/dom/TreeWalker.h @@ -1,9 +1,11 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) - * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004 Apple Computer, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -26,6 +28,7 @@ #define TreeWalker_h #include "Traversal.h" +#include <wtf/RefPtr.h> namespace WebCore { @@ -33,30 +36,23 @@ namespace WebCore { class TreeWalker : public Traversal { public: - TreeWalker(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); + TreeWalker(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences); Node* currentNode() const { return m_current.get(); } - void setCurrentNode(PassRefPtr<Node>, ExceptionCode&); - - Node* parentNode(KJS::JSValue*& exception); - Node* firstChild(KJS::JSValue*& exception); - Node* lastChild(KJS::JSValue*& exception); - Node* previousSibling(KJS::JSValue*& exception); - Node* nextSibling(KJS::JSValue*& exception); - Node* previousNode(KJS::JSValue*& exception); - Node* nextNode(KJS::JSValue*& exception); + void setCurrentNode(Node*, ExceptionCode&); - // For non-JS bindings. Silently ignores the JavaScript exception if any. - Node* parentNode() { KJS::JSValue* exception; return parentNode(exception); } - Node* firstChild() { KJS::JSValue* exception; return firstChild(exception); } - Node* lastChild() { KJS::JSValue* exception; return lastChild(exception); } - Node* previousSibling() { KJS::JSValue* exception; return previousSibling(exception); } - Node* nextSibling() { KJS::JSValue* exception; return nextSibling(exception); } - Node* previousNode() { KJS::JSValue* exception; return previousNode(exception); } - Node* nextNode() { KJS::JSValue* exception; return nextNode(exception); } + Node* parentNode(); + Node* firstChild(); + Node* lastChild(); + Node* previousSibling(); + Node* nextSibling(); + Node* previousNode(); + Node* nextNode(); private: - Node* setCurrent(PassRefPtr<Node>); + // convenience for when it is known there will be no exception + void setCurrentNode(Node*); + bool ancestorRejected(const Node*) const; RefPtr<Node> m_current; }; diff --git a/WebCore/dom/TreeWalker.idl b/WebCore/dom/TreeWalker.idl index 4f98d3a..bc983c3 100644 --- a/WebCore/dom/TreeWalker.idl +++ b/WebCore/dom/TreeWalker.idl @@ -29,13 +29,13 @@ module traversal { attribute Node currentNode setter raises(DOMException); - [Custom] Node parentNode(); - [Custom] Node firstChild(); - [Custom] Node lastChild(); - [Custom] Node previousSibling(); - [Custom] Node nextSibling(); - [Custom] Node previousNode(); - [Custom] Node nextNode(); + Node parentNode(); + Node firstChild(); + Node lastChild(); + Node previousSibling(); + Node nextSibling(); + Node previousNode(); + Node nextNode(); }; } diff --git a/WebCore/dom/XMLTokenizer.cpp b/WebCore/dom/XMLTokenizer.cpp index fe7c95a..7ba424c 100644 --- a/WebCore/dom/XMLTokenizer.cpp +++ b/WebCore/dom/XMLTokenizer.cpp @@ -1,6 +1,8 @@ -/* +/** + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 2000 Peter Kelly (pmk@post.com) - * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006 Apple Computer, Inc. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * Copyright (C) 2007 Trolltech ASA @@ -42,7 +44,6 @@ #include "HTMLStyleElement.h" #include "HTMLTokenizer.h" #include "ProcessingInstruction.h" -#include "ResourceError.h" #include "ResourceHandle.h" #include "ResourceRequest.h" #include "ResourceResponse.h" @@ -54,7 +55,6 @@ #endif #include <wtf/Platform.h> #include <wtf/StringExtras.h> -#include <wtf/Threading.h> #include <wtf/Vector.h> #if ENABLE(XSLT) @@ -340,16 +340,14 @@ public: // -------------------------------- static int globalDescriptor = 0; -static DocLoader* globalDocLoader = 0; -static ThreadIdentifier libxmlLoaderThread = 0; static int matchFunc(const char* uri) { - // Only match loads initiated due to uses of libxml2 from within XMLTokenizer to avoid - // interfering with client applications that also use libxml2. http://bugs.webkit.org/show_bug.cgi?id=17353 - return globalDocLoader && currentThread() == libxmlLoaderThread; + return 1; // Match everything. } +static DocLoader* globalDocLoader = 0; + class OffsetBuffer { public: OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { } @@ -379,24 +377,15 @@ static bool shouldAllowExternalLoad(const char* inURI) } static void* openFunc(const char* uri) { - ASSERT(globalDocLoader); - ASSERT(currentThread() == libxmlLoaderThread); - - if (!shouldAllowExternalLoad(uri)) + if (!globalDocLoader || !shouldAllowExternalLoad(uri)) return &globalDescriptor; ResourceError error; ResourceResponse response; Vector<char> data; - DocLoader* docLoader = globalDocLoader; - globalDocLoader = 0; - // FIXME: We should restore the original global error handler as well. - - if (docLoader->frame()) - docLoader->frame()->loader()->loadResourceSynchronously(KURL(uri), error, response, data); - - globalDocLoader = docLoader; + if (globalDocLoader->frame()) + globalDocLoader->frame()->loader()->loadResourceSynchronously(KURL(uri), error, response, data); return new OffsetBuffer(data); } @@ -443,7 +432,6 @@ static xmlParserCtxtPtr createStringParser(xmlSAXHandlerPtr handlers, void* user xmlInitParser(); xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc); xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc); - libxmlLoaderThread = currentThread(); didInit = true; } @@ -862,7 +850,7 @@ void XMLTokenizer::endElementNs() if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE) scriptCode += static_cast<CharacterData*>(child)->data(); } - m_view->frame()->loader()->executeScript(m_doc->url().string(), m_scriptStartLine - 1, scriptCode); + m_view->frame()->loader()->executeScript(m_doc->url(), m_scriptStartLine - 1, scriptCode); } m_requestingScript = false; @@ -1009,8 +997,11 @@ void XMLTokenizer::internalSubset(const xmlChar* name, const xmlChar* externalID return; } - if (m_doc) - m_doc->addChild(new DocumentType(m_doc, toString(name), toString(externalID), toString(systemID))); + Document* doc = m_doc; + if (!doc) + return; + + doc->setDocType(new DocumentType(doc, toString(name), toString(externalID), toString(systemID))); } static inline XMLTokenizer* getTokenizer(void* closure) @@ -1288,7 +1279,7 @@ void XMLTokenizer::end() { #if ENABLE(XSLT) if (m_sawXSLTransform) { - m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->url().string())); + m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->url())); m_doc->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets. m_doc->updateStyleSelector(); @@ -1437,7 +1428,7 @@ bool XMLTokenizer::isWaitingForScripts() const } #if ENABLE(XSLT) -void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const String& url) +void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const DeprecatedString& url) { if (source.isEmpty()) return 0; @@ -1456,7 +1447,7 @@ void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const Strin xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char*>(source.characters()), source.length() * sizeof(UChar), - url.latin1().data(), + url.ascii(), BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", XSLT_PARSE_OPTIONS); @@ -1935,7 +1926,7 @@ void XMLTokenizer::parseEndElement() if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE) scriptCode += static_cast<CharacterData*>(child)->data(); } - m_view->frame()->loader()->executeScript(m_doc->url().string(), m_scriptStartLine - 1, scriptCode); + m_view->frame()->loader()->executeScript(m_doc->url(), m_scriptStartLine - 1, scriptCode); } m_requestingScript = false; } @@ -2096,7 +2087,7 @@ void XMLTokenizer::parseDtd() setIsXHTMLDocument(true); // controls if we replace entities or not. } if (!m_parsingFragment) - m_doc->addChild(new DocumentType(m_doc, name, publicId, systemId)); + m_doc->setDocType(new DocumentType(m_doc, name, publicId, systemId)); } #endif diff --git a/WebCore/dom/XMLTokenizer.h b/WebCore/dom/XMLTokenizer.h index e754e84..d7dff71 100644 --- a/WebCore/dom/XMLTokenizer.h +++ b/WebCore/dom/XMLTokenizer.h @@ -1,6 +1,8 @@ /* + * This file is part of the DOM implementation for KDE. + * * Copyright (C) 2000 Peter Kelly (pmk@post.com) - * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005, 2006 Apple Computer, Inc. * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) * Copyright (C) 2007 Trolltech ASA * @@ -24,6 +26,115 @@ #ifndef XMLTokenizer_h #define XMLTokenizer_h +#if USE(EXPAT) + +#include "CachedResourceClient.h" +#include "SegmentedString.h" +#include "StringHash.h" +#include "Tokenizer.h" +#include <libexpat/expat.h> +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + + class Node; + class CachedScript; + class DocumentFragment; + class Document; + class Element; + class FrameView; + class PendingCallbacks; + + class XMLTokenizer : public Tokenizer, public CachedResourceClient { + public: + XMLTokenizer(Document *, FrameView * = 0); + XMLTokenizer(DocumentFragment *, Element *); + ~XMLTokenizer(); + + enum ErrorType { warning, nonFatal, fatal }; + + // from Tokenizer + virtual bool write(const SegmentedString &str, bool); + virtual void finish(); + virtual bool isWaitingForScripts() const; + virtual void stopParsing(); + virtual bool wellFormed() const { return !m_sawError; } + virtual int lineNumber() const; + virtual int columnNumber() const; + + // from CachedObjectClient + virtual void notifyFinished(CachedResource *finishedObj); + + // callbacks from parser expat + void startElementNs(const XML_Char *name, const XML_Char **atts); + void endElementNs(); + void characters(const XML_Char *s, int len); + void processingInstruction(const XML_Char *target, const XML_Char *data); + void comment(const XML_Char *s); + void startCdata(); + void endCdata(); + + void error(ErrorType type, const char* m, int lineNumber, int columnNumber); + + // utilities + XML_Parser getXMLParser() const { return m_parser; } + void setXMLParser(XML_Parser parser) { m_parser = parser; } + + private: + void setCurrentNode(Node*); + + void end(); + + void pauseParsing(); + void resumeParsing(); + + void reportError(); + void insertErrorMessageBlock(); + + bool enterText(); + void exitText(); + + Document *m_doc; + FrameView *m_view; + + XML_Parser m_parser; + + Node *m_currentNode; + bool m_currentNodeIsReferenced; + + bool m_sawError; + bool m_sawXSLTransform; + bool m_sawFirstElement; + + bool m_parserPaused; + bool m_requestingScript; + bool m_finishCalled; + + int m_errorCount; + String m_errorMessages; + + CachedScript *m_pendingScript; + RefPtr<Element> m_scriptElement; + int m_scriptStartLine; + + bool m_parsingFragment; + String m_defaultNamespaceURI; + + typedef HashMap<String, String> PrefixForNamespaceMap; + PrefixForNamespaceMap m_prefixToNamespaceMap; + + OwnPtr<PendingCallbacks> m_pendingCallbacks; + SegmentedString m_pendingSrc; + }; + +HashMap<String, String> parseAttributes(const String&, bool& attrsOK); +bool parseXMLDocumentFragment(const String&, DocumentFragment*, Element* parent = 0); + +} // namespace WebCore + +#else // USE(EXPAT) + #include "CachedResourceClient.h" #include "SegmentedString.h" #include "StringHash.h" @@ -168,7 +279,7 @@ namespace WebCore { }; #if ENABLE(XSLT) -void* xmlDocPtrForString(DocLoader*, const String& source, const String& url); +void* xmlDocPtrForString(DocLoader*, const String& source, const DeprecatedString& url); void setLoaderForLibXMLCallbacks(DocLoader*); #endif @@ -177,4 +288,6 @@ bool parseXMLDocumentFragment(const String&, DocumentFragment*, Element* parent } // namespace WebCore +#endif // USE(EXPAT) + #endif // XMLTokenizer_h diff --git a/WebCore/dom/xml_expat_tokenizer.cpp b/WebCore/dom/xml_expat_tokenizer.cpp new file mode 100644 index 0000000..cf9ab93 --- /dev/null +++ b/WebCore/dom/xml_expat_tokenizer.cpp @@ -0,0 +1,1025 @@ +/** + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 2000 Peter Kelly (pmk@post.com) + * Copyright (C) 2005, 2006 Apple Computer, Inc. + * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * Copyright (C) 2007 Samuel Weinig (sam@webkit.org) + * Copyright (C) 2007 The Android Open Source Project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "XMLTokenizer.h" + +#include "CDATASection.h" +#include "CachedScript.h" +#include "Comment.h" +#include "CString.h" +#include "DocLoader.h" +#include "Document.h" +#include "DocumentFragment.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "FrameView.h" +#include "HTMLNames.h" +#include "HTMLScriptElement.h" +#include "HTMLTableSectionElement.h" +#include "HTMLTokenizer.h" +#include "ProcessingInstruction.h" +#include "EventNames.h" + +// strndup is not available everywhere, so here is a portable version <reed> +static char* portable_strndup(const char src[], size_t len) +{ + char* origDst = (char*)malloc(len + 1); + if (NULL == origDst) + return NULL; + + char* dst = origDst; + while (len-- > 0) { + if ((*dst++ = *src++) == 0) + return origDst; + } + *dst = 0; + return origDst; +} + +namespace WebCore { + +using namespace EventNames; +using namespace HTMLNames; + +const int maxErrors = 25; + +class PendingCallbacks { +public: + PendingCallbacks() { + m_callbacks.setAutoDelete(true); + } + + void appendStartElementNSCallback(const XML_Char* name, const XML_Char** atts) { + PendingStartElementNSCallback* callback = new PendingStartElementNSCallback; + + callback->name = strdup(name); + callback->count = 0; + while (atts[callback->count]) + callback->count++; + callback->atts = (XML_Char**)malloc(sizeof(XML_Char*) * (callback->count+1)); + for (int i=0; i<callback->count; i++) + callback->atts[i] = strdup(atts[i]); + callback->atts[callback->count] = NULL; + + m_callbacks.append(callback); + } + + void appendEndElementNSCallback() { + PendingEndElementNSCallback* callback = new PendingEndElementNSCallback; + + m_callbacks.append(callback); + } + + void appendCharactersCallback(const XML_Char* s, int len) { + PendingCharactersCallback* callback = new PendingCharactersCallback; + + callback->s = portable_strndup(s, len); + callback->len = len; + + m_callbacks.append(callback); + } + + void appendProcessingInstructionCallback(const XML_Char* target, const XML_Char* data) { + PendingProcessingInstructionCallback* callback = new PendingProcessingInstructionCallback; + + callback->target = strdup(target); + callback->data = strdup(data); + + m_callbacks.append(callback); + } + + void appendStartCDATABlockCallback() { + PendingStartCDATABlockCallback* callback = new PendingStartCDATABlockCallback; + + m_callbacks.append(callback); + } + + void appendEndCDATABlockCallback() { + PendingEndCDATABlockCallback* callback = new PendingEndCDATABlockCallback; + + m_callbacks.append(callback); + } + + void appendCommentCallback(const XML_Char* s) { + PendingCommentCallback* callback = new PendingCommentCallback; + + callback->s = strdup(s); + + m_callbacks.append(callback); + } + + void appendErrorCallback(XMLTokenizer::ErrorType type, const char* message, int lineNumber, int columnNumber) { + PendingErrorCallback* callback = new PendingErrorCallback; + + callback->message = strdup(message); + callback->type = type; + callback->lineNumber = lineNumber; + callback->columnNumber = columnNumber; + + m_callbacks.append(callback); + } + + void callAndRemoveFirstCallback(XMLTokenizer* tokenizer) { + PendingCallback* cb = m_callbacks.getFirst(); + + cb->call(tokenizer); + m_callbacks.removeFirst(); + } + + bool isEmpty() const { return m_callbacks.isEmpty(); } + +private: + struct PendingCallback { + + virtual ~PendingCallback() { } + + virtual void call(XMLTokenizer* tokenizer) = 0; + }; + + struct PendingStartElementNSCallback : public PendingCallback { + virtual ~PendingStartElementNSCallback() { + free(name); + for (int i=0; i<count; i++) + free(atts[i]); + free(atts); + } + + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->startElementNs(name, (const XML_Char**)(atts)); + } + + XML_Char* name; + int count; + XML_Char** atts; + }; + + struct PendingEndElementNSCallback : public PendingCallback { + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->endElementNs(); + } + }; + + struct PendingCharactersCallback : public PendingCallback { + virtual ~PendingCharactersCallback() { + free(s); + } + + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->characters(s, len); + } + + XML_Char* s; + int len; + }; + + struct PendingProcessingInstructionCallback : public PendingCallback { + virtual ~PendingProcessingInstructionCallback() { + free(target); + free(data); + } + + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->processingInstruction(target, data); + } + + XML_Char* target; + XML_Char* data; + }; + + struct PendingStartCDATABlockCallback : public PendingCallback { + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->startCdata(); + } + }; + + struct PendingEndCDATABlockCallback : public PendingCallback { + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->endCdata(); + } + }; + + struct PendingCommentCallback : public PendingCallback { + virtual ~PendingCommentCallback() { + free(s); + } + + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->comment(s); + } + + XML_Char* s; + }; + + struct PendingErrorCallback: public PendingCallback { + virtual ~PendingErrorCallback() { + free (message); + } + + virtual void call(XMLTokenizer* tokenizer) { + tokenizer->error(type, message, lineNumber, columnNumber); + } + + XMLTokenizer::ErrorType type; + char* message; + int lineNumber; + int columnNumber; + }; + +public: + DeprecatedPtrList<PendingCallback> m_callbacks; +}; + +// -------------------------------- + +XMLTokenizer::XMLTokenizer(Document *_doc, FrameView *_view) + : m_doc(_doc) + , m_view(_view) + , m_parser(0) + , m_currentNode(_doc) + , m_currentNodeIsReferenced(false) + , m_sawError(false) + , m_sawXSLTransform(false) + , m_sawFirstElement(false) + , m_parserPaused(false) + , m_requestingScript(false) + , m_finishCalled(false) + , m_errorCount(0) + , m_pendingScript(0) + , m_scriptStartLine(0) + , m_parsingFragment(false) + , m_pendingCallbacks(new PendingCallbacks) +{ +} + +XMLTokenizer::XMLTokenizer(DocumentFragment *fragment, Element *parentElement) + : m_doc(fragment->document()) + , m_view(0) + , m_parser(0) + , m_currentNode(fragment) + , m_currentNodeIsReferenced(fragment) + , m_sawError(false) + , m_sawXSLTransform(false) + , m_sawFirstElement(false) + , m_parserPaused(false) + , m_requestingScript(false) + , m_finishCalled(false) + , m_errorCount(0) + , m_pendingScript(0) + , m_scriptStartLine(0) + , m_parsingFragment(true) + , m_pendingCallbacks(new PendingCallbacks) +{ + if (fragment) + fragment->ref(); + if (m_doc) + m_doc->ref(); + + // Add namespaces based on the parent node + Vector<Element*> elemStack; + while (parentElement) { + elemStack.append(parentElement); + + Node* n = parentElement->parentNode(); + if (!n || !n->isElementNode()) + break; + parentElement = static_cast<Element*>(n); + } + + if (elemStack.isEmpty()) + return; + + for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) { + if (NamedAttrMap* attrs = element->attributes()) { + for (unsigned i = 0; i < attrs->length(); i++) { + Attribute* attr = attrs->attributeItem(i); + if (attr->localName() == "xmlns") + m_defaultNamespaceURI = attr->value(); + else if (attr->prefix() == "xmlns") + m_prefixToNamespaceMap.set(attr->localName(), attr->value()); + } + } + } +} + +XMLTokenizer::~XMLTokenizer() +{ + setCurrentNode(0); + if (m_parsingFragment && m_doc) + m_doc->deref(); + if (m_pendingScript) + m_pendingScript->deref(this); +} + +void XMLTokenizer::setCurrentNode(Node* n) +{ + bool nodeNeedsReference = n && n != m_doc; + if (nodeNeedsReference) + n->ref(); + if (m_currentNodeIsReferenced) + m_currentNode->deref(); + m_currentNode = n; + m_currentNodeIsReferenced = nodeNeedsReference; +} + +// use space instead of ':' as separator because ':' can be inside an uri +const XML_Char tripletSep=' '; + +inline DeprecatedString toQString(const XML_Char* str, unsigned int len) +{ + return DeprecatedString::fromUtf8(reinterpret_cast<const char *>(str), len); +} + +inline DeprecatedString toQString(const XML_Char* str) +{ + return DeprecatedString::fromUtf8(str ? reinterpret_cast<const char *>(str) : ""); +} + +// triplet is formatted as URI + sep + local_name + sep + prefix. +static inline void splitTriplet(const XML_Char *name, String &uri, String &localname, String &prefix) +{ + String string[3]; + int found = 0; + const char *start = reinterpret_cast<const char *>(name); + + while(start && (found < 3)) { + char *next = strchr(start, tripletSep); + if (next) { + string[found++] = toQString(start, (next-start)); + start = next+1; + } else { + string[found++] = toQString(start); + break; + } + } + + switch(found) { + case 1: + localname = string[0]; + break; + case 2: + uri = string[0]; + localname = string[1]; + break; + case 3: + uri = string[0]; + localname = string[1]; + prefix = string[2]; + break; + } +} + +static inline void handleElementNamespaces(Element *newElement, const String &uri, const String &prefix, ExceptionCode &exceptioncode) +{ + if (uri.isEmpty()) + return; + + String namespaceQName("xmlns"); + if(!prefix.isEmpty()) + namespaceQName += String(":")+ prefix; + newElement->setAttributeNS(String("http://www.w3.org/2000/xmlns/"), namespaceQName, uri, exceptioncode); +} + +static inline void handleElementAttributes(Element *newElement, const XML_Char **atts, ExceptionCode &exceptioncode) +{ + for (int i = 0; atts[i]; i += 2) { + String attrURI, attrLocalName, attrPrefix; + splitTriplet(atts[i], attrURI, attrLocalName, attrPrefix); + String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + String(":") + attrLocalName; + String attrValue = toQString(atts[i+1]); + newElement->setAttributeNS(attrURI, attrQName, attrValue, exceptioncode); + if (exceptioncode) // exception while setting attributes + return; + } +} + +void XMLTokenizer::startElementNs(const XML_Char *name, const XML_Char **atts) +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendStartElementNSCallback(name, atts); + return; + } + + m_sawFirstElement = true; + + exitText(); + + String uri, localName, prefix; + splitTriplet(name, uri, localName, prefix); + String qName = prefix.isEmpty() ? localName : prefix + ":" + localName; + + if (m_parsingFragment && uri.isEmpty()) { + if (!prefix.isEmpty()) + uri = String(m_prefixToNamespaceMap.get(prefix.impl())); + else + uri = m_defaultNamespaceURI; + } + + ExceptionCode ec = 0; + RefPtr<Element> newElement = m_doc->createElementNS(uri, qName, ec); + if (!newElement) { + stopParsing(); + return; + } + + handleElementNamespaces(newElement.get(), uri, prefix, ec); + if (ec) { + stopParsing(); + return; + } + + handleElementAttributes(newElement.get(), atts, ec); + if (ec) { + stopParsing(); + return; + } + + if (newElement->hasTagName(scriptTag)) + static_cast<HTMLScriptElement*>(newElement.get())->setCreatedByParser(true); + + if (newElement->hasTagName(HTMLNames::scriptTag)) + m_scriptStartLine = lineNumber(); + + if (!m_currentNode->addChild(newElement.get())) { + stopParsing(); + return; + } + + setCurrentNode(newElement.get()); + if (m_view && !newElement->attached()) + newElement->attach(); +} + +void XMLTokenizer::endElementNs() +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendEndElementNSCallback(); + return; + } + + exitText(); + + Node* n = m_currentNode; + RefPtr<Node> parent = n->parentNode(); + n->finishedParsing(); + + // don't load external scripts for standalone documents (for now) + if (n->isElementNode() && m_view && static_cast<Element*>(n)->hasTagName(scriptTag)) { + ASSERT(!m_pendingScript); + + m_requestingScript = true; + + Element* scriptElement = static_cast<Element*>(n); + String scriptHref; + + if (static_cast<Element*>(n)->hasTagName(scriptTag)) + scriptHref = scriptElement->getAttribute(srcAttr); + + if (!scriptHref.isEmpty()) { + // we have a src attribute + const AtomicString& charset = scriptElement->getAttribute(charsetAttr); + if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) { + m_scriptElement = scriptElement; + m_pendingScript->ref(this); + + // m_pendingScript will be 0 if script was already loaded and ref() executed it + if (m_pendingScript) + pauseParsing(); + } else + m_scriptElement = 0; + + } else { + String scriptCode = ""; + for (Node* child = scriptElement->firstChild(); child; child = child->nextSibling()) { + if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE) + scriptCode += static_cast<CharacterData*>(child)->data(); + } + m_view->frame()->loader()->executeScript(m_doc->URL(), m_scriptStartLine - 1, scriptCode); + } + + m_requestingScript = false; + } + + setCurrentNode(parent.get()); +} + +void XMLTokenizer::characters(const XML_Char *s, int len) +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendCharactersCallback(s, len); + return; + } + + if (m_currentNode->isTextNode() || enterText()) { + ExceptionCode ec = 0; + static_cast<Text*>(m_currentNode)->appendData(toQString(s, len), ec); + } +} + +bool XMLTokenizer::enterText() +{ + RefPtr<Node> newNode = new Text(m_doc, ""); + if (!m_currentNode->addChild(newNode.get())) + return false; + setCurrentNode(newNode.get()); + return true; +} + +void XMLTokenizer::exitText() +{ + if (m_parserStopped) + return; + + if (!m_currentNode || !m_currentNode->isTextNode()) + return; + + if (m_view && m_currentNode && !m_currentNode->attached()) + m_currentNode->attach(); + + // FIXME: What's the right thing to do if the parent is really 0? + // Just leaving the current node set to the text node doesn't make much sense. + if (Node* par = m_currentNode->parentNode()) + setCurrentNode(par); +} + +void XMLTokenizer::processingInstruction(const XML_Char *target, const XML_Char *data) +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendProcessingInstructionCallback(target, data); + return; + } + + exitText(); + + // ### handle exceptions + int exception = 0; + RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction( + toQString(target), toQString(data), exception); + if (exception) + return; + + if (!m_currentNode->addChild(pi.get())) + return; + if (m_view && !pi->attached()) + pi->attach(); + + // don't load stylesheets for standalone documents + if (m_doc->frame()) { + m_sawXSLTransform = !m_sawFirstElement && !pi->checkStyleSheet(); + if (m_sawXSLTransform) + stopParsing(); + } +} + +void XMLTokenizer::comment(const XML_Char *s) +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendCommentCallback(s); + return; + } + + exitText(); + + RefPtr<Node> newNode = m_doc->createComment(toQString(s)); + m_currentNode->addChild(newNode.get()); + if (m_view && !newNode->attached()) + newNode->attach(); +} + +void XMLTokenizer::startCdata() +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendStartCDATABlockCallback(); + return; + } + + exitText(); + + RefPtr<Node> newNode = new CDATASection(m_doc, ""); + if (!m_currentNode->addChild(newNode.get())) + return; + if (m_view && !newNode->attached()) + newNode->attach(); + setCurrentNode(newNode.get()); +} + +void XMLTokenizer::endCdata() +{ + if (m_parserStopped) + return; + + if (m_parserPaused) { + m_pendingCallbacks->appendEndCDATABlockCallback(); + return; + } + + if (m_currentNode->parentNode() != 0) + setCurrentNode(m_currentNode->parentNode()); +} + +static void XMLCALL startElementHandler(void *userdata, const XML_Char *name, const XML_Char **atts) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->startElementNs(name, atts); +} + +static void XMLCALL endElementHandler(void *userdata, const XML_Char *name) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->endElementNs(); +} + +static void charactersHandler(void *userdata, const XML_Char *s, int len) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->characters(s, len); +} + +static void processingInstructionHandler(void *userdata, const XML_Char *target, const XML_Char *data) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->processingInstruction(target, data); +} + +static void commentHandler(void *userdata, const XML_Char *comment) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->comment(comment); +} + +static void startCdataHandler(void *userdata) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->startCdata(); +} + +static void endCdataHandler(void *userdata) +{ + XMLTokenizer *tokenizer = static_cast<XMLTokenizer *>(userdata); + tokenizer->endCdata(); +} + +static int unknownEncodingHandler(void *userdata, const XML_Char *name, XML_Encoding *info) +{ + // Expat doesn't like latin1 so we have to build this map + // to do conversion correctly. + // FIXME: Create a wrapper for expat that looks like libxml. + if (strcasecmp(name, "latin1") == 0) + { + for (int i=0; i<256; i++) { + info->map[i] = i; + } + return XML_STATUS_OK; + } + return XML_STATUS_ERROR; +} + +bool XMLTokenizer::write(const SegmentedString&s, bool /*appendData*/ ) +{ + String parseString = s.toString(); + + if (m_parserStopped || m_sawXSLTransform) + return false; + + if (m_parserPaused) { + m_pendingSrc.append(s); + return false; + } + + if (!m_parser) { + static const UChar BOM = 0xFEFF; + static const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM); + m_parser = XML_ParserCreateNS(BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE", tripletSep); + XML_SetUserData(m_parser, (void *)this); + XML_SetReturnNSTriplet(m_parser, true); + + XML_SetStartElementHandler(m_parser, startElementHandler); + XML_SetEndElementHandler(m_parser, endElementHandler); + XML_SetCharacterDataHandler(m_parser, charactersHandler); + XML_SetProcessingInstructionHandler(m_parser, processingInstructionHandler); + XML_SetCommentHandler(m_parser, commentHandler); + XML_SetStartCdataSectionHandler(m_parser, startCdataHandler); + XML_SetEndCdataSectionHandler(m_parser, endCdataHandler); + XML_SetUnknownEncodingHandler(m_parser, unknownEncodingHandler, NULL); + } + + enum XML_Status result = XML_Parse(m_parser, (const char*)parseString.characters(), sizeof(UChar) * parseString.length(), false); + if (result == XML_STATUS_ERROR) { + reportError(); + return false; + } + + return true; +} + +void XMLTokenizer::end() +{ + if (m_parser) { + XML_Parse(m_parser, 0, 0, true); + XML_ParserFree(m_parser); + m_parser = 0; + } + + if (m_sawError) + insertErrorMessageBlock(); + else { + exitText(); + m_doc->updateStyleSelector(); + } + + setCurrentNode(0); + m_doc->finishedParsing(); +} + +void XMLTokenizer::finish() +{ + if (m_parserPaused) + m_finishCalled = true; + else + end(); +} + +void XMLTokenizer::reportError() +{ + ErrorType type = nonFatal; + enum XML_Error code = XML_GetErrorCode(m_parser); + switch (code) { + case XML_ERROR_NO_MEMORY: + type = fatal; + break; + case XML_ERROR_FINISHED: + type = warning; + break; + default: + type = nonFatal; + } + error(type, XML_ErrorString(code), lineNumber(), columnNumber()); +} + +void XMLTokenizer::error(ErrorType type, const char* m, int lineNumber, int columnNumber) +{ + if (type == fatal || m_errorCount < maxErrors) { + switch (type) { + case warning: + m_errorMessages += String::format("warning on line %d at column %d: %s", lineNumber, columnNumber, m); + break; + case fatal: + case nonFatal: + m_errorMessages += String::format("error on line %d at column %d: %s", lineNumber, columnNumber, m); + } + ++m_errorCount; + } + + if (type != warning) + m_sawError = true; + + if (type == fatal) + stopParsing(); +} + +static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages) +{ + ExceptionCode ec = 0; + RefPtr<Element> reportElement = doc->createElementNS(xhtmlNamespaceURI, "parsererror", ec); + reportElement->setAttribute(styleAttr, "display:block; pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black"); + + RefPtr<Element> h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec); + reportElement->appendChild(h3.get(), ec); + h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec); + + RefPtr<Element> fixed = doc->createElementNS(xhtmlNamespaceURI, "div", ec); + reportElement->appendChild(fixed.get(), ec); + fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px"); + fixed->appendChild(doc->createTextNode(errorMessages), ec); + + h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec); + reportElement->appendChild(h3.get(), ec); + h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec); + + return reportElement; +} + +void XMLTokenizer::insertErrorMessageBlock() +{ + // One or more errors occurred during parsing of the code. Display an error block to the user above + // the normal content (the DOM tree is created manually and includes line/col info regarding + // where the errors are located) + + // Create elements for display + ExceptionCode ec = 0; + Document* doc = m_doc; + Node* documentElement = doc->documentElement(); + if (!documentElement) { + RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec); + doc->appendChild(rootElement, ec); + RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec); + rootElement->appendChild(body, ec); + documentElement = body.get(); + } + + RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages); + documentElement->insertBefore(reportElement, documentElement->firstChild(), ec); + doc->updateRendering(); +} + +void XMLTokenizer::notifyFinished(CachedResource *finishedObj) +{ + ASSERT(m_pendingScript == finishedObj); + + String cachedScriptUrl = m_pendingScript->url(); + String scriptSource = m_pendingScript->script(); + bool errorOccurred = m_pendingScript->errorOccurred(); + m_pendingScript->deref(this); + m_pendingScript = 0; + + RefPtr<Element> e = m_scriptElement; + m_scriptElement = 0; + + if (errorOccurred) + EventTargetNodeCast(e.get())->dispatchHTMLEvent(errorEvent, true, false); + else { + m_view->frame()->loader()->executeScript(cachedScriptUrl, 0, scriptSource); + EventTargetNodeCast(e.get())->dispatchHTMLEvent(loadEvent, false, false); + } + + m_scriptElement = 0; + + if (!m_requestingScript) + resumeParsing(); +} + +bool XMLTokenizer::isWaitingForScripts() const +{ + return m_pendingScript != 0; +} + +Tokenizer *newXMLTokenizer(Document *d, FrameView *v) +{ + return new XMLTokenizer(d, v); +} + +int XMLTokenizer::lineNumber() const +{ + return XML_GetCurrentLineNumber(m_parser); +} + +int XMLTokenizer::columnNumber() const +{ + return XML_GetCurrentColumnNumber(m_parser); +} + +void XMLTokenizer::stopParsing() +{ + Tokenizer::stopParsing(); + if (m_parser) + XML_StopParser(m_parser, 0); +} + +void XMLTokenizer::pauseParsing() +{ + if (m_parsingFragment) + return; + + m_parserPaused = true; +} + +void XMLTokenizer::resumeParsing() +{ + ASSERT(m_parserPaused); + + m_parserPaused = false; + + // First, execute any pending callbacks + while (!m_pendingCallbacks->isEmpty()) { + m_pendingCallbacks->callAndRemoveFirstCallback(this); + + // A callback paused the parser + if (m_parserPaused) + return; + } + + // Then, write any pending data + SegmentedString rest = m_pendingSrc; + m_pendingSrc.clear(); + write(rest, false); + + // Finally, if finish() has been called and write() didn't result + // in any further callbacks being queued, call end() + if (m_finishCalled && m_pendingCallbacks->isEmpty()) + end(); +} + +// -------------------------------- + +bool parseXMLDocumentFragment(const String &string, DocumentFragment *fragment, Element *parent) +{ + XMLTokenizer tokenizer(fragment, parent); + + XML_Parser parser = XML_ParserCreateNS(NULL, tripletSep); + tokenizer.setXMLParser(parser); + + XML_SetUserData(parser, (void *)&tokenizer); + XML_SetReturnNSTriplet(parser, true); + + XML_SetStartElementHandler(parser, startElementHandler); + XML_SetEndElementHandler(parser, endElementHandler); + XML_SetCharacterDataHandler(parser, charactersHandler); + XML_SetProcessingInstructionHandler(parser, processingInstructionHandler); + XML_SetCommentHandler(parser, commentHandler); + XML_SetStartCdataSectionHandler(parser, startCdataHandler); + XML_SetEndCdataSectionHandler(parser, endCdataHandler); + + CString cString = string.utf8(); + int result = XML_Parse(parser, cString.data(), cString.length(), true); + + XML_ParserFree(parser); + tokenizer.setXMLParser(0); + + return result != XML_STATUS_ERROR; +} + +// -------------------------------- + +struct AttributeParseState { + HashMap<String, String> attributes; + bool gotAttributes; +}; + +static void attributesStartElementHandler(void *userData, const XML_Char *name, const XML_Char **atts) +{ + if (strcmp(name, "attrs") != 0) + return; + + if (atts[0] == 0 ) + return; + + AttributeParseState *state = static_cast<AttributeParseState *>(userData); + state->gotAttributes = true; + + for (int i = 0; atts[i]; i += 2) { + DeprecatedString attrName = toQString(atts[i]); + DeprecatedString attrValue = toQString(atts[i+1]); + state->attributes.set(attrName, attrValue); + } +} + +HashMap<String, String> parseAttributes(const String& string, bool& attrsOK) +{ + AttributeParseState state; + state.gotAttributes = false; + + XML_Parser parser = XML_ParserCreateNS(NULL, tripletSep); + XML_SetUserData(parser, (void *)&state); + XML_SetReturnNSTriplet(parser, true); + + XML_SetStartElementHandler(parser, attributesStartElementHandler); + String input = "<?xml version=\"1.0\"?><attrs " + string.deprecatedString() + " />"; + CString cString = input.deprecatedString().utf8(); + if ( XML_Parse(parser, cString.data(), cString.length(), true) != XML_STATUS_ERROR ) + attrsOK = state.gotAttributes; + XML_ParserFree(parser); + + return state.attributes; +} + +} |