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, 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 "HTMLEmbedElement.h"
26
27#include "CSSHelper.h"
28#include "CSSPropertyNames.h"
29#include "Frame.h"
30#include "HTMLDocument.h"
31#include "HTMLImageLoader.h"
32#include "HTMLNames.h"
33#include "HTMLObjectElement.h"
34#include "MappedAttribute.h"
35#include "RenderEmbeddedObject.h"
36#include "RenderImage.h"
37#include "RenderWidget.h"
38#include "ScriptController.h"
39#include "Settings.h"
40
41namespace WebCore {
42
43using namespace HTMLNames;
44
45inline HTMLEmbedElement::HTMLEmbedElement(const QualifiedName& tagName, Document* document)
46    : HTMLPlugInImageElement(tagName, document)
47    , m_needWidgetUpdate(false)
48{
49    ASSERT(hasTagName(embedTag));
50}
51
52PassRefPtr<HTMLEmbedElement> HTMLEmbedElement::create(const QualifiedName& tagName, Document* document)
53{
54    return adoptRef(new HTMLEmbedElement(tagName, document));
55}
56
57static inline RenderWidget* findWidgetRenderer(const Node* n)
58{
59    if (!n->renderer())
60        do
61            n = n->parentNode();
62        while (n && !n->hasTagName(objectTag));
63
64    if (n && n->renderer() && n->renderer()->isWidget())
65        return toRenderWidget(n->renderer());
66
67    return 0;
68}
69
70RenderWidget* HTMLEmbedElement::renderWidgetForJSBindings() const
71{
72    document()->updateLayoutIgnorePendingStylesheets();
73    return findWidgetRenderer(this);
74}
75
76bool HTMLEmbedElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
77{
78    if (attrName == hiddenAttr) {
79        result = eUniversal;
80        return false;
81    }
82
83    return HTMLPlugInElement::mapToEntry(attrName, result);
84}
85
86void HTMLEmbedElement::parseMappedAttribute(MappedAttribute* attr)
87{
88    const AtomicString& value = attr->value();
89
90    if (attr->name() == typeAttr) {
91        m_serviceType = value.string().lower();
92        int pos = m_serviceType.find(";");
93        if (pos != -1)
94            m_serviceType = m_serviceType.left(pos);
95        if (!isImageType() && m_imageLoader)
96            m_imageLoader.clear();
97    } else if (attr->name() == codeAttr)
98        m_url = deprecatedParseURL(value.string());
99    else if (attr->name() == srcAttr) {
100        m_url = deprecatedParseURL(value.string());
101        if (renderer() && isImageType()) {
102            if (!m_imageLoader)
103                m_imageLoader.set(new HTMLImageLoader(this));
104            m_imageLoader->updateFromElementIgnoringPreviousError();
105        }
106    } else if (attr->name() == hiddenAttr) {
107        if (equalIgnoringCase(value.string(), "yes") || equalIgnoringCase(value.string(), "true")) {
108            // FIXME: Not dynamic, since we add this but don't remove it, but it may be OK for now
109            // that this rarely-used attribute won't work properly if you remove it.
110            addCSSLength(attr, CSSPropertyWidth, "0");
111            addCSSLength(attr, CSSPropertyHeight, "0");
112        }
113    } else if (attr->name() == nameAttr) {
114        if (inDocument() && document()->isHTMLDocument()) {
115            HTMLDocument* document = static_cast<HTMLDocument*>(this->document());
116            document->removeNamedItem(m_name);
117            document->addNamedItem(value);
118        }
119        m_name = value;
120    } else
121        HTMLPlugInElement::parseMappedAttribute(attr);
122}
123
124bool HTMLEmbedElement::rendererIsNeeded(RenderStyle* style)
125{
126    if (isImageType())
127        return HTMLPlugInElement::rendererIsNeeded(style);
128
129    Frame* frame = document()->frame();
130    if (!frame)
131        return false;
132
133    Node* p = parentNode();
134    if (p && p->hasTagName(objectTag)) {
135        ASSERT(p->renderer());
136        return false;
137    }
138
139#if ENABLE(DASHBOARD_SUPPORT)
140    // Workaround for <rdar://problem/6642221>.
141    if (Settings* settings = frame->settings()) {
142        if (settings->usesDashboardBackwardCompatibilityMode())
143            return true;
144    }
145#endif
146
147    return HTMLPlugInElement::rendererIsNeeded(style);
148}
149
150RenderObject* HTMLEmbedElement::createRenderer(RenderArena* arena, RenderStyle*)
151{
152    if (isImageType())
153        return new (arena) RenderImage(this);
154    return new (arena) RenderEmbeddedObject(this);
155}
156
157void HTMLEmbedElement::attach()
158{
159    m_needWidgetUpdate = true;
160
161    bool isImage = isImageType();
162
163    if (!isImage)
164        queuePostAttachCallback(&HTMLPlugInElement::updateWidgetCallback, this);
165
166    HTMLPlugInElement::attach();
167
168    if (isImage && renderer()) {
169        if (!m_imageLoader)
170            m_imageLoader.set(new HTMLImageLoader(this));
171        m_imageLoader->updateFromElement();
172
173        if (renderer())
174            toRenderImage(renderer())->setCachedImage(m_imageLoader->image());
175    }
176}
177
178void HTMLEmbedElement::updateWidget()
179{
180    document()->updateStyleIfNeeded();
181    if (m_needWidgetUpdate && renderer() && !isImageType())
182        toRenderEmbeddedObject(renderer())->updateWidget(true);
183}
184
185void HTMLEmbedElement::insertedIntoDocument()
186{
187    if (document()->isHTMLDocument())
188        static_cast<HTMLDocument*>(document())->addNamedItem(m_name);
189
190    String width = getAttribute(widthAttr);
191    String height = getAttribute(heightAttr);
192    if (!width.isEmpty() || !height.isEmpty()) {
193        Node* n = parent();
194        while (n && !n->hasTagName(objectTag))
195            n = n->parent();
196        if (n) {
197            if (!width.isEmpty())
198                static_cast<HTMLObjectElement*>(n)->setAttribute(widthAttr, width);
199            if (!height.isEmpty())
200                static_cast<HTMLObjectElement*>(n)->setAttribute(heightAttr, height);
201        }
202    }
203
204    HTMLPlugInElement::insertedIntoDocument();
205}
206
207void HTMLEmbedElement::removedFromDocument()
208{
209    if (document()->isHTMLDocument())
210        static_cast<HTMLDocument*>(document())->removeNamedItem(m_name);
211
212    HTMLPlugInElement::removedFromDocument();
213}
214
215void HTMLEmbedElement::attributeChanged(Attribute* attr, bool preserveDecls)
216{
217    HTMLPlugInElement::attributeChanged(attr, preserveDecls);
218
219    if ((attr->name() == widthAttr || attr->name() == heightAttr) && !attr->isEmpty()) {
220        Node* n = parent();
221        while (n && !n->hasTagName(objectTag))
222            n = n->parent();
223        if (n)
224            static_cast<HTMLObjectElement*>(n)->setAttribute(attr->name(), attr->value());
225    }
226}
227
228bool HTMLEmbedElement::isURLAttribute(Attribute* attr) const
229{
230    return attr->name() == srcAttr;
231}
232
233const QualifiedName& HTMLEmbedElement::imageSourceAttributeName() const
234{
235    return srcAttr;
236}
237
238void HTMLEmbedElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
239{
240    HTMLPlugInImageElement::addSubresourceAttributeURLs(urls);
241
242    addSubresourceURL(urls, document()->completeURL(getAttribute(srcAttr)));
243}
244
245}
246