summaryrefslogtreecommitdiff
path: root/Source/WebCore/html/HTMLObjectElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/HTMLObjectElement.cpp')
-rw-r--r--Source/WebCore/html/HTMLObjectElement.cpp225
1 files changed, 116 insertions, 109 deletions
diff --git a/Source/WebCore/html/HTMLObjectElement.cpp b/Source/WebCore/html/HTMLObjectElement.cpp
index 222f99d43..1a49f0899 100644
--- a/Source/WebCore/html/HTMLObjectElement.cpp
+++ b/Source/WebCore/html/HTMLObjectElement.cpp
@@ -2,7 +2,7 @@
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Stefan Schimanski (1Stein@gmx.de)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
@@ -27,11 +27,7 @@
#include "Attribute.h"
#include "CSSValueKeywords.h"
#include "CachedImage.h"
-#include "Chrome.h"
-#include "ChromeClient.h"
#include "ElementIterator.h"
-#include "EventNames.h"
-#include "ExceptionCode.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLDocument.h"
@@ -55,8 +51,8 @@
#include <wtf/Ref.h>
#if PLATFORM(IOS)
-#include "RuntimeApplicationChecksIOS.h"
-#include "WebCoreSystemInterface.h"
+#include "RuntimeApplicationChecks.h"
+#include <wtf/spi/darwin/dyldSPI.h>
#endif
namespace WebCore {
@@ -64,29 +60,29 @@ namespace WebCore {
using namespace HTMLNames;
inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
- : HTMLPlugInImageElement(tagName, document, createdByParser, ShouldNotPreferPlugInsForImages)
+ : HTMLPlugInImageElement(tagName, document, createdByParser)
+ , FormAssociatedElement(form)
, m_docNamedItem(true)
, m_useFallbackContent(false)
{
ASSERT(hasTagName(objectTag));
- setForm(form ? form : HTMLFormElement::findClosestFormAncestor(*this));
}
inline HTMLObjectElement::~HTMLObjectElement()
{
}
-PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
+Ref<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document& document, HTMLFormElement* form, bool createdByParser)
{
- return adoptRef(new HTMLObjectElement(tagName, document, form, createdByParser));
+ return adoptRef(*new HTMLObjectElement(tagName, document, form, createdByParser));
}
-RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
+RenderWidget* HTMLObjectElement::renderWidgetLoadingPlugin() const
{
// Needs to load the plugin immediatedly because this function is called
// when JavaScript code accesses the plugin.
// FIXME: <rdar://16893708> Check if dispatching events here is safe.
- document().updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasksSynchronously);
+ document().updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks::Synchronously);
return renderWidget(); // This will return 0 if the renderer is not a RenderWidget.
}
@@ -107,58 +103,58 @@ void HTMLObjectElement::collectStyleForPresentationAttribute(const QualifiedName
void HTMLObjectElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
{
+ bool invalidateRenderer = false;
+
if (name == formAttr)
formAttributeChanged();
else if (name == typeAttr) {
- m_serviceType = value.lower();
- size_t pos = m_serviceType.find(";");
- if (pos != notFound)
- m_serviceType = m_serviceType.left(pos);
- if (renderer())
- setNeedsWidgetUpdate(true);
+ m_serviceType = value.string().left(value.find(';')).convertToASCIILowercase();
+ invalidateRenderer = !hasAttributeWithoutSynchronization(classidAttr);
+ setNeedsWidgetUpdate(true);
} else if (name == dataAttr) {
m_url = stripLeadingAndTrailingHTMLSpaces(value);
document().updateStyleIfNeeded();
- if (renderer()) {
- setNeedsWidgetUpdate(true);
- if (isImageType()) {
- if (!m_imageLoader)
- m_imageLoader = adoptPtr(new HTMLImageLoader(this));
- m_imageLoader->updateFromElementIgnoringPreviousError();
- }
+ if (isImageType() && renderer()) {
+ if (!m_imageLoader)
+ m_imageLoader = std::make_unique<HTMLImageLoader>(*this);
+ m_imageLoader->updateFromElementIgnoringPreviousError();
}
+ invalidateRenderer = !hasAttributeWithoutSynchronization(classidAttr);
+ setNeedsWidgetUpdate(true);
} else if (name == classidAttr) {
- m_classId = value;
- if (renderer())
- setNeedsWidgetUpdate(true);
- } else if (name == onbeforeloadAttr)
- setAttributeEventListener(eventNames().beforeloadEvent, name, value);
- else
+ invalidateRenderer = true;
+ setNeedsWidgetUpdate(true);
+ } else
HTMLPlugInImageElement::parseAttribute(name, value);
+
+ if (!invalidateRenderer || !isConnected() || !renderer())
+ return;
+
+ clearUseFallbackContent();
+ invalidateStyleAndRenderersForSubtree();
}
-static void mapDataParamToSrc(Vector<String>* paramNames, Vector<String>* paramValues)
+static void mapDataParamToSrc(Vector<String>& paramNames, Vector<String>& paramValues)
{
- // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
- // require "src" attribute).
- int srcIndex = -1, dataIndex = -1;
- for (unsigned int i = 0; i < paramNames->size(); ++i) {
- if (equalIgnoringCase((*paramNames)[i], "src"))
- srcIndex = i;
- else if (equalIgnoringCase((*paramNames)[i], "data"))
- dataIndex = i;
+ // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP require "src" attribute).
+ bool foundSrcParam = false;
+ String dataParamValue;
+ for (unsigned i = 0; i < paramNames.size(); ++i) {
+ if (equalLettersIgnoringASCIICase(paramNames[i], "src"))
+ foundSrcParam = true;
+ else if (equalLettersIgnoringASCIICase(paramNames[i], "data"))
+ dataParamValue = paramValues[i];
}
-
- if (srcIndex == -1 && dataIndex != -1) {
- paramNames->append("src");
- paramValues->append((*paramValues)[dataIndex]);
+ if (!foundSrcParam && !dataParamValue.isNull()) {
+ paramNames.append(ASCIILiteral("src"));
+ paramValues.append(WTFMove(dataParamValue));
}
}
#if PLATFORM(IOS)
static bool shouldNotPerformURLAdjustment()
{
- static bool shouldNotPerformURLAdjustment = applicationIsNASAHD() && !iosExecutableWasLinkedOnOrAfterVersion(wkIOSSystemVersion_5_0);
+ static bool shouldNotPerformURLAdjustment = IOSApplication::isNASAHD() && dyld_get_program_sdk_version() < DYLD_IOS_VERSION_5_0;
return shouldNotPerformURLAdjustment;
}
#endif
@@ -166,7 +162,7 @@ static bool shouldNotPerformURLAdjustment()
// FIXME: This function should not deal with url or serviceType!
void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<String>& paramValues, String& url, String& serviceType)
{
- HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames;
+ HashSet<StringImpl*, ASCIICaseInsensitiveHash> uniqueParamNames;
String urlParameter;
// Scan the PARAM children and store their name/value pairs.
@@ -181,12 +177,12 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S
paramValues.append(param.value());
// FIXME: url adjustment does not belong in this function.
- if (url.isEmpty() && urlParameter.isEmpty() && (equalIgnoringCase(name, "src") || equalIgnoringCase(name, "movie") || equalIgnoringCase(name, "code") || equalIgnoringCase(name, "url")))
+ if (url.isEmpty() && urlParameter.isEmpty() && (equalLettersIgnoringASCIICase(name, "src") || equalLettersIgnoringASCIICase(name, "movie") || equalLettersIgnoringASCIICase(name, "code") || equalLettersIgnoringASCIICase(name, "url")))
urlParameter = stripLeadingAndTrailingHTMLSpaces(param.value());
// FIXME: serviceType calculation does not belong in this function.
- if (serviceType.isEmpty() && equalIgnoringCase(name, "type")) {
+ if (serviceType.isEmpty() && equalLettersIgnoringASCIICase(name, "type")) {
serviceType = param.value();
- size_t pos = serviceType.find(";");
+ size_t pos = serviceType.find(';');
if (pos != notFound)
serviceType = serviceType.left(pos);
}
@@ -214,7 +210,7 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S
}
}
- mapDataParamToSrc(&paramNames, &paramValues);
+ mapDataParamToSrc(paramNames, paramValues);
// HTML5 says that an object resource's URL is specified by the object's data
// attribute, not by a param element. However, for compatibility, allow the
@@ -227,7 +223,7 @@ void HTMLObjectElement::parametersForPlugin(Vector<String>& paramNames, Vector<S
if (url.isEmpty() && !urlParameter.isEmpty()) {
SubframeLoader& loader = document().frame()->loader().subframeLoader();
- if (loader.resourceWillUsePlugin(urlParameter, serviceType, shouldPreferPlugInsForImages()))
+ if (loader.resourceWillUsePlugin(urlParameter, serviceType))
url = urlParameter;
}
}
@@ -237,10 +233,10 @@ bool HTMLObjectElement::hasFallbackContent() const
{
for (Node* child = firstChild(); child; child = child->nextSibling()) {
// Ignore whitespace-only text, and <param> tags, any other content is fallback content.
- if (child->isTextNode()) {
- if (!toText(child)->containsOnlyWhitespace())
+ if (is<Text>(*child)) {
+ if (!downcast<Text>(*child).containsOnlyWhitespace())
return true;
- } else if (!child->hasTagName(paramTag))
+ } else if (!is<HTMLParamElement>(*child))
return true;
}
return false;
@@ -254,26 +250,24 @@ bool HTMLObjectElement::shouldAllowQuickTimeClassIdQuirk()
// 'generator' meta tag is present. Only apply this quirk if there is no
// fallback content, which ensures the quirk will disable itself if Wiki
// Server is updated to generate an alternate embed tag as fallback content.
+
if (!document().page()
|| !document().page()->settings().needsSiteSpecificQuirks()
|| hasFallbackContent()
- || !equalIgnoringCase(classId(), "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"))
+ || !equalLettersIgnoringASCIICase(attributeWithoutSynchronization(classidAttr), "clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b"))
return false;
- RefPtr<NodeList> metaElements = document().getElementsByTagName(HTMLNames::metaTag.localName());
- unsigned length = metaElements->length();
- for (unsigned i = 0; i < length; ++i) {
- HTMLMetaElement& metaElement = toHTMLMetaElement(*metaElements->item(i));
- if (equalIgnoringCase(metaElement.name(), "generator") && metaElement.content().startsWith("Mac OS X Server Web Services Server", false))
+ for (auto& metaElement : descendantsOfType<HTMLMetaElement>(document())) {
+ if (equalLettersIgnoringASCIICase(metaElement.name(), "generator") && metaElement.content().startsWith("Mac OS X Server Web Services Server", false))
return true;
}
-
+
return false;
}
bool HTMLObjectElement::hasValidClassId()
{
- if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && classId().startsWith("java:", false))
+ if (MIMETypeRegistry::isJavaAppletMIMEType(serviceType()) && attributeWithoutSynchronization(classidAttr).startsWith("java:", false))
return true;
if (shouldAllowQuickTimeClassIdQuirk())
@@ -281,12 +275,12 @@ bool HTMLObjectElement::hasValidClassId()
// HTML5 says that fallback content should be rendered if a non-empty
// classid is specified for which the UA can't find a suitable plug-in.
- return classId().isEmpty();
+ return attributeWithoutSynchronization(classidAttr).isEmpty();
}
// FIXME: This should be unified with HTMLEmbedElement::updateWidget and
// moved down into HTMLPluginImageElement.cpp
-void HTMLObjectElement::updateWidget(PluginCreationOption pluginCreationOption)
+void HTMLObjectElement::updateWidget(CreatePlugins createPlugins)
{
ASSERT(!renderEmbeddedObject()->isPluginUnavailable());
ASSERT(needsWidgetUpdate());
@@ -316,18 +310,18 @@ void HTMLObjectElement::updateWidget(PluginCreationOption pluginCreationOption)
// FIXME: It's sadness that we have this special case here.
// See http://trac.webkit.org/changeset/25128 and
// plugins/netscape-plugin-setwindow-size.html
- if (pluginCreationOption == CreateOnlyNonNetscapePlugins && wouldLoadAsNetscapePlugin(url, serviceType)) {
+ if (createPlugins == CreatePlugins::No && wouldLoadAsPlugIn(url, serviceType)) {
// Ensure updateWidget() is called again during layout to create the Netscape plug-in.
setNeedsWidgetUpdate(true);
return;
}
- Ref<HTMLObjectElement> protect(*this); // beforeload and plugin loading can make arbitrary DOM mutations.
+ Ref<HTMLObjectElement> protectedThis(*this); // beforeload and plugin loading can make arbitrary DOM mutations.
bool beforeLoadAllowedLoad = guardedDispatchBeforeLoadEvent(url);
if (!renderer()) // Do not load the plugin if beforeload removed this element or its renderer.
return;
- bool success = beforeLoadAllowedLoad && hasValidClassId();
+ bool success = beforeLoadAllowedLoad && hasValidClassId() && allowedToLoadFrameURL(url);
if (success)
success = requestObject(url, serviceType, paramNames, paramValues);
if (!success && hasFallbackContent())
@@ -338,7 +332,12 @@ Node::InsertionNotificationRequest HTMLObjectElement::insertedInto(ContainerNode
{
HTMLPlugInImageElement::insertedInto(insertionPoint);
FormAssociatedElement::insertedInto(insertionPoint);
- return InsertionDone;
+ return InsertionShouldCallFinishedInsertingSubtree;
+}
+
+void HTMLObjectElement::finishedInsertingSubtree()
+{
+ resetFormOwner();
}
void HTMLObjectElement::removedFrom(ContainerNode& insertionPoint)
@@ -350,21 +349,21 @@ void HTMLObjectElement::removedFrom(ContainerNode& insertionPoint)
void HTMLObjectElement::childrenChanged(const ChildChange& change)
{
updateDocNamedItem();
- if (inDocument() && !useFallbackContent()) {
+ if (isConnected() && !useFallbackContent()) {
setNeedsWidgetUpdate(true);
- setNeedsStyleRecalc();
+ invalidateStyleForSubtree();
}
HTMLPlugInImageElement::childrenChanged(change);
}
bool HTMLObjectElement::isURLAttribute(const Attribute& attribute) const
{
- return attribute.name() == dataAttr || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#') || HTMLPlugInImageElement::isURLAttribute(attribute);
+ return attribute.name() == dataAttr || attribute.name() == codebaseAttr || (attribute.name() == usemapAttr && attribute.value().string()[0] != '#') || HTMLPlugInImageElement::isURLAttribute(attribute);
}
const AtomicString& HTMLObjectElement::imageSourceURL() const
{
- return getAttribute(dataAttr);
+ return attributeWithoutSynchronization(dataAttr);
}
void HTMLObjectElement::renderFallbackContent()
@@ -372,35 +371,37 @@ void HTMLObjectElement::renderFallbackContent()
if (useFallbackContent())
return;
- if (!inDocument())
+ if (!isConnected())
return;
- setNeedsStyleRecalc(ReconstructRenderTree);
+ invalidateStyleAndRenderersForSubtree();
// Before we give up and use fallback content, check to see if this is a MIME type issue.
- if (m_imageLoader && m_imageLoader->image() && m_imageLoader->image()->status() != CachedResource::LoadError) {
- m_serviceType = m_imageLoader->image()->response().mimeType();
+ auto* loader = imageLoader();
+ if (loader && loader->image() && loader->image()->status() != CachedResource::LoadError) {
+ m_serviceType = loader->image()->response().mimeType();
if (!isImageType()) {
// If we don't think we have an image type anymore, then clear the image from the loader.
- m_imageLoader->setImage(0);
+ loader->clearImage();
return;
}
}
m_useFallbackContent = true;
- // This is here mainly to keep acid2 non-flaky. A style recalc is required to make fallback resources to load. Without forcing
- // this may happen after all the other resources have been loaded and the document is already considered complete.
- // FIXME: Disentangle fallback content handling from style recalcs.
+ // This was added to keep Acid 2 non-flaky. A style recalc is required to make fallback resources load.
+ // Without forcing, this may happen after all the other resources have been loaded and the document is already
+ // considered complete. FIXME: Would be better to address this with incrementLoadEventDelayCount instead
+ // or disentangle loading from style entirely.
document().updateStyleIfNeeded();
}
// FIXME: This should be removed, all callers are almost certainly wrong.
static bool isRecognizedTagName(const QualifiedName& tagName)
{
- DEFINE_STATIC_LOCAL(HashSet<AtomicStringImpl*>, tagList, ());
- if (tagList.isEmpty()) {
- const QualifiedName* const * tags = HTMLNames::getHTMLTags();
+ static NeverDestroyed<HashSet<AtomicStringImpl*>> tagList;
+ if (tagList.get().isEmpty()) {
+ auto* tags = HTMLNames::getHTMLTags();
for (size_t i = 0; i < HTMLNames::HTMLTagsCount; i++) {
if (*tags[i] == bgsoundTag
|| *tags[i] == commandTag
@@ -414,10 +415,10 @@ static bool isRecognizedTagName(const QualifiedName& tagName)
// because that changes how we parse documents.
continue;
}
- tagList.add(tags[i]->localName().impl());
+ tagList.get().add(tags[i]->localName().impl());
}
}
- return tagList.contains(tagName.localName().impl());
+ return tagList.get().contains(tagName.localName().impl());
}
void HTMLObjectElement::updateDocNamedItem()
@@ -429,35 +430,35 @@ void HTMLObjectElement::updateDocNamedItem()
bool isNamedItem = true;
Node* child = firstChild();
while (child && isNamedItem) {
- if (child->isElementNode()) {
- Element* element = toElement(child);
+ if (is<Element>(*child)) {
+ Element& element = downcast<Element>(*child);
// FIXME: Use of isRecognizedTagName is almost certainly wrong here.
- if (isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
+ if (isRecognizedTagName(element.tagQName()) && !element.hasTagName(paramTag))
isNamedItem = false;
- } else if (child->isTextNode()) {
- if (!toText(child)->containsOnlyWhitespace())
+ } else if (is<Text>(*child)) {
+ if (!downcast<Text>(*child).containsOnlyWhitespace())
isNamedItem = false;
} else
isNamedItem = false;
child = child->nextSibling();
}
- if (isNamedItem != wasNamedItem && inDocument() && document().isHTMLDocument()) {
- HTMLDocument* document = toHTMLDocument(&this->document());
+ if (isNamedItem != wasNamedItem && isConnected() && !isInShadowTree() && is<HTMLDocument>(document())) {
+ HTMLDocument& document = downcast<HTMLDocument>(this->document());
const AtomicString& id = getIdAttribute();
if (!id.isEmpty()) {
if (isNamedItem)
- document->addDocumentNamedItem(*id.impl(), *this);
+ document.addDocumentNamedItem(*id.impl(), *this);
else
- document->removeDocumentNamedItem(*id.impl(), *this);
+ document.removeDocumentNamedItem(*id.impl(), *this);
}
const AtomicString& name = getNameAttribute();
if (!name.isEmpty() && id != name) {
if (isNamedItem)
- document->addDocumentNamedItem(*name.impl(), *this);
+ document.addDocumentNamedItem(*name.impl(), *this);
else
- document->removeDocumentNamedItem(*name.impl(), *this);
+ document.removeDocumentNamedItem(*name.impl(), *this);
}
}
m_docNamedItem = isNamedItem;
@@ -465,14 +466,14 @@ void HTMLObjectElement::updateDocNamedItem()
bool HTMLObjectElement::containsJavaApplet() const
{
- if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr)))
+ if (MIMETypeRegistry::isJavaAppletMIMEType(attributeWithoutSynchronization(typeAttr)))
return true;
for (auto& child : childrenOfType<Element>(*this)) {
- if (child.hasTagName(paramTag) && equalIgnoringCase(child.getNameAttribute(), "type")
- && MIMETypeRegistry::isJavaAppletMIMEType(child.getAttribute(valueAttr).string()))
+ if (child.hasTagName(paramTag) && equalLettersIgnoringASCIICase(child.getNameAttribute(), "type")
+ && MIMETypeRegistry::isJavaAppletMIMEType(child.attributeWithoutSynchronization(valueAttr).string()))
return true;
- if (child.hasTagName(objectTag) && toHTMLObjectElement(child).containsJavaApplet())
+ if (child.hasTagName(objectTag) && downcast<HTMLObjectElement>(child).containsJavaApplet())
return true;
if (child.hasTagName(appletTag))
return true;
@@ -485,16 +486,16 @@ void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) cons
{
HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
- addSubresourceURL(urls, document().completeURL(getAttribute(dataAttr)));
+ addSubresourceURL(urls, document().completeURL(attributeWithoutSynchronization(dataAttr)));
// FIXME: Passing a string that starts with "#" to the completeURL function does
// not seem like it would work. The image element has similar but not identical code.
- const AtomicString& useMap = getAttribute(usemapAttr);
+ const AtomicString& useMap = attributeWithoutSynchronization(usemapAttr);
if (useMap.startsWith('#'))
addSubresourceURL(urls, document().completeURL(useMap));
}
-void HTMLObjectElement::didMoveToNewDocument(Document* oldDocument)
+void HTMLObjectElement::didMoveToNewDocument(Document& oldDocument)
{
FormAssociatedElement::didMoveToNewDocument(oldDocument);
HTMLPlugInImageElement::didMoveToNewDocument(oldDocument);
@@ -505,19 +506,25 @@ bool HTMLObjectElement::appendFormData(FormDataList& encoding, bool)
if (name().isEmpty())
return false;
- Widget* widget = pluginWidget();
- if (!widget || !widget->isPluginViewBase())
+ // Use PluginLoadingPolicy::DoNotLoad here or it would fire JS events synchronously
+ // which would not be safe here.
+ auto* widget = pluginWidget(PluginLoadingPolicy::DoNotLoad);
+ if (!is<PluginViewBase>(widget))
return false;
String value;
- if (!toPluginViewBase(widget)->getFormValue(value))
+ if (!downcast<PluginViewBase>(*widget).getFormValue(value))
return false;
encoding.appendData(name(), value);
return true;
}
-HTMLFormElement* HTMLObjectElement::virtualForm() const
+bool HTMLObjectElement::canContainRangeEndPoint() const
{
- return FormAssociatedElement::form();
+ // Call through to HTMLElement because we need to skip HTMLPlugInElement
+ // when calling through to the derived class since returns false unconditionally.
+ // An object element with fallback content should basically be treated like
+ // a generic HTML element.
+ return m_useFallbackContent && HTMLElement::canContainRangeEndPoint();
}
}