diff -r 000000000000 -r 4f2f89ce4247 WebCore/html/HTMLObjectElement.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/html/HTMLObjectElement.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,331 @@ +/* + * 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 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 + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "HTMLObjectElement.h" + +#include "Attribute.h" +#include "CSSHelper.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLFormElement.h" +#include "HTMLImageLoader.h" +#include "HTMLNames.h" +#include "MIMETypeRegistry.h" +#include "RenderEmbeddedObject.h" +#include "RenderImage.h" +#include "RenderWidget.h" +#include "ScriptController.h" +#include "ScriptEventListener.h" +#include "Text.h" + +namespace WebCore { + +using namespace HTMLNames; + +inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, bool createdByParser) + : HTMLPlugInImageElement(tagName, document) + , m_docNamedItem(true) + , m_needWidgetUpdate(!createdByParser) + , m_useFallbackContent(false) +{ + ASSERT(hasTagName(objectTag)); +} + +PassRefPtr HTMLObjectElement::create(const QualifiedName& tagName, Document* document, bool createdByParser) +{ + return adoptRef(new HTMLObjectElement(tagName, document, createdByParser)); +} + +RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const +{ + document()->updateLayoutIgnorePendingStylesheets(); + if (!renderer() || !renderer()->isWidget()) + return 0; + return toRenderWidget(renderer()); +} + +void HTMLObjectElement::parseMappedAttribute(Attribute* attr) +{ + String val = attr->value(); + int pos; + if (attr->name() == typeAttr) { + m_serviceType = val.lower(); + pos = m_serviceType.find(";"); + if (pos != -1) + m_serviceType = m_serviceType.left(pos); + if (renderer()) + m_needWidgetUpdate = true; + if (!isImageType() && m_imageLoader) + m_imageLoader.clear(); + } else if (attr->name() == dataAttr) { + m_url = deprecatedParseURL(val); + if (renderer()) + m_needWidgetUpdate = true; + if (renderer() && isImageType()) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElementIgnoringPreviousError(); + } + } else if (attr->name() == classidAttr) { + m_classId = val; + if (renderer()) + m_needWidgetUpdate = true; + } else if (attr->name() == onloadAttr) + setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); + else if (attr->name() == onbeforeloadAttr) + setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr)); + else if (attr->name() == nameAttr) { + const AtomicString& newName = attr->value(); + if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast(this->document()); + document->removeNamedItem(m_name); + document->addNamedItem(newName); + } + m_name = newName; + } else if (isIdAttributeName(attr->name())) { + const AtomicString& newId = attr->value(); + if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast(this->document()); + document->removeExtraNamedItem(m_id); + document->addExtraNamedItem(newId); + } + m_id = newId; + // also call superclass + HTMLPlugInElement::parseMappedAttribute(attr); + } else + HTMLPlugInElement::parseMappedAttribute(attr); +} + +bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style) +{ + Frame* frame = document()->frame(); + if (!frame) + return false; + + // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal. + // Gears expects the plugin to be instantiated even if display:none is set + // for the object element. + bool isGearsPlugin = equalIgnoringCase(getAttribute(typeAttr), "application/x-googlegears"); + return isGearsPlugin || HTMLPlugInElement::rendererIsNeeded(style); +} + +RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle* style) +{ + if (m_useFallbackContent) + return RenderObject::createObject(this, style); + if (isImageType()) + return new (arena) RenderImage(this); + return new (arena) RenderEmbeddedObject(this); +} + +void HTMLObjectElement::attach() +{ + bool isImage = isImageType(); + + if (!isImage) + queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this); + + HTMLPlugInElement::attach(); + + if (isImage && renderer() && !m_useFallbackContent) { + if (!m_imageLoader) + m_imageLoader.set(new HTMLImageLoader(this)); + m_imageLoader->updateFromElement(); + } +} + +void HTMLObjectElement::updateWidget() +{ + document()->updateStyleIfNeeded(); + if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType()) + toRenderEmbeddedObject(renderer())->updateWidget(true); +} + +void HTMLObjectElement::finishParsingChildren() +{ + HTMLPlugInElement::finishParsingChildren(); + if (!m_useFallbackContent) { + m_needWidgetUpdate = true; + if (inDocument()) + setNeedsStyleRecalc(); + } +} + +void HTMLObjectElement::detach() +{ + if (attached() && renderer() && !m_useFallbackContent) + // Update the widget the next time we attach (detaching destroys the plugin). + m_needWidgetUpdate = true; + HTMLPlugInElement::detach(); +} + +void HTMLObjectElement::insertedIntoDocument() +{ + if (isDocNamedItem() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast(this->document()); + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } + + HTMLPlugInElement::insertedIntoDocument(); +} + +void HTMLObjectElement::removedFromDocument() +{ + if (isDocNamedItem() && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast(this->document()); + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + + HTMLPlugInElement::removedFromDocument(); +} + +void HTMLObjectElement::recalcStyle(StyleChange ch) +{ + if (!m_useFallbackContent && m_needWidgetUpdate && renderer() && !isImageType()) { + detach(); + attach(); + } + HTMLPlugInElement::recalcStyle(ch); +} + +void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + updateDocNamedItem(); + if (inDocument() && !m_useFallbackContent) { + m_needWidgetUpdate = true; + setNeedsStyleRecalc(); + } + HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); +} + +bool HTMLObjectElement::isURLAttribute(Attribute *attr) const +{ + return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#')); +} + +const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const +{ + return dataAttr; +} + +void HTMLObjectElement::renderFallbackContent() +{ + if (m_useFallbackContent) + return; + + if (!inDocument()) + return; + + // 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_serviceType = m_imageLoader->image()->response().mimeType(); + if (!isImageType()) { + // If we don't think we have an image type anymore, then ditch the image loader. + m_imageLoader.clear(); + detach(); + attach(); + return; + } + } + + // Mark ourselves as using the fallback content. + m_useFallbackContent = true; + + // Now do a detach and reattach. + // FIXME: Style gets recalculated which is suboptimal. + detach(); + attach(); +} + +void HTMLObjectElement::updateDocNamedItem() +{ + // The rule is " elements with no children other than + // elements, unknown elements and whitespace can be + // found by name in a document, and other elements cannot." + bool wasNamedItem = m_docNamedItem; + bool isNamedItem = true; + Node* child = firstChild(); + while (child && isNamedItem) { + if (child->isElementNode()) { + Element* element = static_cast(child); + if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag)) + isNamedItem = false; + } else if (child->isTextNode()) { + if (!static_cast(child)->containsOnlyWhitespace()) + isNamedItem = false; + } else + isNamedItem = false; + child = child->nextSibling(); + } + if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) { + HTMLDocument* document = static_cast(this->document()); + if (isNamedItem) { + document->addNamedItem(m_name); + document->addExtraNamedItem(m_id); + } else { + document->removeNamedItem(m_name); + document->removeExtraNamedItem(m_id); + } + } + m_docNamedItem = isNamedItem; +} + +bool HTMLObjectElement::containsJavaApplet() const +{ + if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr))) + return true; + + for (Element* child = firstElementChild(); child; child = child->nextElementSibling()) { + if (child->hasTagName(paramTag) + && equalIgnoringCase(child->getAttribute(nameAttr), "type") + && MIMETypeRegistry::isJavaAppletMIMEType(child->getAttribute(valueAttr).string())) + return true; + if (child->hasTagName(objectTag) + && static_cast(child)->containsJavaApplet()) + return true; + if (child->hasTagName(appletTag)) + return true; + } + + return false; +} + +void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet& urls) const +{ + HTMLPlugInImageElement::addSubresourceAttributeURLs(urls); + + addSubresourceURL(urls, document()->completeURL(getAttribute(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); + if (useMap.startsWith("#")) + addSubresourceURL(urls, document()->completeURL(useMap)); +} + +}