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/dom/custom/CustomElementRegistrationContext.h" 40 #include "core/html/HTMLDocument.h" 41 #include "core/html/HTMLMediaElement.h" 42 #include "core/html/HTMLViewSourceDocument.h" 43 #include "core/html/ImageDocument.h" 44 #include "core/html/MediaDocument.h" 45 #include "core/html/PluginDocument.h" 46 #include "core/html/TextDocument.h" 47 #include "core/loader/FrameLoader.h" 48 #include "core/frame/Frame.h" 49 #include "core/page/Page.h" 50 #include "core/svg/SVGDocument.h" 51 #include "platform/ContentType.h" 52 #include "platform/MIMETypeRegistry.h" 53 #include "platform/graphics/Image.h" 54 #include "platform/graphics/media/MediaPlayer.h" 55 #include "platform/plugins/PluginData.h" 56 #include "platform/weborigin/SecurityOrigin.h" 57 #include "wtf/StdLibExtras.h" 58 59 namespace WebCore { 60 61 typedef HashSet<String, CaseFoldingHash> FeatureSet; 62 63 static void addString(FeatureSet& set, const char* string) 64 { 65 set.add(string); 66 } 67 68 static bool isSupportedSVG10Feature(const String& feature, const String& version) 69 { 70 if (!version.isEmpty() && version != "1.0") 71 return false; 72 73 static bool initialized = false; 74 DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); 75 if (!initialized) { 76 #if ENABLE(SVG_FONTS) 77 addString(svgFeatures, "svg"); 78 addString(svgFeatures, "svg.static"); 79 #endif 80 // addString(svgFeatures, "svg.animation"); 81 // addString(svgFeatures, "svg.dynamic"); 82 // addString(svgFeatures, "svg.dom.animation"); 83 // addString(svgFeatures, "svg.dom.dynamic"); 84 #if ENABLE(SVG_FONTS) 85 addString(svgFeatures, "dom"); 86 addString(svgFeatures, "dom.svg"); 87 addString(svgFeatures, "dom.svg.static"); 88 #endif 89 // addString(svgFeatures, "svg.all"); 90 // addString(svgFeatures, "dom.svg.all"); 91 initialized = true; 92 } 93 return feature.startsWith("org.w3c.", false) 94 && svgFeatures.contains(feature.right(feature.length() - 8)); 95 } 96 97 static bool isSupportedSVG11Feature(const String& feature, const String& version) 98 { 99 if (!version.isEmpty() && version != "1.1") 100 return false; 101 102 static bool initialized = false; 103 DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); 104 if (!initialized) { 105 // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets 106 // lack of Font and Filter support. 107 // http://bugs.webkit.org/show_bug.cgi?id=15480 108 #if ENABLE(SVG_FONTS) 109 addString(svgFeatures, "SVG"); 110 addString(svgFeatures, "SVGDOM"); 111 addString(svgFeatures, "SVG-static"); 112 addString(svgFeatures, "SVGDOM-static"); 113 #endif 114 addString(svgFeatures, "SVG-animation"); 115 addString(svgFeatures, "SVGDOM-animation"); 116 // addString(svgFeatures, "SVG-dynamic); 117 // addString(svgFeatures, "SVGDOM-dynamic); 118 addString(svgFeatures, "CoreAttribute"); 119 addString(svgFeatures, "Structure"); 120 addString(svgFeatures, "BasicStructure"); 121 addString(svgFeatures, "ContainerAttribute"); 122 addString(svgFeatures, "ConditionalProcessing"); 123 addString(svgFeatures, "Image"); 124 addString(svgFeatures, "Style"); 125 addString(svgFeatures, "ViewportAttribute"); 126 addString(svgFeatures, "Shape"); 127 addString(svgFeatures, "Text"); 128 addString(svgFeatures, "BasicText"); 129 addString(svgFeatures, "PaintAttribute"); 130 addString(svgFeatures, "BasicPaintAttribute"); 131 addString(svgFeatures, "OpacityAttribute"); 132 addString(svgFeatures, "GraphicsAttribute"); 133 addString(svgFeatures, "BaseGraphicsAttribute"); 134 addString(svgFeatures, "Marker"); 135 // addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037 136 addString(svgFeatures, "Gradient"); 137 addString(svgFeatures, "Pattern"); 138 addString(svgFeatures, "Clip"); 139 addString(svgFeatures, "BasicClip"); 140 addString(svgFeatures, "Mask"); 141 addString(svgFeatures, "Filter"); 142 addString(svgFeatures, "BasicFilter"); 143 addString(svgFeatures, "DocumentEventsAttribute"); 144 addString(svgFeatures, "GraphicalEventsAttribute"); 145 // addString(svgFeatures, "AnimationEventsAttribute"); 146 addString(svgFeatures, "Cursor"); 147 addString(svgFeatures, "Hyperlinking"); 148 addString(svgFeatures, "XlinkAttribute"); 149 addString(svgFeatures, "ExternalResourcesRequired"); 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 PassRefPtr<DocumentType> DOMImplementation::createDocumentType(const AtomicString& qualifiedName, 182 const String& publicId, const String& systemId, ExceptionState& exceptionState) 183 { 184 AtomicString prefix, localName; 185 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState)) 186 return 0; 187 188 return DocumentType::create(&m_document, qualifiedName, publicId, systemId); 189 } 190 191 DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/) 192 { 193 return 0; 194 } 195 196 PassRefPtr<Document> DOMImplementation::createDocument(const AtomicString& namespaceURI, 197 const AtomicString& qualifiedName, DocumentType* doctype, ExceptionState& exceptionState) 198 { 199 RefPtr<Document> doc; 200 DocumentInit init = DocumentInit::fromContext(m_document.contextDocument()); 201 if (namespaceURI == SVGNames::svgNamespaceURI) { 202 doc = SVGDocument::create(init); 203 } else if (namespaceURI == HTMLNames::xhtmlNamespaceURI) { 204 doc = Document::createXHTML(init.withRegistrationContext(m_document.registrationContext())); 205 } else { 206 doc = Document::create(init); 207 } 208 209 doc->setSecurityOrigin(m_document.securityOrigin()->isolatedCopy()); 210 doc->setContextFeatures(m_document.contextFeatures()); 211 212 RefPtr<Node> documentElement; 213 if (!qualifiedName.isEmpty()) { 214 documentElement = doc->createElementNS(namespaceURI, qualifiedName, exceptionState); 215 if (exceptionState.hadException()) 216 return 0; 217 } 218 219 if (doctype) 220 doc->appendChild(doctype); 221 if (documentElement) 222 doc->appendChild(documentElement.release()); 223 224 return doc.release(); 225 } 226 227 PassRefPtr<CSSStyleSheet> DOMImplementation::createCSSStyleSheet(const String&, const String& media) 228 { 229 // FIXME: Title should be set. 230 // FIXME: Media could have wrong syntax, in which case we should generate an exception. 231 RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::create(StyleSheetContents::create()); 232 sheet->setMediaQueries(MediaQuerySet::create(media)); 233 return sheet; 234 } 235 236 bool DOMImplementation::isXMLMIMEType(const String& mimeType) 237 { 238 if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl") 239 return true; 240 241 // Per RFCs 3023 and 2045 a mime type is of the form: 242 // ^[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+/[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]+\+xml$ 243 244 int length = mimeType.length(); 245 if (length < 7) 246 return false; 247 248 if (mimeType[0] == '/' || 249 mimeType[length - 5] == '/' || 250 mimeType[length - 4] != '+' || 251 mimeType[length - 3] != 'x' || 252 mimeType[length - 2] != 'm' || 253 mimeType[length - 1] != 'l') 254 return false; 255 256 bool hasSlash = false; 257 for (int i = 0; i < length - 4; ++i) { 258 UChar ch = mimeType[i]; 259 if (ch >= '0' && ch <= '9') 260 continue; 261 if (ch >= 'a' && ch <= 'z') 262 continue; 263 if (ch >= 'A' && ch <= 'Z') 264 continue; 265 switch (ch) { 266 case '_': 267 case '-': 268 case '+': 269 case '~': 270 case '!': 271 case '$': 272 case '^': 273 case '{': 274 case '}': 275 case '|': 276 case '.': 277 case '%': 278 case '\'': 279 case '`': 280 case '#': 281 case '&': 282 case '*': 283 continue; 284 case '/': 285 if (hasSlash) 286 return false; 287 hasSlash = true; 288 continue; 289 default: 290 return false; 291 } 292 } 293 294 return true; 295 } 296 297 bool DOMImplementation::isTextMIMEType(const String& mimeType) 298 { 299 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) 300 || mimeType == "application/json" // Render JSON as text/plain. 301 || (mimeType.startsWith("text/") && mimeType != "text/html" 302 && mimeType != "text/xml" && mimeType != "text/xsl")) 303 return true; 304 305 return false; 306 } 307 308 PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title) 309 { 310 DocumentInit init = DocumentInit::fromContext(m_document.contextDocument()) 311 .withRegistrationContext(m_document.registrationContext()); 312 RefPtr<HTMLDocument> d = HTMLDocument::create(init); 313 d->open(); 314 d->write("<!doctype html><html><body></body></html>"); 315 if (!title.isNull()) 316 d->setTitle(title); 317 d->setSecurityOrigin(m_document.securityOrigin()->isolatedCopy()); 318 d->setContextFeatures(m_document.contextFeatures()); 319 return d.release(); 320 } 321 322 PassRefPtr<Document> DOMImplementation::createDocument(const String& type, Frame* frame, const KURL& url, bool inViewSourceMode) 323 { 324 return createDocument(type, DocumentInit(url, frame), inViewSourceMode); 325 } 326 327 PassRefPtr<Document> DOMImplementation::createDocument(const String& type, const DocumentInit& init, bool inViewSourceMode) 328 { 329 if (inViewSourceMode) 330 return HTMLViewSourceDocument::create(init, 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(init); 335 if (type == "application/xhtml+xml") 336 return Document::createXHTML(init); 337 338 PluginData* pluginData = 0; 339 if (init.frame() && init.frame()->page() && init.frame()->loader().allowPlugins(NotAboutToInstantiatePlugin)) 340 pluginData = init.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(init); 346 if (Image::supportsType(type)) 347 return ImageDocument::create(init); 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(init); 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(init); 358 if (isTextMIMEType(type)) 359 return TextDocument::create(init); 360 if (type == "image/svg+xml") 361 return SVGDocument::create(init); 362 if (isXMLMIMEType(type)) 363 return Document::create(init); 364 365 return HTMLDocument::create(init); 366 } 367 368 } 369