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