| 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 "DocumentType.h" |
|---|
| 31 | #include "Element.h" |
|---|
| 32 | #include "ExceptionCode.h" |
|---|
| 33 | #include "Frame.h" |
|---|
| 34 | #include "FTPDirectoryDocument.h" |
|---|
| 35 | #include "HTMLDocument.h" |
|---|
| 36 | #include "HTMLNames.h" |
|---|
| 37 | #include "HTMLViewSourceDocument.h" |
|---|
| 38 | #include "Image.h" |
|---|
| 39 | #include "ImageDocument.h" |
|---|
| 40 | #include "MediaDocument.h" |
|---|
| 41 | #include "MediaList.h" |
|---|
| 42 | #include "MediaPlayer.h" |
|---|
| 43 | #include "MIMETypeRegistry.h" |
|---|
| 44 | #include "Page.h" |
|---|
| 45 | #include "PluginData.h" |
|---|
| 46 | #include "PluginDocument.h" |
|---|
| 47 | #include "RegularExpression.h" |
|---|
| 48 | #include "Settings.h" |
|---|
| 49 | #include "TextDocument.h" |
|---|
| 50 | #include "XMLNames.h" |
|---|
| 51 | #include <wtf/StdLibExtras.h> |
|---|
| 52 | |
|---|
| 53 | #if ENABLE(SVG) |
|---|
| 54 | #include "SVGNames.h" |
|---|
| 55 | #include "SVGDocument.h" |
|---|
| 56 | #endif |
|---|
| 57 | |
|---|
| 58 | #if ENABLE(WML) |
|---|
| 59 | #include "WMLNames.h" |
|---|
| 60 | #include "WMLDocument.h" |
|---|
| 61 | #endif |
|---|
| 62 | |
|---|
| 63 | namespace WebCore { |
|---|
| 64 | |
|---|
| 65 | #if ENABLE(SVG) |
|---|
| 66 | |
|---|
| 67 | typedef HashSet<String, CaseFoldingHash> FeatureSet; |
|---|
| 68 | |
|---|
| 69 | static void addString(FeatureSet& set, const char* string) |
|---|
| 70 | { |
|---|
| 71 | set.add(string); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | static bool isSVG10Feature(const String &feature) |
|---|
| 75 | { |
|---|
| 76 | static bool initialized = false; |
|---|
| 77 | DEFINE_STATIC_LOCAL(FeatureSet, svgFeatures, ()); |
|---|
| 78 | if (!initialized) { |
|---|
| 79 | #if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(FILTERS) && ENABLE(SVG_FONTS) |
|---|
| 80 | addString(svgFeatures, "svg"); |
|---|
| 81 | addString(svgFeatures, "svg.static"); |
|---|
| 82 | #endif |
|---|
| 83 | // addString(svgFeatures, "svg.animation"); |
|---|
| 84 | // addString(svgFeatures, "svg.dynamic"); |
|---|
| 85 | // addString(svgFeatures, "svg.dom.animation"); |
|---|
| 86 | // addString(svgFeatures, "svg.dom.dynamic"); |
|---|
| 87 | #if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(FILTERS) && ENABLE(SVG_FONTS) |
|---|
| 88 | addString(svgFeatures, "dom"); |
|---|
| 89 | addString(svgFeatures, "dom.svg"); |
|---|
| 90 | addString(svgFeatures, "dom.svg.static"); |
|---|
| 91 | #endif |
|---|
| 92 | // addString(svgFeatures, "svg.all"); |
|---|
| 93 | // addString(svgFeatures, "dom.svg.all"); |
|---|
| 94 | initialized = true; |
|---|
| 95 | } |
|---|
| 96 | return svgFeatures.contains(feature); |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | static bool isSVG11Feature(const String &feature) |
|---|
| 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_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(FILTERS) && ENABLE(SVG_FONTS) |
|---|
| 108 | addString(svgFeatures, "SVG"); |
|---|
| 109 | addString(svgFeatures, "SVGDOM"); |
|---|
| 110 | addString(svgFeatures, "SVG-static"); |
|---|
| 111 | addString(svgFeatures, "SVGDOM-static"); |
|---|
| 112 | #endif |
|---|
| 113 | #if ENABLE(SVG_ANIMATION) |
|---|
| 114 | addString(svgFeatures, "SVG-animation"); |
|---|
| 115 | addString(svgFeatures, "SVGDOM-animation"); |
|---|
| 116 | #endif |
|---|
| 117 | // addString(svgFeatures, "SVG-dynamic); |
|---|
| 118 | // addString(svgFeatures, "SVGDOM-dynamic); |
|---|
| 119 | addString(svgFeatures, "CoreAttribute"); |
|---|
| 120 | #if ENABLE(SVG_USE) |
|---|
| 121 | addString(svgFeatures, "Structure"); |
|---|
| 122 | addString(svgFeatures, "BasicStructure"); |
|---|
| 123 | #endif |
|---|
| 124 | addString(svgFeatures, "ContainerAttribute"); |
|---|
| 125 | addString(svgFeatures, "ConditionalProcessing"); |
|---|
| 126 | addString(svgFeatures, "Image"); |
|---|
| 127 | addString(svgFeatures, "Style"); |
|---|
| 128 | addString(svgFeatures, "ViewportAttribute"); |
|---|
| 129 | addString(svgFeatures, "Shape"); |
|---|
| 130 | // addString(svgFeatures, "Text"); // requires altGlyph, bug 6426 |
|---|
| 131 | addString(svgFeatures, "BasicText"); |
|---|
| 132 | addString(svgFeatures, "PaintAttribute"); |
|---|
| 133 | addString(svgFeatures, "BasicPaintAttribute"); |
|---|
| 134 | addString(svgFeatures, "OpacityAttribute"); |
|---|
| 135 | addString(svgFeatures, "GraphicsAttribute"); |
|---|
| 136 | addString(svgFeatures, "BaseGraphicsAttribute"); |
|---|
| 137 | addString(svgFeatures, "Marker"); |
|---|
| 138 | // addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037 |
|---|
| 139 | addString(svgFeatures, "Gradient"); |
|---|
| 140 | addString(svgFeatures, "Pattern"); |
|---|
| 141 | addString(svgFeatures, "Clip"); |
|---|
| 142 | addString(svgFeatures, "BasicClip"); |
|---|
| 143 | addString(svgFeatures, "Mask"); |
|---|
| 144 | #if ENABLE(FILTERS) |
|---|
| 145 | // addString(svgFeatures, "Filter"); |
|---|
| 146 | addString(svgFeatures, "BasicFilter"); |
|---|
| 147 | #endif |
|---|
| 148 | addString(svgFeatures, "DocumentEventsAttribute"); |
|---|
| 149 | addString(svgFeatures, "GraphicalEventsAttribute"); |
|---|
| 150 | // addString(svgFeatures, "AnimationEventsAttribute"); |
|---|
| 151 | addString(svgFeatures, "Cursor"); |
|---|
| 152 | addString(svgFeatures, "Hyperlinking"); |
|---|
| 153 | addString(svgFeatures, "XlinkAttribute"); |
|---|
| 154 | addString(svgFeatures, "ExternalResourcesRequired"); |
|---|
| 155 | // addString(svgFeatures, "View"); // buggy <view> support, bug 16962 |
|---|
| 156 | addString(svgFeatures, "Script"); |
|---|
| 157 | #if ENABLE(SVG_ANIMATION) |
|---|
| 158 | addString(svgFeatures, "Animation"); |
|---|
| 159 | #endif |
|---|
| 160 | #if ENABLE(SVG_FONTS) |
|---|
| 161 | addString(svgFeatures, "Font"); |
|---|
| 162 | addString(svgFeatures, "BasicFont"); |
|---|
| 163 | #endif |
|---|
| 164 | #if ENABLE(SVG_FOREIGN_OBJECT) |
|---|
| 165 | addString(svgFeatures, "Extensibility"); |
|---|
| 166 | #endif |
|---|
| 167 | initialized = true; |
|---|
| 168 | } |
|---|
| 169 | return svgFeatures.contains(feature); |
|---|
| 170 | } |
|---|
| 171 | #endif |
|---|
| 172 | |
|---|
| 173 | bool DOMImplementation::hasFeature(const String& feature, const String& version) |
|---|
| 174 | { |
|---|
| 175 | String lower = feature.lower(); |
|---|
| 176 | if (lower == "core" || lower == "html" || lower == "xml" || lower == "xhtml") |
|---|
| 177 | return version.isEmpty() || version == "1.0" || version == "2.0"; |
|---|
| 178 | if (lower == "css" |
|---|
| 179 | || lower == "css2" |
|---|
| 180 | || lower == "events" |
|---|
| 181 | || lower == "htmlevents" |
|---|
| 182 | || lower == "mouseevents" |
|---|
| 183 | || lower == "mutationevents" |
|---|
| 184 | || lower == "range" |
|---|
| 185 | || lower == "stylesheets" |
|---|
| 186 | || lower == "traversal" |
|---|
| 187 | || lower == "uievents" |
|---|
| 188 | || lower == "views") |
|---|
| 189 | return version.isEmpty() || version == "2.0"; |
|---|
| 190 | if (lower == "xpath" || lower == "textevents") |
|---|
| 191 | return version.isEmpty() || version == "3.0"; |
|---|
| 192 | |
|---|
| 193 | #if ENABLE(SVG) |
|---|
| 194 | if ((version.isEmpty() || version == "1.1") && feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)) { |
|---|
| 195 | if (isSVG11Feature(feature.right(feature.length() - 35))) |
|---|
| 196 | return true; |
|---|
| 197 | } |
|---|
| 198 | |
|---|
| 199 | if ((version.isEmpty() || version == "1.0") && feature.startsWith("org.w3c.", false)) { |
|---|
| 200 | if (isSVG10Feature(feature.right(feature.length() - 8))) |
|---|
| 201 | return true; |
|---|
| 202 | } |
|---|
| 203 | #endif |
|---|
| 204 | |
|---|
| 205 | return false; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | PassRefPtr<DocumentType> DOMImplementation::createDocumentType(const String& qualifiedName, |
|---|
| 209 | const String& publicId, const String& systemId, ExceptionCode& ec) |
|---|
| 210 | { |
|---|
| 211 | String prefix, localName; |
|---|
| 212 | if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec)) |
|---|
| 213 | return 0; |
|---|
| 214 | |
|---|
| 215 | return DocumentType::create(0, qualifiedName, publicId, systemId); |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/) |
|---|
| 219 | { |
|---|
| 220 | return 0; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceURI, |
|---|
| 224 | const String& qualifiedName, DocumentType* doctype, ExceptionCode& ec) |
|---|
| 225 | { |
|---|
| 226 | // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was |
|---|
| 227 | // created from a different implementation. |
|---|
| 228 | bool shouldThrowWrongDocErr = false; |
|---|
| 229 | if (doctype && doctype->document()) |
|---|
| 230 | shouldThrowWrongDocErr = true; |
|---|
| 231 | |
|---|
| 232 | RefPtr<Document> doc; |
|---|
| 233 | #if ENABLE(SVG) |
|---|
| 234 | if (namespaceURI == SVGNames::svgNamespaceURI) |
|---|
| 235 | doc = SVGDocument::create(0); |
|---|
| 236 | else |
|---|
| 237 | #endif |
|---|
| 238 | #if ENABLE(WML) |
|---|
| 239 | if (namespaceURI == WMLNames::wmlNamespaceURI) |
|---|
| 240 | doc = WMLDocument::create(0); |
|---|
| 241 | else |
|---|
| 242 | #endif |
|---|
| 243 | if (namespaceURI == HTMLNames::xhtmlNamespaceURI) |
|---|
| 244 | doc = Document::createXHTML(0); |
|---|
| 245 | else |
|---|
| 246 | doc = Document::create(0); |
|---|
| 247 | |
|---|
| 248 | // now get the interesting parts of the doctype |
|---|
| 249 | if (doctype) |
|---|
| 250 | doc->addChild(doctype); |
|---|
| 251 | |
|---|
| 252 | if (!qualifiedName.isEmpty()) { |
|---|
| 253 | RefPtr<Node> documentElement = doc->createElementNS(namespaceURI, qualifiedName, ec); |
|---|
| 254 | if (ec) |
|---|
| 255 | return 0; |
|---|
| 256 | doc->addChild(documentElement.release()); |
|---|
| 257 | } |
|---|
| 258 | |
|---|
| 259 | // Hixie's interpretation of the DOM Core spec suggests we should prefer |
|---|
| 260 | // other exceptions to WRONG_DOCUMENT_ERR (based on order mentioned in spec) |
|---|
| 261 | if (shouldThrowWrongDocErr) { |
|---|
| 262 | ec = WRONG_DOCUMENT_ERR; |
|---|
| 263 | return 0; |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | return doc.release(); |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | PassRefPtr<CSSStyleSheet> DOMImplementation::createCSSStyleSheet(const String&, const String& media, ExceptionCode&) |
|---|
| 270 | { |
|---|
| 271 | // FIXME: Title should be set. |
|---|
| 272 | // FIXME: Media could have wrong syntax, in which case we should generate an exception. |
|---|
| 273 | RefPtr<CSSStyleSheet> sheet = CSSStyleSheet::create(); |
|---|
| 274 | sheet->setMedia(MediaList::createAllowingDescriptionSyntax(sheet.get(), media)); |
|---|
| 275 | return sheet.release(); |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | PassRefPtr<Document> DOMImplementation::createDocument(Frame* frame) |
|---|
| 279 | { |
|---|
| 280 | return Document::create(frame); |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(Frame* frame) |
|---|
| 284 | { |
|---|
| 285 | return HTMLDocument::create(frame); |
|---|
| 286 | } |
|---|
| 287 | |
|---|
| 288 | bool DOMImplementation::isXMLMIMEType(const String& mimeType) |
|---|
| 289 | { |
|---|
| 290 | if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl") |
|---|
| 291 | return true; |
|---|
| 292 | static const char* const validChars = "[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]"; // per RFCs: 3023, 2045 |
|---|
| 293 | DEFINE_STATIC_LOCAL(RegularExpression, xmlTypeRegExp, (String("^") + validChars + "+/" + validChars + "+\\+xml$", TextCaseSensitive)); |
|---|
| 294 | return xmlTypeRegExp.match(mimeType) > -1; |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | bool DOMImplementation::isTextMIMEType(const String& mimeType) |
|---|
| 298 | { |
|---|
| 299 | if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || |
|---|
| 300 | (mimeType.startsWith("text/") && mimeType != "text/html" && |
|---|
| 301 | mimeType != "text/xml" && mimeType != "text/xsl")) |
|---|
| 302 | return true; |
|---|
| 303 | |
|---|
| 304 | return false; |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title) |
|---|
| 308 | { |
|---|
| 309 | RefPtr<HTMLDocument> d = HTMLDocument::create(0); |
|---|
| 310 | d->open(); |
|---|
| 311 | d->write("<!doctype html><html><head><title>" + title + "</title></head><body></body></html>"); |
|---|
| 312 | return d.release(); |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| 315 | PassRefPtr<Document> DOMImplementation::createDocument(const String& type, Frame* frame, bool inViewSourceMode) |
|---|
| 316 | { |
|---|
| 317 | if (inViewSourceMode) |
|---|
| 318 | return HTMLViewSourceDocument::create(frame, type); |
|---|
| 319 | |
|---|
| 320 | // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those. |
|---|
| 321 | if (type == "text/html") |
|---|
| 322 | return HTMLDocument::create(frame); |
|---|
| 323 | if (type == "application/xhtml+xml" |
|---|
| 324 | #if ENABLE(XHTMLMP) |
|---|
| 325 | || type == "application/vnd.wap.xhtml+xml" |
|---|
| 326 | #endif |
|---|
| 327 | ) |
|---|
| 328 | return Document::createXHTML(frame); |
|---|
| 329 | |
|---|
| 330 | #if ENABLE(WML) |
|---|
| 331 | if (type == "text/vnd.wap.wml" || type == "application/vnd.wap.wmlc") |
|---|
| 332 | return WMLDocument::create(frame); |
|---|
| 333 | #endif |
|---|
| 334 | |
|---|
| 335 | #if ENABLE(FTPDIR) |
|---|
| 336 | // Plugins cannot take FTP from us either |
|---|
| 337 | if (type == "application/x-ftp-directory") |
|---|
| 338 | return FTPDirectoryDocument::create(frame); |
|---|
| 339 | #endif |
|---|
| 340 | |
|---|
| 341 | PluginData* pluginData = 0; |
|---|
| 342 | if (frame && frame->page() && frame->page()->settings()->arePluginsEnabled()) |
|---|
| 343 | pluginData = frame->page()->pluginData(); |
|---|
| 344 | |
|---|
| 345 | // PDF is one image type for which a plugin can override built-in support. |
|---|
| 346 | // We do not want QuickTime to take over all image types, obviously. |
|---|
| 347 | if ((type == "application/pdf" || type == "text/pdf") && pluginData && pluginData->supportsMimeType(type)) |
|---|
| 348 | return PluginDocument::create(frame); |
|---|
| 349 | if (Image::supportsType(type)) |
|---|
| 350 | return ImageDocument::create(frame); |
|---|
| 351 | |
|---|
| 352 | #if ENABLE(VIDEO) |
|---|
| 353 | // Check to see if the type can be played by our MediaPlayer, if so create a MediaDocument |
|---|
| 354 | if (MediaPlayer::supportsType(ContentType(type))) |
|---|
| 355 | return MediaDocument::create(frame); |
|---|
| 356 | #endif |
|---|
| 357 | |
|---|
| 358 | // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed. |
|---|
| 359 | // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle, |
|---|
| 360 | // and also serves as an optimization to prevent loading the plug-in database in the common case. |
|---|
| 361 | if (type != "text/plain" && pluginData && pluginData->supportsMimeType(type)) |
|---|
| 362 | return PluginDocument::create(frame); |
|---|
| 363 | if (isTextMIMEType(type)) |
|---|
| 364 | return TextDocument::create(frame); |
|---|
| 365 | |
|---|
| 366 | #if ENABLE(SVG) |
|---|
| 367 | if (type == "image/svg+xml") { |
|---|
| 368 | #if ENABLE(DASHBOARD_SUPPORT) |
|---|
| 369 | Settings* settings = frame ? frame->settings() : 0; |
|---|
| 370 | if (!settings || !settings->usesDashboardBackwardCompatibilityMode()) |
|---|
| 371 | #endif |
|---|
| 372 | return SVGDocument::create(frame); |
|---|
| 373 | } |
|---|
| 374 | #endif |
|---|
| 375 | if (isXMLMIMEType(type)) |
|---|
| 376 | return Document::create(frame); |
|---|
| 377 | |
|---|
| 378 | return HTMLDocument::create(frame); |
|---|
| 379 | } |
|---|
| 380 | |
|---|
| 381 | } |
|---|