summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp')
-rw-r--r--src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp b/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp
new file mode 100644
index 0000000..c411e50
--- /dev/null
+++ b/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * 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 "XMLTokenizer.h"
+
+#include "CDATASection.h"
+#include "CString.h"
+#include "CachedScript.h"
+#include "Comment.h"
+#include "DocLoader.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DocumentType.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLLinkElement.h"
+#include "HTMLNames.h"
+#include "HTMLScriptElement.h"
+#include "HTMLStyleElement.h"
+#include "ProcessingInstruction.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#include "ScriptController.h"
+#include "ScriptSourceCode.h"
+#include "ScriptValue.h"
+#include "TextResourceDecoder.h"
+#include <wtf/Platform.h>
+#include <wtf/StringExtras.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#include "SVGScriptElement.h"
+#include "SVGStyleElement.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+const int maxErrors = 25;
+
+bool isScriptElement(Element* element)
+{
+ return element->hasTagName(HTMLNames::scriptTag)
+#if ENABLE(SVG)
+ || element->hasTagName(SVGNames::scriptTag)
+#endif
+ ;
+}
+
+ScriptElement* castToScriptElement(Element* element)
+{
+ ASSERT(isScriptElement(element));
+
+ if (element->hasTagName(HTMLNames::scriptTag))
+ return static_cast<HTMLScriptElement*>(element);
+
+#if ENABLE(SVG)
+ if (element->hasTagName(SVGNames::scriptTag))
+ return static_cast<SVGScriptElement*>(element);
+#endif
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+#if ENABLE(WML)
+bool XMLTokenizer::isWMLDocument() const
+{
+ if (m_doc)
+ return m_doc->isWMLDocument();
+
+ return false;
+}
+#endif
+
+void XMLTokenizer::setCurrentNode(Node* n)
+{
+ bool nodeNeedsReference = n && n != m_doc;
+ if (nodeNeedsReference)
+ n->ref();
+ if (m_currentNodeIsReferenced)
+ m_currentNode->deref();
+ m_currentNode = n;
+ m_currentNodeIsReferenced = nodeNeedsReference;
+}
+
+bool XMLTokenizer::write(const SegmentedString& s, bool /*appendData*/)
+{
+ String parseString = s.toString();
+
+ if (m_sawXSLTransform || !m_sawFirstElement)
+ m_originalSourceForTransform += parseString;
+
+ if (m_parserStopped || m_sawXSLTransform)
+ return false;
+
+ if (m_parserPaused) {
+ m_pendingSrc.append(s);
+ return false;
+ }
+
+ doWrite(s.toString());
+ return false;
+}
+
+void XMLTokenizer::handleError(ErrorType type, const char* m, int lineNumber, int columnNumber)
+{
+ if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber && m_lastErrorColumn != columnNumber)) {
+ switch (type) {
+ case warning:
+ m_errorMessages += String::format("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
+ break;
+ case fatal:
+ case nonFatal:
+ m_errorMessages += String::format("error on line %d at column %d: %s", lineNumber, columnNumber, m);
+ }
+
+ m_lastErrorLine = lineNumber;
+ m_lastErrorColumn = columnNumber;
+ ++m_errorCount;
+ }
+
+ if (type != warning)
+ m_sawError = true;
+
+ if (type == fatal)
+ stopParsing();
+}
+
+bool XMLTokenizer::enterText()
+{
+#if !USE(QXMLSTREAM)
+ ASSERT(m_bufferedText.size() == 0);
+#endif
+ RefPtr<Node> newNode = new Text(m_doc, "");
+ if (!m_currentNode->addChild(newNode.get()))
+ return false;
+ setCurrentNode(newNode.get());
+ return true;
+}
+
+#if !USE(QXMLSTREAM)
+static inline String toString(const xmlChar* str, unsigned len)
+{
+ return UTF8Encoding().decode(reinterpret_cast<const char*>(str), len);
+}
+#endif
+
+
+void XMLTokenizer::exitText()
+{
+ if (m_parserStopped)
+ return;
+
+ if (!m_currentNode || !m_currentNode->isTextNode())
+ return;
+
+#if !USE(QXMLSTREAM)
+ ExceptionCode ec = 0;
+ static_cast<Text*>(m_currentNode)->appendData(toString(m_bufferedText.data(), m_bufferedText.size()), ec);
+ Vector<xmlChar> empty;
+ m_bufferedText.swap(empty);
+#endif
+
+ if (m_view && m_currentNode && !m_currentNode->attached())
+ m_currentNode->attach();
+
+ // FIXME: What's the right thing to do if the parent is really 0?
+ // Just leaving the current node set to the text node doesn't make much sense.
+ if (Node* par = m_currentNode->parentNode())
+ setCurrentNode(par);
+}
+
+void XMLTokenizer::end()
+{
+ doEnd();
+
+ if (m_sawError)
+ insertErrorMessageBlock();
+ else {
+ exitText();
+ m_doc->updateStyleSelector();
+ }
+
+ setCurrentNode(0);
+ if (!m_parsingFragment)
+ m_doc->finishedParsing();
+}
+
+void XMLTokenizer::finish()
+{
+ if (m_parserPaused)
+ m_finishCalled = true;
+ else
+ end();
+}
+
+static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages)
+{
+ ExceptionCode ec = 0;
+ RefPtr<Element> reportElement = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "parsererror", ec);
+ reportElement->setAttribute(HTMLNames::styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
+
+ RefPtr<Element> h3 = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "h3", ec);
+ reportElement->appendChild(h3.get(), ec);
+ h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
+
+ RefPtr<Element> fixed = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "div", ec);
+ reportElement->appendChild(fixed.get(), ec);
+ fixed->setAttribute(HTMLNames::styleAttr, "font-family:monospace;font-size:12px");
+ fixed->appendChild(doc->createTextNode(errorMessages), ec);
+
+ h3 = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "h3", ec);
+ reportElement->appendChild(h3.get(), ec);
+ h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
+
+ return reportElement;
+}
+
+void XMLTokenizer::insertErrorMessageBlock()
+{
+#if USE(QXMLSTREAM)
+ if (m_parsingFragment)
+ return;
+#endif
+ // One or more errors occurred during parsing of the code. Display an error block to the user above
+ // the normal content (the DOM tree is created manually and includes line/col info regarding
+ // where the errors are located)
+
+ // Create elements for display
+ ExceptionCode ec = 0;
+ Document* doc = m_doc;
+ Node* documentElement = doc->documentElement();
+ if (!documentElement) {
+ RefPtr<Node> rootElement = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "html", ec);
+ doc->appendChild(rootElement, ec);
+ RefPtr<Node> body = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "body", ec);
+ rootElement->appendChild(body, ec);
+ documentElement = body.get();
+ }
+#if ENABLE(SVG)
+ else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
+ RefPtr<Node> rootElement = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "html", ec);
+ RefPtr<Node> body = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "body", ec);
+ rootElement->appendChild(body, ec);
+ body->appendChild(documentElement, ec);
+ doc->appendChild(rootElement.get(), ec);
+ documentElement = body.get();
+ }
+#endif
+#if ENABLE(WML)
+ else if (isWMLDocument()) {
+ RefPtr<Node> rootElement = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "html", ec);
+ RefPtr<Node> body = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "body", ec);
+ rootElement->appendChild(body, ec);
+ body->appendChild(documentElement, ec);
+ doc->appendChild(rootElement.get(), ec);
+ documentElement = body.get();
+ }
+#endif
+
+ RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
+ documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
+#if ENABLE(XSLT)
+ if (doc->transformSourceDocument()) {
+ RefPtr<Element> par = doc->createElementNS(HTMLNames::xhtmlNamespaceURI, "p", ec);
+ reportElement->appendChild(par, ec);
+ par->setAttribute(HTMLNames::styleAttr, "white-space: normal");
+ par->appendChild(doc->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."), ec);
+ }
+#endif
+ doc->updateRendering();
+}
+
+void XMLTokenizer::notifyFinished(CachedResource* finishedObj)
+{
+ ASSERT(m_pendingScript == finishedObj);
+ ASSERT(m_pendingScript->accessCount() > 0);
+
+ ScriptSourceCode sourceCode(m_pendingScript.get());
+ bool errorOccurred = m_pendingScript->errorOccurred();
+
+ m_pendingScript->removeClient(this);
+ m_pendingScript = 0;
+
+ RefPtr<Element> e = m_scriptElement;
+ m_scriptElement = 0;
+
+ ScriptElement* scriptElement = castToScriptElement(e.get());
+ ASSERT(scriptElement);
+
+ if (errorOccurred)
+ scriptElement->dispatchErrorEvent();
+ else {
+ m_view->frame()->loader()->executeScript(sourceCode);
+ scriptElement->dispatchLoadEvent();
+ }
+
+ m_scriptElement = 0;
+
+ if (!m_requestingScript)
+ resumeParsing();
+}
+
+bool XMLTokenizer::isWaitingForScripts() const
+{
+ return m_pendingScript;
+}
+
+void XMLTokenizer::pauseParsing()
+{
+ if (m_parsingFragment)
+ return;
+
+ m_parserPaused = true;
+}
+
+}
+