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