Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
      6  * Copyright (C) 2006 Samuel Weinig (sam (at) webkit.org)
      7  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #include "config.h"
     26 #include "core/dom/DOMImplementation.h"
     27 
     28 #include "bindings/core/v8/ExceptionState.h"
     29 #include "core/HTMLNames.h"
     30 #include "core/SVGNames.h"
     31 #include "core/css/CSSStyleSheet.h"
     32 #include "core/css/MediaList.h"
     33 #include "core/css/StyleSheetContents.h"
     34 #include "core/dom/ContextFeatures.h"
     35 #include "core/dom/DocumentInit.h"
     36 #include "core/dom/DocumentType.h"
     37 #include "core/dom/Element.h"
     38 #include "core/dom/ExceptionCode.h"
     39 #include "core/dom/Text.h"
     40 #include "core/dom/XMLDocument.h"
     41 #include "core/dom/custom/CustomElementRegistrationContext.h"
     42 #include "core/frame/LocalFrame.h"
     43 #include "core/frame/UseCounter.h"
     44 #include "core/html/HTMLDocument.h"
     45 #include "core/html/HTMLHeadElement.h"
     46 #include "core/html/HTMLMediaElement.h"
     47 #include "core/html/HTMLTitleElement.h"
     48 #include "core/html/HTMLViewSourceDocument.h"
     49 #include "core/html/ImageDocument.h"
     50 #include "core/html/MediaDocument.h"
     51 #include "core/html/PluginDocument.h"
     52 #include "core/html/TextDocument.h"
     53 #include "core/loader/FrameLoader.h"
     54 #include "core/page/Page.h"
     55 #include "platform/ContentType.h"
     56 #include "platform/MIMETypeRegistry.h"
     57 #include "platform/graphics/Image.h"
     58 #include "platform/graphics/media/MediaPlayer.h"
     59 #include "platform/plugins/PluginData.h"
     60 #include "platform/weborigin/SecurityOrigin.h"
     61 #include "wtf/StdLibExtras.h"
     62 
     63 namespace blink {
     64 
     65 typedef HashSet<String, CaseFoldingHash> FeatureSet;
     66 
     67 static void addString(FeatureSet& set, const char* string)
     68 {
     69     set.add(string);
     70 }
     71 
     72 static bool isSupportedSVG10Feature(const String& feature, const String& version)
     73 {
     74     if (!version.isEmpty() && version != "1.0")
     75         return false;
     76 
     77     static bool initialized = false;
     78     DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
     79     if (!initialized) {
     80 #if ENABLE(SVG_FONTS)
     81         addString(svgFeatures, "svg");
     82         addString(svgFeatures, "svg.static");
     83 #endif
     84 //      addString(svgFeatures, "svg.animation");
     85 //      addString(svgFeatures, "svg.dynamic");
     86 //      addString(svgFeatures, "svg.dom.animation");
     87 //      addString(svgFeatures, "svg.dom.dynamic");
     88 #if ENABLE(SVG_FONTS)
     89         addString(svgFeatures, "dom");
     90         addString(svgFeatures, "dom.svg");
     91         addString(svgFeatures, "dom.svg.static");
     92 #endif
     93 //      addString(svgFeatures, "svg.all");
     94 //      addString(svgFeatures, "dom.svg.all");
     95         initialized = true;
     96     }
     97     return feature.startsWith("org.w3c.", false)
     98         && svgFeatures.contains(feature.right(feature.length() - 8));
     99 }
    100 
    101 static bool isSupportedSVG11Feature(const String& feature, const String& version)
    102 {
    103     if (!version.isEmpty() && version != "1.1")
    104         return false;
    105 
    106     static bool initialized = false;
    107     DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
    108     if (!initialized) {
    109         // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets
    110         // lack of Font and Filter support.
    111         // http://bugs.webkit.org/show_bug.cgi?id=15480
    112 #if ENABLE(SVG_FONTS)
    113         addString(svgFeatures, "SVG");
    114         addString(svgFeatures, "SVGDOM");
    115         addString(svgFeatures, "SVG-static");
    116         addString(svgFeatures, "SVGDOM-static");
    117 #endif
    118         addString(svgFeatures, "SVG-animation");
    119         addString(svgFeatures, "SVGDOM-animation");
    120 //      addString(svgFeatures, "SVG-dynamic);
    121 //      addString(svgFeatures, "SVGDOM-dynamic);
    122         addString(svgFeatures, "CoreAttribute");
    123         addString(svgFeatures, "Structure");
    124         addString(svgFeatures, "BasicStructure");
    125         addString(svgFeatures, "ContainerAttribute");
    126         addString(svgFeatures, "ConditionalProcessing");
    127         addString(svgFeatures, "Image");
    128         addString(svgFeatures, "Style");
    129         addString(svgFeatures, "ViewportAttribute");
    130         addString(svgFeatures, "Shape");
    131         addString(svgFeatures, "Text");
    132         addString(svgFeatures, "BasicText");
    133         addString(svgFeatures, "PaintAttribute");
    134         addString(svgFeatures, "BasicPaintAttribute");
    135         addString(svgFeatures, "OpacityAttribute");
    136         addString(svgFeatures, "GraphicsAttribute");
    137         addString(svgFeatures, "BaseGraphicsAttribute");
    138         addString(svgFeatures, "Marker");
    139 //      addString(svgFeatures, "ColorProfile");
    140         addString(svgFeatures, "Gradient");
    141         addString(svgFeatures, "Pattern");
    142         addString(svgFeatures, "Clip");
    143         addString(svgFeatures, "BasicClip");
    144         addString(svgFeatures, "Mask");
    145         addString(svgFeatures, "Filter");
    146         addString(svgFeatures, "BasicFilter");
    147         addString(svgFeatures, "DocumentEventsAttribute");
    148         addString(svgFeatures, "GraphicalEventsAttribute");
    149 //      addString(svgFeatures, "AnimationEventsAttribute");
    150         addString(svgFeatures, "Cursor");
    151         addString(svgFeatures, "Hyperlinking");
    152         addString(svgFeatures, "XlinkAttribute");
    153         addString(svgFeatures, "View");
    154         addString(svgFeatures, "Script");
    155         addString(svgFeatures, "Animation");
    156 #if ENABLE(SVG_FONTS)
    157         addString(svgFeatures, "Font");
    158         addString(svgFeatures, "BasicFont");
    159 #endif
    160         addString(svgFeatures, "Extensibility");
    161         initialized = true;
    162     }
    163     return feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)
    164         && svgFeatures.contains(feature.right(feature.length() - 35));
    165 }
    166 
    167 DOMImplementation::DOMImplementation(Document& document)
    168     : m_document(document)
    169 {
    170 }
    171 
    172 bool DOMImplementation::hasFeature(const String& feature, const String& version)
    173 {
    174     if (feature.startsWith("http://www.w3.org/TR/SVG", false)
    175     || feature.startsWith("org.w3c.dom.svg", false)
    176     || feature.startsWith("org.w3c.svg", false)) {
    177         // FIXME: SVG 2.0 support?
    178         return isSupportedSVG10Feature(feature, version) || isSupportedSVG11Feature(feature, version);
    179     }
    180     return true;
    181 }
    182 
    183 bool DOMImplementation::hasFeatureForBindings(const String& feature, const String& version)
    184 {
    185     if (!hasFeature(feature, version)) {
    186         UseCounter::count(m_document, UseCounter::DOMImplementationHasFeatureReturnFalse);
    187         return false;
    188     }
    189     return true;
    190 }
    191 
    192 PassRefPtrWillBeRawPtr<DocumentType> DOMImplementation::createDocumentType(const AtomicString& qualifiedName,
    193     const String& publicId, const String& systemId, ExceptionState& exceptionState)
    194 {
    195     AtomicString prefix, localName;
    196     if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
    197         return nullptr;
    198 
    199     return DocumentType::create(m_document, qualifiedName, publicId, systemId);
    200 }
    201 
    202 PassRefPtrWillBeRawPtr<XMLDocument> DOMImplementation::createDocument(const AtomicString& namespaceURI,
    203     const AtomicString& qualifiedName, DocumentType* doctype, ExceptionState& exceptionState)
    204 {
    205     RefPtrWillBeRawPtr<XMLDocument> doc = nullptr;
    206     DocumentInit init = DocumentInit::fromContext(document().contextDocument());
    207     if (namespaceURI == SVGNames::svgNamespaceURI) {
    208         doc = XMLDocument::createSVG(init);
    209     } else if (namespaceURI == HTMLNames::xhtmlNamespaceURI) {
    210         doc = XMLDocument::createXHTML(init.withRegistrationContext(document().registrationContext()));
    211     } else {
    212         doc = XMLDocument::create(init);
    213     }
    214 
    215     doc->setSecurityOrigin(document().securityOrigin()->isolatedCopy());
    216     doc->setContextFeatures(document().contextFeatures());
    217 
    218     RefPtrWillBeRawPtr<Node> documentElement = nullptr;
    219     if (!qualifiedName.isEmpty()) {
    220         documentElement = doc->createElementNS(namespaceURI, qualifiedName, exceptionState);
    221         if (exceptionState.hadException())
    222             return nullptr;
    223     }
    224 
    225     if (doctype)
    226         doc->appendChild(doctype);
    227     if (documentElement)
    228         doc->appendChild(documentElement.release());
    229 
    230     return doc.release();
    231 }
    232 
    233 bool DOMImplementation::isXMLMIMEType(const String& mimeType)
    234 {
    235     if (equalIgnoringCase(mimeType, "text/xml")
    236         || equalIgnoringCase(mimeType, "application/xml")
    237         || equalIgnoringCase(mimeType, "text/xsl"))
    238         return true;
    239 
    240     // Per RFCs 3023 and 2045, an XML MIME type is of the form:
    241     // ^[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+/[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+\+xml$
    242 
    243     int length = mimeType.length();
    244     if (length < 7)
    245         return false;
    246 
    247     if (mimeType[0] == '/' || mimeType[length - 5] == '/' || !mimeType.endsWith("+xml", false))
    248         return false;
    249 
    250     bool hasSlash = false;
    251     for (int i = 0; i < length - 4; ++i) {
    252         UChar ch = mimeType[i];
    253         if (ch >= '0' && ch <= '9')
    254             continue;
    255         if (ch >= 'a' && ch <= 'z')
    256             continue;
    257         if (ch >= 'A' && ch <= 'Z')
    258             continue;
    259         switch (ch) {
    260         case '_':
    261         case '-':
    262         case '+':
    263         case '~':
    264         case '!':
    265         case '$':
    266         case '^':
    267         case '{':
    268         case '}':
    269         case '|':
    270         case '.':
    271         case '%':
    272         case '\'':
    273         case '`':
    274         case '#':
    275         case '&':
    276         case '*':
    277             continue;
    278         case '/':
    279             if (hasSlash)
    280                 return false;
    281             hasSlash = true;
    282             continue;
    283         default:
    284             return false;
    285         }
    286     }
    287 
    288     return true;
    289 }
    290 
    291 bool DOMImplementation::isJSONMIMEType(const String& mimeType)
    292 {
    293     if (mimeType.startsWith("application/json", false))
    294         return true;
    295     if (mimeType.startsWith("application/", false)) {
    296         size_t subtype = mimeType.find("+json", 12, false);
    297         if (subtype != kNotFound) {
    298             // Just check that a parameter wasn't matched.
    299             size_t parameterMarker = mimeType.find(";");
    300             if (parameterMarker == kNotFound) {
    301                 unsigned endSubtype = static_cast<unsigned>(subtype) + 5;
    302                 return endSubtype == mimeType.length() || isASCIISpace(mimeType[endSubtype]);
    303             }
    304             return parameterMarker > subtype;
    305         }
    306     }
    307     return false;
    308 }
    309 
    310 static bool isTextPlainType(const String& mimeType)
    311 {
    312     return mimeType.startsWith("text/", false)
    313         && !(equalIgnoringCase(mimeType, "text/html")
    314             || equalIgnoringCase(mimeType, "text/xml")
    315             || equalIgnoringCase(mimeType, "text/xsl"));
    316 }
    317 
    318 bool DOMImplementation::isTextMIMEType(const String& mimeType)
    319 {
    320     return MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || isJSONMIMEType(mimeType) || isTextPlainType(mimeType);
    321 }
    322 
    323 PassRefPtrWillBeRawPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title)
    324 {
    325     DocumentInit init = DocumentInit::fromContext(document().contextDocument())
    326         .withRegistrationContext(document().registrationContext());
    327     RefPtrWillBeRawPtr<HTMLDocument> d = HTMLDocument::create(init);
    328     d->open();
    329     d->write("<!doctype html><html><head></head><body></body></html>");
    330     if (!title.isNull()) {
    331         HTMLHeadElement* headElement = d->head();
    332         ASSERT(headElement);
    333         RefPtrWillBeRawPtr<HTMLTitleElement> titleElement = HTMLTitleElement::create(*d);
    334         headElement->appendChild(titleElement);
    335         titleElement->appendChild(d->createTextNode(title), ASSERT_NO_EXCEPTION);
    336     }
    337     d->setSecurityOrigin(document().securityOrigin()->isolatedCopy());
    338     d->setContextFeatures(document().contextFeatures());
    339     return d.release();
    340 }
    341 
    342 PassRefPtrWillBeRawPtr<Document> DOMImplementation::createDocument(const String& type, LocalFrame* frame, const KURL& url, bool inViewSourceMode)
    343 {
    344     return createDocument(type, DocumentInit(url, frame), inViewSourceMode);
    345 }
    346 
    347 PassRefPtrWillBeRawPtr<Document> DOMImplementation::createDocument(const String& type, const DocumentInit& init, bool inViewSourceMode)
    348 {
    349     if (inViewSourceMode)
    350         return HTMLViewSourceDocument::create(init, type);
    351 
    352     // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those.
    353     if (type == "text/html")
    354         return HTMLDocument::create(init);
    355     if (type == "application/xhtml+xml")
    356         return XMLDocument::createXHTML(init);
    357 
    358     PluginData* pluginData = 0;
    359     if (init.frame() && init.frame()->page() && init.frame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
    360         pluginData = init.frame()->page()->pluginData();
    361 
    362     // PDF is one image type for which a plugin can override built-in support.
    363     // We do not want QuickTime to take over all image types, obviously.
    364     if ((type == "application/pdf" || type == "text/pdf") && pluginData && pluginData->supportsMimeType(type))
    365         return PluginDocument::create(init);
    366     if (Image::supportsType(type))
    367         return ImageDocument::create(init);
    368 
    369     // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument
    370     if (HTMLMediaElement::supportsType(ContentType(type)))
    371         return MediaDocument::create(init);
    372 
    373     // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed.
    374     // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle,
    375     // and also serves as an optimization to prevent loading the plug-in database in the common case.
    376     if (type != "text/plain" && pluginData && pluginData->supportsMimeType(type))
    377         return PluginDocument::create(init);
    378     if (isTextMIMEType(type))
    379         return TextDocument::create(init);
    380     if (type == "image/svg+xml")
    381         return XMLDocument::createSVG(init);
    382     if (isXMLMIMEType(type))
    383         return XMLDocument::create(init);
    384 
    385     return HTMLDocument::create(init);
    386 }
    387 
    388 void DOMImplementation::trace(Visitor* visitor)
    389 {
    390     visitor->trace(m_document);
    391 }
    392 
    393 }
    394