2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 2000 Simon Hausmann <hausmann@kde.org>
4 * (C) 2000 Stefan Schimanski (1Stein@gmx.de)
5 * Copyright (C) 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
25 #include "RenderPartObject.h"
28 #include "FrameLoaderClient.h"
29 #include "HTMLEmbedElement.h"
30 #include "HTMLIFrameElement.h"
31 #include "HTMLNames.h"
32 #include "HTMLObjectElement.h"
33 #include "HTMLParamElement.h"
34 #include "MIMETypeRegistry.h"
36 #include "PluginData.h"
37 #include "RenderView.h"
40 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
41 #include "HTMLVideoElement.h"
46 using namespace HTMLNames
;
48 RenderPartObject::RenderPartObject(Element
* element
)
51 // init RenderObject attributes
53 m_hasFallbackContent
= false;
55 if (element
->hasTagName(embedTag
) || element
->hasTagName(objectTag
))
56 view()->frameView()->setIsVisuallyNonEmpty();
59 RenderPartObject::~RenderPartObject()
62 frameView()->removeWidgetToUpdate(this);
65 static bool isURLAllowed(Document
* doc
, const String
& url
)
67 if (doc
->frame()->page()->frameCount() >= 200)
70 // We allow one level of self-reference because some sites depend on that.
71 // But we don't allow more than one.
72 KURL completeURL
= doc
->completeURL(url
);
73 bool foundSelfReference
= false;
74 for (Frame
* frame
= doc
->frame(); frame
; frame
= frame
->tree()->parent()) {
75 if (equalIgnoringRef(frame
->loader()->url(), completeURL
)) {
76 if (foundSelfReference
)
78 foundSelfReference
= true;
84 typedef HashMap
<String
, String
, CaseFoldingHash
> ClassIdToTypeMap
;
86 static ClassIdToTypeMap
* createClassIdToTypeMap()
88 ClassIdToTypeMap
* map
= new ClassIdToTypeMap
;
89 map
->add("clsid:D27CDB6E-AE6D-11CF-96B8-444553540000", "application/x-shockwave-flash");
90 map
->add("clsid:CFCDAA03-8BE4-11CF-B84B-0020AFBBCCFA", "audio/x-pn-realaudio-plugin");
91 map
->add("clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B", "video/quicktime");
92 map
->add("clsid:166B1BCA-3F9C-11CF-8075-444553540000", "application/x-director");
93 #if ENABLE(ACTIVEX_TYPE_CONVERSION_WMPLAYER)
94 map
->add("clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6", "application/x-mplayer2");
95 map
->add("clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95", "application/x-mplayer2");
100 static const String
& activeXType()
102 DEFINE_STATIC_LOCAL(String
, activeXType
, ("application/x-oleobject"));
106 static inline bool havePlugin(const PluginData
* pluginData
, const String
& type
)
108 return pluginData
&& !type
.isEmpty() && pluginData
->supportsMimeType(type
);
111 static String
serviceTypeForClassId(const String
& classId
, const PluginData
* pluginData
)
113 // Return early if classId is empty (since we won't do anything below).
114 // Furthermore, if classId is null, calling get() below will crash.
115 if (classId
.isEmpty())
118 static ClassIdToTypeMap
* map
= createClassIdToTypeMap();
119 String type
= map
->get(classId
);
121 // If we do have a plug-in that supports generic ActiveX content and don't have a plug-in
122 // for the MIME type we came up with, ignore the MIME type we came up with and just use
124 if (havePlugin(pluginData
, activeXType()) && !havePlugin(pluginData
, type
))
125 return activeXType();
130 static inline bool shouldUseEmbedDescendant(HTMLObjectElement
* objectElement
, const PluginData
* pluginData
)
133 UNUSED_PARAM(objectElement
);
134 UNUSED_PARAM(pluginData
);
135 // On Mac, we always want to use the embed descendant.
138 // If we have both an <object> and <embed>, we always want to use the <embed> except when we have
139 // an ActiveX plug-in and plan to use it.
140 return !(havePlugin(pluginData
, activeXType())
141 && serviceTypeForClassId(objectElement
->classId(), pluginData
) == activeXType());
145 static void mapDataParamToSrc(Vector
<String
>* paramNames
, Vector
<String
>* paramValues
)
147 // Some plugins don't understand the "data" attribute of the OBJECT tag (i.e. Real and WMP
148 // require "src" attribute).
149 int srcIndex
= -1, dataIndex
= -1;
150 for (unsigned int i
= 0; i
< paramNames
->size(); ++i
) {
151 if (equalIgnoringCase((*paramNames
)[i
], "src"))
153 else if (equalIgnoringCase((*paramNames
)[i
], "data"))
157 if (srcIndex
== -1 && dataIndex
!= -1) {
158 paramNames
->append("src");
159 paramValues
->append((*paramValues
)[dataIndex
]);
163 void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins
)
167 Vector
<String
> paramNames
;
168 Vector
<String
> paramValues
;
169 Frame
* frame
= frameView()->frame();
171 if (node()->hasTagName(objectTag
)) {
172 HTMLObjectElement
* o
= static_cast<HTMLObjectElement
*>(node());
174 o
->setNeedWidgetUpdate(false);
175 if (!o
->isFinishedParsingChildren())
178 // Check for a child EMBED tag.
179 HTMLEmbedElement
* embed
= 0;
180 const PluginData
* pluginData
= frame
->page()->pluginData();
181 if (shouldUseEmbedDescendant(o
, pluginData
)) {
182 for (Node
* child
= o
->firstChild(); child
; ) {
183 if (child
->hasTagName(embedTag
)) {
184 embed
= static_cast<HTMLEmbedElement
*>(child
);
186 } else if (child
->hasTagName(objectTag
))
187 child
= child
->nextSibling(); // Don't descend into nested OBJECT tags
189 child
= child
->traverseNextNode(o
); // Otherwise descend (EMBEDs may be inside COMMENT tags)
193 // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT.
194 HTMLElement
*embedOrObject
;
196 embedOrObject
= (HTMLElement
*)embed
;
198 serviceType
= embed
->serviceType();
200 embedOrObject
= (HTMLElement
*)o
;
202 // If there was no URL or type defined in EMBED, try the OBJECT tag.
205 if (serviceType
.isEmpty())
206 serviceType
= o
->serviceType();
208 HashSet
<StringImpl
*, CaseFoldingHash
> uniqueParamNames
;
210 // Scan the PARAM children.
211 // Get the URL and type from the params if we don't already have them.
212 // Get the attributes from the params if there is no EMBED tag.
213 Node
*child
= o
->firstChild();
214 while (child
&& (url
.isEmpty() || serviceType
.isEmpty() || !embed
)) {
215 if (child
->hasTagName(paramTag
)) {
216 HTMLParamElement
* p
= static_cast<HTMLParamElement
*>(child
);
217 String name
= p
->name();
218 if (url
.isEmpty() && (equalIgnoringCase(name
, "src") || equalIgnoringCase(name
, "movie") || equalIgnoringCase(name
, "code") || equalIgnoringCase(name
, "url")))
220 if (serviceType
.isEmpty() && equalIgnoringCase(name
, "type")) {
221 serviceType
= p
->value();
222 int pos
= serviceType
.find(";");
224 serviceType
= serviceType
.left(pos
);
226 if (!embed
&& !name
.isEmpty()) {
227 uniqueParamNames
.add(name
.impl());
228 paramNames
.append(p
->name());
229 paramValues
.append(p
->value());
232 child
= child
->nextSibling();
235 // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag
236 // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is
237 // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means
238 // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM,
239 // else our Java plugin will misinterpret it. [4004531]
241 if (!embed
&& MIMETypeRegistry::isJavaAppletMIMEType(serviceType
)) {
242 codebase
= "codebase";
243 uniqueParamNames
.add(codebase
.impl()); // pretend we found it in a PARAM already
246 // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values.
247 NamedNodeMap
* attributes
= embedOrObject
->attributes();
249 for (unsigned i
= 0; i
< attributes
->length(); ++i
) {
250 Attribute
* it
= attributes
->attributeItem(i
);
251 const AtomicString
& name
= it
->name().localName();
252 if (embed
|| !uniqueParamNames
.contains(name
.impl())) {
253 paramNames
.append(name
.string());
254 paramValues
.append(it
->value().string());
259 mapDataParamToSrc(¶mNames
, ¶mValues
);
261 // If we still don't have a type, try to map from a specific CLASSID to a type.
262 if (serviceType
.isEmpty())
263 serviceType
= serviceTypeForClassId(o
->classId(), pluginData
);
265 if (!isURLAllowed(document(), url
))
268 // Find out if we support fallback content.
269 m_hasFallbackContent
= false;
270 for (Node
*child
= o
->firstChild(); child
&& !m_hasFallbackContent
; child
= child
->nextSibling()) {
271 if ((!child
->isTextNode() && !child
->hasTagName(embedTag
) && !child
->hasTagName(paramTag
)) || // Discount <embed> and <param>
272 (child
->isTextNode() && !static_cast<Text
*>(child
)->containsOnlyWhitespace()))
273 m_hasFallbackContent
= true;
276 if (onlyCreateNonNetscapePlugins
) {
279 completedURL
= frame
->loader()->completeURL(url
);
281 if (frame
->loader()->client()->objectContentType(completedURL
, serviceType
) == ObjectContentNetscapePlugin
)
285 bool success
= frame
->loader()->requestObject(this, url
, AtomicString(o
->name()), serviceType
, paramNames
, paramValues
);
286 if (!success
&& m_hasFallbackContent
)
287 o
->renderFallbackContent();
288 } else if (node()->hasTagName(embedTag
)) {
289 HTMLEmbedElement
*o
= static_cast<HTMLEmbedElement
*>(node());
290 o
->setNeedWidgetUpdate(false);
292 serviceType
= o
->serviceType();
294 if (url
.isEmpty() && serviceType
.isEmpty())
296 if (!isURLAllowed(document(), url
))
299 // add all attributes set on the embed object
300 NamedNodeMap
* a
= o
->attributes();
302 for (unsigned i
= 0; i
< a
->length(); ++i
) {
303 Attribute
* it
= a
->attributeItem(i
);
304 paramNames
.append(it
->name().localName().string());
305 paramValues
.append(it
->value().string());
309 if (onlyCreateNonNetscapePlugins
) {
312 completedURL
= frame
->loader()->completeURL(url
);
314 if (frame
->loader()->client()->objectContentType(completedURL
, serviceType
) == ObjectContentNetscapePlugin
)
319 frame
->loader()->requestObject(this, url
, o
->getAttribute(nameAttr
), serviceType
, paramNames
, paramValues
);
321 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
322 else if (node()->hasTagName(videoTag
) || node()->hasTagName(audioTag
)) {
323 HTMLMediaElement
* o
= static_cast<HTMLMediaElement
*>(node());
325 o
->setNeedWidgetUpdate(false);
326 if (node()->hasTagName(videoTag
)) {
327 HTMLVideoElement
* vid
= static_cast<HTMLVideoElement
*>(node());
328 String poster
= vid
->poster();
329 if (!poster
.isEmpty()) {
330 paramNames
.append("_media_element_poster_");
331 paramValues
.append(poster
);
335 url
= o
->initialURL();
336 if (!url
.isEmpty()) {
337 paramNames
.append("_media_element_src_");
338 paramValues
.append(url
);
341 serviceType
= "application/x-media-element-proxy-plugin";
342 frame
->loader()->requestObject(this, url
, nullAtom
, serviceType
, paramNames
, paramValues
);
347 void RenderPartObject::layout()
349 ASSERT(needsLayout());
353 adjustOverflowForBoxShadowAndReflect();
355 RenderPart::layout();
357 if (!widget() && frameView())
358 frameView()->addWidgetToUpdate(this);
360 setNeedsLayout(false);
363 void RenderPartObject::viewCleared()
365 if (node() && widget() && widget()->isFrameView()) {
366 FrameView
* view
= static_cast<FrameView
*>(widget());
369 if (node()->hasTagName(iframeTag
)) {
370 HTMLIFrameElement
* frame
= static_cast<HTMLIFrameElement
*>(node());
371 marginw
= frame
->getMarginWidth();
372 marginh
= frame
->getMarginHeight();
375 view
->setMarginWidth(marginw
);
377 view
->setMarginHeight(marginh
);