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/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/XMLDocument.h"
     40 #include "core/dom/custom/CustomElementRegistrationContext.h"
     41 #include "core/frame/LocalFrame.h"
     42 #include "core/frame/UseCounter.h"
     43 #include "core/html/HTMLDocument.h"
     44 #include "core/html/HTMLMediaElement.h"
     45 #include "core/html/HTMLViewSourceDocument.h"
     46 #include "core/html/ImageDocument.h"
     47 #include "core/html/MediaDocument.h"
     48 #include "core/html/PluginDocument.h"
     49 #include "core/html/TextDocument.h"
     50 #include "core/loader/FrameLoader.h"
     51 #include "core/page/Page.h"
     52 #include "platform/ContentType.h"
     53 #include "platform/MIMETypeRegistry.h"
     54 #include "platform/graphics/Image.h"
     55 #include "platform/graphics/media/MediaPlayer.h"
     56 #include "platform/plugins/PluginData.h"
     57 #include "platform/weborigin/SecurityOrigin.h"
     58 #include "wtf/StdLibExtras.h"
     59 
     60 namespace WebCore {
     61 
     62 typedef HashSet<String, CaseFoldingHash> FeatureSet;
     63 
     64 static void addString(FeatureSet& set, const char* string)
     65 {
     66     set.add(string);
     67 }
     68 
     69 static bool isSupportedSVG10Feature(const String& feature, const String& version)
     70 {
     71     if (!version.isEmpty() && version != "1.0")
     72         return false;
     73 
     74     static bool initialized = false;
     75     DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
     76     if (!initialized) {
     77 #if ENABLE(SVG_FONTS)
     78         addString(svgFeatures, "svg");
     79         addString(svgFeatures, "svg.static");
     80 #endif
     81 //      addString(svgFeatures, "svg.animation");
     82 //      addString(svgFeatures, "svg.dynamic");
     83 //      addString(svgFeatures, "svg.dom.animation");
     84 //      addString(svgFeatures, "svg.dom.dynamic");
     85 #if ENABLE(SVG_FONTS)
     86         addString(svgFeatures, "dom");
     87         addString(svgFeatures, "dom.svg");
     88         addString(svgFeatures, "dom.svg.static");
     89 #endif
     90 //      addString(svgFeatures, "svg.all");
     91 //      addString(svgFeatures, "dom.svg.all");
     92         initialized = true;
     93     }
     94     return feature.startsWith("org.w3c.", false)
     95         && svgFeatures.contains(feature.right(feature.length() - 8));
     96 }
     97 
     98 static bool isSupportedSVG11Feature(const String& feature, const String& version)
     99 {
    100     if (!version.isEmpty() && version != "1.1")
    101         return false;
    102 
    103     static bool initialized = false;
    104     DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ());
    105     if (!initialized) {
    106         // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets
    107         // lack of Font and Filter support.
    108         // http://bugs.webkit.org/show_bug.cgi?id=15480
    109 #if ENABLE(SVG_FONTS)
    110         addString(svgFeatures, "SVG");
    111         addString(svgFeatures, "SVGDOM");
    112         addString(svgFeatures, "SVG-static");
    113         addString(svgFeatures, "SVGDOM-static");
    114 #endif
    115         addString(svgFeatures, "SVG-animation");
    116         addString(svgFeatures, "SVGDOM-animation");
    117 //      addString(svgFeatures, "SVG-dynamic);
    118 //      addString(svgFeatures, "SVGDOM-dynamic);
    119         addString(svgFeatures, "CoreAttribute");
    120         addString(svgFeatures, "Structure");
    121         addString(svgFeatures, "BasicStructure");
    122         addString(svgFeatures, "ContainerAttribute");
    123         addString(svgFeatures, "ConditionalProcessing");
    124         addString(svgFeatures, "Image");
    125         addString(svgFeatures, "Style");
    126         addString(svgFeatures, "ViewportAttribute");
    127         addString(svgFeatures, "Shape");
    128         addString(svgFeatures, "Text");
    129         addString(svgFeatures, "BasicText");
    130         addString(svgFeatures, "PaintAttribute");
    131         addString(svgFeatures, "BasicPaintAttribute");
    132         addString(svgFeatures, "OpacityAttribute");
    133         addString(svgFeatures, "GraphicsAttribute");
    134         addString(svgFeatures, "BaseGraphicsAttribute");
    135         addString(svgFeatures, "Marker");
    136 //      addString(svgFeatures, "ColorProfile");
    137         addString(svgFeatures, "Gradient");
    138         addString(svgFeatures, "Pattern");
    139         addString(svgFeatures, "Clip");
    140         addString(svgFeatures, "BasicClip");
    141         addString(svgFeatures, "Mask");
    142         addString(svgFeatures, "Filter");
    143         addString(svgFeatures, "BasicFilter");
    144         addString(svgFeatures, "DocumentEventsAttribute");
    145         addString(svgFeatures, "GraphicalEventsAttribute");
    146 //      addString(svgFeatures, "AnimationEventsAttribute");
    147         addString(svgFeatures, "Cursor");
    148         addString(svgFeatures, "Hyperlinking");
    149         addString(svgFeatures, "XlinkAttribute");
    150         addString(svgFeatures, "View");
    151         addString(svgFeatures, "Script");
    152         addString(svgFeatures, "Animation");
    153 #if ENABLE(SVG_FONTS)
    154         addString(svgFeatures, "Font");
    155         addString(svgFeatures, "BasicFont");
    156 #endif
    157         addString(svgFeatures, "Extensibility");
    158         initialized = true;
    159     }
    160     return feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)
    161         && svgFeatures.contains(feature.right(feature.length() - 35));
    162 }
    163 
    164 DOMImplementation::DOMImplementation(Document& document)
    165     : m_document(document)
    166 {
    167     ScriptWrappable::init(this);
    168 }
    169 
    170 bool DOMImplementation::hasFeature(const String& feature, const String& version)
    171 {
    172     if (feature.startsWith("http://www.w3.org/TR/SVG", false)
    173     || feature.startsWith("org.w3c.dom.svg", false)
    174     || feature.startsWith("org.w3c.svg", false)) {
    175         // FIXME: SVG 2.0 support?
    176         return isSupportedSVG10Feature(feature, version) || isSupportedSVG11Feature(feature, version);
    177     }
    178     return true;
    179 }
    180 
    181 bool DOMImplementation::hasFeatureForBindings(const String& feature, const String& version)
    182 {
    183     if (!hasFeature(feature, version)) {
    184         UseCounter::count(m_document, UseCounter::DOMImplementationHasFeatureReturnFalse);
    185         return false;
    186     }
    187     return true;
    188 }
    189 
    190 PassRefPtrWillBeRawPtr<DocumentType> DOMImplementation::createDocumentType(const AtomicString& qualifiedName,
    191     const String& publicId, const String& systemId, ExceptionState& exceptionState)
    192 {
    193     AtomicString prefix, localName;
    194     if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
    195         return nullptr;
    196 
    197     return DocumentType::create(m_document, qualifiedName, publicId, systemId);
    198 }
    199 
    200 PassRefPtrWillBeRawPtr<XMLDocument> DOMImplementation::createDocument(const AtomicString& namespaceURI,
    201     const AtomicString& qualifiedName, DocumentType* doctype, ExceptionState& exceptionState)
    202 {
    203     RefPtrWillBeRawPtr<XMLDocument> doc = nullptr;
    204     DocumentInit init = DocumentInit::fromContext(document().contextDocument());
    205     if (namespaceURI == SVGNames::svgNamespaceURI) {
    206         doc = XMLDocument::createSVG(init);
    207     } else if (namespaceURI == HTMLNames::xhtmlNamespaceURI) {
    208         doc = XMLDocument::createXHTML(init.withRegistrationContext(document().registrationContext()));
    209     } else {
    210         doc = XMLDocument::create(init);
    211     }
    212 
    213     doc->setSecurityOrigin(document().securityOrigin()->isolatedCopy());
    214     doc->setContextFeatures(document().contextFeatures());
    215 
    216     RefPtrWillBeRawPtr<Node> documentElement = nullptr;
    217     if (!qualifiedName.isEmpty()) {
    218         documentElement = doc->createElementNS(namespaceURI, qualifiedName, exceptionState);
    219         if (exceptionState.hadException())
    220             return nullptr;
    221     }
    222 
    223     if (doctype)
    224         doc->appendChild(doctype);
    225     if (documentElement)
    226         doc->appendChild(documentElement.release());
    227 
    228     return doc.release();
    229 }
    230 
    231 bool DOMImplementation::isXMLMIMEType(const String& mimeType)
    232 {
    233     if (equalIgnoringCase(mimeType, "text/xml")
    234         || equalIgnoringCase(mimeType, "application/xml")
    235         || equalIgnoringCase(mimeType, "text/xsl"))
    236         return true;
    237 
    238     // Per RFCs 3023 and 2045, an XML MIME type is of the form:
    239     // ^[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+/[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+\+xml$
    240 
    241     int length = mimeType.length();
    242     if (length < 7)
    243         return false;
    244 
    245     if (mimeType[0] == '/' || mimeType[length - 5] == '/' || !mimeType.endsWith("+xml", false))
    246         return false;
    247 
    248     bool hasSlash = false;
    249     for (int i = 0; i < length - 4; ++i) {
    250         UChar ch = mimeType[i];
    251         if (ch >= '0' && ch <= '9')
    252             continue;
    253         if (ch >= 'a' && ch <= 'z')
    254             continue;
    255         if (ch >= 'A' && ch <= 'Z')
    256             continue;
    257         switch (ch) {
    258         case '_':
    259         case '-':
    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             continue;
    276         case '/':
    277             if (hasSlash)
    278                 return false;
    279             hasSlash = true;
    280             continue;
    281         default:
    282             return false;
    283         }
    284     }
    285 
    286     return true;
    287 }
    288 
    289 bool DOMImplementation::isJSONMIMEType(const String& mimeType)
    290 {
    291     if (mimeType.startsWith("application/json", false))
    292         return true;
    293     if (mimeType.startsWith("application/", false)) {
    294         size_t subtype = mimeType.find("+json", 12, false);
    295         if (subtype != kNotFound) {
    296             // Just check that a parameter wasn't matched.
    297             size_t parameterMarker = mimeType.find(";");
    298             if (parameterMarker == kNotFound) {
    299                 unsigned endSubtype = static_cast<unsigned>(subtype) + 5;
    300                 return endSubtype == mimeType.length() || isASCIISpace(mimeType[endSubtype]);
    301             }
    302             return parameterMarker > subtype;
    303         }
    304     }
    305     return false;
    306 }
    307 
    308 static bool isTextPlainType(const String& mimeType)
    309 {
    310     return mimeType.startsWith("text/", false)
    311         && !(equalIgnoringCase(mimeType, "text/html")
    312             || equalIgnoringCase(mimeType, "text/xml")
    313             || equalIgnoringCase(mimeType, "text/xsl"));
    314 }
    315 
    316 bool DOMImplementation::isTextMIMEType(const String& mimeType)
    317 {
    318     return MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || isJSONMIMEType(mimeType) || isTextPlainType(mimeType);
    319 }
    320 
    321 PassRefPtrWillBeRawPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title)
    322 {
    323     DocumentInit init = DocumentInit::fromContext(document().contextDocument())
    324         .withRegistrationContext(document().registrationContext());
    325     RefPtrWillBeRawPtr<HTMLDocument> d = HTMLDocument::create(init);
    326     d->open();
    327     d->write("<!doctype html><html><body></body></html>");
    328     if (!title.isNull())
    329         d->setTitle(title);
    330     d->setSecurityOrigin(document().securityOrigin()->isolatedCopy());
    331     d->setContextFeatures(document().contextFeatures());
    332     return d.release();
    333 }
    334 
    335 PassRefPtrWillBeRawPtr<Document> DOMImplementation::createDocument(const String& type, LocalFrame* frame, const KURL& url, bool inViewSourceMode)
    336 {
    337     return createDocument(type, DocumentInit(url, frame), inViewSourceMode);
    338 }
    339 
    340 PassRefPtrWillBeRawPtr<Document> DOMImplementation::createDocument(const String& type, const DocumentInit& init, bool inViewSourceMode)
    341 {
    342     if (inViewSourceMode)
    343         return HTMLViewSourceDocument::create(init, type);
    344 
    345     // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those.
    346     if (type == "text/html")
    347         return HTMLDocument::create(init);
    348     if (type == "application/xhtml+xml")
    349         return XMLDocument::createXHTML(init);
    350 
    351     PluginData* pluginData = 0;
    352     if (init.frame() && init.frame()->page() && init.frame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
    353         pluginData = init.frame()->page()->pluginData();
    354 
    355     // PDF is one image type for which a plugin can override built-in support.
    356     // We do not want QuickTime to take over all image types, obviously.
    357     if ((type == "application/pdf" || type == "text/pdf") && pluginData && pluginData->supportsMimeType(type))
    358         return PluginDocument::create(init);
    359     if (Image::supportsType(type))
    360         return ImageDocument::create(init);
    361 
    362     // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument
    363     if (HTMLMediaElement::supportsType(ContentType(type)))
    364         return MediaDocument::create(init);
    365 
    366     // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed.
    367     // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle,
    368     // and also serves as an optimization to prevent loading the plug-in database in the common case.
    369     if (type != "text/plain" && pluginData && pluginData->supportsMimeType(type))
    370         return PluginDocument::create(init);
    371     if (isTextMIMEType(type))
    372         return TextDocument::create(init);
    373     if (type == "image/svg+xml")
    374         return XMLDocument::createSVG(init);
    375     if (isXMLMIMEType(type))
    376         return XMLDocument::create(init);
    377 
    378     return HTMLDocument::create(init);
    379 }
    380 
    381 void DOMImplementation::trace(Visitor* visitor)
    382 {
    383     visitor->trace(m_document);
    384 }
    385 
    386 }
    387