2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 * Copyright (C) Research In Motion Limited 2009. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include "SubframeLoader.h"
37 #include "FrameLoaderClient.h"
38 #include "HTMLAppletElement.h"
39 #include "HTMLFrameElementBase.h"
40 #include "HTMLNames.h"
41 #include "HTMLPlugInImageElement.h"
42 #include "MIMETypeRegistry.h"
44 #include "PluginData.h"
45 #include "PluginDocument.h"
46 #include "RenderEmbeddedObject.h"
47 #include "RenderView.h"
50 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
51 #include "HTMLMediaElement.h"
52 #include "RenderVideo.h"
57 using namespace HTMLNames;
59 SubframeLoader::SubframeLoader(Frame* frame)
60 : m_containsPlugins(false)
65 void SubframeLoader::clear()
67 m_containsPlugins = false;
70 bool SubframeLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
72 // Support for <frame src="javascript:string">
75 if (protocolIsJavaScript(urlString)) {
76 scriptURL = completeURL(urlString); // completeURL() encodes the URL.
79 url = completeURL(urlString);
81 Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList);
85 if (!scriptURL.isEmpty())
86 frame->script()->executeIfJavaScriptURL(scriptURL);
91 bool SubframeLoader::resourceWillUsePlugin(const String& url, const String& mimeType, bool shouldPreferPlugInsForImages)
95 completedURL = completeURL(url);
98 return shouldUsePlugin(completedURL, mimeType, shouldPreferPlugInsForImages, false, useFallback);
101 bool SubframeLoader::requestPlugin(HTMLPlugInImageElement* ownerElement, const KURL& url, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
103 Settings* settings = m_frame->settings();
104 if ((!allowPlugins(AboutToInstantiatePlugin)
105 // Application plug-ins are plug-ins implemented by the user agent, for example Qt plug-ins,
106 // as opposed to third-party code such as Flash. The user agent decides whether or not they are
107 // permitted, rather than WebKit.
108 && !MIMETypeRegistry::isApplicationPluginMIMEType(mimeType))
109 || (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
112 if (m_frame->document() && m_frame->document()->securityOrigin()->isSandboxed(SandboxPlugins))
115 ASSERT(ownerElement->hasTagName(objectTag) || ownerElement->hasTagName(embedTag));
116 return loadPlugin(ownerElement, url, mimeType, paramNames, paramValues, useFallback);
119 bool SubframeLoader::requestObject(HTMLPlugInImageElement* ownerElement, const String& url, const AtomicString& frameName, const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
121 if (url.isEmpty() && mimeType.isEmpty())
124 // FIXME: None of this code should use renderers!
125 RenderEmbeddedObject* renderer = ownerElement->renderEmbeddedObject();
132 completedURL = completeURL(url);
135 if (shouldUsePlugin(completedURL, mimeType, ownerElement->shouldPreferPlugInsForImages(), renderer->hasFallbackContent(), useFallback))
136 return requestPlugin(ownerElement, completedURL, mimeType, paramNames, paramValues, useFallback);
138 // If the plug-in element already contains a subframe, loadOrRedirectSubframe will re-use it. Otherwise,
139 // it will create a new frame and set it as the RenderPart's widget, causing what was previously
140 // in the widget to be torn down.
141 return loadOrRedirectSubframe(ownerElement, completedURL, frameName, true, true);
144 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
145 PassRefPtr<Widget> SubframeLoader::loadMediaPlayerProxyPlugin(Node* node, const KURL& url,
146 const Vector<String>& paramNames, const Vector<String>& paramValues)
148 ASSERT(node->hasTagName(videoTag) || node->hasTagName(audioTag));
152 completedURL = completeURL(url);
154 if (!m_frame->document()->securityOrigin()->canDisplay(completedURL)) {
155 FrameLoader::reportLocalLoadFailed(m_frame, completedURL.string());
159 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(node);
160 RenderPart* renderer = toRenderPart(node->renderer());
164 size = IntSize(renderer->contentWidth(), renderer->contentHeight());
165 else if (mediaElement->isVideo())
166 size = RenderVideo::defaultSize();
168 m_frame->loader()->checkIfRunInsecureContent(m_frame->document()->securityOrigin(), completedURL);
170 RefPtr<Widget> widget = m_frame->loader()->client()->createMediaPlayerProxyPlugin(size, mediaElement, completedURL,
171 paramNames, paramValues, "application/x-media-element-proxy-plugin");
173 if (widget && renderer) {
174 renderer->setWidget(widget);
175 renderer->node()->setNeedsStyleRecalc(SyntheticStyleChange);
177 m_containsPlugins = true;
179 return widget ? widget.release() : 0;
181 #endif // ENABLE(PLUGIN_PROXY_FOR_VIDEO)
183 PassRefPtr<Widget> SubframeLoader::createJavaAppletWidget(const IntSize& size, HTMLAppletElement* element, const HashMap<String, String>& args)
185 String baseURLString;
186 String codeBaseURLString;
187 Vector<String> paramNames;
188 Vector<String> paramValues;
189 HashMap<String, String>::const_iterator end = args.end();
190 for (HashMap<String, String>::const_iterator it = args.begin(); it != end; ++it) {
191 if (equalIgnoringCase(it->first, "baseurl"))
192 baseURLString = it->second;
193 else if (equalIgnoringCase(it->first, "codebase"))
194 codeBaseURLString = it->second;
195 paramNames.append(it->first);
196 paramValues.append(it->second);
199 if (!codeBaseURLString.isEmpty()) {
200 KURL codeBaseURL = completeURL(codeBaseURLString);
201 if (!element->document()->securityOrigin()->canDisplay(codeBaseURL)) {
202 FrameLoader::reportLocalLoadFailed(m_frame, codeBaseURL.string());
207 if (baseURLString.isEmpty())
208 baseURLString = m_frame->document()->baseURL().string();
209 KURL baseURL = completeURL(baseURLString);
211 RefPtr<Widget> widget;
212 if (allowPlugins(AboutToInstantiatePlugin))
213 widget = m_frame->loader()->client()->createJavaAppletWidget(size, element, baseURL, paramNames, paramValues);
217 m_containsPlugins = true;
221 Frame* SubframeLoader::loadOrRedirectSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList)
223 Frame* frame = ownerElement->contentFrame();
225 frame->navigationScheduler()->scheduleLocationChange(m_frame->document()->securityOrigin(), url.string(), m_frame->loader()->outgoingReferrer(), lockHistory, lockBackForwardList);
227 frame = loadSubframe(ownerElement, url, frameName, m_frame->loader()->outgoingReferrer());
231 Frame* SubframeLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
233 bool allowsScrolling = true;
234 int marginWidth = -1;
235 int marginHeight = -1;
236 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
237 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
238 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
239 marginWidth = o->marginWidth();
240 marginHeight = o->marginHeight();
243 if (!ownerElement->document()->securityOrigin()->canDisplay(url)) {
244 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
248 bool hideReferrer = SecurityOrigin::shouldHideReferrer(url, referrer);
249 RefPtr<Frame> frame = m_frame->loader()->client()->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, allowsScrolling, marginWidth, marginHeight);
252 m_frame->loader()->checkCallImplicitClose();
256 // All new frames will have m_isComplete set to true at this point due to synchronously loading
257 // an empty document in FrameLoader::init(). But many frames will now be starting an
258 // asynchronous load of url, so we set m_isComplete to false and then check if the load is
259 // actually completed below. (Note that we set m_isComplete to false even for synchronous
260 // loads, so that checkCompleted() below won't bail early.)
261 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
262 frame->loader()->started();
264 RenderObject* renderer = ownerElement->renderer();
265 FrameView* view = frame->view();
266 if (renderer && renderer->isWidget() && view)
267 toRenderWidget(renderer)->setWidget(view);
269 m_frame->loader()->checkCallImplicitClose();
271 // Some loads are performed synchronously (e.g., about:blank and loads
272 // cancelled by returning a null ResourceRequest from requestFromDelegate).
273 // In these cases, the synchronous load would have finished
274 // before we could connect the signals, so make sure to send the
275 // completed() signal for the child by hand and mark the load as being
277 // FIXME: In this case the Frame will have finished loading before
278 // it's being added to the child list. It would be a good idea to
279 // create the child first, then invoke the loader separately.
280 if (frame->loader()->state() == FrameStateComplete && !frame->loader()->policyDocumentLoader())
281 frame->loader()->checkCompleted();
286 bool SubframeLoader::allowPlugins(ReasonForCallingAllowPlugins reason)
288 Settings* settings = m_frame->settings();
289 bool allowed = m_frame->loader()->client()->allowPlugins(settings && settings->arePluginsEnabled());
290 if (!allowed && reason == AboutToInstantiatePlugin)
291 m_frame->loader()->client()->didNotAllowPlugins();
295 bool SubframeLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages, bool hasFallback, bool& useFallback)
297 if (m_frame->loader()->client()->shouldUsePluginDocument(mimeType)) {
302 // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that
303 // can handle TIFF (which QuickTime can also handle) they probably intended to override QT.
304 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) {
305 const PluginData* pluginData = m_frame->page()->pluginData();
306 String pluginName = pluginData ? pluginData->pluginNameForMimeType(mimeType) : String();
307 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false))
311 ObjectContentType objectType = m_frame->loader()->client()->objectContentType(url, mimeType, shouldPreferPlugInsForImages);
312 // If an object's content can't be handled and it has no fallback, let
313 // it be handled as a plugin to show the broken plugin icon.
314 useFallback = objectType == ObjectContentNone && hasFallback;
315 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
318 Document* SubframeLoader::document() const
320 return m_frame->document();
323 bool SubframeLoader::loadPlugin(HTMLPlugInImageElement* pluginElement, const KURL& url, const String& mimeType,
324 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
326 RenderEmbeddedObject* renderer = pluginElement->renderEmbeddedObject();
328 // FIXME: This code should not depend on renderer!
329 if (!renderer || useFallback)
332 if (!document()->securityOrigin()->canDisplay(url)) {
333 FrameLoader::reportLocalLoadFailed(m_frame, url.string());
337 FrameLoader* frameLoader = m_frame->loader();
338 frameLoader->checkIfRunInsecureContent(document()->securityOrigin(), url);
340 IntSize contentSize(renderer->contentWidth(), renderer->contentHeight());
341 bool loadManually = document()->isPluginDocument() && !m_containsPlugins && toPluginDocument(document())->shouldLoadPluginManually();
342 RefPtr<Widget> widget = frameLoader->client()->createPlugin(contentSize,
343 pluginElement, url, paramNames, paramValues, mimeType, loadManually);
346 renderer->setShowsMissingPluginIndicator();
350 renderer->setWidget(widget);
351 m_containsPlugins = true;
353 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) || ENABLE(3D_PLUGIN)
354 pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
359 KURL SubframeLoader::completeURL(const String& url) const
361 ASSERT(m_frame->document());
362 return m_frame->document()->completeURL(url);
365 } // namespace WebCore