• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20 
21 #include "config.h"
22 #include "HTMLPlugInImageElement.h"
23 
24 #include "Frame.h"
25 #include "FrameLoader.h"
26 #include "FrameLoaderClient.h"
27 #include "HTMLImageLoader.h"
28 #include "HTMLNames.h"
29 #include "Image.h"
30 #include "Page.h"
31 #include "RenderEmbeddedObject.h"
32 #include "RenderImage.h"
33 
34 namespace WebCore {
35 
HTMLPlugInImageElement(const QualifiedName & tagName,Document * document,bool createdByParser,PreferPlugInsForImagesOption preferPlugInsForImagesOption)36 HTMLPlugInImageElement::HTMLPlugInImageElement(const QualifiedName& tagName, Document* document, bool createdByParser, PreferPlugInsForImagesOption preferPlugInsForImagesOption)
37     : HTMLPlugInElement(tagName, document)
38     // m_needsWidgetUpdate(!createdByParser) allows HTMLObjectElement to delay
39     // widget updates until after all children are parsed.  For HTMLEmbedElement
40     // this delay is unnecessary, but it is simpler to make both classes share
41     // the same codepath in this class.
42     , m_needsWidgetUpdate(!createdByParser)
43     , m_shouldPreferPlugInsForImages(preferPlugInsForImagesOption == ShouldPreferPlugInsForImages)
44 {
45 }
46 
renderEmbeddedObject() const47 RenderEmbeddedObject* HTMLPlugInImageElement::renderEmbeddedObject() const
48 {
49     // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
50     // when using fallback content.
51     if (!renderer() || !renderer()->isEmbeddedObject())
52         return 0;
53     return toRenderEmbeddedObject(renderer());
54 }
55 
isImageType()56 bool HTMLPlugInImageElement::isImageType()
57 {
58     if (m_serviceType.isEmpty() && protocolIs(m_url, "data"))
59         m_serviceType = mimeTypeFromDataURL(m_url);
60 
61     if (Frame* frame = document()->frame()) {
62         KURL completedURL = frame->loader()->completeURL(m_url);
63         return frame->loader()->client()->objectContentType(completedURL, m_serviceType, shouldPreferPlugInsForImages()) == ObjectContentImage;
64     }
65 
66     return Image::supportsType(m_serviceType);
67 }
68 
69 // We don't use m_url, as it may not be the final URL that the object loads,
70 // depending on <param> values.
allowedToLoadFrameURL(const String & url)71 bool HTMLPlugInImageElement::allowedToLoadFrameURL(const String& url)
72 {
73     ASSERT(document());
74     ASSERT(document()->frame());
75     if (document()->frame()->page()->frameCount() >= Page::maxNumberOfFrames)
76         return false;
77 
78     // We allow one level of self-reference because some sites depend on that.
79     // But we don't allow more than one.
80     KURL completeURL = document()->completeURL(url);
81     bool foundSelfReference = false;
82     for (Frame* frame = document()->frame(); frame; frame = frame->tree()->parent()) {
83         if (equalIgnoringFragmentIdentifier(frame->document()->url(), completeURL)) {
84             if (foundSelfReference)
85                 return false;
86             foundSelfReference = true;
87         }
88     }
89     return true;
90 }
91 
92 // We don't use m_url, or m_serviceType as they may not be the final values
93 // that <object> uses depending on <param> values.
wouldLoadAsNetscapePlugin(const String & url,const String & serviceType)94 bool HTMLPlugInImageElement::wouldLoadAsNetscapePlugin(const String& url, const String& serviceType)
95 {
96     ASSERT(document());
97     ASSERT(document()->frame());
98     FrameLoader* frameLoader = document()->frame()->loader();
99     ASSERT(frameLoader);
100     KURL completedURL;
101     if (!url.isEmpty())
102         completedURL = frameLoader->completeURL(url);
103 
104     if (frameLoader->client()->objectContentType(completedURL, serviceType, shouldPreferPlugInsForImages()) == ObjectContentNetscapePlugin)
105         return true;
106     return false;
107 }
108 
createRenderer(RenderArena * arena,RenderStyle * style)109 RenderObject* HTMLPlugInImageElement::createRenderer(RenderArena* arena, RenderStyle* style)
110 {
111     // Fallback content breaks the DOM->Renderer class relationship of this
112     // class and all superclasses because createObject won't necessarily
113     // return a RenderEmbeddedObject, RenderPart or even RenderWidget.
114     if (useFallbackContent())
115         return RenderObject::createObject(this, style);
116     if (isImageType()) {
117         RenderImage* image = new (arena) RenderImage(this);
118         image->setImageResource(RenderImageResource::create());
119         return image;
120     }
121     return new (arena) RenderEmbeddedObject(this);
122 }
123 
recalcStyle(StyleChange ch)124 void HTMLPlugInImageElement::recalcStyle(StyleChange ch)
125 {
126     // FIXME: Why is this necessary?  Manual re-attach is almost always wrong.
127     if (!useFallbackContent() && needsWidgetUpdate() && renderer() && !isImageType()) {
128         detach();
129         attach();
130     }
131     HTMLPlugInElement::recalcStyle(ch);
132 }
133 
attach()134 void HTMLPlugInImageElement::attach()
135 {
136     bool isImage = isImageType();
137 
138     if (!isImage)
139         queuePostAttachCallback(&HTMLPlugInImageElement::updateWidgetCallback, this);
140 
141     HTMLPlugInElement::attach();
142 
143     if (isImage && renderer() && !useFallbackContent()) {
144         if (!m_imageLoader)
145             m_imageLoader = adoptPtr(new HTMLImageLoader(this));
146         m_imageLoader->updateFromElement();
147     }
148 }
149 
detach()150 void HTMLPlugInImageElement::detach()
151 {
152     // FIXME: Because of the insanity that is HTMLPlugInImageElement::recalcStyle,
153     // we can end up detaching during an attach() call, before we even have a
154     // renderer.  In that case, don't mark the widget for update.
155     if (attached() && renderer() && !useFallbackContent())
156         // Update the widget the next time we attach (detaching destroys the plugin).
157         setNeedsWidgetUpdate(true);
158     HTMLPlugInElement::detach();
159 }
160 
updateWidgetIfNecessary()161 void HTMLPlugInImageElement::updateWidgetIfNecessary()
162 {
163     document()->updateStyleIfNeeded();
164 
165     if (!needsWidgetUpdate() || useFallbackContent() || isImageType())
166         return;
167 
168     if (!renderEmbeddedObject() || renderEmbeddedObject()->pluginCrashedOrWasMissing())
169         return;
170 
171     updateWidget(CreateOnlyNonNetscapePlugins);
172 }
173 
finishParsingChildren()174 void HTMLPlugInImageElement::finishParsingChildren()
175 {
176     HTMLPlugInElement::finishParsingChildren();
177     if (useFallbackContent())
178         return;
179 
180     setNeedsWidgetUpdate(true);
181     if (inDocument())
182         setNeedsStyleRecalc();
183 }
184 
willMoveToNewOwnerDocument()185 void HTMLPlugInImageElement::willMoveToNewOwnerDocument()
186 {
187     if (m_imageLoader)
188         m_imageLoader->elementWillMoveToNewOwnerDocument();
189     HTMLPlugInElement::willMoveToNewOwnerDocument();
190 }
191 
updateWidgetCallback(Node * n)192 void HTMLPlugInImageElement::updateWidgetCallback(Node* n)
193 {
194     static_cast<HTMLPlugInImageElement*>(n)->updateWidgetIfNecessary();
195 }
196 
197 } // namespace WebCore
198