Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 2000 Peter Kelly (pmk (at) post.com)
      3  * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
      4  * Copyright (C) 2006 Alexey Proskuryakov (ap (at) webkit.org)
      5  * Copyright (C) 2007 Samuel Weinig (sam (at) 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, 2009 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 "CachedResourceLoader.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 "HTMLEntityParser.h"
     40 #include "HTMLHtmlElement.h"
     41 #include "HTMLLinkElement.h"
     42 #include "HTMLNames.h"
     43 #include "HTMLStyleElement.h"
     44 #include "ProcessingInstruction.h"
     45 #include "ResourceError.h"
     46 #include "ResourceHandle.h"
     47 #include "ResourceRequest.h"
     48 #include "ResourceResponse.h"
     49 #include "ScriptableDocumentParser.h"
     50 #include "ScriptController.h"
     51 #include "ScriptElement.h"
     52 #include "ScriptSourceCode.h"
     53 #include "ScriptValue.h"
     54 #include "TextResourceDecoder.h"
     55 #include "TransformSource.h"
     56 #include <QDebug>
     57 #include <wtf/StringExtras.h>
     58 #include <wtf/Threading.h>
     59 #include <wtf/Vector.h>
     60 #include <wtf/text/CString.h>
     61 
     62 #if ENABLE(XHTMLMP)
     63 #include "HTMLNames.h"
     64 #include "HTMLScriptElement.h"
     65 #endif
     66 
     67 using namespace std;
     68 
     69 namespace WebCore {
     70 
     71 class EntityResolver : public QXmlStreamEntityResolver {
     72     virtual QString resolveUndeclaredEntity(const QString &name);
     73 };
     74 
     75 QString EntityResolver::resolveUndeclaredEntity(const QString &name)
     76 {
     77     UChar c = decodeNamedEntity(name.toUtf8().constData());
     78     return QString(c);
     79 }
     80 
     81 // --------------------------------
     82 
     83 bool XMLDocumentParser::supportsXMLVersion(const String& version)
     84 {
     85     return version == "1.0";
     86 }
     87 
     88 XMLDocumentParser::XMLDocumentParser(Document* document, FrameView* frameView)
     89     : ScriptableDocumentParser(document)
     90     , m_view(frameView)
     91     , m_wroteText(false)
     92     , m_currentNode(document)
     93     , m_sawError(false)
     94     , m_sawCSS(false)
     95     , m_sawXSLTransform(false)
     96     , m_sawFirstElement(false)
     97     , m_isXHTMLDocument(false)
     98 #if ENABLE(XHTMLMP)
     99     , m_isXHTMLMPDocument(false)
    100     , m_hasDocTypeDeclaration(false)
    101 #endif
    102     , m_parserPaused(false)
    103     , m_requestingScript(false)
    104     , m_finishCalled(false)
    105     , m_errorCount(0)
    106     , m_lastErrorPosition(TextPosition1::belowRangePosition())
    107     , m_pendingScript(0)
    108     , m_scriptStartPosition(TextPosition1::belowRangePosition())
    109     , m_parsingFragment(false)
    110     , m_scriptingPermission(FragmentScriptingAllowed)
    111 {
    112     m_stream.setEntityResolver(new EntityResolver);
    113 }
    114 
    115 XMLDocumentParser::XMLDocumentParser(DocumentFragment* fragment, Element* parentElement, FragmentScriptingPermission permission)
    116     : ScriptableDocumentParser(fragment->document())
    117     , m_view(0)
    118     , m_wroteText(false)
    119     , m_currentNode(fragment)
    120     , m_sawError(false)
    121     , m_sawCSS(false)
    122     , m_sawXSLTransform(false)
    123     , m_sawFirstElement(false)
    124     , m_isXHTMLDocument(false)
    125 #if ENABLE(XHTMLMP)
    126     , m_isXHTMLMPDocument(false)
    127     , m_hasDocTypeDeclaration(false)
    128 #endif
    129     , m_parserPaused(false)
    130     , m_requestingScript(false)
    131     , m_finishCalled(false)
    132     , m_errorCount(0)
    133     , m_lastErrorPosition(TextPosition1::belowRangePosition())
    134     , m_pendingScript(0)
    135     , m_scriptStartPosition(TextPosition1::belowRangePosition())
    136     , m_parsingFragment(true)
    137     , m_scriptingPermission(permission)
    138 {
    139     fragment->ref();
    140 
    141     // Add namespaces based on the parent node
    142     Vector<Element*> elemStack;
    143     while (parentElement) {
    144         elemStack.append(parentElement);
    145 
    146         Node* n = parentElement->parentNode();
    147         if (!n || !n->isElementNode())
    148             break;
    149         parentElement = static_cast<Element*>(n);
    150     }
    151 
    152     if (elemStack.isEmpty())
    153         return;
    154 
    155     QXmlStreamNamespaceDeclarations namespaces;
    156     for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
    157         if (NamedNodeMap* attrs = element->attributes()) {
    158             for (unsigned i = 0; i < attrs->length(); i++) {
    159                 Attribute* attr = attrs->attributeItem(i);
    160                 if (attr->localName() == "xmlns")
    161                     m_defaultNamespaceURI = attr->value();
    162                 else if (attr->prefix() == "xmlns")
    163                     namespaces.append(QXmlStreamNamespaceDeclaration(attr->localName(), attr->value()));
    164             }
    165         }
    166     }
    167     m_stream.addExtraNamespaceDeclarations(namespaces);
    168     m_stream.setEntityResolver(new EntityResolver);
    169 
    170     // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace.
    171     if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument())
    172         m_defaultNamespaceURI = parentElement->namespaceURI();
    173 }
    174 
    175 XMLDocumentParser::~XMLDocumentParser()
    176 {
    177     clearCurrentNodeStack();
    178     if (m_pendingScript)
    179         m_pendingScript->removeClient(this);
    180     delete m_stream.entityResolver();
    181 }
    182 
    183 void XMLDocumentParser::doWrite(const String& parseString)
    184 {
    185     m_wroteText = true;
    186 
    187     if (document()->decoder() && document()->decoder()->sawError()) {
    188         // If the decoder saw an error, report it as fatal (stops parsing)
    189         handleError(fatal, "Encoding error", lineNumber(), columnNumber());
    190         return;
    191     }
    192 
    193     QString data(parseString);
    194     if (!data.isEmpty()) {
    195         // JavaScript may cause the parser to detach,
    196         // keep this alive until this function is done.
    197         RefPtr<XMLDocumentParser> protect(this);
    198 
    199         m_stream.addData(data);
    200         parse();
    201     }
    202 
    203     return;
    204 }
    205 
    206 void XMLDocumentParser::initializeParserContext(const char*)
    207 {
    208     DocumentParser::startParsing();
    209     m_sawError = false;
    210     m_sawCSS = false;
    211     m_sawXSLTransform = false;
    212     m_sawFirstElement = false;
    213 }
    214 
    215 void XMLDocumentParser::doEnd()
    216 {
    217 #if ENABLE(XSLT)
    218     if (m_sawXSLTransform) {
    219         document()->setTransformSource(new TransformSource(m_originalSourceForTransform));
    220         document()->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
    221         document()->styleSelectorChanged(RecalcStyleImmediately);
    222         document()->setParsing(true);
    223         DocumentParser::stopParsing();
    224     }
    225 #endif
    226 
    227     if (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError
    228         || (m_wroteText && !m_sawFirstElement && !m_sawXSLTransform && !m_sawError))
    229         handleError(fatal, qPrintable(m_stream.errorString()), lineNumber(), columnNumber());
    230 }
    231 
    232 int XMLDocumentParser::lineNumber() const
    233 {
    234     return m_stream.lineNumber();
    235 }
    236 
    237 int XMLDocumentParser::columnNumber() const
    238 {
    239     return m_stream.columnNumber();
    240 }
    241 
    242 TextPosition0 XMLDocumentParser::textPosition() const
    243 {
    244     return TextPosition0(WTF::ZeroBasedNumber::fromZeroBasedInt(lineNumber()), WTF::ZeroBasedNumber::fromZeroBasedInt(columnNumber()));
    245 }
    246 
    247 // This method incorrectly reinterprets zero-base lineNumber method as one-based number.
    248 // FIXME: This error is kept for compatibility. We should fix it eventually.
    249 TextPosition1 XMLDocumentParser::textPositionOneBased() const
    250 {
    251     return TextPosition1(WTF::OneBasedNumber::fromOneBasedInt(lineNumber()), WTF::OneBasedNumber::fromOneBasedInt(columnNumber()));
    252 }
    253 
    254 void XMLDocumentParser::stopParsing()
    255 {
    256     ScriptableDocumentParser::stopParsing();
    257 }
    258 
    259 void XMLDocumentParser::resumeParsing()
    260 {
    261     ASSERT(m_parserPaused);
    262 
    263     m_parserPaused = false;
    264 
    265     // First, execute any pending callbacks
    266     parse();
    267     if (m_parserPaused)
    268         return;
    269 
    270     // Then, write any pending data
    271     SegmentedString rest = m_pendingSrc;
    272     m_pendingSrc.clear();
    273     append(rest);
    274 
    275     // Finally, if finish() has been called and append() didn't result
    276     // in any further callbacks being queued, call end()
    277     if (m_finishCalled && !m_parserPaused && !m_pendingScript)
    278         end();
    279 }
    280 
    281 bool XMLDocumentParser::appendFragmentSource(const String& source)
    282 {
    283     ASSERT(!m_sawFirstElement);
    284     append(String("<qxmlstreamdummyelement>"));
    285     append(source);
    286     append(String("</qxmlstreamdummyelement>"));
    287     return !hasError();
    288 }
    289 
    290 // --------------------------------
    291 
    292 struct AttributeParseState {
    293     HashMap<String, String> attributes;
    294     bool gotAttributes;
    295 };
    296 
    297 static void attributesStartElementNsHandler(AttributeParseState* state, const QXmlStreamAttributes& attrs)
    298 {
    299     if (attrs.count() <= 0)
    300         return;
    301 
    302     state->gotAttributes = true;
    303 
    304     for (int i = 0; i < attrs.count(); i++) {
    305         const QXmlStreamAttribute& attr = attrs[i];
    306         String attrLocalName = attr.name();
    307         String attrValue     = attr.value();
    308         String attrURI       = attr.namespaceUri();
    309         String attrQName     = attr.qualifiedName();
    310         state->attributes.set(attrQName, attrValue);
    311     }
    312 }
    313 
    314 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
    315 {
    316     AttributeParseState state;
    317     state.gotAttributes = false;
    318 
    319     QXmlStreamReader stream;
    320     QString dummy = QString(QLatin1String("<?xml version=\"1.0\"?><attrs %1 />")).arg(string);
    321     stream.addData(dummy);
    322     while (!stream.atEnd()) {
    323         stream.readNext();
    324         if (stream.isStartElement()) {
    325             attributesStartElementNsHandler(&state, stream.attributes());
    326         }
    327     }
    328     attrsOK = state.gotAttributes;
    329     return state.attributes;
    330 }
    331 
    332 static inline String prefixFromQName(const QString& qName)
    333 {
    334     const int offset = qName.indexOf(QLatin1Char(':'));
    335     if (offset <= 0)
    336         return String();
    337     else
    338         return qName.left(offset);
    339 }
    340 
    341 static inline void handleElementNamespaces(Element* newElement, const QXmlStreamNamespaceDeclarations &ns,
    342                                            ExceptionCode& ec, FragmentScriptingPermission scriptingPermission)
    343 {
    344     for (int i = 0; i < ns.count(); ++i) {
    345         const QXmlStreamNamespaceDeclaration &decl = ns[i];
    346         String namespaceURI = decl.namespaceUri();
    347         String namespaceQName = decl.prefix().isEmpty() ? String("xmlns") : String("xmlns:");
    348         namespaceQName.append(decl.prefix());
    349         newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec, scriptingPermission);
    350         if (ec) // exception setting attributes
    351             return;
    352     }
    353 }
    354 
    355 static inline void handleElementAttributes(Element* newElement, const QXmlStreamAttributes &attrs, ExceptionCode& ec,
    356                                            FragmentScriptingPermission scriptingPermission)
    357 {
    358     for (int i = 0; i < attrs.count(); ++i) {
    359         const QXmlStreamAttribute &attr = attrs[i];
    360         String attrLocalName = attr.name();
    361         String attrValue     = attr.value();
    362         String attrURI       = attr.namespaceUri().isEmpty() ? String() : String(attr.namespaceUri());
    363         String attrQName     = attr.qualifiedName();
    364         newElement->setAttributeNS(attrURI, attrQName, attrValue, ec, scriptingPermission);
    365         if (ec) // exception setting attributes
    366             return;
    367     }
    368 }
    369 
    370 void XMLDocumentParser::parse()
    371 {
    372     while (!isStopped() && !m_parserPaused && !m_stream.atEnd()) {
    373         m_stream.readNext();
    374         switch (m_stream.tokenType()) {
    375         case QXmlStreamReader::StartDocument: {
    376             startDocument();
    377         }
    378             break;
    379         case QXmlStreamReader::EndDocument: {
    380             endDocument();
    381         }
    382             break;
    383         case QXmlStreamReader::StartElement: {
    384 #if ENABLE(XHTMLMP)
    385             if (document()->isXHTMLMPDocument() && !m_hasDocTypeDeclaration) {
    386                 handleError(fatal, "DOCTYPE declaration lost.", lineNumber(), columnNumber());
    387                 break;
    388             }
    389 #endif
    390             parseStartElement();
    391         }
    392             break;
    393         case QXmlStreamReader::EndElement: {
    394             parseEndElement();
    395         }
    396             break;
    397         case QXmlStreamReader::Characters: {
    398             if (m_stream.isCDATA()) {
    399                 //cdata
    400                 parseCdata();
    401             } else {
    402                 //characters
    403                 parseCharacters();
    404             }
    405         }
    406             break;
    407         case QXmlStreamReader::Comment: {
    408             parseComment();
    409         }
    410             break;
    411         case QXmlStreamReader::DTD: {
    412             //qDebug()<<"------------- DTD";
    413             parseDtd();
    414 #if ENABLE(XHTMLMP)
    415             m_hasDocTypeDeclaration = true;
    416 #endif
    417         }
    418             break;
    419         case QXmlStreamReader::EntityReference: {
    420             //qDebug()<<"---------- ENTITY = "<<m_stream.name().toString()
    421             //        <<", t = "<<m_stream.text().toString();
    422             if (isXHTMLDocument()
    423 #if ENABLE(XHTMLMP)
    424                 || isXHTMLMPDocument()
    425 #endif
    426 #if ENABLE(WML)
    427                 || isWMLDocument()
    428 #endif
    429                ) {
    430                 QString entity = m_stream.name().toString();
    431                 UChar c = decodeNamedEntity(entity.toUtf8().constData());
    432                 if (!m_currentNode->isTextNode())
    433                     enterText();
    434                 ExceptionCode ec = 0;
    435                 String str(&c, 1);
    436                 // qDebug()<<" ------- adding entity "<<str;
    437                 static_cast<Text*>(m_currentNode)->appendData(str, ec);
    438             }
    439         }
    440             break;
    441         case QXmlStreamReader::ProcessingInstruction: {
    442             parseProcessingInstruction();
    443         }
    444             break;
    445         default: {
    446             if (m_stream.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
    447                 ErrorType type = (m_stream.error() == QXmlStreamReader::NotWellFormedError) ?
    448                                  fatal : warning;
    449                 handleError(type, qPrintable(m_stream.errorString()), lineNumber(),
    450                             columnNumber());
    451             }
    452         }
    453             break;
    454         }
    455     }
    456 }
    457 
    458 void XMLDocumentParser::startDocument()
    459 {
    460     initializeParserContext();
    461     ExceptionCode ec = 0;
    462 
    463     if (!m_parsingFragment) {
    464         document()->setXMLStandalone(m_stream.isStandaloneDocument(), ec);
    465 
    466         QStringRef version = m_stream.documentVersion();
    467         if (!version.isEmpty())
    468             document()->setXMLVersion(version, ec);
    469         QStringRef encoding = m_stream.documentEncoding();
    470         if (!encoding.isEmpty())
    471             document()->setXMLEncoding(encoding);
    472     }
    473 }
    474 
    475 void XMLDocumentParser::parseStartElement()
    476 {
    477     if (!m_sawFirstElement && m_parsingFragment) {
    478         // skip dummy element for fragments
    479         m_sawFirstElement = true;
    480         return;
    481     }
    482 
    483     exitText();
    484 
    485     String localName = m_stream.name();
    486     String uri       = m_stream.namespaceUri();
    487     String prefix    = prefixFromQName(m_stream.qualifiedName().toString());
    488 
    489     if (m_parsingFragment && uri.isNull()) {
    490         Q_ASSERT(prefix.isNull());
    491         uri = m_defaultNamespaceURI;
    492     }
    493 
    494     QualifiedName qName(prefix, localName, uri);
    495     RefPtr<Element> newElement = document()->createElement(qName, true);
    496     if (!newElement) {
    497         stopParsing();
    498         return;
    499     }
    500 
    501 #if ENABLE(XHTMLMP)
    502     if (!m_sawFirstElement && isXHTMLMPDocument()) {
    503         // As per 7.1 section of OMA-WAP-XHTMLMP-V1_1-20061020-A.pdf,
    504         // we should make sure that the root element MUST be 'html' and
    505         // ensure the name of the default namespace on the root elment 'html'
    506         // MUST be 'http://www.w3.org/1999/xhtml'
    507         if (localName != HTMLNames::htmlTag.localName()) {
    508             handleError(fatal, "XHTMLMP document expects 'html' as root element.", lineNumber(), columnNumber());
    509             return;
    510         }
    511 
    512         if (uri.isNull()) {
    513             m_defaultNamespaceURI = HTMLNames::xhtmlNamespaceURI;
    514             uri = m_defaultNamespaceURI;
    515             m_stream.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration(prefix, HTMLNames::xhtmlNamespaceURI));
    516         }
    517     }
    518 #endif
    519 
    520     bool isFirstElement = !m_sawFirstElement;
    521     m_sawFirstElement = true;
    522 
    523     ExceptionCode ec = 0;
    524     handleElementNamespaces(newElement.get(), m_stream.namespaceDeclarations(), ec, m_scriptingPermission);
    525     if (ec) {
    526         stopParsing();
    527         return;
    528     }
    529 
    530     handleElementAttributes(newElement.get(), m_stream.attributes(), ec, m_scriptingPermission);
    531     if (ec) {
    532         stopParsing();
    533         return;
    534     }
    535 
    536     ScriptElement* scriptElement = toScriptElement(newElement.get());
    537     if (scriptElement)
    538         m_scriptStartPosition = textPositionOneBased();
    539 
    540     m_currentNode->deprecatedParserAddChild(newElement.get());
    541 
    542     pushCurrentNode(newElement.get());
    543     if (m_view && !newElement->attached())
    544         newElement->attach();
    545 
    546 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    547     if (newElement->hasTagName(HTMLNames::htmlTag))
    548         static_cast<HTMLHtmlElement*>(newElement.get())->insertedByParser();
    549 #endif
    550 
    551     if (isFirstElement && document()->frame())
    552         document()->frame()->loader()->dispatchDocumentElementAvailable();
    553 }
    554 
    555 void XMLDocumentParser::parseEndElement()
    556 {
    557     exitText();
    558 
    559     RefPtr<Node> n = m_currentNode;
    560     n->finishParsingChildren();
    561 
    562     if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n.get()))) {
    563         popCurrentNode();
    564         ExceptionCode ec;
    565         n->remove(ec);
    566         return;
    567     }
    568 
    569     if (!n->isElementNode() || !m_view) {
    570         if (!m_currentNodeStack.isEmpty())
    571             popCurrentNode();
    572         return;
    573     }
    574 
    575     Element* element = static_cast<Element*>(n.get());
    576 
    577     // The element's parent may have already been removed from document.
    578     // Parsing continues in this case, but scripts aren't executed.
    579     if (!element->inDocument()) {
    580         popCurrentNode();
    581         return;
    582     }
    583 
    584     ScriptElement* scriptElement = toScriptElement(element);
    585     if (!scriptElement) {
    586         popCurrentNode();
    587         return;
    588     }
    589 
    590     // don't load external scripts for standalone documents (for now)
    591     ASSERT(!m_pendingScript);
    592     m_requestingScript = true;
    593 
    594     bool successfullyPrepared = scriptElement->prepareScript(m_scriptStartPosition, ScriptElement::AllowLegacyTypeInTypeAttribute);
    595     if (!successfullyPrepared) {
    596 #if ENABLE(XHTMLMP)
    597         if (!scriptElement->isScriptTypeSupported(ScriptElement::AllowLegacyTypeInTypeAttribute))
    598             document()->setShouldProcessNoscriptElement(true);
    599 #endif
    600     } else {
    601         if (scriptElement->readyToBeParserExecuted())
    602             scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));
    603         else if (scriptElement->willBeParserExecuted()) {
    604             m_pendingScript = scriptElement->cachedScript();
    605             m_scriptElement = element;
    606             m_pendingScript->addClient(this);
    607 
    608             // m_pendingScript will be 0 if script was already loaded and addClient() executed it.
    609             if (m_pendingScript)
    610                 pauseParsing();
    611         } else
    612             m_scriptElement = 0;
    613     }
    614     m_requestingScript = false;
    615     popCurrentNode();
    616 }
    617 
    618 void XMLDocumentParser::parseCharacters()
    619 {
    620     if (!m_currentNode->isTextNode())
    621         enterText();
    622     ExceptionCode ec = 0;
    623     static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
    624 }
    625 
    626 void XMLDocumentParser::parseProcessingInstruction()
    627 {
    628     exitText();
    629 
    630     // ### handle exceptions
    631     int exception = 0;
    632     RefPtr<ProcessingInstruction> pi = document()->createProcessingInstruction(
    633         m_stream.processingInstructionTarget(),
    634         m_stream.processingInstructionData(), exception);
    635     if (exception)
    636         return;
    637 
    638     pi->setCreatedByParser(true);
    639 
    640     m_currentNode->deprecatedParserAddChild(pi.get());
    641     if (m_view && !pi->attached())
    642         pi->attach();
    643 
    644     pi->finishParsingChildren();
    645 
    646     if (pi->isCSS())
    647         m_sawCSS = true;
    648 #if ENABLE(XSLT)
    649     m_sawXSLTransform = !m_sawFirstElement && pi->isXSL();
    650     if (m_sawXSLTransform && !document()->transformSourceDocument())
    651         stopParsing();
    652 #endif
    653 }
    654 
    655 void XMLDocumentParser::parseCdata()
    656 {
    657     exitText();
    658 
    659     RefPtr<Node> newNode = CDATASection::create(document(), m_stream.text());
    660 
    661     m_currentNode->deprecatedParserAddChild(newNode.get());
    662     if (m_view && !newNode->attached())
    663         newNode->attach();
    664 }
    665 
    666 void XMLDocumentParser::parseComment()
    667 {
    668     exitText();
    669 
    670     RefPtr<Node> newNode = Comment::create(document(), m_stream.text());
    671 
    672     m_currentNode->deprecatedParserAddChild(newNode.get());
    673     if (m_view && !newNode->attached())
    674         newNode->attach();
    675 }
    676 
    677 void XMLDocumentParser::endDocument()
    678 {
    679 #if ENABLE(XHTMLMP)
    680     m_hasDocTypeDeclaration = false;
    681 #endif
    682 }
    683 
    684 bool XMLDocumentParser::hasError() const
    685 {
    686     return m_stream.hasError();
    687 }
    688 
    689 void XMLDocumentParser::parseDtd()
    690 {
    691     QStringRef name = m_stream.dtdName();
    692     QStringRef publicId = m_stream.dtdPublicId();
    693     QStringRef systemId = m_stream.dtdSystemId();
    694 
    695     //qDebug() << dtd << name << publicId << systemId;
    696     if ((publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Transitional//EN"))
    697         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1//EN"))
    698         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Strict//EN"))
    699         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Frameset//EN"))
    700         || (publicId == QLatin1String("-//W3C//DTD XHTML Basic 1.0//EN"))
    701         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"))
    702         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"))
    703 #if !ENABLE(XHTMLMP)
    704         || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
    705 #endif
    706        )
    707         setIsXHTMLDocument(true); // controls if we replace entities or not.
    708 #if ENABLE(XHTMLMP)
    709     else if ((publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.1//EN"))
    710              || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))) {
    711         if (AtomicString(name) != HTMLNames::htmlTag.localName()) {
    712             handleError(fatal, "Invalid DOCTYPE declaration, expected 'html' as root element.", lineNumber(), columnNumber());
    713             return;
    714         }
    715 
    716         if (document()->isXHTMLMPDocument()) // check if the MIME type is correct with this method
    717             setIsXHTMLMPDocument(true);
    718         else
    719             setIsXHTMLDocument(true);
    720     }
    721 #endif
    722 #if ENABLE(WML)
    723     else if (document()->isWMLDocument()
    724              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.3//EN")
    725              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.2//EN")
    726              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.1//EN")
    727              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.0//EN"))
    728         handleError(fatal, "Invalid DTD Public ID", lineNumber(), columnNumber());
    729 #endif
    730     if (!m_parsingFragment)
    731         document()->parserAddChild(DocumentType::create(document(), name, publicId, systemId));
    732 
    733 }
    734 }
    735