WebCore/html/HTMLObjectElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
       
     4  *           (C) 2000 Stefan Schimanski (1Stein@gmx.de)
       
     5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
       
     6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public License
       
    19  * along with this library; see the file COPYING.LIB.  If not, write to
       
    20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    21  * Boston, MA 02110-1301, USA.
       
    22  */
       
    23 
       
    24 #include "config.h"
       
    25 #include "HTMLObjectElement.h"
       
    26 
       
    27 #include "Attribute.h"
       
    28 #include "CSSHelper.h"
       
    29 #include "EventNames.h"
       
    30 #include "ExceptionCode.h"
       
    31 #include "Frame.h"
       
    32 #include "HTMLDocument.h"
       
    33 #include "HTMLFormElement.h"
       
    34 #include "HTMLImageLoader.h"
       
    35 #include "HTMLNames.h"
       
    36 #include "MIMETypeRegistry.h"
       
    37 #include "RenderEmbeddedObject.h"
       
    38 #include "RenderImage.h"
       
    39 #include "RenderWidget.h"
       
    40 #include "ScriptController.h"
       
    41 #include "ScriptEventListener.h"
       
    42 #include "Text.h"
       
    43 
       
    44 namespace WebCore {
       
    45 
       
    46 using namespace HTMLNames;
       
    47 
       
    48 inline HTMLObjectElement::HTMLObjectElement(const QualifiedName& tagName, Document* document, bool createdByParser) 
       
    49     : HTMLPlugInImageElement(tagName, document)
       
    50     , m_docNamedItem(true)
       
    51     , m_needWidgetUpdate(!createdByParser)
       
    52     , m_useFallbackContent(false)
       
    53 {
       
    54     ASSERT(hasTagName(objectTag));
       
    55 }
       
    56 
       
    57 PassRefPtr<HTMLObjectElement> HTMLObjectElement::create(const QualifiedName& tagName, Document* document, bool createdByParser)
       
    58 {
       
    59     return adoptRef(new HTMLObjectElement(tagName, document, createdByParser));
       
    60 }
       
    61 
       
    62 RenderWidget* HTMLObjectElement::renderWidgetForJSBindings() const
       
    63 {
       
    64     document()->updateLayoutIgnorePendingStylesheets();
       
    65     if (!renderer() || !renderer()->isWidget())
       
    66         return 0;
       
    67     return toRenderWidget(renderer());
       
    68 }
       
    69 
       
    70 void HTMLObjectElement::parseMappedAttribute(Attribute* attr)
       
    71 {
       
    72     String val = attr->value();
       
    73     int pos;
       
    74     if (attr->name() == typeAttr) {
       
    75         m_serviceType = val.lower();
       
    76         pos = m_serviceType.find(";");
       
    77         if (pos != -1)
       
    78           m_serviceType = m_serviceType.left(pos);
       
    79         if (renderer())
       
    80           m_needWidgetUpdate = true;
       
    81         if (!isImageType() && m_imageLoader)
       
    82           m_imageLoader.clear();
       
    83     } else if (attr->name() == dataAttr) {
       
    84         m_url = deprecatedParseURL(val);
       
    85         if (renderer())
       
    86           m_needWidgetUpdate = true;
       
    87         if (renderer() && isImageType()) {
       
    88           if (!m_imageLoader)
       
    89               m_imageLoader.set(new HTMLImageLoader(this));
       
    90           m_imageLoader->updateFromElementIgnoringPreviousError();
       
    91         }
       
    92     } else if (attr->name() == classidAttr) {
       
    93         m_classId = val;
       
    94         if (renderer())
       
    95           m_needWidgetUpdate = true;
       
    96     } else if (attr->name() == onloadAttr)
       
    97         setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
       
    98     else if (attr->name() == onbeforeloadAttr)
       
    99         setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
       
   100     else if (attr->name() == nameAttr) {
       
   101         const AtomicString& newName = attr->value();
       
   102         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
       
   103             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   104             document->removeNamedItem(m_name);
       
   105             document->addNamedItem(newName);
       
   106         }
       
   107         m_name = newName;
       
   108     } else if (isIdAttributeName(attr->name())) {
       
   109         const AtomicString& newId = attr->value();
       
   110         if (isDocNamedItem() && inDocument() && document()->isHTMLDocument()) {
       
   111             HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   112             document->removeExtraNamedItem(m_id);
       
   113             document->addExtraNamedItem(newId);
       
   114         }
       
   115         m_id = newId;
       
   116         // also call superclass
       
   117         HTMLPlugInElement::parseMappedAttribute(attr);
       
   118     } else
       
   119         HTMLPlugInElement::parseMappedAttribute(attr);
       
   120 }
       
   121 
       
   122 bool HTMLObjectElement::rendererIsNeeded(RenderStyle* style)
       
   123 {
       
   124     Frame* frame = document()->frame();
       
   125     if (!frame)
       
   126         return false;
       
   127     
       
   128     // Temporary Workaround for Gears plugin - see bug 24215 for details and bug 24346 to track removal.
       
   129     // Gears expects the plugin to be instantiated even if display:none is set
       
   130     // for the object element.
       
   131     bool isGearsPlugin = equalIgnoringCase(getAttribute(typeAttr), "application/x-googlegears");
       
   132     return isGearsPlugin || HTMLPlugInElement::rendererIsNeeded(style);
       
   133 }
       
   134 
       
   135 RenderObject *HTMLObjectElement::createRenderer(RenderArena* arena, RenderStyle* style)
       
   136 {
       
   137     if (m_useFallbackContent)
       
   138         return RenderObject::createObject(this, style);
       
   139     if (isImageType())
       
   140         return new (arena) RenderImage(this);
       
   141     return new (arena) RenderEmbeddedObject(this);
       
   142 }
       
   143 
       
   144 void HTMLObjectElement::attach()
       
   145 {
       
   146     bool isImage = isImageType();
       
   147 
       
   148     if (!isImage)
       
   149         queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
       
   150 
       
   151     HTMLPlugInElement::attach();
       
   152 
       
   153     if (isImage && renderer() && !m_useFallbackContent) {
       
   154         if (!m_imageLoader)
       
   155             m_imageLoader.set(new HTMLImageLoader(this));
       
   156         m_imageLoader->updateFromElement();
       
   157     }
       
   158 }
       
   159 
       
   160 void HTMLObjectElement::updateWidget()
       
   161 {
       
   162     document()->updateStyleIfNeeded();
       
   163     if (m_needWidgetUpdate && renderer() && !m_useFallbackContent && !isImageType())
       
   164         toRenderEmbeddedObject(renderer())->updateWidget(true);
       
   165 }
       
   166 
       
   167 void HTMLObjectElement::finishParsingChildren()
       
   168 {
       
   169     HTMLPlugInElement::finishParsingChildren();
       
   170     if (!m_useFallbackContent) {
       
   171         m_needWidgetUpdate = true;
       
   172         if (inDocument())
       
   173             setNeedsStyleRecalc();
       
   174     }
       
   175 }
       
   176 
       
   177 void HTMLObjectElement::detach()
       
   178 {
       
   179     if (attached() && renderer() && !m_useFallbackContent)
       
   180         // Update the widget the next time we attach (detaching destroys the plugin).
       
   181         m_needWidgetUpdate = true;
       
   182     HTMLPlugInElement::detach();
       
   183 }
       
   184 
       
   185 void HTMLObjectElement::insertedIntoDocument()
       
   186 {
       
   187     if (isDocNamedItem() && document()->isHTMLDocument()) {
       
   188         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   189         document->addNamedItem(m_name);
       
   190         document->addExtraNamedItem(m_id);
       
   191     }
       
   192 
       
   193     HTMLPlugInElement::insertedIntoDocument();
       
   194 }
       
   195 
       
   196 void HTMLObjectElement::removedFromDocument()
       
   197 {
       
   198     if (isDocNamedItem() && document()->isHTMLDocument()) {
       
   199         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   200         document->removeNamedItem(m_name);
       
   201         document->removeExtraNamedItem(m_id);
       
   202     }
       
   203 
       
   204     HTMLPlugInElement::removedFromDocument();
       
   205 }
       
   206 
       
   207 void HTMLObjectElement::recalcStyle(StyleChange ch)
       
   208 {
       
   209     if (!m_useFallbackContent && m_needWidgetUpdate && renderer() && !isImageType()) {
       
   210         detach();
       
   211         attach();
       
   212     }
       
   213     HTMLPlugInElement::recalcStyle(ch);
       
   214 }
       
   215 
       
   216 void HTMLObjectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
       
   217 {
       
   218     updateDocNamedItem();
       
   219     if (inDocument() && !m_useFallbackContent) {
       
   220         m_needWidgetUpdate = true;
       
   221         setNeedsStyleRecalc();
       
   222     }
       
   223     HTMLPlugInElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
       
   224 }
       
   225 
       
   226 bool HTMLObjectElement::isURLAttribute(Attribute *attr) const
       
   227 {
       
   228     return (attr->name() == dataAttr || (attr->name() == usemapAttr && attr->value().string()[0] != '#'));
       
   229 }
       
   230 
       
   231 const QualifiedName& HTMLObjectElement::imageSourceAttributeName() const
       
   232 {
       
   233     return dataAttr;
       
   234 }
       
   235 
       
   236 void HTMLObjectElement::renderFallbackContent()
       
   237 {
       
   238     if (m_useFallbackContent)
       
   239         return;
       
   240     
       
   241     if (!inDocument())
       
   242         return;
       
   243 
       
   244     // Before we give up and use fallback content, check to see if this is a MIME type issue.
       
   245     if (m_imageLoader && m_imageLoader->image()) {
       
   246         m_serviceType = m_imageLoader->image()->response().mimeType();
       
   247         if (!isImageType()) {
       
   248             // If we don't think we have an image type anymore, then ditch the image loader.
       
   249             m_imageLoader.clear();        
       
   250             detach();
       
   251             attach();
       
   252             return;
       
   253         }
       
   254     }
       
   255 
       
   256     // Mark ourselves as using the fallback content.
       
   257     m_useFallbackContent = true;
       
   258 
       
   259     // Now do a detach and reattach.    
       
   260     // FIXME: Style gets recalculated which is suboptimal.
       
   261     detach();
       
   262     attach();
       
   263 }
       
   264 
       
   265 void HTMLObjectElement::updateDocNamedItem()
       
   266 {
       
   267     // The rule is "<object> elements with no children other than
       
   268     // <param> elements, unknown elements and whitespace can be
       
   269     // found by name in a document, and other <object> elements cannot."
       
   270     bool wasNamedItem = m_docNamedItem;
       
   271     bool isNamedItem = true;
       
   272     Node* child = firstChild();
       
   273     while (child && isNamedItem) {
       
   274         if (child->isElementNode()) {
       
   275             Element* element = static_cast<Element*>(child);
       
   276             if (HTMLElement::isRecognizedTagName(element->tagQName()) && !element->hasTagName(paramTag))
       
   277                 isNamedItem = false;
       
   278         } else if (child->isTextNode()) {
       
   279             if (!static_cast<Text*>(child)->containsOnlyWhitespace())
       
   280                 isNamedItem = false;
       
   281         } else
       
   282             isNamedItem = false;
       
   283         child = child->nextSibling();
       
   284     }
       
   285     if (isNamedItem != wasNamedItem && document()->isHTMLDocument()) {
       
   286         HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
       
   287         if (isNamedItem) {
       
   288             document->addNamedItem(m_name);
       
   289             document->addExtraNamedItem(m_id);
       
   290         } else {
       
   291             document->removeNamedItem(m_name);
       
   292             document->removeExtraNamedItem(m_id);
       
   293         }
       
   294     }
       
   295     m_docNamedItem = isNamedItem;
       
   296 }
       
   297 
       
   298 bool HTMLObjectElement::containsJavaApplet() const
       
   299 {
       
   300     if (MIMETypeRegistry::isJavaAppletMIMEType(getAttribute(typeAttr)))
       
   301         return true;
       
   302         
       
   303     for (Element* child = firstElementChild(); child; child = child->nextElementSibling()) {
       
   304         if (child->hasTagName(paramTag)
       
   305                 && equalIgnoringCase(child->getAttribute(nameAttr), "type")
       
   306                 && MIMETypeRegistry::isJavaAppletMIMEType(child->getAttribute(valueAttr).string()))
       
   307             return true;
       
   308         if (child->hasTagName(objectTag)
       
   309                 && static_cast<HTMLObjectElement*>(child)->containsJavaApplet())
       
   310             return true;
       
   311         if (child->hasTagName(appletTag))
       
   312             return true;
       
   313     }
       
   314     
       
   315     return false;
       
   316 }
       
   317 
       
   318 void HTMLObjectElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
       
   319 {
       
   320     HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
       
   321 
       
   322     addSubresourceURL(urls, document()->completeURL(getAttribute(dataAttr)));
       
   323 
       
   324     // FIXME: Passing a string that starts with "#" to the completeURL function does
       
   325     // not seem like it would work. The image element has similar but not identical code.
       
   326     const AtomicString& useMap = getAttribute(usemapAttr);
       
   327     if (useMap.startsWith("#"))
       
   328         addSubresourceURL(urls, document()->completeURL(useMap));
       
   329 }
       
   330 
       
   331 }