03b083ec1c925ccd51e6b1d21c9b52ea16bce9ce
[WebKit-https.git] / WebCore / dom / XMLDocumentParserQt.cpp
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, 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_sawXSLTransform(false)
95     , m_sawFirstElement(false)
96     , m_isXHTMLDocument(false)
97 #if ENABLE(XHTMLMP)
98     , m_isXHTMLMPDocument(false)
99     , m_hasDocTypeDeclaration(false)
100 #endif
101     , m_parserPaused(false)
102     , m_requestingScript(false)
103     , m_finishCalled(false)
104     , m_errorCount(0)
105     , m_lastErrorLine(0)
106     , m_lastErrorColumn(0)
107     , m_pendingScript(0)
108     , m_scriptStartLine(0)
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_sawXSLTransform(false)
122     , m_sawFirstElement(false)
123     , m_isXHTMLDocument(false)
124 #if ENABLE(XHTMLMP)
125     , m_isXHTMLMPDocument(false)
126     , m_hasDocTypeDeclaration(false)
127 #endif
128     , m_parserPaused(false)
129     , m_requestingScript(false)
130     , m_finishCalled(false)
131     , m_errorCount(0)
132     , m_lastErrorLine(0)
133     , m_lastErrorColumn(0)
134     , m_pendingScript(0)
135     , m_scriptStartLine(0)
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         m_stream.addData(data);
196         parse();
197     }
198
199     return;
200 }
201
202 void XMLDocumentParser::initializeParserContext(const char*)
203 {
204     DocumentParser::startParsing();
205     m_sawError = false;
206     m_sawXSLTransform = false;
207     m_sawFirstElement = false;
208 }
209
210 void XMLDocumentParser::doEnd()
211 {
212 #if ENABLE(XSLT)
213     if (m_sawXSLTransform) {
214         document()->setTransformSource(new TransformSource(m_originalSourceForTransform));
215         document()->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
216         document()->styleSelectorChanged(RecalcStyleImmediately);
217         document()->setParsing(true);
218         DocumentParser::stopParsing();
219     }
220 #endif
221
222     if (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError
223         || (m_wroteText && !m_sawFirstElement && !m_sawXSLTransform && !m_sawError))
224         handleError(fatal, qPrintable(m_stream.errorString()), lineNumber(), columnNumber());
225 }
226
227 int XMLDocumentParser::lineNumber() const
228 {
229     return m_stream.lineNumber();
230 }
231
232 int XMLDocumentParser::columnNumber() const
233 {
234     return m_stream.columnNumber();
235 }
236
237 void XMLDocumentParser::stopParsing()
238 {
239     ScriptableDocumentParser::stopParsing();
240 }
241
242 void XMLDocumentParser::resumeParsing()
243 {
244     ASSERT(m_parserPaused);
245
246     m_parserPaused = false;
247
248     // First, execute any pending callbacks
249     parse();
250     if (m_parserPaused)
251         return;
252
253     // Then, write any pending data
254     SegmentedString rest = m_pendingSrc;
255     m_pendingSrc.clear();
256     append(rest);
257
258     // Finally, if finish() has been called and append() didn't result
259     // in any further callbacks being queued, call end()
260     if (m_finishCalled && !m_parserPaused && !m_pendingScript)
261         end();
262 }
263
264 bool XMLDocumentParser::appendFragmentSource(const String& source)
265 {
266     ASSERT(!m_sawFirstElement);
267     append(String("<qxmlstreamdummyelement>"));
268     append(source);
269     append(String("</qxmlstreamdummyelement>"));
270     return !hasError();
271 }
272
273 // --------------------------------
274
275 struct AttributeParseState {
276     HashMap<String, String> attributes;
277     bool gotAttributes;
278 };
279
280 static void attributesStartElementNsHandler(AttributeParseState* state, const QXmlStreamAttributes& attrs)
281 {
282     if (attrs.count() <= 0)
283         return;
284
285     state->gotAttributes = true;
286
287     for (int i = 0; i < attrs.count(); i++) {
288         const QXmlStreamAttribute& attr = attrs[i];
289         String attrLocalName = attr.name();
290         String attrValue     = attr.value();
291         String attrURI       = attr.namespaceUri();
292         String attrQName     = attr.qualifiedName();
293         state->attributes.set(attrQName, attrValue);
294     }
295 }
296
297 HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
298 {
299     AttributeParseState state;
300     state.gotAttributes = false;
301
302     QXmlStreamReader stream;
303     QString dummy = QString(QLatin1String("<?xml version=\"1.0\"?><attrs %1 />")).arg(string);
304     stream.addData(dummy);
305     while (!stream.atEnd()) {
306         stream.readNext();
307         if (stream.isStartElement()) {
308             attributesStartElementNsHandler(&state, stream.attributes());
309         }
310     }
311     attrsOK = state.gotAttributes;
312     return state.attributes;
313 }
314
315 static inline String prefixFromQName(const QString& qName)
316 {
317     const int offset = qName.indexOf(QLatin1Char(':'));
318     if (offset <= 0)
319         return String();
320     else
321         return qName.left(offset);
322 }
323
324 static inline void handleElementNamespaces(Element* newElement, const QXmlStreamNamespaceDeclarations &ns,
325                                            ExceptionCode& ec, FragmentScriptingPermission scriptingPermission)
326 {
327     for (int i = 0; i < ns.count(); ++i) {
328         const QXmlStreamNamespaceDeclaration &decl = ns[i];
329         String namespaceURI = decl.namespaceUri();
330         String namespaceQName = decl.prefix().isEmpty() ? String("xmlns") : String("xmlns:");
331         namespaceQName.append(decl.prefix());
332         newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec, scriptingPermission);
333         if (ec) // exception setting attributes
334             return;
335     }
336 }
337
338 static inline void handleElementAttributes(Element* newElement, const QXmlStreamAttributes &attrs, ExceptionCode& ec,
339                                            FragmentScriptingPermission scriptingPermission)
340 {
341     for (int i = 0; i < attrs.count(); ++i) {
342         const QXmlStreamAttribute &attr = attrs[i];
343         String attrLocalName = attr.name();
344         String attrValue     = attr.value();
345         String attrURI       = attr.namespaceUri().isEmpty() ? String() : String(attr.namespaceUri());
346         String attrQName     = attr.qualifiedName();
347         newElement->setAttributeNS(attrURI, attrQName, attrValue, ec, scriptingPermission);
348         if (ec) // exception setting attributes
349             return;
350     }
351 }
352
353 void XMLDocumentParser::parse()
354 {
355     while (!isStopped() && !m_parserPaused && !m_stream.atEnd()) {
356         m_stream.readNext();
357         switch (m_stream.tokenType()) {
358         case QXmlStreamReader::StartDocument: {
359             startDocument();
360         }
361             break;
362         case QXmlStreamReader::EndDocument: {
363             endDocument();
364         }
365             break;
366         case QXmlStreamReader::StartElement: {
367 #if ENABLE(XHTMLMP)
368             if (document()->isXHTMLMPDocument() && !m_hasDocTypeDeclaration) {
369                 handleError(fatal, "DOCTYPE declaration lost.", lineNumber(), columnNumber());
370                 break;
371             }
372 #endif
373             parseStartElement();
374         }
375             break;
376         case QXmlStreamReader::EndElement: {
377             parseEndElement();
378         }
379             break;
380         case QXmlStreamReader::Characters: {
381             if (m_stream.isCDATA()) {
382                 //cdata
383                 parseCdata();
384             } else {
385                 //characters
386                 parseCharacters();
387             }
388         }
389             break;
390         case QXmlStreamReader::Comment: {
391             parseComment();
392         }
393             break;
394         case QXmlStreamReader::DTD: {
395             //qDebug()<<"------------- DTD";
396             parseDtd();
397 #if ENABLE(XHTMLMP)
398             m_hasDocTypeDeclaration = true;
399 #endif
400         }
401             break;
402         case QXmlStreamReader::EntityReference: {
403             //qDebug()<<"---------- ENTITY = "<<m_stream.name().toString()
404             //        <<", t = "<<m_stream.text().toString();
405             if (isXHTMLDocument()
406 #if ENABLE(XHTMLMP)
407                 || isXHTMLMPDocument()
408 #endif
409 #if ENABLE(WML)
410                 || isWMLDocument()
411 #endif
412                ) {
413                 QString entity = m_stream.name().toString();
414                 UChar c = decodeNamedEntity(entity.toUtf8().constData());
415                 if (!m_currentNode->isTextNode())
416                     enterText();
417                 ExceptionCode ec = 0;
418                 String str(&c, 1);
419                 // qDebug()<<" ------- adding entity "<<str;
420                 static_cast<Text*>(m_currentNode)->appendData(str, ec);
421             }
422         }
423             break;
424         case QXmlStreamReader::ProcessingInstruction: {
425             parseProcessingInstruction();
426         }
427             break;
428         default: {
429             if (m_stream.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
430                 ErrorType type = (m_stream.error() == QXmlStreamReader::NotWellFormedError) ?
431                                  fatal : warning;
432                 handleError(type, qPrintable(m_stream.errorString()), lineNumber(),
433                             columnNumber());
434             }
435         }
436             break;
437         }
438     }
439 }
440
441 void XMLDocumentParser::startDocument()
442 {
443     initializeParserContext();
444     ExceptionCode ec = 0;
445
446     if (!m_parsingFragment) {
447         document()->setXMLStandalone(m_stream.isStandaloneDocument(), ec);
448
449         QStringRef version = m_stream.documentVersion();
450         if (!version.isEmpty())
451             document()->setXMLVersion(version, ec);
452         QStringRef encoding = m_stream.documentEncoding();
453         if (!encoding.isEmpty())
454             document()->setXMLEncoding(encoding);
455     }
456 }
457
458 void XMLDocumentParser::parseStartElement()
459 {
460     if (!m_sawFirstElement && m_parsingFragment) {
461         // skip dummy element for fragments
462         m_sawFirstElement = true;
463         return;
464     }
465
466     exitText();
467
468     String localName = m_stream.name();
469     String uri       = m_stream.namespaceUri();
470     String prefix    = prefixFromQName(m_stream.qualifiedName().toString());
471
472     if (m_parsingFragment && uri.isNull()) {
473         Q_ASSERT(prefix.isNull());
474         uri = m_defaultNamespaceURI;
475     }
476
477     QualifiedName qName(prefix, localName, uri);
478     RefPtr<Element> newElement = document()->createElement(qName, true);
479     if (!newElement) {
480         stopParsing();
481         return;
482     }
483
484 #if ENABLE(XHTMLMP)
485     if (!m_sawFirstElement && isXHTMLMPDocument()) {
486         // As per 7.1 section of OMA-WAP-XHTMLMP-V1_1-20061020-A.pdf,
487         // we should make sure that the root element MUST be 'html' and
488         // ensure the name of the default namespace on the root elment 'html'
489         // MUST be 'http://www.w3.org/1999/xhtml'
490         if (localName != HTMLNames::htmlTag.localName()) {
491             handleError(fatal, "XHTMLMP document expects 'html' as root element.", lineNumber(), columnNumber());
492             return;
493         }
494
495         if (uri.isNull()) {
496             m_defaultNamespaceURI = HTMLNames::xhtmlNamespaceURI;
497             uri = m_defaultNamespaceURI;
498             m_stream.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration(prefix, HTMLNames::xhtmlNamespaceURI));
499         }
500     }
501 #endif
502
503     bool isFirstElement = !m_sawFirstElement;
504     m_sawFirstElement = true;
505
506     ExceptionCode ec = 0;
507     handleElementNamespaces(newElement.get(), m_stream.namespaceDeclarations(), ec, m_scriptingPermission);
508     if (ec) {
509         stopParsing();
510         return;
511     }
512
513     handleElementAttributes(newElement.get(), m_stream.attributes(), ec, m_scriptingPermission);
514     if (ec) {
515         stopParsing();
516         return;
517     }
518
519     ScriptElement* scriptElement = toScriptElement(newElement.get());
520     if (scriptElement)
521         m_scriptStartLine = lineNumber();
522
523     m_currentNode->deprecatedParserAddChild(newElement.get());
524
525     pushCurrentNode(newElement.get());
526     if (m_view && !newElement->attached())
527         newElement->attach();
528
529 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
530     if (newElement->hasTagName(HTMLNames::htmlTag))
531         static_cast<HTMLHtmlElement*>(newElement.get())->insertedByParser();
532 #endif
533
534     if (isFirstElement && document()->frame())
535         document()->frame()->loader()->dispatchDocumentElementAvailable();
536 }
537
538 void XMLDocumentParser::parseEndElement()
539 {
540     exitText();
541
542     Node* n = m_currentNode;
543     n->finishParsingChildren();
544
545     if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n))) {
546         popCurrentNode();
547         ExceptionCode ec;
548         n->remove(ec);
549         return;
550     }
551
552     if (!n->isElementNode() || !m_view) {
553         if (!m_currentNodeStack.isEmpty())
554             popCurrentNode();
555         return;
556     }
557
558     Element* element = static_cast<Element*>(n);
559
560     // The element's parent may have already been removed from document.
561     // Parsing continues in this case, but scripts aren't executed.
562     if (!element->inDocument()) {
563         popCurrentNode();
564         return;
565     }
566
567     ScriptElement* scriptElement = toScriptElement(element);
568     if (!scriptElement) {
569         popCurrentNode();
570         return;
571     }
572
573     // don't load external scripts for standalone documents (for now)
574     ASSERT(!m_pendingScript);
575     m_requestingScript = true;
576
577 #if ENABLE(XHTMLMP)
578     if (!scriptElement->shouldExecuteAsJavaScript())
579         document()->setShouldProcessNoscriptElement(true);
580     else
581 #endif
582     {
583         String scriptHref = scriptElement->sourceAttributeValue();
584         if (!scriptHref.isEmpty()) {
585             // we have a src attribute
586             String scriptCharset = scriptElement->scriptCharset();
587             if (element->dispatchBeforeLoadEvent(scriptHref) &&
588                 (m_pendingScript = document()->cachedResourceLoader()->requestScript(scriptHref, scriptCharset))) {
589                 m_scriptElement = element;
590                 m_pendingScript->addClient(this);
591
592                 // m_pendingScript will be 0 if script was already loaded and ref() executed it
593                 if (m_pendingScript)
594                     pauseParsing();
595             } else
596                 m_scriptElement = 0;
597         } else
598             m_view->frame()->script()->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartLine));
599     }
600     m_requestingScript = false;
601     popCurrentNode();
602 }
603
604 void XMLDocumentParser::parseCharacters()
605 {
606     if (!m_currentNode->isTextNode())
607         enterText();
608     ExceptionCode ec = 0;
609     static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
610 }
611
612 void XMLDocumentParser::parseProcessingInstruction()
613 {
614     exitText();
615
616     // ### handle exceptions
617     int exception = 0;
618     RefPtr<ProcessingInstruction> pi = document()->createProcessingInstruction(
619         m_stream.processingInstructionTarget(),
620         m_stream.processingInstructionData(), exception);
621     if (exception)
622         return;
623
624     pi->setCreatedByParser(true);
625
626     m_currentNode->deprecatedParserAddChild(pi.get());
627     if (m_view && !pi->attached())
628         pi->attach();
629
630     pi->finishParsingChildren();
631
632 #if ENABLE(XSLT)
633     m_sawXSLTransform = !m_sawFirstElement && pi->isXSL();
634     if (m_sawXSLTransform && !document()->transformSourceDocument())
635         stopParsing();
636 #endif
637 }
638
639 void XMLDocumentParser::parseCdata()
640 {
641     exitText();
642
643     RefPtr<Node> newNode = CDATASection::create(document(), m_stream.text());
644
645     m_currentNode->deprecatedParserAddChild(newNode.get());
646     if (m_view && !newNode->attached())
647         newNode->attach();
648 }
649
650 void XMLDocumentParser::parseComment()
651 {
652     exitText();
653
654     RefPtr<Node> newNode = Comment::create(document(), m_stream.text());
655
656     m_currentNode->deprecatedParserAddChild(newNode.get());
657     if (m_view && !newNode->attached())
658         newNode->attach();
659 }
660
661 void XMLDocumentParser::endDocument()
662 {
663 #if ENABLE(XHTMLMP)
664     m_hasDocTypeDeclaration = false;
665 #endif
666 }
667
668 bool XMLDocumentParser::hasError() const
669 {
670     return m_stream.hasError();
671 }
672
673 void XMLDocumentParser::parseDtd()
674 {
675     QStringRef name = m_stream.dtdName();
676     QStringRef publicId = m_stream.dtdPublicId();
677     QStringRef systemId = m_stream.dtdSystemId();
678
679     //qDebug() << dtd << name << publicId << systemId;
680     if ((publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Transitional//EN"))
681         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1//EN"))
682         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Strict//EN"))
683         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.0 Frameset//EN"))
684         || (publicId == QLatin1String("-//W3C//DTD XHTML Basic 1.0//EN"))
685         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN"))
686         || (publicId == QLatin1String("-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN"))
687 #if !ENABLE(XHTMLMP)
688         || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
689 #endif
690        )
691         setIsXHTMLDocument(true); // controls if we replace entities or not.
692 #if ENABLE(XHTMLMP)
693     else if ((publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.1//EN"))
694              || (publicId == QLatin1String("-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))) {
695         if (AtomicString(name) != HTMLNames::htmlTag.localName()) {
696             handleError(fatal, "Invalid DOCTYPE declaration, expected 'html' as root element.", lineNumber(), columnNumber());
697             return;
698         }
699
700         if (document()->isXHTMLMPDocument()) // check if the MIME type is correct with this method
701             setIsXHTMLMPDocument(true);
702         else
703             setIsXHTMLDocument(true);
704     }
705 #endif
706 #if ENABLE(WML)
707     else if (document()->isWMLDocument()
708              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.3//EN")
709              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.2//EN")
710              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.1//EN")
711              && publicId != QLatin1String("-//WAPFORUM//DTD WML 1.0//EN"))
712         handleError(fatal, "Invalid DTD Public ID", lineNumber(), columnNumber());
713 #endif
714     if (!m_parsingFragment)
715         document()->parserAddChild(DocumentType::create(document(), name, publicId, systemId));
716
717 }
718 }
719