WebCore/dom/XMLDocumentParser.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2000 Peter Kelly (pmk@post.com)
       
     3  * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
       
     4  * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
       
     5  * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
       
     6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
       
     7  * Copyright (C) 2008 Holger Hans Peter Freyther
       
     8  * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
       
     9  *
       
    10  * This library is free software; you can redistribute it and/or
       
    11  * modify it under the terms of the GNU Library General Public
       
    12  * License as published by the Free Software Foundation; either
       
    13  * version 2 of the License, or (at your option) any later version.
       
    14  *
       
    15  * This library is distributed in the hope that it will be useful,
       
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    18  * Library General Public License for more details.
       
    19  *
       
    20  * You should have received a copy of the GNU Library General Public License
       
    21  * along with this library; see the file COPYING.LIB.  If not, write to
       
    22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    23  * Boston, MA 02110-1301, USA.
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 #include "XMLDocumentParser.h"
       
    28 
       
    29 #include "CDATASection.h"
       
    30 #include "CachedScript.h"
       
    31 #include "Comment.h"
       
    32 #include "DocLoader.h"
       
    33 #include "Document.h"
       
    34 #include "DocumentFragment.h"
       
    35 #include "DocumentType.h"
       
    36 #include "Frame.h"
       
    37 #include "FrameLoader.h"
       
    38 #include "FrameView.h"
       
    39 #include "HTMLLinkElement.h"
       
    40 #include "HTMLNames.h"
       
    41 #include "HTMLStyleElement.h"
       
    42 #include "ImageLoader.h"
       
    43 #include "ProcessingInstruction.h"
       
    44 #include "ResourceError.h"
       
    45 #include "ResourceHandle.h"
       
    46 #include "ResourceRequest.h"
       
    47 #include "ResourceResponse.h"
       
    48 #include "ScriptController.h"
       
    49 #include "ScriptElement.h"
       
    50 #include "ScriptSourceCode.h"
       
    51 #include "ScriptValue.h"
       
    52 #include "TextResourceDecoder.h"
       
    53 #include "TreeDepthLimit.h"
       
    54 #include <wtf/text/CString.h>
       
    55 #include <wtf/StringExtras.h>
       
    56 #include <wtf/Threading.h>
       
    57 #include <wtf/Vector.h>
       
    58 
       
    59 #if ENABLE(SVG)
       
    60 #include "SVGNames.h"
       
    61 #include "SVGStyleElement.h"
       
    62 #endif
       
    63 
       
    64 using namespace std;
       
    65 
       
    66 namespace WebCore {
       
    67 
       
    68 using namespace HTMLNames;
       
    69 
       
    70 const int maxErrors = 25;
       
    71 
       
    72 #if ENABLE(WML)
       
    73 bool XMLDocumentParser::isWMLDocument() const
       
    74 {
       
    75     return document()->isWMLDocument();
       
    76 }
       
    77 #endif
       
    78 
       
    79 void XMLDocumentParser::pushCurrentNode(Node* n)
       
    80 {
       
    81     ASSERT(n);
       
    82     ASSERT(m_currentNode);
       
    83     if (n != document())
       
    84         n->ref();
       
    85     m_currentNodeStack.append(m_currentNode);
       
    86     m_currentNode = n;
       
    87     if (m_currentNodeStack.size() > maxDOMTreeDepth)
       
    88         handleError(fatal, "Excessive node nesting.", lineNumber(), columnNumber());
       
    89 }
       
    90 
       
    91 void XMLDocumentParser::popCurrentNode()
       
    92 {
       
    93     if (!m_currentNode)
       
    94         return;
       
    95     ASSERT(m_currentNodeStack.size());
       
    96 
       
    97     if (m_currentNode != document())
       
    98         m_currentNode->deref();
       
    99 
       
   100     m_currentNode = m_currentNodeStack.last();
       
   101     m_currentNodeStack.removeLast();
       
   102 }
       
   103 
       
   104 void XMLDocumentParser::clearCurrentNodeStack()
       
   105 {
       
   106     if (m_currentNode && m_currentNode != document())
       
   107         m_currentNode->deref();
       
   108     m_currentNode = 0;
       
   109 
       
   110     if (m_currentNodeStack.size()) { // Aborted parsing.
       
   111         for (size_t i = m_currentNodeStack.size() - 1; i != 0; --i)
       
   112             m_currentNodeStack[i]->deref();
       
   113         if (m_currentNodeStack[0] && m_currentNodeStack[0] != document())
       
   114             m_currentNodeStack[0]->deref();
       
   115         m_currentNodeStack.clear();
       
   116     }
       
   117 }
       
   118 
       
   119 void XMLDocumentParser::insert(const SegmentedString& source)
       
   120 {
       
   121     // FIXME: This is a hack to work around the fact that XMLHttpRequest
       
   122     // responseXML() calls Document::write() which in turn calls insert(). In
       
   123     // HTML, that's correct, as insert() implies a synchronous parse.  For XML,
       
   124     // all parsing is synchronous but document.write shouldn't be supported.
       
   125     append(source);
       
   126 }
       
   127 
       
   128 void XMLDocumentParser::append(const SegmentedString& s)
       
   129 {
       
   130     String parseString = s.toString();
       
   131 
       
   132     if (m_sawXSLTransform || !m_sawFirstElement)
       
   133         m_originalSourceForTransform += parseString;
       
   134 
       
   135     if (m_parserStopped || m_sawXSLTransform)
       
   136         return;
       
   137 
       
   138     if (m_parserPaused) {
       
   139         m_pendingSrc.append(s);
       
   140         return;
       
   141     }
       
   142 
       
   143     doWrite(s.toString());
       
   144 
       
   145     // After parsing, go ahead and dispatch image beforeload events.
       
   146     ImageLoader::dispatchPendingBeforeLoadEvents();
       
   147 }
       
   148 
       
   149 void XMLDocumentParser::handleError(ErrorType type, const char* m, int lineNumber, int columnNumber)
       
   150 {
       
   151     if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber && m_lastErrorColumn != columnNumber)) {
       
   152         switch (type) {
       
   153             case warning:
       
   154                 m_errorMessages += String::format("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
       
   155                 break;
       
   156             case fatal:
       
   157             case nonFatal:
       
   158                 m_errorMessages += String::format("error on line %d at column %d: %s", lineNumber, columnNumber, m);
       
   159         }
       
   160 
       
   161         m_lastErrorLine = lineNumber;
       
   162         m_lastErrorColumn = columnNumber;
       
   163         ++m_errorCount;
       
   164     }
       
   165 
       
   166     if (type != warning)
       
   167         m_sawError = true;
       
   168 
       
   169     if (type == fatal)
       
   170         stopParsing();
       
   171 }
       
   172 
       
   173 bool XMLDocumentParser::enterText()
       
   174 {
       
   175 #if !USE(QXMLSTREAM)
       
   176     ASSERT(m_bufferedText.size() == 0);
       
   177 #endif
       
   178     RefPtr<Node> newNode = Text::create(document(), "");
       
   179     if (!m_currentNode->legacyParserAddChild(newNode.get()))
       
   180         return false;
       
   181     pushCurrentNode(newNode.get());
       
   182     return true;
       
   183 }
       
   184 
       
   185 #if !USE(QXMLSTREAM)
       
   186 static inline String toString(const xmlChar* str, unsigned len)
       
   187 {
       
   188     return UTF8Encoding().decode(reinterpret_cast<const char*>(str), len);
       
   189 }
       
   190 #endif
       
   191 
       
   192 
       
   193 void XMLDocumentParser::exitText()
       
   194 {
       
   195     if (m_parserStopped)
       
   196         return;
       
   197 
       
   198     if (!m_currentNode || !m_currentNode->isTextNode())
       
   199         return;
       
   200 
       
   201 #if !USE(QXMLSTREAM)
       
   202     ExceptionCode ec = 0;
       
   203     static_cast<Text*>(m_currentNode)->appendData(toString(m_bufferedText.data(), m_bufferedText.size()), ec);
       
   204     Vector<xmlChar> empty;
       
   205     m_bufferedText.swap(empty);
       
   206 #endif
       
   207 
       
   208     if (m_view && m_currentNode && !m_currentNode->attached())
       
   209         m_currentNode->attach();
       
   210 
       
   211     popCurrentNode();
       
   212 }
       
   213 
       
   214 void XMLDocumentParser::end()
       
   215 {
       
   216     doEnd();
       
   217 
       
   218     // doEnd() could process a script tag, thus pausing parsing.
       
   219     if (m_parserPaused)
       
   220         return;
       
   221 
       
   222     if (m_sawError)
       
   223         insertErrorMessageBlock();
       
   224     else {
       
   225         exitText();
       
   226         document()->updateStyleSelector();
       
   227     }
       
   228 
       
   229     clearCurrentNodeStack();
       
   230     if (!m_parsingFragment)
       
   231         document()->finishedParsing();
       
   232 }
       
   233 
       
   234 void XMLDocumentParser::finish()
       
   235 {
       
   236     if (m_parserPaused)
       
   237         m_finishCalled = true;
       
   238     else
       
   239         end();
       
   240 }
       
   241 
       
   242 bool XMLDocumentParser::finishWasCalled()
       
   243 {
       
   244     return m_finishCalled;
       
   245 }
       
   246 
       
   247 static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages)
       
   248 {
       
   249     RefPtr<Element> reportElement = doc->createElement(QualifiedName(nullAtom, "parsererror", xhtmlNamespaceURI), false);
       
   250     reportElement->setAttribute(styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
       
   251 
       
   252     ExceptionCode ec = 0;
       
   253     RefPtr<Element> h3 = doc->createElement(h3Tag, false);
       
   254     reportElement->appendChild(h3.get(), ec);
       
   255     h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
       
   256 
       
   257     RefPtr<Element> fixed = doc->createElement(divTag, false);
       
   258     reportElement->appendChild(fixed.get(), ec);
       
   259     fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px");
       
   260     fixed->appendChild(doc->createTextNode(errorMessages), ec);
       
   261 
       
   262     h3 = doc->createElement(h3Tag, false);
       
   263     reportElement->appendChild(h3.get(), ec);
       
   264     h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
       
   265 
       
   266     return reportElement;
       
   267 }
       
   268 
       
   269 void XMLDocumentParser::insertErrorMessageBlock()
       
   270 {
       
   271 #if USE(QXMLSTREAM)
       
   272     if (m_parsingFragment)
       
   273         return;
       
   274 #endif
       
   275     // One or more errors occurred during parsing of the code. Display an error block to the user above
       
   276     // the normal content (the DOM tree is created manually and includes line/col info regarding
       
   277     // where the errors are located)
       
   278 
       
   279     // Create elements for display
       
   280     ExceptionCode ec = 0;
       
   281     Document* doc = document();
       
   282     Node* documentElement = doc->documentElement();
       
   283     if (!documentElement) {
       
   284         RefPtr<Node> rootElement = doc->createElement(htmlTag, false);
       
   285         doc->appendChild(rootElement, ec);
       
   286         RefPtr<Node> body = doc->createElement(bodyTag, false);
       
   287         rootElement->appendChild(body, ec);
       
   288         documentElement = body.get();
       
   289     }
       
   290 #if ENABLE(SVG)
       
   291     else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
       
   292         RefPtr<Node> rootElement = doc->createElement(htmlTag, false);
       
   293         RefPtr<Node> body = doc->createElement(bodyTag, false);
       
   294         rootElement->appendChild(body, ec);
       
   295         body->appendChild(documentElement, ec);
       
   296         doc->appendChild(rootElement.get(), ec);
       
   297         documentElement = body.get();
       
   298     }
       
   299 #endif
       
   300 #if ENABLE(WML)
       
   301     else if (isWMLDocument()) {
       
   302         RefPtr<Node> rootElement = doc->createElement(htmlTag, false);
       
   303         RefPtr<Node> body = doc->createElement(bodyTag, false);
       
   304         rootElement->appendChild(body, ec);
       
   305         body->appendChild(documentElement, ec);
       
   306         doc->appendChild(rootElement.get(), ec);
       
   307         documentElement = body.get();
       
   308     }
       
   309 #endif
       
   310 
       
   311     RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
       
   312     documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
       
   313 #if ENABLE(XSLT)
       
   314     if (doc->transformSourceDocument()) {
       
   315         RefPtr<Element> par = doc->createElement(pTag, false);
       
   316         reportElement->appendChild(par, ec);
       
   317         par->setAttribute(styleAttr, "white-space: normal");
       
   318         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);
       
   319     }
       
   320 #endif
       
   321     doc->updateStyleIfNeeded();
       
   322 }
       
   323 
       
   324 void XMLDocumentParser::notifyFinished(CachedResource* unusedResource)
       
   325 {
       
   326     ASSERT_UNUSED(unusedResource, unusedResource == m_pendingScript);
       
   327     ASSERT(m_pendingScript->accessCount() > 0);
       
   328 
       
   329     ScriptSourceCode sourceCode(m_pendingScript.get());
       
   330     bool errorOccurred = m_pendingScript->errorOccurred();
       
   331 
       
   332     m_pendingScript->removeClient(this);
       
   333     m_pendingScript = 0;
       
   334 
       
   335     RefPtr<Element> e = m_scriptElement;
       
   336     m_scriptElement = 0;
       
   337 
       
   338     ScriptElement* scriptElement = toScriptElement(e.get());
       
   339     ASSERT(scriptElement);
       
   340 
       
   341     if (errorOccurred)
       
   342         scriptElement->dispatchErrorEvent();
       
   343     else {
       
   344         m_view->frame()->script()->executeScript(sourceCode);
       
   345         scriptElement->dispatchLoadEvent();
       
   346     }
       
   347 
       
   348     m_scriptElement = 0;
       
   349 
       
   350     if (!m_requestingScript)
       
   351         resumeParsing();
       
   352 }
       
   353 
       
   354 bool XMLDocumentParser::isWaitingForScripts() const
       
   355 {
       
   356     return m_pendingScript;
       
   357 }
       
   358 
       
   359 void XMLDocumentParser::pauseParsing()
       
   360 {
       
   361     if (m_parsingFragment)
       
   362         return;
       
   363 
       
   364     m_parserPaused = true;
       
   365 }
       
   366 
       
   367 }