WebCore/html/HTMLObjectElement.cpp
changeset 0 4f2f89ce4247
--- /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> 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<HTMLDocument*>(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<HTMLDocument*>(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<HTMLDocument*>(this->document());
+        document->addNamedItem(m_name);
+        document->addExtraNamedItem(m_id);
+    }
+
+    HTMLPlugInElement::insertedIntoDocument();
+}
+
+void HTMLObjectElement::removedFromDocument()
+{
+    if (isDocNamedItem() && document()->isHTMLDocument()) {
+        HTMLDocument* document = static_cast<HTMLDocument*>(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 "<object> elements with no children other than
+    // <param> elements, unknown elements and whitespace can be
+    // found by name in a document, and other <object> elements cannot."
+    bool wasNamedItem = m_docNamedItem;
+    bool isNamedItem = true;
+    Node* child = firstChild();
+    while (child && isNamedItem) {
+        if (child->isElementNode()) {
+            Element* element = static_cast<Element*>(child);
+            if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
+                isNamedItem = false;
+        } else if (child->isTextNode()) {
+            if (!static_cast<Text*>(child)->containsOnlyWhitespace())
+                isNamedItem = false;
+        } else
+            isNamedItem = false;
+        child = child->nextSibling();
+    }
+    if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
+        HTMLDocument* document = static_cast<HTMLDocument*>(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<HTMLObjectElement*>(child)->containsJavaApplet())
+            return true;
+        if (child->hasTagName(appletTag))
+            return true;
+    }
+    
+    return false;
+}
+
+void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& 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));
+}
+
+}