1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 6 * Copyright (C) 2006 Samuel Weinig (sam@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 "DOMImplementation.h" 27 28#include "ContentType.h" 29#include "CSSStyleSheet.h" 30#include "ContextFeatures.h" 31#include "DocumentType.h" 32#include "Element.h" 33#include "ExceptionCode.h" 34#include "Frame.h" 35#include "FrameLoader.h" 36#include "FrameLoaderClient.h" 37#include "FTPDirectoryDocument.h" 38#include "HTMLDocument.h" 39#include "HTMLNames.h" 40#include "HTMLViewSourceDocument.h" 41#include "Image.h" 42#include "ImageDocument.h" 43#include "MediaDocument.h" 44#include "MediaList.h" 45#include "MediaPlayer.h" 46#include "MIMETypeRegistry.h" 47#include "Page.h" 48#include "PluginData.h" 49#include "PluginDocument.h" 50#include "SecurityOrigin.h" 51#include "Settings.h" 52#include "StyleSheetContents.h" 53#include "TextDocument.h" 54#include "ThreadGlobalData.h" 55#include "XMLNames.h" 56#include <wtf/StdLibExtras.h> 57 58#if ENABLE(SVG) 59#include "SVGNames.h" 60#include "SVGDocument.h" 61#endif 62 63namespace WebCore { 64 65typedef HashSet<String, CaseFoldingHash> FeatureSet; 66 67static void addString(FeatureSet& set, const char* string) 68{ 69 set.add(string); 70} 71 72#if ENABLE(VIDEO) 73class DOMImplementationSupportsTypeClient : public MediaPlayerSupportsTypeClient { 74public: 75 DOMImplementationSupportsTypeClient(bool needsHacks, const String& host) 76 : m_needsHacks(needsHacks) 77 , m_host(host) 78 { 79 } 80 81private: 82 virtual bool mediaPlayerNeedsSiteSpecificHacks() const OVERRIDE { return m_needsHacks; } 83 virtual String mediaPlayerDocumentHost() const OVERRIDE { return m_host; } 84 85 bool m_needsHacks; 86 String m_host; 87}; 88#endif 89 90#if ENABLE(SVG) 91 92static bool isSVG10Feature(const String &feature, const String &version) 93{ 94 if (!version.isEmpty() && version != "1.0") 95 return false; 96 97 static bool initialized = false; 98 DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); 99 if (!initialized) { 100#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) 101 addString(svgFeatures, "svg"); 102 addString(svgFeatures, "svg.static"); 103#endif 104// addString(svgFeatures, "svg.animation"); 105// addString(svgFeatures, "svg.dynamic"); 106// addString(svgFeatures, "svg.dom.animation"); 107// addString(svgFeatures, "svg.dom.dynamic"); 108#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) 109 addString(svgFeatures, "dom"); 110 addString(svgFeatures, "dom.svg"); 111 addString(svgFeatures, "dom.svg.static"); 112#endif 113// addString(svgFeatures, "svg.all"); 114// addString(svgFeatures, "dom.svg.all"); 115 initialized = true; 116 } 117 return feature.startsWith("org.w3c.", false) 118 && svgFeatures.contains(feature.right(feature.length() - 8)); 119} 120 121static bool isSVG11Feature(const String &feature, const String &version) 122{ 123 if (!version.isEmpty() && version != "1.1") 124 return false; 125 126 static bool initialized = false; 127 DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); 128 if (!initialized) { 129 // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets 130 // lack of Font and Filter support. 131 // http://bugs.webkit.org/show_bug.cgi?id=15480 132#if ENABLE(FILTERS) && ENABLE(SVG_FONTS) 133 addString(svgFeatures, "SVG"); 134 addString(svgFeatures, "SVGDOM"); 135 addString(svgFeatures, "SVG-static"); 136 addString(svgFeatures, "SVGDOM-static"); 137#endif 138 addString(svgFeatures, "SVG-animation"); 139 addString(svgFeatures, "SVGDOM-animation"); 140// addString(svgFeatures, "SVG-dynamic); 141// addString(svgFeatures, "SVGDOM-dynamic); 142 addString(svgFeatures, "CoreAttribute"); 143 addString(svgFeatures, "Structure"); 144 addString(svgFeatures, "BasicStructure"); 145 addString(svgFeatures, "ContainerAttribute"); 146 addString(svgFeatures, "ConditionalProcessing"); 147 addString(svgFeatures, "Image"); 148 addString(svgFeatures, "Style"); 149 addString(svgFeatures, "ViewportAttribute"); 150 addString(svgFeatures, "Shape"); 151 addString(svgFeatures, "Text"); 152 addString(svgFeatures, "BasicText"); 153 addString(svgFeatures, "PaintAttribute"); 154 addString(svgFeatures, "BasicPaintAttribute"); 155 addString(svgFeatures, "OpacityAttribute"); 156 addString(svgFeatures, "GraphicsAttribute"); 157 addString(svgFeatures, "BaseGraphicsAttribute"); 158 addString(svgFeatures, "Marker"); 159// addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037 160 addString(svgFeatures, "Gradient"); 161 addString(svgFeatures, "Pattern"); 162 addString(svgFeatures, "Clip"); 163 addString(svgFeatures, "BasicClip"); 164 addString(svgFeatures, "Mask"); 165#if ENABLE(FILTERS) 166 addString(svgFeatures, "Filter"); 167 addString(svgFeatures, "BasicFilter"); 168#endif 169 addString(svgFeatures, "DocumentEventsAttribute"); 170 addString(svgFeatures, "GraphicalEventsAttribute"); 171// addString(svgFeatures, "AnimationEventsAttribute"); 172 addString(svgFeatures, "Cursor"); 173 addString(svgFeatures, "Hyperlinking"); 174 addString(svgFeatures, "XlinkAttribute"); 175 addString(svgFeatures, "ExternalResourcesRequired"); 176 addString(svgFeatures, "View"); 177 addString(svgFeatures, "Script"); 178 addString(svgFeatures, "Animation"); 179#if ENABLE(SVG_FONTS) 180 addString(svgFeatures, "Font"); 181 addString(svgFeatures, "BasicFont"); 182#endif 183 addString(svgFeatures, "Extensibility"); 184 initialized = true; 185 } 186 return feature.startsWith("http://www.w3.org/tr/svg11/feature#", false) 187 && svgFeatures.contains(feature.right(feature.length() - 35)); 188} 189#endif 190 191static bool isEvents2Feature(const String &feature, const String &version) 192{ 193 if (!version.isEmpty() && version != "2.0") 194 return false; 195 196 static bool initialized = false; 197 DEFINE_STATIC_LOCAL(FeatureSet, events2Features, ()); 198 if (!initialized) { 199 addString(events2Features, "Events"); 200 addString(events2Features, "HTMLEvents"); 201 addString(events2Features, "MouseEvents"); 202 addString(events2Features, "MutationEvents"); 203 addString(events2Features, "UIEvents"); 204 initialized = true; 205 } 206 return events2Features.contains(feature); 207} 208 209static bool isEvents3Feature(const String &feature, const String &version) 210{ 211 if (!version.isEmpty() && version != "3.0") 212 return false; 213 214 static bool initialized = false; 215 DEFINE_STATIC_LOCAL(FeatureSet, events3Features, ()); 216 if (!initialized) { 217 // FIXME: We probably support many of these features. 218// addString(events3Features, "CompositionEvents"); 219// addString(events3Features, "Events"); 220// addString(events3Features, "FocusEvents"); 221// addString(events3Features, "HTMLEvents"); 222// addString(events3Features, "KeyboardEvents"); 223// addString(events3Features, "MouseEvents"); 224// addString(events3Features, "MutationEvents"); 225// addString(events3Features, "MutationNameEvents"); 226 addString(events3Features, "TextEvents"); 227// addString(events3Features, "UIEvents"); 228// addString(events3Features, "WheelEvents"); 229 initialized = true; 230 } 231 // FIXME: We do not yet support Events 3 "extended feature strings". 232 return events3Features.contains(feature); 233} 234 235DOMImplementation::DOMImplementation(Document* document) 236 : m_document(document) 237{ 238} 239 240bool DOMImplementation::hasFeature(const String& feature, const String& version) 241{ 242 String lower = feature.lower(); 243 if (lower == "core" || lower == "html" || lower == "xml" || lower == "xhtml") 244 return version.isEmpty() || version == "1.0" || version == "2.0"; 245 if (lower == "css" 246 || lower == "css2" 247 || lower == "range" 248 || lower == "stylesheets" 249 || lower == "traversal" 250 || lower == "views") 251 return version.isEmpty() || version == "2.0"; 252 if (isEvents2Feature(feature, version)) 253 return true; 254 if (lower == "xpath") 255 return version.isEmpty() || version == "3.0"; 256 if (isEvents3Feature(feature, version)) 257 return true; 258 259#if ENABLE(SVG) 260 if (isSVG11Feature(feature, version)) 261 return true; 262 if (isSVG10Feature(feature, version)) 263 return true; 264#endif 265 266 return false; 267} 268 269PassRefPtr<DocumentType> DOMImplementation::createDocumentType(const String& qualifiedName, 270 const String& publicId, const String& systemId, ExceptionCode& ec) 271{ 272 String prefix, localName; 273 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) 274 return 0; 275 276 return DocumentType::create(0, qualifiedName, publicId, systemId); 277} 278 279DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/) 280{ 281 return 0; 282} 283 284PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceURI, 285 const String& qualifiedName, DocumentType* doctype, ExceptionCode& ec) 286{ 287 RefPtr<Document> doc; 288#if ENABLE(SVG) 289 if (namespaceURI == SVGNames::svgNamespaceURI) 290 doc = SVGDocument::create(0, KURL()); 291 else 292#endif 293 if (namespaceURI == HTMLNames::xhtmlNamespaceURI) 294 doc = Document::createXHTML(0, KURL()); 295 else 296 doc = Document::create(0, KURL()); 297 298 doc->setSecurityOrigin(m_document->securityOrigin()); 299 doc->setContextFeatures(m_document->contextFeatures()); 300 301 RefPtr<Node> documentElement; 302 if (!qualifiedName.isEmpty()) { 303 documentElement = doc->createElementNS(namespaceURI, qualifiedName, ec); 304 if (ec) 305 return 0; 306 } 307 308 // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was 309 // created from a different implementation. 310 // Hixie's interpretation of the DOM Core spec suggests we should prefer 311 // other exceptions to WRONG_DOCUMENT_ERR (based on order mentioned in spec), 312 // but this matches the new DOM Core spec (http://www.w3.org/TR/domcore/). 313 if (doctype && doctype->document()) { 314 ec = WRONG_DOCUMENT_ERR; 315 return 0; 316 } 317 318 if (doctype) 319 doc->appendChild(doctype); 320 if (documentElement) 321 doc->appendChild(documentElement.release()); 322 323 return doc.release(); 324} 325 326PassRefPtr<CSSStyleSheet> DOMImplementation::createCSSStyleSheet(const String&, const String& media, ExceptionCode&) 327{ 328 // FIXME: Title should be set. 329 // FIXME: Media could have wrong syntax, in which case we should generate an exception. 330 RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::create(StyleSheetContents::create()); 331 sheet->setMediaQueries(MediaQuerySet::createAllowingDescriptionSyntax(media)); 332 return sheet; 333} 334 335static inline bool isValidXMLMIMETypeChar(UChar c) 336{ 337 // Valid characters per RFCs 3023 and 2045: 338 // 0-9a-zA-Z_-+~!$^{}|.%'`#&* 339 return isASCIIAlphanumeric(c) || c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' 340 || c == '-' || c == '.' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || c == '~'; 341} 342 343bool DOMImplementation::isXMLMIMEType(const String& mimeType) 344{ 345 if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl") 346 return true; 347 348 if (!mimeType.endsWith("+xml")) 349 return false; 350 351 size_t slashPosition = mimeType.find('/'); 352 // Take into account the '+xml' ending of mimeType. 353 if (slashPosition == notFound || !slashPosition || slashPosition == mimeType.length() - 5) 354 return false; 355 356 // Again, mimeType ends with '+xml', no need to check the validity of that substring. 357 for (size_t i = 0; i < mimeType.length() - 4; ++i) { 358 if (!isValidXMLMIMETypeChar(mimeType[i]) && i != slashPosition) 359 return false; 360 } 361 362 return true; 363} 364 365bool DOMImplementation::isTextMIMEType(const String& mimeType) 366{ 367 if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) 368 || mimeType == "application/json" // Render JSON as text/plain. 369 || (mimeType.startsWith("text/") && mimeType != "text/html" 370 && mimeType != "text/xml" && mimeType != "text/xsl")) 371 return true; 372 373 return false; 374} 375 376PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title) 377{ 378 RefPtr<HTMLDocument> d = HTMLDocument::create(0, KURL()); 379 d->open(); 380 d->write("<!doctype html><html><body></body></html>"); 381 if (!title.isNull()) 382 d->setTitle(title); 383 d->setSecurityOrigin(m_document->securityOrigin()); 384 d->setContextFeatures(m_document->contextFeatures()); 385 return d.release(); 386} 387 388PassRefPtr<Document> DOMImplementation::createDocument(const String& type, Frame* frame, const KURL& url, bool inViewSourceMode) 389{ 390 if (inViewSourceMode) 391 return HTMLViewSourceDocument::create(frame, url, type); 392 393 // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those. 394 if (type == "text/html") 395 return HTMLDocument::create(frame, url); 396 if (type == "application/xhtml+xml") 397 return Document::createXHTML(frame, url); 398 399#if ENABLE(FTPDIR) 400 // Plugins cannot take FTP from us either 401 if (type == "application/x-ftp-directory") 402 return FTPDirectoryDocument::create(frame, url); 403#endif 404 405 PluginData* pluginData = 0; 406 PluginData::AllowedPluginTypes allowedPluginTypes = PluginData::OnlyApplicationPlugins; 407 if (frame && frame->page()) { 408 if (frame->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin)) 409 allowedPluginTypes = PluginData::AllPlugins; 410 411 pluginData = frame->page()->pluginData(); 412 } 413 414 // PDF is one image type for which a plugin can override built-in support. 415 // We do not want QuickTime to take over all image types, obviously. 416 if ((MIMETypeRegistry::isPDFOrPostScriptMIMEType(type)) && pluginData && pluginData->supportsMimeType(type, allowedPluginTypes)) 417 return PluginDocument::create(frame, url); 418 if (Image::supportsType(type)) 419 return ImageDocument::create(frame, url); 420 421#if ENABLE(VIDEO) 422 // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument 423 // Key system is not applicable here. 424 DOMImplementationSupportsTypeClient client(frame && frame->settings() && frame->settings()->needsSiteSpecificQuirks(), url.host()); 425 if (MediaPlayer::supportsType(ContentType(type), String(), url, &client)) 426 return MediaDocument::create(frame, url); 427#endif 428 429 // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed. 430 // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle, 431 // and also serves as an optimization to prevent loading the plug-in database in the common case. 432 if (type != "text/plain" && ((pluginData && pluginData->supportsMimeType(type, allowedPluginTypes)) || (frame && frame->loader()->client()->shouldAlwaysUsePluginDocument(type)))) 433 return PluginDocument::create(frame, url); 434 if (isTextMIMEType(type)) 435 return TextDocument::create(frame, url); 436 437#if ENABLE(SVG) 438 if (type == "image/svg+xml") 439 return SVGDocument::create(frame, url); 440#endif 441 if (isXMLMIMEType(type)) 442 return Document::create(frame, url); 443 444 return HTMLDocument::create(frame, url); 445} 446 447} 448