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