summaryrefslogtreecommitdiffstats
path: root/WebCore/dom
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/dom')
-rw-r--r--WebCore/dom/ContainerNode.cpp180
-rw-r--r--WebCore/dom/ContainerNode.h18
-rw-r--r--WebCore/dom/DOMImplementation.cpp4
-rw-r--r--WebCore/dom/DeviceOrientationController.cpp17
-rw-r--r--WebCore/dom/Document.cpp574
-rw-r--r--WebCore/dom/Document.h46
-rw-r--r--WebCore/dom/DocumentFragment.cpp6
-rw-r--r--WebCore/dom/DocumentFragment.h2
-rw-r--r--WebCore/dom/DocumentMarkerController.cpp527
-rw-r--r--WebCore/dom/DocumentMarkerController.h72
-rw-r--r--WebCore/dom/DocumentParser.cpp13
-rw-r--r--WebCore/dom/DocumentParser.h32
-rw-r--r--WebCore/dom/Element.cpp11
-rw-r--r--WebCore/dom/EventNames.h3
-rw-r--r--WebCore/dom/EventTarget.cpp10
-rw-r--r--WebCore/dom/EventTarget.h6
-rw-r--r--WebCore/dom/Node.cpp19
-rw-r--r--WebCore/dom/Node.h28
-rw-r--r--WebCore/dom/Position.h2
-rw-r--r--WebCore/dom/RawDataDocumentParser.h7
-rw-r--r--WebCore/dom/ScriptableDocumentParser.h3
-rw-r--r--WebCore/dom/SelectElement.cpp1
-rw-r--r--WebCore/dom/TreeWalker.cpp2
-rw-r--r--WebCore/dom/XMLDocumentParser.cpp52
-rw-r--r--WebCore/dom/XMLDocumentParser.h23
-rw-r--r--WebCore/dom/XMLDocumentParserLibxml2.cpp90
-rw-r--r--WebCore/dom/XMLDocumentParserQt.cpp59
27 files changed, 1039 insertions, 768 deletions
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp
index e559ba7..ef62b38 100644
--- a/WebCore/dom/ContainerNode.cpp
+++ b/WebCore/dom/ContainerNode.cpp
@@ -134,31 +134,12 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
if (child->parentNode())
break;
- ASSERT(!child->nextSibling());
- ASSERT(!child->previousSibling());
-
- // Add child before "next".
- forbidEventDispatch();
- Node* prev = next->previousSibling();
- ASSERT(m_lastChild != prev);
- next->setPreviousSibling(child);
- if (prev) {
- ASSERT(m_firstChild != next);
- ASSERT(prev->nextSibling() == next);
- prev->setNextSibling(child);
- } else {
- ASSERT(m_firstChild == next);
- m_firstChild = child;
- }
- child->setParent(this);
- child->setPreviousSibling(prev);
- child->setNextSibling(next.get());
- allowEventDispatch();
+ insertBeforeCommon(next.get(), child);
// Send notification about the children change.
childrenChanged(false, refChildPreviousSibling.get(), next.get(), 1);
notifyChildInserted(child);
-
+
// Add child to the rendering tree.
if (attached() && !child->attached() && child->parent() == this) {
if (shouldLazyAttach)
@@ -176,6 +157,57 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
return true;
}
+void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild)
+{
+ ASSERT(newChild);
+ ASSERT(!newChild->parent()); // Use insertBefore if you need to handle reparenting (and want DOM mutation events).
+ ASSERT(!newChild->nextSibling());
+ ASSERT(!newChild->previousSibling());
+
+ forbidEventDispatch();
+ Node* prev = nextChild->previousSibling();
+ ASSERT(m_lastChild != prev);
+ nextChild->setPreviousSibling(newChild);
+ if (prev) {
+ ASSERT(m_firstChild != nextChild);
+ ASSERT(prev->nextSibling() == nextChild);
+ prev->setNextSibling(newChild);
+ } else {
+ ASSERT(m_firstChild == nextChild);
+ m_firstChild = newChild;
+ }
+ newChild->setParent(this);
+ newChild->setPreviousSibling(prev);
+ newChild->setNextSibling(nextChild);
+ allowEventDispatch();
+}
+
+void ContainerNode::parserInsertBefore(PassRefPtr<Node> newChild, Node* nextChild)
+{
+ ASSERT(newChild);
+ ASSERT(nextChild);
+ ASSERT(nextChild->parentNode() == this);
+
+ NodeVector targets;
+ collectTargetNodes(newChild.get(), targets);
+ if (targets.isEmpty())
+ return;
+
+ if (nextChild->previousSibling() == newChild || nextChild == newChild) // nothing to do
+ return;
+
+ RefPtr<Node> next = nextChild;
+ RefPtr<Node> nextChildPreviousSibling = nextChild->previousSibling();
+ for (NodeVector::const_iterator it = targets.begin(); it != targets.end(); ++it) {
+ Node* child = it->get();
+
+ insertBeforeCommon(next.get(), child);
+
+ childrenChanged(true, nextChildPreviousSibling.get(), nextChild, 1);
+ notifyChildInserted(child);
+ }
+}
+
bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec, bool shouldLazyAttach)
{
// Check that this node is not "floating".
@@ -367,31 +399,9 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
// that no callers call with ref count == 0 and parent = 0 (as of this
// writing, there are definitely callers who call that way).
- forbidEventDispatch();
-
- // Remove from rendering tree
- if (child->attached())
- child->detach();
-
- // Remove the child
- Node *prev, *next;
- prev = child->previousSibling();
- next = child->nextSibling();
-
- if (next)
- next->setPreviousSibling(prev);
- if (prev)
- prev->setNextSibling(next);
- if (m_firstChild == child)
- m_firstChild = next;
- if (m_lastChild == child)
- m_lastChild = prev;
-
- child->setPreviousSibling(0);
- child->setNextSibling(0);
- child->setParent(0);
-
- allowEventDispatch();
+ Node* prev = child->previousSibling();
+ Node* next = child->nextSibling();
+ removeBetween(prev, next, child.get());
// Dispatch post-removal mutation events
childrenChanged(false, prev, next, -1);
@@ -405,6 +415,50 @@ bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
return child;
}
+void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* oldChild)
+{
+ ASSERT(oldChild);
+ ASSERT(oldChild->parentNode() == this);
+
+ forbidEventDispatch();
+
+ // Remove from rendering tree
+ if (oldChild->attached())
+ oldChild->detach();
+
+ if (nextChild)
+ nextChild->setPreviousSibling(previousChild);
+ if (previousChild)
+ previousChild->setNextSibling(nextChild);
+ if (m_firstChild == oldChild)
+ m_firstChild = nextChild;
+ if (m_lastChild == oldChild)
+ m_lastChild = previousChild;
+
+ oldChild->setPreviousSibling(0);
+ oldChild->setNextSibling(0);
+ oldChild->setParent(0);
+
+ allowEventDispatch();
+}
+
+void ContainerNode::parserRemoveChild(Node* oldChild)
+{
+ ASSERT(oldChild);
+ ASSERT(oldChild->parentNode() == this);
+
+ Node* prev = oldChild->previousSibling();
+ Node* next = oldChild->nextSibling();
+
+ removeBetween(prev, next, oldChild);
+
+ childrenChanged(true, prev, next, -1);
+ if (oldChild->inDocument())
+ oldChild->removedFromDocument();
+ else
+ oldChild->removedFromTree(true);
+}
+
// this differs from other remove functions because it forcibly removes all the children,
// regardless of read-only status or event exceptions, e.g.
bool ContainerNode::removeChildren()
@@ -534,45 +588,27 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
return true;
}
-void ContainerNode::addChildCommon(Node* newChild)
+void ContainerNode::parserAddChild(PassRefPtr<Node> newChild)
{
- ASSERT(!newChild->parent()); // Use appendChild if you need to handle reparenting.
+ ASSERT(newChild);
+ ASSERT(!newChild->parent()); // Use appendChild if you need to handle reparenting (and want DOM mutation events).
+
forbidEventDispatch();
Node* last = m_lastChild;
// FIXME: This method should take a PassRefPtr.
- appendChildToContainer<Node, ContainerNode>(newChild, this);
+ appendChildToContainer<Node, ContainerNode>(newChild.get(), this);
allowEventDispatch();
+ // FIXME: Why doesn't this use notifyChildInserted(newChild) instead?
document()->incDOMTreeVersion();
if (inDocument())
newChild->insertedIntoDocument();
childrenChanged(true, last, 0, 1);
}
-void ContainerNode::parserAddChild(PassRefPtr<Node> newChild)
+void ContainerNode::deprecatedParserAddChild(PassRefPtr<Node> node)
{
- ASSERT(newChild);
- // This function is only used during parsing.
- // It does not send any DOM mutation events or handle reparenting.
-
- addChildCommon(newChild.get());
-}
-
-ContainerNode* ContainerNode::legacyParserAddChild(PassRefPtr<Node> newChild)
-{
- ASSERT(newChild);
- // This function is only used during parsing.
- // It does not send any DOM mutation events.
-
- // Check for consistency with DTD, but only when parsing HTML.
- if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
- return 0;
-
- addChildCommon(newChild.get());
-
- if (newChild->isElementNode())
- return static_cast<ContainerNode*>(newChild.get());
- return this;
+ parserAddChild(node);
}
void ContainerNode::suspendPostAttachCallbacks()
diff --git a/WebCore/dom/ContainerNode.h b/WebCore/dom/ContainerNode.h
index a27d95b..ad0a54a 100644
--- a/WebCore/dom/ContainerNode.h
+++ b/WebCore/dom/ContainerNode.h
@@ -48,8 +48,12 @@ public:
virtual bool removeChild(Node* child, ExceptionCode&);
virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&, bool shouldLazyAttach = false);
- virtual ContainerNode* legacyParserAddChild(PassRefPtr<Node>);
- virtual void parserAddChild(PassRefPtr<Node>);
+ // These methods are only used during parsing.
+ // They don't send DOM mutation events or handle reparenting.
+ // However, arbitrary code may be run by beforeload handlers.
+ void parserAddChild(PassRefPtr<Node>);
+ void parserRemoveChild(Node*);
+ void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild);
bool hasChildNodes() const { return m_firstChild; }
virtual void attach();
@@ -95,8 +99,14 @@ protected:
void setLastChild(Node* child) { m_lastChild = child; }
private:
- // FIXME: This should take a PassRefPtr.
- void addChildCommon(Node*);
+ // Never call this function directly. If you're trying to call this
+ // function, your code is either wrong or you're supposed to call
+ // parserAddChild. Please do not call parserAddChild unless you are the
+ // parser!
+ virtual void deprecatedParserAddChild(PassRefPtr<Node>);
+
+ void removeBetween(Node* previousChild, Node* nextChild, Node* oldChild);
+ void insertBeforeCommon(Node* nextChild, Node* oldChild);
static void dispatchPostAttachCallbacks();
diff --git a/WebCore/dom/DOMImplementation.cpp b/WebCore/dom/DOMImplementation.cpp
index 467f1fc..30e889f 100644
--- a/WebCore/dom/DOMImplementation.cpp
+++ b/WebCore/dom/DOMImplementation.cpp
@@ -258,9 +258,9 @@ PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceUR
// FIXME: Shouldn't this call appendChild instead?
if (doctype)
- doc->legacyParserAddChild(doctype);
+ doc->parserAddChild(doctype);
if (documentElement)
- doc->legacyParserAddChild(documentElement.release());
+ doc->parserAddChild(documentElement.release());
return doc.release();
}
diff --git a/WebCore/dom/DeviceOrientationController.cpp b/WebCore/dom/DeviceOrientationController.cpp
index 111577f..a744366 100644
--- a/WebCore/dom/DeviceOrientationController.cpp
+++ b/WebCore/dom/DeviceOrientationController.cpp
@@ -44,9 +44,9 @@ DeviceOrientationController::DeviceOrientationController(Page* page, DeviceOrien
void DeviceOrientationController::timerFired(Timer<DeviceOrientationController>* timer)
{
ASSERT_UNUSED(timer, timer == &m_timer);
- ASSERT(!m_client || m_client->lastOrientation());
+ ASSERT(m_client->lastOrientation());
- RefPtr<DeviceOrientation> orientation = m_client ? m_client->lastOrientation() : DeviceOrientation::create();
+ RefPtr<DeviceOrientation> orientation = m_client->lastOrientation();
RefPtr<DeviceOrientationEvent> event = DeviceOrientationEvent::create(eventNames().deviceorientationEvent, orientation.get());
Vector<DOMWindow*> listenersVector;
@@ -58,11 +58,10 @@ void DeviceOrientationController::timerFired(Timer<DeviceOrientationController>*
void DeviceOrientationController::addListener(DOMWindow* window)
{
- // If no client is present, we should fire an event with all parameters null. If
- // the client already has an orientation, we should fire an event with that
- // orientation. In both cases, the event is fired asynchronously, but without
+ // If the client already has an orientation, we should fire an event with that
+ // orientation. The event is fired asynchronously, but without
// waiting for the client to get a new orientation.
- if (!m_client || m_client->lastOrientation()) {
+ if (m_client->lastOrientation()) {
m_newListeners.add(window);
if (!m_timer.isActive())
m_timer.startOneShot(0);
@@ -71,7 +70,7 @@ void DeviceOrientationController::addListener(DOMWindow* window)
// The client must not call back synchronously.
bool wasEmpty = m_listeners.isEmpty();
m_listeners.add(window);
- if (wasEmpty && m_client)
+ if (wasEmpty)
m_client->startUpdating();
}
@@ -79,7 +78,7 @@ void DeviceOrientationController::removeListener(DOMWindow* window)
{
m_listeners.remove(window);
m_newListeners.remove(window);
- if (m_listeners.isEmpty() && m_client)
+ if (m_listeners.isEmpty())
m_client->stopUpdating();
}
@@ -91,7 +90,7 @@ void DeviceOrientationController::removeAllListeners(DOMWindow* window)
m_listeners.removeAll(window);
m_newListeners.remove(window);
- if (m_listeners.isEmpty() && m_client)
+ if (m_listeners.isEmpty())
m_client->stopUpdating();
}
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
index 20c6b16..03ad8e7 100644
--- a/WebCore/dom/Document.cpp
+++ b/WebCore/dom/Document.cpp
@@ -89,7 +89,6 @@
#include "InspectorController.h"
#include "InspectorTimelineAgent.h"
#include "KeyboardEvent.h"
-#include "LegacyHTMLTreeBuilder.h"
#include "Logging.h"
#include "MessageEvent.h"
#include "MouseEvent.h"
@@ -123,7 +122,6 @@
#include "StaticHashSetNodeList.h"
#include "StyleSheetList.h"
#include "TextEvent.h"
-#include "TextIterator.h"
#include "TextResourceDecoder.h"
#include "Timer.h"
#include "TransformSource.h"
@@ -165,10 +163,6 @@
#include "XSLTProcessor.h"
#endif
-#if ENABLE(XBL)
-#include "XBLBindingManager.h"
-#endif
-
#if ENABLE(SVG)
#include "SVGDocumentExtensions.h"
#include "SVGElementFactory.h"
@@ -394,9 +388,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_asyncScriptRunner(AsyncScriptRunner::create())
, m_xmlVersion("1.0")
, m_xmlStandalone(false)
-#if ENABLE(XBL)
- , m_bindingManager(new XBLBindingManager(this))
-#endif
, m_savedRenderer(0)
, m_designMode(inherit)
, m_selfOnlyRefCount(0)
@@ -441,8 +432,14 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
#if !PLATFORM(ANDROID)
m_axObjectCache = 0;
+<<<<<<< HEAD
#endif
+=======
+
+ m_markers = new DocumentMarkerController();
+
+>>>>>>> webkit.org at r66079
m_docLoader = new DocLoader(this);
m_visuallyOrdered = false;
@@ -515,10 +512,9 @@ void Document::removedLastRef()
removeAllChildren();
- deleteAllValues(m_markers);
- m_markers.clear();
+ m_markers->detach();
- m_parser.clear();
+ detachParser();
m_cssCanvasElements.clear();
@@ -551,18 +547,19 @@ Document::~Document()
destroyAllWrapperCaches();
#endif
- m_parser.clear();
+ // Currently we believe that Document can never outlive the parser.
+ // Although the Document may be replaced synchronously, DocumentParsers
+ // generally keep at least one reference to an Element which would in turn
+ // has a reference to the Document. If you hit this ASSERT, then that
+ // assumption is wrong. DocumentParser::detach() should ensure that even
+ // if the DocumentParser outlives the Document it won't cause badness.
+ ASSERT(!m_parser || m_parser->refCount() == 1);
+ detachParser();
m_document = 0;
m_docLoader.clear();
m_renderArena.clear();
-#if ENABLE(XBL)
- m_bindingManager.clear();
-#endif
-
- deleteAllValues(m_markers);
-
clearAXObjectCache();
m_decoder = 0;
@@ -1009,8 +1006,11 @@ void Document::setXMLVersion(const String& version, ExceptionCode& ec)
ec = NOT_SUPPORTED_ERR;
return;
}
-
- // FIXME: Also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document.
+
+ if (!XMLDocumentParser::supportsXMLVersion(version)) {
+ ec = NOT_SUPPORTED_ERR;
+ return;
+ }
m_xmlVersion = version;
}
@@ -1514,6 +1514,8 @@ bail_out:
void Document::updateStyleIfNeeded()
{
+ ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
+
if (!childNeedsStyleRecalc() || inPageCache())
return;
@@ -1822,10 +1824,10 @@ void Document::setVisuallyOrdered()
renderer()->style()->setVisuallyOrdered(true);
}
-DocumentParser* Document::createParser()
+PassRefPtr<DocumentParser> Document::createParser()
{
// FIXME: this should probably pass the frame instead
- return new XMLDocumentParser(this, view());
+ return XMLDocumentParser::create(this, view());
}
ScriptableDocumentParser* Document::scriptableDocumentParser() const
@@ -1859,6 +1861,14 @@ void Document::open(Document* ownerDocument)
m_frame->loader()->didExplicitOpen();
}
+void Document::detachParser()
+{
+ if (!m_parser)
+ return;
+ m_parser->detach();
+ m_parser.clear();
+}
+
void Document::cancelParsing()
{
if (m_parser) {
@@ -1866,7 +1876,7 @@ void Document::cancelParsing()
// the onload handler when closing as a side effect of a cancel-style
// change, such as opening a new document or closing the window while
// still parsing
- m_parser.clear();
+ detachParser();
close();
}
}
@@ -1875,8 +1885,6 @@ void Document::implicitOpen()
{
cancelParsing();
- m_parser.clear();
-
removeChildren();
m_parser = createParser();
@@ -1953,6 +1961,26 @@ void Document::close()
}
}
+// FIXME: These settings probably don't work anymore. We should either remove
+// them or make them work properly.
+#ifdef BUILDING_ON_LEOPARD
+static bool shouldCreateImplicitHead(Document* document)
+{
+ ASSERT(document);
+ Settings* settings = document->page() ? document->page()->settings() : 0;
+ return settings ? !settings->needsLeopardMailQuirks() : true;
+}
+#elif defined(BUILDING_ON_TIGER)
+static bool shouldCreateImplicitHead(Document* document)
+{
+ ASSERT(document);
+ Settings* settings = document->page() ? document->page()->settings() : 0;
+ return settings ? !settings->needsTigerMailQuirks() : true;
+}
+#else
+inline bool shouldCreateImplicitHead(Document*) { return true; }
+#endif
+
void Document::implicitClose()
{
// If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached.
@@ -1974,7 +2002,7 @@ void Document::implicitClose()
// We have to clear the parser, in case someone document.write()s from the
// onLoad event handler, as in Radar 3206524.
- m_parser.clear();
+ detachParser();
// Parser should have picked up all preloads by now
m_docLoader->clearPreloads();
@@ -3233,7 +3261,7 @@ void Document::textInserted(Node* text, unsigned offset, unsigned length)
}
// Update the markers for spelling and grammar checking.
- shiftMarkers(text, offset, length);
+ m_markers->shiftMarkers(text, offset, length);
}
void Document::textRemoved(Node* text, unsigned offset, unsigned length)
@@ -3245,8 +3273,8 @@ void Document::textRemoved(Node* text, unsigned offset, unsigned length)
}
// Update the markers for spelling and grammar checking.
- removeMarkers(text, offset, length);
- shiftMarkers(text, offset + length, 0 - length);
+ m_markers->removeMarkers(text, offset, length);
+ m_markers->shiftMarkers(text, offset + length, 0 - length);
}
void Document::textNodesMerged(Text* oldNode, unsigned offset)
@@ -3822,6 +3850,9 @@ static Editor::Command command(Document* document, const String& commandName, bo
Frame* frame = document->frame();
if (!frame || frame->document() != document)
return Editor::Command();
+
+ document->updateStyleIfNeeded();
+
return frame->editor()->command(commandName,
userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
}
@@ -3856,489 +3887,6 @@ String Document::queryCommandValue(const String& commandName)
return command(this, commandName).value();
}
-static IntRect placeholderRectForMarker()
-{
- return IntRect(-1, -1, -1, -1);
-}
-
-void Document::addMarker(Range* range, DocumentMarker::MarkerType type, String description)
-{
- // Use a TextIterator to visit the potentially multiple nodes the range covers.
- for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
- RefPtr<Range> textPiece = markedText.range();
- int exception = 0;
- DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description, false};
- addMarker(textPiece->startContainer(exception), marker);
- }
-}
-
-void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType)
-{
- if (m_markers.isEmpty())
- return;
-
- ExceptionCode ec = 0;
- Node* startContainer = range->startContainer(ec);
- Node* endContainer = range->endContainer(ec);
-
- Node* pastLastNode = range->pastLastNode();
- for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
- int startOffset = node == startContainer ? range->startOffset(ec) : 0;
- int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
- int length = endOffset - startOffset;
- removeMarkers(node, startOffset, length, markerType);
- }
-}
-
-// Markers are stored in order sorted by their start offset.
-// Markers of the same type do not overlap each other.
-
-void Document::addMarker(Node* node, DocumentMarker newMarker)
-{
- ASSERT(newMarker.endOffset >= newMarker.startOffset);
- if (newMarker.endOffset == newMarker.startOffset)
- return;
-
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
-
- if (!vectorPair) {
- vectorPair = new MarkerMapVectorPair;
- vectorPair->first.append(newMarker);
- vectorPair->second.append(placeholderRectForMarker());
- m_markers.set(node, vectorPair);
- } else {
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- size_t numMarkers = markers.size();
- ASSERT(numMarkers == rects.size());
- size_t i;
- // Iterate over all markers whose start offset is less than or equal to the new marker's.
- // If one of them is of the same type as the new marker and touches it or intersects with it
- // (there is at most one), remove it and adjust the new marker's start offset to encompass it.
- for (i = 0; i < numMarkers; ++i) {
- DocumentMarker marker = markers[i];
- if (marker.startOffset > newMarker.startOffset)
- break;
- if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) {
- newMarker.startOffset = marker.startOffset;
- markers.remove(i);
- rects.remove(i);
- numMarkers--;
- break;
- }
- }
- size_t j = i;
- // Iterate over all markers whose end offset is less than or equal to the new marker's,
- // removing markers of the same type as the new marker which touch it or intersect with it,
- // adjusting the new marker's end offset to cover them if necessary.
- while (j < numMarkers) {
- DocumentMarker marker = markers[j];
- if (marker.startOffset > newMarker.endOffset)
- break;
- if (marker.type == newMarker.type) {
- markers.remove(j);
- rects.remove(j);
- if (newMarker.endOffset <= marker.endOffset) {
- newMarker.endOffset = marker.endOffset;
- break;
- }
- numMarkers--;
- } else
- j++;
- }
- // At this point i points to the node before which we want to insert.
- markers.insert(i, newMarker);
- rects.insert(i, placeholderRectForMarker());
- }
-
- // repaint the affected node
- if (node->renderer())
- node->renderer()->repaint();
-}
-
-// copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
-// useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
-void Document::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType markerType)
-{
- if (length <= 0)
- return;
-
- MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
- if (!vectorPair)
- return;
-
- ASSERT(vectorPair->first.size() == vectorPair->second.size());
-
- bool docDirty = false;
- unsigned endOffset = startOffset + length - 1;
- Vector<DocumentMarker>& markers = vectorPair->first;
- for (size_t i = 0; i != markers.size(); ++i) {
- DocumentMarker marker = markers[i];
-
- // stop if we are now past the specified range
- if (marker.startOffset > endOffset)
- break;
-
- // skip marker that is before the specified range or is the wrong type
- if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
- continue;
-
- // pin the marker to the specified range and apply the shift delta
- docDirty = true;
- if (marker.startOffset < startOffset)
- marker.startOffset = startOffset;
- if (marker.endOffset > endOffset)
- marker.endOffset = endOffset;
- marker.startOffset += delta;
- marker.endOffset += delta;
-
- addMarker(dstNode, marker);
- }
-
- // repaint the affected node
- if (docDirty && dstNode->renderer())
- dstNode->renderer()->repaint();
-}
-
-void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType)
-{
- if (length <= 0)
- return;
-
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
- if (!vectorPair)
- return;
-
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- ASSERT(markers.size() == rects.size());
- bool docDirty = false;
- unsigned endOffset = startOffset + length;
- for (size_t i = 0; i < markers.size();) {
- DocumentMarker marker = markers[i];
-
- // markers are returned in order, so stop if we are now past the specified range
- if (marker.startOffset >= endOffset)
- break;
-
- // skip marker that is wrong type or before target
- if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) {
- i++;
- continue;
- }
-
- // at this point we know that marker and target intersect in some way
- docDirty = true;
-
- // pitch the old marker and any associated rect
- markers.remove(i);
- rects.remove(i);
-
- // add either of the resulting slices that are left after removing target
- if (startOffset > marker.startOffset) {
- DocumentMarker newLeft = marker;
- newLeft.endOffset = startOffset;
- markers.insert(i, newLeft);
- rects.insert(i, placeholderRectForMarker());
- // i now points to the newly-inserted node, but we want to skip that one
- i++;
- }
- if (marker.endOffset > endOffset) {
- DocumentMarker newRight = marker;
- newRight.startOffset = endOffset;
- markers.insert(i, newRight);
- rects.insert(i, placeholderRectForMarker());
- // i now points to the newly-inserted node, but we want to skip that one
- i++;
- }
- }
-
- if (markers.isEmpty()) {
- ASSERT(rects.isEmpty());
- m_markers.remove(node);
- delete vectorPair;
- }
-
- // repaint the affected node
- if (docDirty && node->renderer())
- node->renderer()->repaint();
-}
-
-DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
-{
- // outer loop: process each node that contains any markers
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
- // inner loop; process each marker in this node
- MarkerMapVectorPair* vectorPair = nodeIterator->second;
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- ASSERT(markers.size() == rects.size());
- unsigned markerCount = markers.size();
- for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
- DocumentMarker& marker = markers[markerIndex];
-
- // skip marker that is wrong type
- if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
- continue;
-
- IntRect& r = rects[markerIndex];
-
- // skip placeholder rects
- if (r == placeholderRectForMarker())
- continue;
-
- if (r.contains(point))
- return &marker;
- }
- }
-
- return 0;
-}
-
-Vector<DocumentMarker> Document::markersForNode(Node* node)
-{
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
- if (vectorPair)
- return vectorPair->first;
- return Vector<DocumentMarker>();
-}
-
-Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
-{
- Vector<IntRect> result;
-
- // outer loop: process each node
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
- // inner loop; process each marker in this node
- MarkerMapVectorPair* vectorPair = nodeIterator->second;
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- ASSERT(markers.size() == rects.size());
- unsigned markerCount = markers.size();
- for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
- DocumentMarker marker = markers[markerIndex];
-
- // skip marker that is wrong type
- if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
- continue;
-
- IntRect r = rects[markerIndex];
- // skip placeholder rects
- if (r == placeholderRectForMarker())
- continue;
-
- result.append(r);
- }
- }
-
- return result;
-}
-
-void Document::removeMarkers(Node* node)
-{
- MarkerMap::iterator i = m_markers.find(node);
- if (i != m_markers.end()) {
- delete i->second;
- m_markers.remove(i);
- if (RenderObject* renderer = node->renderer())
- renderer->repaint();
- }
-}
-
-void Document::removeMarkers(DocumentMarker::MarkerType markerType)
-{
- // outer loop: process each markered node in the document
- MarkerMap markerMapCopy = m_markers;
- MarkerMap::iterator end = markerMapCopy.end();
- for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
- Node* node = i->first.get();
- bool nodeNeedsRepaint = false;
-
- // inner loop: process each marker in the current node
- MarkerMapVectorPair* vectorPair = i->second;
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- ASSERT(markers.size() == rects.size());
- for (size_t i = 0; i != markers.size();) {
- DocumentMarker marker = markers[i];
-
- // skip nodes that are not of the specified type
- if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) {
- ++i;
- continue;
- }
-
- // pitch the old marker
- markers.remove(i);
- rects.remove(i);
- nodeNeedsRepaint = true;
- // markerIterator now points to the next node
- }
-
- // Redraw the node if it changed. Do this before the node is removed from m_markers, since
- // m_markers might contain the last reference to the node.
- if (nodeNeedsRepaint) {
- RenderObject* renderer = node->renderer();
- if (renderer)
- renderer->repaint();
- }
-
- // delete the node's list if it is now empty
- if (markers.isEmpty()) {
- ASSERT(rects.isEmpty());
- m_markers.remove(node);
- delete vectorPair;
- }
- }
-}
-
-void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
-{
- // outer loop: process each markered node in the document
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
- Node* node = i->first.get();
-
- // inner loop: process each marker in the current node
- MarkerMapVectorPair* vectorPair = i->second;
- Vector<DocumentMarker>& markers = vectorPair->first;
- bool nodeNeedsRepaint = false;
- for (size_t i = 0; i != markers.size(); ++i) {
- DocumentMarker marker = markers[i];
-
- // skip nodes that are not of the specified type
- if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
- nodeNeedsRepaint = true;
- break;
- }
- }
-
- if (!nodeNeedsRepaint)
- continue;
-
- // cause the node to be redrawn
- if (RenderObject* renderer = node->renderer())
- renderer->repaint();
- }
-}
-
-void Document::setRenderedRectForMarker(Node* node, const DocumentMarker& marker, const IntRect& r)
-{
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
- if (!vectorPair) {
- ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
- return;
- }
-
- Vector<DocumentMarker>& markers = vectorPair->first;
- ASSERT(markers.size() == vectorPair->second.size());
- unsigned markerCount = markers.size();
- for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
- DocumentMarker m = markers[markerIndex];
- if (m == marker) {
- vectorPair->second[markerIndex] = r;
- return;
- }
- }
-
- ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
-}
-
-void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
-{
- // outer loop: process each markered node in the document
- MarkerMap::iterator end = m_markers.end();
- for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
-
- // inner loop: process each rect in the current node
- MarkerMapVectorPair* vectorPair = i->second;
- Vector<IntRect>& rects = vectorPair->second;
-
- unsigned rectCount = rects.size();
- for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
- if (rects[rectIndex].intersects(r))
- rects[rectIndex] = placeholderRectForMarker();
- }
-}
-
-void Document::shiftMarkers(Node* node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
-{
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
- if (!vectorPair)
- return;
-
- Vector<DocumentMarker>& markers = vectorPair->first;
- Vector<IntRect>& rects = vectorPair->second;
- ASSERT(markers.size() == rects.size());
-
- bool docDirty = false;
- for (size_t i = 0; i != markers.size(); ++i) {
- DocumentMarker& marker = markers[i];
- if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
- ASSERT((int)marker.startOffset + delta >= 0);
- marker.startOffset += delta;
- marker.endOffset += delta;
- docDirty = true;
-
- // Marker moved, so previously-computed rendered rectangle is now invalid
- rects[i] = placeholderRectForMarker();
- }
- }
-
- // repaint the affected node
- if (docDirty && node->renderer())
- node->renderer()->repaint();
-}
-
-void Document::setMarkersActive(Range* range, bool active)
-{
- if (m_markers.isEmpty())
- return;
-
- ExceptionCode ec = 0;
- Node* startContainer = range->startContainer(ec);
- Node* endContainer = range->endContainer(ec);
-
- Node* pastLastNode = range->pastLastNode();
- for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
- int startOffset = node == startContainer ? range->startOffset(ec) : 0;
- int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
- setMarkersActive(node, startOffset, endOffset, active);
- }
-}
-
-void Document::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
-{
- MarkerMapVectorPair* vectorPair = m_markers.get(node);
- if (!vectorPair)
- return;
-
- Vector<DocumentMarker>& markers = vectorPair->first;
- ASSERT(markers.size() == vectorPair->second.size());
-
- bool docDirty = false;
- for (size_t i = 0; i != markers.size(); ++i) {
- DocumentMarker& marker = markers[i];
-
- // Markers are returned in order, so stop if we are now past the specified range.
- if (marker.startOffset >= endOffset)
- break;
-
- // Skip marker that is wrong type or before target.
- if (marker.endOffset < startOffset || marker.type != DocumentMarker::TextMatch)
- continue;
-
- marker.activeMatch = active;
- docDirty = true;
- }
-
- // repaint the affected node
- if (docDirty && node->renderer())
- node->renderer()->repaint();
-}
-
#if ENABLE(XSLT)
void Document::applyXSLTransform(ProcessingInstruction* pi)
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
index fc57ddb..ff7e646 100644
--- a/WebCore/dom/Document.h
+++ b/WebCore/dom/Document.h
@@ -32,7 +32,7 @@
#include "CollectionType.h"
#include "Color.h"
#include "ContainerNode.h"
-#include "DocumentMarker.h"
+#include "DocumentMarkerController.h"
#include "QualifiedName.h"
#include "ScriptExecutionContext.h"
#include "Timer.h"
@@ -125,10 +125,6 @@ class SVGDocumentExtensions;
class TransformSource;
#endif
-#if ENABLE(XBL)
-class XBLBindingManager;
-#endif
-
#if ENABLE(XPATH)
class XPathEvaluator;
class XPathExpression;
@@ -563,7 +559,7 @@ public:
CSSStyleSheet* elementSheet();
CSSStyleSheet* mappedElementSheet();
- virtual DocumentParser* createParser();
+ virtual PassRefPtr<DocumentParser> createParser();
DocumentParser* parser() const { return m_parser.get(); }
ScriptableDocumentParser* scriptableDocumentParser() const;
@@ -819,6 +815,8 @@ public:
HTMLHeadElement* head();
+ DocumentMarkerController* markers() const { return m_markers.get(); }
+
bool execCommand(const String& command, bool userInterface = false, const String& value = String());
bool queryCommandEnabled(const String& command);
bool queryCommandIndeterm(const String& command);
@@ -826,24 +824,6 @@ public:
bool queryCommandSupported(const String& command);
String queryCommandValue(const String& command);
- void addMarker(Range*, DocumentMarker::MarkerType, String description = String());
- void addMarker(Node*, DocumentMarker);
- void copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void removeMarkers(Range*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void removeMarkers(Node*);
- void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void setRenderedRectForMarker(Node*, const DocumentMarker&, const IntRect&);
- void invalidateRenderedRectsForMarkersInRect(const IntRect&);
- void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- void setMarkersActive(Range*, bool);
- void setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool);
-
- DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
- Vector<DocumentMarker> markersForNode(Node*);
- Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
-
// designMode support
enum InheritedBool { off = false, on = true, inherit };
void setDesignMode(InheritedBool value);
@@ -866,11 +846,6 @@ public:
TransformSource* transformSource() const { return m_transformSource.get(); }
#endif
-#if ENABLE(XBL)
- // XBL methods
- XBLBindingManager* bindingManager() const { return m_bindingManager.get(); }
-#endif
-
void incDOMTreeVersion() { ++m_domTreeVersion; }
unsigned domTreeVersion() const { return m_domTreeVersion; }
@@ -1035,6 +1010,7 @@ protected:
private:
+ void detachParser();
typedef void (*ArgumentsCallback)(const String& keyString, const String& valueString, Document*, void* data);
void processArguments(const String& features, void* data, ArgumentsCallback);
@@ -1079,7 +1055,7 @@ private:
Frame* m_frame;
OwnPtr<DocLoader> m_docLoader;
- OwnPtr<DocumentParser> m_parser;
+ RefPtr<DocumentParser> m_parser;
bool m_wellFormed;
// Document URLs.
@@ -1193,6 +1169,7 @@ private:
OwnPtr<RenderArena> m_renderArena;
+<<<<<<< HEAD
typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair;
typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap;
MarkerMap m_markers;
@@ -1200,6 +1177,10 @@ private:
#if !PLATFORM(ANDROID)
mutable AXObjectCache* m_axObjectCache;
#endif
+=======
+ mutable AXObjectCache* m_axObjectCache;
+ OwnPtr<DocumentMarkerController> m_markers;
+>>>>>>> webkit.org at r66079
Timer<Document> m_updateFocusAppearanceTimer;
@@ -1221,10 +1202,13 @@ private:
RefPtr<Document> m_transformSourceDocument;
#endif
+<<<<<<< HEAD
#if ENABLE(XBL)
OwnPtr<XBLBindingManager> m_bindingManager; // The access point through which documents and elements communicate with XBL.
#endif
+=======
+>>>>>>> webkit.org at r66079
typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName;
ImageMapsByName m_imageMapsByName;
@@ -1327,7 +1311,7 @@ inline bool Node::isDocumentNode() const
// here because it uses a Document method but we really want to inline it
inline Node::Node(Document* document, ConstructionType type)
- : TreeShared<Node>(initialRefCount(type))
+ : TreeShared<ContainerNode>(initialRefCount(type))
, m_document(document)
, m_previous(0)
, m_next(0)
diff --git a/WebCore/dom/DocumentFragment.cpp b/WebCore/dom/DocumentFragment.cpp
index 70e57b9..c9c3020 100644
--- a/WebCore/dom/DocumentFragment.cpp
+++ b/WebCore/dom/DocumentFragment.cpp
@@ -75,12 +75,6 @@ PassRefPtr<Node> DocumentFragment::cloneNode(bool deep)
return clone.release();
}
-bool DocumentFragment::shouldUseLegacyHTMLParser() const
-{
- return document()->page() && document()->page()->settings()
- && !document()->page()->settings()->html5ParserEnabled();
-}
-
void DocumentFragment::parseHTML(const String& source, Element* contextElement, FragmentScriptingPermission scriptingPermission)
{
HTMLDocumentParser::parseDocumentFragment(source, this, contextElement, scriptingPermission);
diff --git a/WebCore/dom/DocumentFragment.h b/WebCore/dom/DocumentFragment.h
index d3dadb8..d588b4e 100644
--- a/WebCore/dom/DocumentFragment.h
+++ b/WebCore/dom/DocumentFragment.h
@@ -39,8 +39,6 @@ public:
private:
DocumentFragment(Document*);
- bool shouldUseLegacyHTMLParser() const;
-
virtual String nodeName() const;
virtual NodeType nodeType() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
diff --git a/WebCore/dom/DocumentMarkerController.cpp b/WebCore/dom/DocumentMarkerController.cpp
new file mode 100644
index 0000000..2b7fd85
--- /dev/null
+++ b/WebCore/dom/DocumentMarkerController.cpp
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "DocumentMarkerController.h"
+
+#include "Node.h"
+#include "Range.h"
+#include "TextIterator.h"
+
+namespace WebCore {
+
+static IntRect placeholderRectForMarker()
+{
+ return IntRect(-1, -1, -1, -1);
+}
+
+void DocumentMarkerController::detach()
+{
+ if (m_markers.isEmpty())
+ return;
+ deleteAllValues(m_markers);
+ m_markers.clear();
+}
+
+void DocumentMarkerController::addMarker(Range* range, DocumentMarker::MarkerType type, String description)
+{
+ // Use a TextIterator to visit the potentially multiple nodes the range covers.
+ for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
+ RefPtr<Range> textPiece = markedText.range();
+ int exception = 0;
+ DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description, false};
+ addMarker(textPiece->startContainer(exception), marker);
+ }
+}
+
+void DocumentMarkerController::removeMarkers(Range* range, DocumentMarker::MarkerType markerType)
+{
+ if (m_markers.isEmpty())
+ return;
+
+ ExceptionCode ec = 0;
+ Node* startContainer = range->startContainer(ec);
+ Node* endContainer = range->endContainer(ec);
+
+ Node* pastLastNode = range->pastLastNode();
+ for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
+ int startOffset = node == startContainer ? range->startOffset(ec) : 0;
+ int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
+ int length = endOffset - startOffset;
+ removeMarkers(node, startOffset, length, markerType);
+ }
+}
+
+// Markers are stored in order sorted by their start offset.
+// Markers of the same type do not overlap each other.
+
+void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker)
+{
+ ASSERT(newMarker.endOffset >= newMarker.startOffset);
+ if (newMarker.endOffset == newMarker.startOffset)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+
+ if (!vectorPair) {
+ vectorPair = new MarkerMapVectorPair;
+ vectorPair->first.append(newMarker);
+ vectorPair->second.append(placeholderRectForMarker());
+ m_markers.set(node, vectorPair);
+ } else {
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ size_t numMarkers = markers.size();
+ ASSERT(numMarkers == rects.size());
+ size_t i;
+ // Iterate over all markers whose start offset is less than or equal to the new marker's.
+ // If one of them is of the same type as the new marker and touches it or intersects with it
+ // (there is at most one), remove it and adjust the new marker's start offset to encompass it.
+ for (i = 0; i < numMarkers; ++i) {
+ DocumentMarker marker = markers[i];
+ if (marker.startOffset > newMarker.startOffset)
+ break;
+ if (marker.type == newMarker.type && marker.endOffset >= newMarker.startOffset) {
+ newMarker.startOffset = marker.startOffset;
+ markers.remove(i);
+ rects.remove(i);
+ numMarkers--;
+ break;
+ }
+ }
+ size_t j = i;
+ // Iterate over all markers whose end offset is less than or equal to the new marker's,
+ // removing markers of the same type as the new marker which touch it or intersect with it,
+ // adjusting the new marker's end offset to cover them if necessary.
+ while (j < numMarkers) {
+ DocumentMarker marker = markers[j];
+ if (marker.startOffset > newMarker.endOffset)
+ break;
+ if (marker.type == newMarker.type) {
+ markers.remove(j);
+ rects.remove(j);
+ if (newMarker.endOffset <= marker.endOffset) {
+ newMarker.endOffset = marker.endOffset;
+ break;
+ }
+ numMarkers--;
+ } else
+ j++;
+ }
+ // At this point i points to the node before which we want to insert.
+ markers.insert(i, newMarker);
+ rects.insert(i, placeholderRectForMarker());
+ }
+
+ // repaint the affected node
+ if (node->renderer())
+ node->renderer()->repaint();
+}
+
+// copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
+// useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
+void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType markerType)
+{
+ if (length <= 0)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
+ if (!vectorPair)
+ return;
+
+ ASSERT(vectorPair->first.size() == vectorPair->second.size());
+
+ bool docDirty = false;
+ unsigned endOffset = startOffset + length - 1;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker marker = markers[i];
+
+ // stop if we are now past the specified range
+ if (marker.startOffset > endOffset)
+ break;
+
+ // skip marker that is before the specified range or is the wrong type
+ if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
+ continue;
+
+ // pin the marker to the specified range and apply the shift delta
+ docDirty = true;
+ if (marker.startOffset < startOffset)
+ marker.startOffset = startOffset;
+ if (marker.endOffset > endOffset)
+ marker.endOffset = endOffset;
+ marker.startOffset += delta;
+ marker.endOffset += delta;
+
+ addMarker(dstNode, marker);
+ }
+
+ // repaint the affected node
+ if (docDirty && dstNode->renderer())
+ dstNode->renderer()->repaint();
+}
+
+void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType)
+{
+ if (length <= 0)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair)
+ return;
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ bool docDirty = false;
+ unsigned endOffset = startOffset + length;
+ for (size_t i = 0; i < markers.size();) {
+ DocumentMarker marker = markers[i];
+
+ // markers are returned in order, so stop if we are now past the specified range
+ if (marker.startOffset >= endOffset)
+ break;
+
+ // skip marker that is wrong type or before target
+ if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) {
+ i++;
+ continue;
+ }
+
+ // at this point we know that marker and target intersect in some way
+ docDirty = true;
+
+ // pitch the old marker and any associated rect
+ markers.remove(i);
+ rects.remove(i);
+
+ // add either of the resulting slices that are left after removing target
+ if (startOffset > marker.startOffset) {
+ DocumentMarker newLeft = marker;
+ newLeft.endOffset = startOffset;
+ markers.insert(i, newLeft);
+ rects.insert(i, placeholderRectForMarker());
+ // i now points to the newly-inserted node, but we want to skip that one
+ i++;
+ }
+ if (marker.endOffset > endOffset) {
+ DocumentMarker newRight = marker;
+ newRight.startOffset = endOffset;
+ markers.insert(i, newRight);
+ rects.insert(i, placeholderRectForMarker());
+ // i now points to the newly-inserted node, but we want to skip that one
+ i++;
+ }
+ }
+
+ if (markers.isEmpty()) {
+ ASSERT(rects.isEmpty());
+ m_markers.remove(node);
+ delete vectorPair;
+ }
+
+ // repaint the affected node
+ if (docDirty && node->renderer())
+ node->renderer()->repaint();
+}
+
+DocumentMarker* DocumentMarkerController::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each node that contains any markers
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
+ // inner loop; process each marker in this node
+ MarkerMapVectorPair* vectorPair = nodeIterator->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker& marker = markers[markerIndex];
+
+ // skip marker that is wrong type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ continue;
+
+ IntRect& r = rects[markerIndex];
+
+ // skip placeholder rects
+ if (r == placeholderRectForMarker())
+ continue;
+
+ if (r.contains(point))
+ return &marker;
+ }
+ }
+
+ return 0;
+}
+
+Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (vectorPair)
+ return vectorPair->first;
+ return Vector<DocumentMarker>();
+}
+
+Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
+{
+ Vector<IntRect> result;
+
+ // outer loop: process each node
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
+ // inner loop; process each marker in this node
+ MarkerMapVectorPair* vectorPair = nodeIterator->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker marker = markers[markerIndex];
+
+ // skip marker that is wrong type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ continue;
+
+ IntRect r = rects[markerIndex];
+ // skip placeholder rects
+ if (r == placeholderRectForMarker())
+ continue;
+
+ result.append(r);
+ }
+ }
+
+ return result;
+}
+
+void DocumentMarkerController::removeMarkers(Node* node)
+{
+ MarkerMap::iterator i = m_markers.find(node);
+ if (i != m_markers.end()) {
+ delete i->second;
+ m_markers.remove(i);
+ if (RenderObject* renderer = node->renderer())
+ renderer->repaint();
+ }
+}
+
+void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap markerMapCopy = m_markers;
+ MarkerMap::iterator end = markerMapCopy.end();
+ for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
+ Node* node = i->first.get();
+ bool nodeNeedsRepaint = false;
+
+ // inner loop: process each marker in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ for (size_t i = 0; i != markers.size();) {
+ DocumentMarker marker = markers[i];
+
+ // skip nodes that are not of the specified type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) {
+ ++i;
+ continue;
+ }
+
+ // pitch the old marker
+ markers.remove(i);
+ rects.remove(i);
+ nodeNeedsRepaint = true;
+ // markerIterator now points to the next node
+ }
+
+ // Redraw the node if it changed. Do this before the node is removed from m_markers, since
+ // m_markers might contain the last reference to the node.
+ if (nodeNeedsRepaint) {
+ RenderObject* renderer = node->renderer();
+ if (renderer)
+ renderer->repaint();
+ }
+
+ // delete the node's list if it is now empty
+ if (markers.isEmpty()) {
+ ASSERT(rects.isEmpty());
+ m_markers.remove(node);
+ delete vectorPair;
+ }
+ }
+}
+
+void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
+ Node* node = i->first.get();
+
+ // inner loop: process each marker in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ bool nodeNeedsRepaint = false;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker marker = markers[i];
+
+ // skip nodes that are not of the specified type
+ if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
+ nodeNeedsRepaint = true;
+ break;
+ }
+ }
+
+ if (!nodeNeedsRepaint)
+ continue;
+
+ // cause the node to be redrawn
+ if (RenderObject* renderer = node->renderer())
+ renderer->repaint();
+ }
+}
+
+void DocumentMarkerController::setRenderedRectForMarker(Node* node, const DocumentMarker& marker, const IntRect& r)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair) {
+ ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
+ return;
+ }
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ ASSERT(markers.size() == vectorPair->second.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker m = markers[markerIndex];
+ if (m == marker) {
+ vectorPair->second[markerIndex] = r;
+ return;
+ }
+ }
+
+ ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
+}
+
+void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
+
+ // inner loop: process each rect in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<IntRect>& rects = vectorPair->second;
+
+ unsigned rectCount = rects.size();
+ for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
+ if (rects[rectIndex].intersects(r))
+ rects[rectIndex] = placeholderRectForMarker();
+ }
+}
+
+void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair)
+ return;
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+
+ bool docDirty = false;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker& marker = markers[i];
+ if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
+ ASSERT((int)marker.startOffset + delta >= 0);
+ marker.startOffset += delta;
+ marker.endOffset += delta;
+ docDirty = true;
+
+ // Marker moved, so previously-computed rendered rectangle is now invalid
+ rects[i] = placeholderRectForMarker();
+ }
+ }
+
+ // repaint the affected node
+ if (docDirty && node->renderer())
+ node->renderer()->repaint();
+}
+
+void DocumentMarkerController::setMarkersActive(Range* range, bool active)
+{
+ if (m_markers.isEmpty())
+ return;
+
+ ExceptionCode ec = 0;
+ Node* startContainer = range->startContainer(ec);
+ Node* endContainer = range->endContainer(ec);
+
+ Node* pastLastNode = range->pastLastNode();
+ for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
+ int startOffset = node == startContainer ? range->startOffset(ec) : 0;
+ int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
+ setMarkersActive(node, startOffset, endOffset, active);
+ }
+}
+
+void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair)
+ return;
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ ASSERT(markers.size() == vectorPair->second.size());
+
+ bool docDirty = false;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker& marker = markers[i];
+
+ // Markers are returned in order, so stop if we are now past the specified range.
+ if (marker.startOffset >= endOffset)
+ break;
+
+ // Skip marker that is wrong type or before target.
+ if (marker.endOffset < startOffset || marker.type != DocumentMarker::TextMatch)
+ continue;
+
+ marker.activeMatch = active;
+ docDirty = true;
+ }
+
+ // repaint the affected node
+ if (docDirty && node->renderer())
+ node->renderer()->repaint();
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/DocumentMarkerController.h b/WebCore/dom/DocumentMarkerController.h
new file mode 100644
index 0000000..8921baa
--- /dev/null
+++ b/WebCore/dom/DocumentMarkerController.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DocumentMarkerController_h
+#define DocumentMarkerController_h
+
+#include "DocumentMarker.h"
+#include <wtf/HashMap.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class IntPoint;
+class IntRect;
+class Node;
+class Range;
+
+class DocumentMarkerController : public Noncopyable {
+public:
+ ~DocumentMarkerController() { detach(); }
+
+ void detach();
+ void addMarker(Range*, DocumentMarker::MarkerType, String description = String());
+ void addMarker(Node*, DocumentMarker);
+ void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Range*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Node*);
+ void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void setRenderedRectForMarker(Node*, const DocumentMarker&, const IntRect&);
+ void invalidateRenderedRectsForMarkersInRect(const IntRect&);
+ void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void setMarkersActive(Range*, bool);
+ void setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool);
+
+ DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ Vector<DocumentMarker> markersForNode(Node*);
+ Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+
+private:
+ typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair;
+ typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap;
+ MarkerMap m_markers;
+};
+
+} // namespace WebCore
+
+#endif // DocumentMarkerController_h
diff --git a/WebCore/dom/DocumentParser.cpp b/WebCore/dom/DocumentParser.cpp
index b80927c..cc4c61b 100644
--- a/WebCore/dom/DocumentParser.cpp
+++ b/WebCore/dom/DocumentParser.cpp
@@ -37,5 +37,18 @@ DocumentParser::DocumentParser(Document* document)
ASSERT(document);
}
+DocumentParser::~DocumentParser()
+{
+ // Document is expected to call detach() before releasing its ref.
+ // This ASSERT is slightly awkward for parsers with a fragment case
+ // as there is no Document to release the ref.
+ ASSERT(!m_document);
+}
+
+void DocumentParser::detach()
+{
+ m_document = 0;
+}
+
};
diff --git a/WebCore/dom/DocumentParser.h b/WebCore/dom/DocumentParser.h
index e942d1f..3c28856 100644
--- a/WebCore/dom/DocumentParser.h
+++ b/WebCore/dom/DocumentParser.h
@@ -24,19 +24,18 @@
#ifndef DocumentParser_h
#define DocumentParser_h
-#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
class Document;
class DocumentWriter;
-class LegacyHTMLTreeBuilder;
class SegmentedString;
class ScriptableDocumentParser;
-class DocumentParser : public Noncopyable {
+class DocumentParser : public RefCounted<DocumentParser> {
public:
- virtual ~DocumentParser() { }
+ virtual ~DocumentParser();
virtual ScriptableDocumentParser* asScriptableDocumentParser() { return 0; }
@@ -56,17 +55,27 @@ public:
virtual void finish() = 0;
virtual bool finishWasCalled() = 0;
- virtual void stopParsing() { m_parserStopped = true; }
// FIXME: processingData() is only used by DocumentLoader::isLoadingInAPISense
// and is very unclear as to what it actually means. The LegacyHTMLDocumentParser
// used to implements it.
virtual bool processingData() const { return false; }
- // FIXME: Exposed for HTMLFormControlElement::removedFromTree. HTML DOM
- // code should not need to reach into implementation details of the parser.
- virtual LegacyHTMLTreeBuilder* htmlTreeBuilder() const { return 0; }
-
- Document* document() const { return m_document; }
+ // document() will return 0 after detach() is called.
+ Document* document() const { ASSERT(m_document); return m_document; }
+ bool isDetached() const { return !m_document; }
+
+ // Document is expected to detach the parser before releasing its ref.
+ // After detach, m_document is cleared. The parser will unwind its
+ // callstacks, but not produce any more nodes.
+ // It is impossible for the parser to touch the rest of WebCore after
+ // detach is called.
+ virtual void detach();
+
+ // stopParsing() is used when a load is canceled/stopped.
+ // stopParsing() is currently different from detach(), but shouldn't be.
+ // It should NOT be ok to call any methods on DocumentParser after either
+ // detach() or stopParsing() but right now only detach() will ASSERT.
+ virtual void stopParsing() { m_parserStopped = true; }
protected:
DocumentParser(Document*);
@@ -74,9 +83,12 @@ protected:
// The parser has buffers, so parsing may continue even after
// it stops receiving data. We use m_parserStopped to stop the parser
// even when it has buffered data.
+ // FIXME: m_document = 0 could be changed to mean "parser stopped".
bool m_parserStopped;
+private:
// Every DocumentParser needs a pointer back to the document.
+ // m_document will be 0 after the parser is stopped.
Document* m_document;
};
diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp
index 849b900..2d44f62 100644
--- a/WebCore/dom/Element.cpp
+++ b/WebCore/dom/Element.cpp
@@ -1213,6 +1213,11 @@ void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicStrin
if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
return;
+ if (namespaceURI.isNull() && !prefix.isNull()) {
+ ec = NAMESPACE_ERR;
+ return;
+ }
+
QualifiedName qName(prefix, localName, namespaceURI);
if (scriptingPermission == FragmentScriptingNotAllowed && (isEventHandlerAttribute(qName) || isAttributeToRemove(qName, value)))
@@ -1293,9 +1298,6 @@ void Element::focus(bool restorePreviousSelection)
if (doc->focusedNode() == this)
return;
- if (!supportsFocus())
- return;
-
// If the stylesheets have already been loaded we can reliably check isFocusable.
// If not, we continue and set the focused node on the focus controller below so
// that it can be updated soon after attach.
@@ -1305,6 +1307,9 @@ void Element::focus(bool restorePreviousSelection)
return;
}
+ if (!supportsFocus())
+ return;
+
RefPtr<Node> protect;
if (Page* page = doc->page()) {
// Focus and change event handlers can cause us to lose our last ref.
diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h
index 4c5a08a..85fe69b 100644
--- a/WebCore/dom/EventNames.h
+++ b/WebCore/dom/EventNames.h
@@ -103,6 +103,9 @@ namespace WebCore {
macro(textInput) \
macro(unload) \
macro(updateready) \
+ macro(write) \
+ macro(writeend) \
+ macro(writestart) \
macro(zoom) \
\
macro(DOMActivate) \
diff --git a/WebCore/dom/EventTarget.cpp b/WebCore/dom/EventTarget.cpp
index 42a153a..effd2a2 100644
--- a/WebCore/dom/EventTarget.cpp
+++ b/WebCore/dom/EventTarget.cpp
@@ -162,12 +162,22 @@ FileReader* EventTarget::toFileReader()
return 0;
}
#endif
+#if ENABLE(FILE_WRITER)
+FileWriter* EventTarget::toFileWriter()
+{
+ return 0;
+}
+#endif
#if ENABLE(INDEXED_DATABASE)
IDBRequest* EventTarget::toIDBRequest()
{
return 0;
}
+IDBTransaction* EventTarget::toIDBTransaction()
+{
+ return 0;
+}
#endif
bool EventTarget::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
diff --git a/WebCore/dom/EventTarget.h b/WebCore/dom/EventTarget.h
index b4aa542..b2985f7 100644
--- a/WebCore/dom/EventTarget.h
+++ b/WebCore/dom/EventTarget.h
@@ -48,7 +48,9 @@ namespace WebCore {
class EventListener;
class EventSource;
class FileReader;
+ class FileWriter;
class IDBRequest;
+ class IDBTransaction;
class MessagePort;
class Node;
class Notification;
@@ -122,9 +124,13 @@ namespace WebCore {
#if ENABLE(BLOB)
virtual FileReader* toFileReader();
#endif
+#if ENABLE(FILE_WRITER)
+ virtual FileWriter* toFileWriter();
+#endif
#if ENABLE(INDEXED_DATABASE)
virtual IDBRequest* toIDBRequest();
+ virtual IDBTransaction* toIDBTransaction();
#endif
virtual ScriptExecutionContext* scriptExecutionContext() const = 0;
diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp
index 98fb2e5..2c63b62 100644
--- a/WebCore/dom/Node.cpp
+++ b/WebCore/dom/Node.cpp
@@ -646,14 +646,8 @@ const AtomicString& Node::virtualNamespaceURI() const
return nullAtom;
}
-ContainerNode* Node::legacyParserAddChild(PassRefPtr<Node>)
+void Node::deprecatedParserAddChild(PassRefPtr<Node>)
{
- return 0;
-}
-
-void Node::parserAddChild(PassRefPtr<Node>)
-{
- ASSERT_NOT_REACHED();
}
bool Node::isContentEditable() const
@@ -1235,11 +1229,6 @@ bool Node::contains(const Node* node) const
return this == node || node->isDescendantOf(this);
}
-bool Node::childAllowed(Node* newChild)
-{
- return childTypeAllowed(newChild->nodeType());
-}
-
void Node::attach()
{
ASSERT(!attached());
@@ -2377,9 +2366,7 @@ void Node::getSubresourceURLs(ListHashSet<KURL>& urls) const
ContainerNode* Node::eventParentNode()
{
- Node* parent = parentNode();
- ASSERT(!parent || parent->isContainerNode());
- return static_cast<ContainerNode*>(parent);
+ return parentNode();
}
Node* Node::enclosingLinkEventParentOrSelf()
@@ -2668,7 +2655,7 @@ static inline SVGElementInstance* eventTargetAsSVGElementInstance(Node* referenc
if (!n->isShadowNode() || !n->isSVGElement())
continue;
- Node* shadowTreeParentElement = n->shadowParentNode();
+ ContainerNode* shadowTreeParentElement = n->shadowParentNode();
ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h
index a1a8878..e4e2b4a 100644
--- a/WebCore/dom/Node.h
+++ b/WebCore/dom/Node.h
@@ -86,8 +86,7 @@ enum StyleChangeType {
SyntheticStyleChange = 3 << nodeStyleChangeShift
};
-// this class implements nodes, which can have a parent but no children:
-class Node : public EventTarget, public TreeShared<Node>, public ScriptWrappable {
+class Node : public EventTarget, public TreeShared<ContainerNode>, public ScriptWrappable {
friend class Document;
public:
enum NodeType {
@@ -134,7 +133,7 @@ public:
virtual String nodeValue() const;
virtual void setNodeValue(const String&, ExceptionCode&);
virtual NodeType nodeType() const = 0;
- Node* parentNode() const { return parent(); }
+ ContainerNode* parentNode() const { return parent(); }
Element* parentElement() const;
Node* previousSibling() const { return m_previous; }
Node* nextSibling() const { return m_next; }
@@ -209,7 +208,7 @@ public:
virtual bool isCharacterDataNode() const { return false; }
bool isDocumentNode() const;
virtual bool isShadowNode() const { return false; }
- virtual Node* shadowParentNode() { return 0; }
+ virtual ContainerNode* shadowParentNode() { return 0; }
Node* shadowAncestorNode();
Node* shadowTreeRootNode();
bool isInShadowTree();
@@ -259,14 +258,9 @@ public:
Element* rootEditableElement() const;
bool inSameContainingBlockFlowElement(Node*);
-
- // Used by the parser. Checks against the DTD, unlike DOM operations like appendChild().
- // Also does not dispatch DOM mutation events.
- // Returns the appropriate container node for future insertions as you parse, or 0 for failure.
- virtual ContainerNode* legacyParserAddChild(PassRefPtr<Node>);
- // addChild is tied into the logic of the LegacyHTMLTreeBuilder. We need
- // a "clean" version to use for the HTML5 version of the HTMLTreeBuilder.
- virtual void parserAddChild(PassRefPtr<Node>);
+
+ // FIXME: All callers of this function are almost certainly wrong!
+ virtual void deprecatedParserAddChild(PassRefPtr<Node>);
// Called by the parser when this element's close tag is reached,
// signaling that all child tags have been parsed and added.
@@ -427,11 +421,9 @@ public:
bool isDescendantOf(const Node*) const;
bool contains(const Node*) const;
- // These two methods are mutually exclusive. The former is used to do strict error-checking
- // when adding children via the public DOM API (e.g., appendChild()). The latter is called only when parsing,
- // to sanity-check against the DTD for error recovery.
+ // This method is used to do strict error-checking when adding children via
+ // the public DOM API (e.g., appendChild()).
void checkAddChild(Node* newChild, ExceptionCode&); // Error-checking when adding via the DOM API
- virtual bool childAllowed(Node* newChild); // Error-checking during parsing that checks the DTD
void checkReplaceChild(Node* newChild, Node* oldChild, ExceptionCode&);
virtual bool canReplaceChild(Node* newChild, Node* oldChild);
@@ -606,8 +598,8 @@ public:
*/
virtual bool disabled() const;
- using TreeShared<Node>::ref;
- using TreeShared<Node>::deref;
+ using TreeShared<ContainerNode>::ref;
+ using TreeShared<ContainerNode>::deref;
virtual EventTargetData* eventTargetData();
virtual EventTargetData* ensureEventTargetData();
diff --git a/WebCore/dom/Position.h b/WebCore/dom/Position.h
index 9f2ee24..552d675 100644
--- a/WebCore/dom/Position.h
+++ b/WebCore/dom/Position.h
@@ -26,9 +26,9 @@
#ifndef Position_h
#define Position_h
+#include "ContainerNode.h"
#include "TextAffinity.h"
#include "TextDirection.h"
-#include "Node.h" // for position creation functions
#include <wtf/Assertions.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
diff --git a/WebCore/dom/RawDataDocumentParser.h b/WebCore/dom/RawDataDocumentParser.h
index 2eb3d0a..093ddaf 100644
--- a/WebCore/dom/RawDataDocumentParser.h
+++ b/WebCore/dom/RawDataDocumentParser.h
@@ -31,17 +31,16 @@
namespace WebCore {
class RawDataDocumentParser : public DocumentParser {
-public:
+protected:
RawDataDocumentParser(Document* document)
: DocumentParser(document)
{
}
-protected:
virtual void finish()
{
- if (!m_parserStopped)
- m_document->finishedParsing();
+ if (!m_parserStopped && !isDetached())
+ document()->finishedParsing();
}
private:
diff --git a/WebCore/dom/ScriptableDocumentParser.h b/WebCore/dom/ScriptableDocumentParser.h
index f5f2e42..e2b3f09 100644
--- a/WebCore/dom/ScriptableDocumentParser.h
+++ b/WebCore/dom/ScriptableDocumentParser.h
@@ -52,9 +52,6 @@ public:
XSSAuditor* xssAuditor() const { return m_xssAuditor; }
void setXSSAuditor(XSSAuditor* auditor) { m_xssAuditor = auditor; }
- // Exposed for LegacyHTMLTreeBuilder::reportErrorToConsole
- virtual bool processingContentWrittenByScript() const { return false; }
-
protected:
ScriptableDocumentParser(Document*, bool viewSourceMode = false);
diff --git a/WebCore/dom/SelectElement.cpp b/WebCore/dom/SelectElement.cpp
index e9958a2..0ca6cb3 100644
--- a/WebCore/dom/SelectElement.cpp
+++ b/WebCore/dom/SelectElement.cpp
@@ -554,6 +554,7 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element
handled = true;
}
#else
+ UNUSED_PARAM(htmlForm);
const Vector<Element*>& listItems = data.listItems(element);
int listIndex = optionToListIndex(data, element, selectedIndex(data, element));
diff --git a/WebCore/dom/TreeWalker.cpp b/WebCore/dom/TreeWalker.cpp
index 9c46fb3..6a8ca87 100644
--- a/WebCore/dom/TreeWalker.cpp
+++ b/WebCore/dom/TreeWalker.cpp
@@ -153,6 +153,7 @@ Node* TreeWalker::previousSibling(ScriptState* state)
case NodeFilter::FILTER_SKIP:
if (sibling->lastChild()) {
sibling = sibling->lastChild();
+ node = sibling;
continue;
}
break;
@@ -189,6 +190,7 @@ Node* TreeWalker::nextSibling(ScriptState* state)
case NodeFilter::FILTER_SKIP:
if (sibling->firstChild()) {
sibling = sibling->firstChild();
+ node = sibling;
continue;
}
break;
diff --git a/WebCore/dom/XMLDocumentParser.cpp b/WebCore/dom/XMLDocumentParser.cpp
index 3d2f324..c6d9f89 100644
--- a/WebCore/dom/XMLDocumentParser.cpp
+++ b/WebCore/dom/XMLDocumentParser.cpp
@@ -132,7 +132,7 @@ void XMLDocumentParser::append(const SegmentedString& s)
if (m_sawXSLTransform || !m_sawFirstElement)
m_originalSourceForTransform += parseString;
- if (m_parserStopped || m_sawXSLTransform)
+ if (isDetached() || m_parserStopped || m_sawXSLTransform)
return;
if (m_parserPaused) {
@@ -170,16 +170,14 @@ void XMLDocumentParser::handleError(ErrorType type, const char* m, int lineNumbe
stopParsing();
}
-bool XMLDocumentParser::enterText()
+void XMLDocumentParser::enterText()
{
#if !USE(QXMLSTREAM)
ASSERT(m_bufferedText.size() == 0);
#endif
RefPtr<Node> newNode = Text::create(document(), "");
- if (!m_currentNode->legacyParserAddChild(newNode.get()))
- return false;
+ m_currentNode->deprecatedParserAddChild(newNode.get());
pushCurrentNode(newNode.get());
- return true;
}
#if !USE(QXMLSTREAM)
@@ -211,8 +209,18 @@ void XMLDocumentParser::exitText()
popCurrentNode();
}
+void XMLDocumentParser::detach()
+{
+ clearCurrentNodeStack();
+ ScriptableDocumentParser::detach();
+}
+
void XMLDocumentParser::end()
{
+ // XMLDocumentParserLibxml2 will do bad things to the document if doEnd() is called.
+ // I don't believe XMLDocumentParserQt needs doEnd called in the fragment case.
+ ASSERT(!m_parsingFragment);
+
doEnd();
// doEnd() could process a script tag, thus pausing parsing.
@@ -227,12 +235,16 @@ void XMLDocumentParser::end()
}
clearCurrentNodeStack();
- if (!m_parsingFragment)
- document()->finishedParsing();
+ document()->finishedParsing();
}
void XMLDocumentParser::finish()
{
+ // FIXME: We should ASSERT(!m_parserStopped) here, since it does not
+ // makes sense to call any methods on DocumentParser once it's been stopped.
+ // However, FrameLoader::stop calls Document::finishParsing unconditionally
+ // which in turn calls m_parser->finish().
+
if (m_parserPaused)
m_finishCalled = true;
else
@@ -338,6 +350,9 @@ void XMLDocumentParser::notifyFinished(CachedResource* unusedResource)
ScriptElement* scriptElement = toScriptElement(e.get());
ASSERT(scriptElement);
+ // JavaScript can detach this parser, make sure it's kept alive even if detached.
+ RefPtr<XMLDocumentParser> protect(this);
+
if (errorOccurred)
scriptElement->dispatchErrorEvent();
else {
@@ -347,7 +362,7 @@ void XMLDocumentParser::notifyFinished(CachedResource* unusedResource)
m_scriptElement = 0;
- if (!m_requestingScript)
+ if (!isDetached() && !m_requestingScript)
resumeParsing();
}
@@ -364,4 +379,25 @@ void XMLDocumentParser::pauseParsing()
m_parserPaused = true;
}
+bool XMLDocumentParser::parseDocumentFragment(const String& chunk, DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission)
+{
+ if (!chunk.length())
+ return true;
+
+ // FIXME: We need to implement the HTML5 XML Fragment parsing algorithm:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-xhtml-syntax.html#xml-fragment-parsing-algorithm
+ // For now we have a hack for script/style innerHTML support:
+ if (contextElement && (contextElement->hasLocalName(HTMLNames::scriptTag) || contextElement->hasLocalName(HTMLNames::styleTag))) {
+ fragment->parserAddChild(fragment->document()->createTextNode(chunk));
+ return true;
+ }
+
+ RefPtr<XMLDocumentParser> parser = XMLDocumentParser::create(fragment, contextElement, scriptingPermission);
+ bool wellFormed = parser->appendFragmentSource(chunk);
+ // Do not call finish(). Current finish() and doEnd() implementations touch the main Document/loader
+ // and can cause crashes in the fragment case.
+ parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction.
+ return wellFormed; // appendFragmentSource()'s wellFormed is more permissive than wellFormed().
}
+
+} // namespace WebCore
diff --git a/WebCore/dom/XMLDocumentParser.h b/WebCore/dom/XMLDocumentParser.h
index 141adf7..4211e4e 100644
--- a/WebCore/dom/XMLDocumentParser.h
+++ b/WebCore/dom/XMLDocumentParser.h
@@ -181,8 +181,15 @@ namespace WebCore {
class XMLDocumentParser : public ScriptableDocumentParser, public CachedResourceClient {
public:
- XMLDocumentParser(Document*, FrameView* = 0);
- XMLDocumentParser(DocumentFragment*, Element*, FragmentScriptingPermission);
+ static PassRefPtr<XMLDocumentParser> create(Document* document, FrameView* view)
+ {
+ return adoptRef(new XMLDocumentParser(document, view));
+ }
+ static PassRefPtr<XMLDocumentParser> create(DocumentFragment* fragment, Element* element, FragmentScriptingPermission permission)
+ {
+ return adoptRef(new XMLDocumentParser(fragment, element, permission));
+ }
+
~XMLDocumentParser();
// Exposed for callbacks:
@@ -199,14 +206,19 @@ namespace WebCore {
bool isWMLDocument() const;
#endif
- static bool parseDocumentFragment(const String&, DocumentFragment*, Element* parent = 0, FragmentScriptingPermission = FragmentScriptingAllowed);
+ static bool parseDocumentFragment(const String&, DocumentFragment*, Element* parent = 0, FragmentScriptingPermission = FragmentScriptingAllowed);
// WMLErrorHandling uses these functions.
virtual bool wellFormed() const { return !m_sawError; }
virtual int lineNumber() const;
virtual int columnNumber() const;
+ static bool supportsXMLVersion(const String&);
+
private:
+ XMLDocumentParser(Document*, FrameView* = 0);
+ XMLDocumentParser(DocumentFragment*, Element*, FragmentScriptingPermission);
+
// From DocumentParser
virtual void insert(const SegmentedString&);
virtual void append(const SegmentedString&);
@@ -214,6 +226,7 @@ namespace WebCore {
virtual bool finishWasCalled();
virtual bool isWaitingForScripts() const;
virtual void stopParsing();
+ virtual void detach();
// from CachedResourceClient
virtual void notifyFinished(CachedResource*);
@@ -223,6 +236,8 @@ namespace WebCore {
void pauseParsing();
void resumeParsing();
+ bool appendFragmentSource(const String&);
+
#if USE(QXMLSTREAM)
private:
void parse();
@@ -260,7 +275,7 @@ public:
void insertErrorMessageBlock();
- bool enterText();
+ void enterText();
void exitText();
void doWrite(const String&);
diff --git a/WebCore/dom/XMLDocumentParserLibxml2.cpp b/WebCore/dom/XMLDocumentParserLibxml2.cpp
index 1309827..37da83c 100644
--- a/WebCore/dom/XMLDocumentParserLibxml2.cpp
+++ b/WebCore/dom/XMLDocumentParserLibxml2.cpp
@@ -522,6 +522,11 @@ PassRefPtr<XMLParserContext> XMLParserContext::createMemoryParser(xmlSAXHandlerP
// --------------------------------
+bool XMLDocumentParser::supportsXMLVersion(const String& version)
+{
+ return version == "1.0";
+}
+
XMLDocumentParser::XMLDocumentParser(Document* document, FrameView* frameView)
: ScriptableDocumentParser(document)
, m_view(frameView)
@@ -616,13 +621,18 @@ XMLParserContext::~XMLParserContext()
XMLDocumentParser::~XMLDocumentParser()
{
- clearCurrentNodeStack();
+ // The XMLDocumentParser will always be detached before being destroyed.
+ ASSERT(m_currentNodeStack.isEmpty());
+ ASSERT(!m_currentNode);
+
+ // FIXME: m_pendingScript handling should be moved into XMLDocumentParser.cpp!
if (m_pendingScript)
m_pendingScript->removeClient(this);
}
void XMLDocumentParser::doWrite(const String& parseString)
{
+ ASSERT(!isDetached());
if (!m_context)
initializeParserContext();
@@ -631,6 +641,10 @@ void XMLDocumentParser::doWrite(const String& parseString)
// libXML throws an error if you try to switch the encoding for an empty string.
if (parseString.length()) {
+ // JavaScript may cause the parser to detach during xmlParseChunk
+ // keep this alive until this function is done.
+ RefPtr<XMLDocumentParser> protect(this);
+
// Hack around libxml2's lack of encoding overide support by manually
// resetting the encoding to UTF-16 before every chunk. Otherwise libxml
// will detect <?xml version="1.0" encoding="<encoding name>"?> blocks
@@ -641,14 +655,18 @@ void XMLDocumentParser::doWrite(const String& parseString)
XMLDocumentParserScope scope(document()->docLoader());
xmlParseChunk(context->context(), reinterpret_cast<const char*>(parseString.characters()), sizeof(UChar) * parseString.length(), 0);
+
+ // JavaScript (which may be run under the xmlParseChunk callstack) may
+ // cause the parser to be stopped or detached.
+ if (isDetached() || m_parserStopped)
+ return;
}
+ // FIXME: Why is this here? And why is it after we process the passed source?
if (document()->decoder() && document()->decoder()->sawError()) {
// If the decoder saw an error, report it as fatal (stops parsing)
handleError(fatal, "Encoding error", context->context()->input->line, context->context()->input->col);
}
-
- return;
}
static inline String toString(const xmlChar* str, unsigned len)
@@ -790,10 +808,7 @@ void XMLDocumentParser::startElementNs(const xmlChar* xmlLocalName, const xmlCha
if (scriptElement)
m_scriptStartLine = lineNumber();
- if (!m_currentNode->legacyParserAddChild(newElement.get())) {
- stopParsing();
- return;
- }
+ m_currentNode->deprecatedParserAddChild(newElement.get());
pushCurrentNode(newElement.get());
if (m_view && !newElement->attached())
@@ -855,6 +870,13 @@ void XMLDocumentParser::endElementNs()
else
#endif
{
+ // FIXME: Script execution should be shared should be shared between
+ // the libxml2 and Qt XMLDocumentParser implementations.
+
+ // JavaScript can detach the parser. Make sure this is not released
+ // before the end of this method.
+ RefPtr<XMLDocumentParser> protect(this);
+
String scriptHref = scriptElement->sourceAttributeValue();
if (!scriptHref.isEmpty()) {
// we have a src attribute
@@ -871,6 +893,10 @@ void XMLDocumentParser::endElementNs()
m_scriptElement = 0;
} else
m_view->frame()->script()->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartLine));
+
+ // JavaScript may have detached the parser
+ if (isDetached())
+ return;
}
m_requestingScript = false;
popCurrentNode();
@@ -886,8 +912,9 @@ void XMLDocumentParser::characters(const xmlChar* s, int len)
return;
}
- if (m_currentNode->isTextNode() || enterText())
- m_bufferedText.append(s, len);
+ if (!m_currentNode->isTextNode())
+ enterText();
+ m_bufferedText.append(s, len);
}
void XMLDocumentParser::error(ErrorType type, const char* message, va_list args)
@@ -935,8 +962,7 @@ void XMLDocumentParser::processingInstruction(const xmlChar* target, const xmlCh
pi->setCreatedByParser(true);
- if (!m_currentNode->legacyParserAddChild(pi.get()))
- return;
+ m_currentNode->deprecatedParserAddChild(pi.get());
if (m_view && !pi->attached())
pi->attach();
@@ -962,8 +988,7 @@ void XMLDocumentParser::cdataBlock(const xmlChar* s, int len)
exitText();
RefPtr<Node> newNode = CDATASection::create(document(), toString(s, len));
- if (!m_currentNode->legacyParserAddChild(newNode.get()))
- return;
+ m_currentNode->deprecatedParserAddChild(newNode.get());
if (m_view && !newNode->attached())
newNode->attach();
}
@@ -981,7 +1006,7 @@ void XMLDocumentParser::comment(const xmlChar* s)
exitText();
RefPtr<Node> newNode = Comment::create(document(), toString(s));
- m_currentNode->legacyParserAddChild(newNode.get());
+ m_currentNode->deprecatedParserAddChild(newNode.get());
if (m_view && !newNode->attached())
newNode->attach();
}
@@ -1045,7 +1070,7 @@ void XMLDocumentParser::internalSubset(const xmlChar* name, const xmlChar* exter
}
#endif
- document()->legacyParserAddChild(DocumentType::create(document(), toString(name), toString(externalID), toString(systemID)));
+ document()->parserAddChild(DocumentType::create(document(), toString(name), toString(externalID), toString(systemID)));
}
}
@@ -1274,8 +1299,10 @@ void XMLDocumentParser::initializeParserContext(const char* chunk)
XMLDocumentParserScope scope(document()->docLoader());
if (m_parsingFragment)
m_context = XMLParserContext::createMemoryParser(&sax, this, chunk);
- else
+ else {
+ ASSERT(!chunk);
m_context = XMLParserContext::createStringParser(&sax, this);
+ }
}
void XMLDocumentParser::doEnd()
@@ -1347,6 +1374,7 @@ void XMLDocumentParser::stopParsing()
void XMLDocumentParser::resumeParsing()
{
+ ASSERT(!isDetached());
ASSERT(m_parserPaused);
m_parserPaused = false;
@@ -1371,29 +1399,29 @@ void XMLDocumentParser::resumeParsing()
end();
}
-// FIXME: This method should be possible to implement using the DocumentParser
-// API, instead of needing to grab at libxml2 state directly.
-bool XMLDocumentParser::parseDocumentFragment(const String& chunk, DocumentFragment* fragment, Element* parent, FragmentScriptingPermission scriptingPermission)
+bool XMLDocumentParser::appendFragmentSource(const String& chunk)
{
- if (!chunk.length())
- return true;
-
- XMLDocumentParser parser(fragment, parent, scriptingPermission);
+ ASSERT(!m_context);
+ ASSERT(m_parsingFragment);
CString chunkAsUtf8 = chunk.utf8();
- parser.initializeParserContext(chunkAsUtf8.data());
-
- xmlParseContent(parser.context());
-
- parser.endDocument();
+ initializeParserContext(chunkAsUtf8.data());
+ xmlParseContent(context());
+ endDocument(); // Close any open text nodes.
+ // FIXME: If this code is actually needed, it should probably move to finish()
+ // XMLDocumentParserQt has a similar check (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError) in doEnd().
// Check if all the chunk has been processed.
- long bytesProcessed = xmlByteConsumed(parser.context());
- if (bytesProcessed == -1 || ((unsigned long)bytesProcessed) != chunkAsUtf8.length())
+ long bytesProcessed = xmlByteConsumed(context());
+ if (bytesProcessed == -1 || ((unsigned long)bytesProcessed) != chunkAsUtf8.length()) {
+ // FIXME: I don't believe we can hit this case without also having seen an error.
+ // If we hit this ASSERT, we've found a test case which demonstrates the need for this code.
+ ASSERT(m_sawError);
return false;
+ }
// No error if the chunk is well formed or it is not but we have no error.
- return parser.context()->wellFormed || xmlCtxtGetLastError(parser.context()) == 0;
+ return context()->wellFormed || !xmlCtxtGetLastError(context());
}
// --------------------------------
diff --git a/WebCore/dom/XMLDocumentParserQt.cpp b/WebCore/dom/XMLDocumentParserQt.cpp
index 715856c..606770f 100644
--- a/WebCore/dom/XMLDocumentParserQt.cpp
+++ b/WebCore/dom/XMLDocumentParserQt.cpp
@@ -78,6 +78,11 @@ QString EntityResolver::resolveUndeclaredEntity(const QString &name)
// --------------------------------
+bool XMLDocumentParser::supportsXMLVersion(const String& version)
+{
+ return version == "1.0";
+}
+
XMLDocumentParser::XMLDocumentParser(Document* document, FrameView* frameView)
: ScriptableDocumentParser(document)
, m_view(frameView)
@@ -254,18 +259,13 @@ void XMLDocumentParser::resumeParsing()
end();
}
-bool XMLDocumentParser::parseDocumentFragment(const String& chunk, DocumentFragment* fragment, Element* parent, FragmentScriptingPermission scriptingPermission)
+bool XMLDocumentParser::appendFragmentSource(const String& source)
{
- if (!chunk.length())
- return true;
-
- XMLDocumentParser parser(fragment, parent, scriptingPermission);
-
- parser.append(String("<qxmlstreamdummyelement>"));
- parser.append(chunk);
- parser.append(String("</qxmlstreamdummyelement>"));
- parser.finish();
- return !parser.hasError();
+ ASSERT(!m_sawFirstElement);
+ append(String("<qxmlstreamdummyelement>"));
+ append(source);
+ append(String("</qxmlstreamdummyelement>"));
+ return !hasError();
}
// --------------------------------
@@ -410,12 +410,12 @@ void XMLDocumentParser::parse()
) {
QString entity = m_stream.name().toString();
UChar c = decodeNamedEntity(entity.toUtf8().constData());
- if (m_currentNode->isTextNode() || enterText()) {
- ExceptionCode ec = 0;
- String str(&c, 1);
- //qDebug()<<" ------- adding entity "<<str;
- static_cast<Text*>(m_currentNode)->appendData(str, ec);
- }
+ if (!m_currentNode->isTextNode())
+ enterText();
+ ExceptionCode ec = 0;
+ String str(&c, 1);
+ // qDebug()<<" ------- adding entity "<<str;
+ static_cast<Text*>(m_currentNode)->appendData(str, ec);
}
}
break;
@@ -518,10 +518,7 @@ void XMLDocumentParser::parseStartElement()
if (scriptElement)
m_scriptStartLine = lineNumber();
- if (!m_currentNode->legacyParserAddChild(newElement.get())) {
- stopParsing();
- return;
- }
+ m_currentNode->deprecatedParserAddChild(newElement.get());
pushCurrentNode(newElement.get());
if (m_view && !newElement->attached())
@@ -599,10 +596,10 @@ void XMLDocumentParser::parseEndElement()
void XMLDocumentParser::parseCharacters()
{
- if (m_currentNode->isTextNode() || enterText()) {
- ExceptionCode ec = 0;
- static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
- }
+ if (!m_currentNode->isTextNode())
+ enterText();
+ ExceptionCode ec = 0;
+ static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
}
void XMLDocumentParser::parseProcessingInstruction()
@@ -619,8 +616,7 @@ void XMLDocumentParser::parseProcessingInstruction()
pi->setCreatedByParser(true);
- if (!m_currentNode->legacyParserAddChild(pi.get()))
- return;
+ m_currentNode->deprecatedParserAddChild(pi.get());
if (m_view && !pi->attached())
pi->attach();
@@ -638,8 +634,8 @@ void XMLDocumentParser::parseCdata()
exitText();
RefPtr<Node> newNode = CDATASection::create(document(), m_stream.text());
- if (!m_currentNode->legacyParserAddChild(newNode.get()))
- return;
+
+ m_currentNode->deprecatedParserAddChild(newNode.get());
if (m_view && !newNode->attached())
newNode->attach();
}
@@ -649,7 +645,8 @@ void XMLDocumentParser::parseComment()
exitText();
RefPtr<Node> newNode = Comment::create(document(), m_stream.text());
- m_currentNode->legacyParserAddChild(newNode.get());
+
+ m_currentNode->deprecatedParserAddChild(newNode.get());
if (m_view && !newNode->attached())
newNode->attach();
}
@@ -708,7 +705,7 @@ void XMLDocumentParser::parseDtd()
handleError(fatal, "Invalid DTD Public ID", lineNumber(), columnNumber());
#endif
if (!m_parsingFragment)
- document()->legacyParserAddChild(DocumentType::create(document(), name, publicId, systemId));
+ document()->parserAddChild(DocumentType::create(document(), name, publicId, systemId));
}
}