1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:set et cin sw=2 sts=2:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla <object> loading code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Christian Biesinger <cbiesinger@web.de>.
20 : * Portions created by the Initial Developer are Copyright (C) 2005
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * A base class implementing nsIObjectLoadingContent for use by
41 : * various content nodes that want to provide plugin/document/image
42 : * loading functionality (eg <embed>, <object>, <applet>, etc).
43 : */
44 :
45 : #ifndef NSOBJECTLOADINGCONTENT_H_
46 : #define NSOBJECTLOADINGCONTENT_H_
47 :
48 : #include "nsImageLoadingContent.h"
49 : #include "nsIStreamListener.h"
50 : #include "nsFrameLoader.h"
51 : #include "nsIInterfaceRequestor.h"
52 : #include "nsIChannelEventSink.h"
53 : #include "nsIObjectLoadingContent.h"
54 : #include "nsIRunnable.h"
55 : #include "nsIFrame.h"
56 : #include "nsPluginInstanceOwner.h"
57 : #include "nsIThreadInternal.h"
58 :
59 : class nsAsyncInstantiateEvent;
60 : class nsStopPluginRunnable;
61 : class AutoNotifier;
62 : class AutoFallback;
63 : class AutoSetInstantiatingToFalse;
64 : class nsObjectFrame;
65 :
66 : enum PluginSupportState {
67 : ePluginUnsupported, // The plugin is not supported (e.g. not installed)
68 : ePluginDisabled, // The plugin has been explicitly disabled by the user
69 : ePluginBlocklisted, // The plugin is blocklisted and disabled
70 : ePluginOutdated, // The plugin is considered outdated, but not disabled
71 : ePluginOtherState, // Something else (e.g. uninitialized or not a plugin)
72 : ePluginCrashed,
73 : ePluginClickToPlay // The plugin is disabled until the user clicks on it
74 : };
75 :
76 : /**
77 : * INVARIANTS OF THIS CLASS
78 : * - mChannel is non-null between asyncOpen and onStopRequest (NOTE: Only needs
79 : * to be valid until onStopRequest is called on mFinalListener, not
80 : * necessarily until the channel calls onStopRequest on us)
81 : * - mChannel corresponds to the channel that gets passed to the
82 : * nsIRequestObserver/nsIStreamListener methods
83 : * - mChannel can be cancelled and ODA calls will stop
84 : * - mFinalListener is non-null (only) after onStartRequest has been called on
85 : * it and before onStopRequest has been called on it
86 : * (i.e. calling onStopRequest doesn't violate the nsIRequestObserver
87 : * contract)
88 : * - mFrameLoader is null while this node is not in a document (XXX this
89 : * invariant only exists due to nsFrameLoader suckage and needs to go away)
90 : * - mInstantiating is true while in LoadObject (it may be true in other
91 : * cases as well). Only the function that set mInstantiating should trigger
92 : * frame construction or notifications like ContentStatesChanged or flushes.
93 : */
94 : class nsObjectLoadingContent : public nsImageLoadingContent
95 : , public nsIStreamListener
96 : , public nsIFrameLoaderOwner
97 : , public nsIObjectLoadingContent
98 : , public nsIInterfaceRequestor
99 : , public nsIChannelEventSink
100 : {
101 : friend class AutoNotifier;
102 : friend class AutoFallback;
103 : friend class AutoSetInstantiatingToFalse;
104 : friend class nsStopPluginRunnable;
105 : friend class nsAsyncInstantiateEvent;
106 :
107 : public:
108 : // This enum's values must be the same as the constants on
109 : // nsIObjectLoadingContent
110 : enum ObjectType {
111 : eType_Loading = TYPE_LOADING, ///< Type not yet known
112 : eType_Image = TYPE_IMAGE, ///< This content is an image
113 : eType_Plugin = TYPE_PLUGIN, ///< This content is a plugin
114 : eType_Document = TYPE_DOCUMENT, ///< This is a document type (e.g. HTML)
115 : eType_Null = TYPE_NULL ///< Type can't be handled
116 : };
117 :
118 : nsObjectLoadingContent();
119 : virtual ~nsObjectLoadingContent();
120 :
121 : NS_DECL_NSIREQUESTOBSERVER
122 : NS_DECL_NSISTREAMLISTENER
123 : NS_DECL_NSIFRAMELOADEROWNER
124 : NS_DECL_NSIOBJECTLOADINGCONTENT
125 : NS_DECL_NSIINTERFACEREQUESTOR
126 : NS_DECL_NSICHANNELEVENTSINK
127 :
128 : #ifdef HAVE_CPP_AMBIGUITY_RESOLVING_USING
129 : // Fix gcc compile warnings
130 : using nsImageLoadingContent::OnStartRequest;
131 : using nsImageLoadingContent::OnDataAvailable;
132 : using nsImageLoadingContent::OnStopRequest;
133 : #endif
134 :
135 0 : ObjectType Type() { return mType; }
136 :
137 : /**
138 : * Object state. This is a bitmask consisting of a subset of
139 : * NS_EVENT_STATE_BROKEN, NS_EVENT_STATE_USERDISABLED and
140 : * NS_EVENT_STATE_SUPPRESSED representing the current state of the object.
141 : */
142 : nsEventStates ObjectState() const;
143 :
144 0 : void SetIsNetworkCreated(bool aNetworkCreated)
145 : {
146 0 : mNetworkCreated = aNetworkCreated;
147 0 : }
148 :
149 : // Can flush layout.
150 : nsresult InstantiatePluginInstance(const char* aMimeType, nsIURI* aURI);
151 :
152 : void NotifyOwnerDocumentActivityChanged();
153 :
154 0 : bool SrcStreamLoading() { return mSrcStreamLoading; };
155 :
156 : protected:
157 : /**
158 : * Load the object from the given URI.
159 : * @param aURI The URI to load.
160 : * @param aNotify If true, nsIDocumentObserver state change notifications
161 : * will be sent as needed.
162 : * @param aTypeHint MIME Type hint. Overridden by the server unless this
163 : * class has the eOverrideServerType capability.
164 : * @param aForceLoad If true, the object will be refetched even if the URI
165 : * is the same as the currently-loaded object.
166 : * @note Prefer the nsIURI-taking version of this function if a URI object
167 : * is already available.
168 : * @see the URI-taking version of this function for a detailed description
169 : * of how a plugin will be found.
170 : */
171 : nsresult LoadObject(const nsAString& aURI,
172 : bool aNotify,
173 : const nsCString& aTypeHint = EmptyCString(),
174 : bool aForceLoad = false);
175 : /**
176 : * Loads the object from the given URI.
177 : *
178 : * The URI and type can both be null; if the URI is null a plugin will be
179 : * instantiated in the hope that there is a <param> with a useful URI
180 : * somewhere around. Other attributes of |this| QI'd to nsIContent will be
181 : * inspected. This function attempts hard to find a suitable plugin.
182 : *
183 : * The instantiated plugin depends on three values:
184 : * - The passed-in URI
185 : * - The passed-in type hint
186 : * - The classid attribute, if eSupportClassID is among the capabilities
187 : * and such an attribute is present..
188 : *
189 : * Supported class ID attributes override any other value.
190 : *
191 : * If no class ID is present and aForceType is true, the handler given by
192 : * aTypeHint will be instantiated for this content.
193 : * If the URI is null or not supported, and a type hint is given, the plugin
194 : * corresponding to that type is instantiated.
195 : *
196 : * Otherwise a request to that URI is made and the type sent by the server
197 : * is used to find a suitable handler.
198 : *
199 : * @param aForceLoad If true, the object will be refetched even if the URI
200 : * is the same as the currently-loaded object.
201 : */
202 : nsresult LoadObject(nsIURI* aURI,
203 : bool aNotify,
204 : const nsCString& aTypeHint = EmptyCString(),
205 : bool aForceLoad = false);
206 :
207 : enum Capabilities {
208 : eSupportImages = PR_BIT(0), // Images are supported (imgILoader)
209 : eSupportPlugins = PR_BIT(1), // Plugins are supported (nsIPluginHost)
210 : eSupportDocuments = PR_BIT(2), // Documents are supported
211 : // (nsIDocumentLoaderFactory)
212 : // This flag always includes SVG
213 : eSupportSVG = PR_BIT(3), // SVG is supported (image/svg+xml)
214 : eSupportClassID = PR_BIT(4), // The classid attribute is supported
215 : eOverrideServerType = PR_BIT(5) // The server-sent MIME type is ignored
216 : // (ignored if no type is specified)
217 : };
218 :
219 : /**
220 : * Returns the list of capabilities this content node supports. This is a
221 : * bitmask consisting of flags from the Capabilities enum.
222 : *
223 : * The default implementation supports all types but no classids.
224 : */
225 : virtual PRUint32 GetCapabilities() const;
226 :
227 : /**
228 : * Fall back to rendering the alternative content.
229 : */
230 : void Fallback(bool aNotify);
231 :
232 : /**
233 : * Subclasses must call this function when they are removed from the
234 : * document.
235 : *
236 : * XXX This is a temporary workaround for docshell suckyness
237 : */
238 : void RemovedFromDocument();
239 :
240 : static void Traverse(nsObjectLoadingContent *tmp,
241 : nsCycleCollectionTraversalCallback &cb);
242 :
243 : void CreateStaticClone(nsObjectLoadingContent* aDest) const;
244 :
245 : void DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner, bool aDelayedStop,
246 : bool aForcedReentry = false);
247 :
248 : private:
249 :
250 : void NotifyContentObjectWrapper();
251 :
252 : /**
253 : * Check whether the given request represents a successful load.
254 : */
255 : static bool IsSuccessfulRequest(nsIRequest* aRequest);
256 :
257 : /**
258 : * Check whether the URI can be handled internally.
259 : */
260 : static bool CanHandleURI(nsIURI* aURI);
261 :
262 : /**
263 : * Checks whether the given type is a supported document type.
264 : */
265 : bool IsSupportedDocument(const nsCString& aType);
266 :
267 : /**
268 : * Unload the currently loaded content. This removes all state related to
269 : * the displayed content and sets the type to eType_Null.
270 : * Note: This does not send any notifications.
271 : */
272 : void UnloadContent();
273 :
274 : /**
275 : * Notifies document observes about a new type/state of this object.
276 : * Triggers frame construction as needed. mType must be set correctly when
277 : * this method is called. This method is cheap if the type and state didn't
278 : * actually change.
279 : *
280 : * @param aSync If a synchronous frame construction is required. If false,
281 : * the construction may either be sync or async.
282 : * @param aNotify if false, only need to update the state of our element.
283 : */
284 : void NotifyStateChanged(ObjectType aOldType, nsEventStates aOldState,
285 : bool aSync, bool aNotify);
286 :
287 : /**
288 : * Fires the "Plugin not found" event. This function doesn't do any checks
289 : * whether it should be fired, the caller should do that.
290 : */
291 : static void FirePluginError(nsIContent* thisContent, PluginSupportState state);
292 :
293 : ObjectType GetTypeOfContent(const nsCString& aMIMEType);
294 :
295 : /**
296 : * For a classid, returns the MIME type that can be used to instantiate
297 : * a plugin for this ID.
298 : *
299 : * @return NS_ERROR_NOT_AVAILABLE Unsupported class ID.
300 : */
301 : nsresult TypeForClassID(const nsAString& aClassID, nsACString& aType);
302 :
303 : /**
304 : * Gets the base URI to be used for this object. This differs from
305 : * nsIContent::GetBaseURI in that it takes codebase attributes into
306 : * account.
307 : */
308 : void GetObjectBaseURI(nsIContent* thisContent, nsIURI** aURI);
309 :
310 :
311 : /**
312 : * Gets the frame that's associated with this content node.
313 : * Does not flush.
314 : */
315 : nsObjectFrame* GetExistingFrame();
316 :
317 : /**
318 : * Handle being blocked by a content policy. aStatus is the nsresult
319 : * return value of the Should* call, while aRetval is what it returned in
320 : * its out parameter.
321 : */
322 : void HandleBeingBlockedByContentPolicy(nsresult aStatus,
323 : PRInt16 aRetval);
324 :
325 : /**
326 : * Get the plugin support state for the given content node and MIME type.
327 : * This is used for purposes of determining whether to fire PluginNotFound
328 : * events etc. aContentType is the MIME type we ended up with.
329 : *
330 : * This should only be called if the type of this content is eType_Null.
331 : */
332 : PluginSupportState GetPluginSupportState(nsIContent* aContent, const nsCString& aContentType);
333 :
334 : /**
335 : * If the plugin for aContentType is disabled, return ePluginDisabled.
336 : * Otherwise (including if there is no plugin for aContentType at all),
337 : * return ePluginUnsupported.
338 : *
339 : * This should only be called if the type of this content is eType_Null.
340 : */
341 : PluginSupportState GetPluginDisabledState(const nsCString& aContentType);
342 :
343 : /**
344 : * When there is no usable plugin available this will send UI events and
345 : * update the AutoFallback object appropriate to the reason for there being
346 : * no plugin available.
347 : */
348 : void UpdateFallbackState(nsIContent* aContent, AutoFallback& fallback, const nsCString& aTypeHint);
349 :
350 : nsresult IsPluginEnabledForType(const nsCString& aMIMEType);
351 : bool IsPluginEnabledByExtension(nsIURI* uri, nsCString& mimeType);
352 :
353 : /**
354 : * The final listener to ship the data to (imagelib, uriloader, etc)
355 : */
356 : nsCOMPtr<nsIStreamListener> mFinalListener;
357 :
358 : /**
359 : * Frame loader, for content documents we load.
360 : */
361 : nsRefPtr<nsFrameLoader> mFrameLoader;
362 :
363 : /**
364 : * A pending nsAsyncInstantiateEvent (may be null). This is a weak ref.
365 : */
366 : nsIRunnable *mPendingInstantiateEvent;
367 :
368 : /**
369 : * The content type of the resource we were last asked to load.
370 : */
371 : nsCString mContentType;
372 :
373 : /**
374 : * The channel that's currently being loaded. This is a weak reference.
375 : * Non-null between asyncOpen and onStopRequest.
376 : */
377 : nsIChannel* mChannel;
378 :
379 : // The data we were last asked to load
380 : nsCOMPtr<nsIURI> mURI;
381 :
382 : /**
383 : * Type of the currently-loaded content.
384 : */
385 : ObjectType mType : 16;
386 :
387 : /**
388 : * Whether we are about to call instantiate on our frame. If we aren't,
389 : * SetFrame needs to asynchronously call Instantiate.
390 : */
391 : bool mInstantiating : 1;
392 : // Blocking status from content policy
393 : bool mUserDisabled : 1;
394 : bool mSuppressed : 1;
395 :
396 : // True when the object is created for an element which the parser has
397 : // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
398 : // it may lose the flag.
399 : bool mNetworkCreated : 1;
400 :
401 : // Used to keep track of whether or not a plugin should be played.
402 : // This is used for click-to-play plugins.
403 : bool mShouldPlay : 1;
404 :
405 : // Protects DoStopPlugin from reentry (bug 724781).
406 : bool mIsStopping : 1;
407 :
408 : // Used to track when we might try to instantiate a plugin instance based on
409 : // a src data stream being delivered to this object. When this is true we don't
410 : // want plugin instance instantiation code to attempt to load src data again or
411 : // we'll deliver duplicate streams. Should be cleared when we are not loading
412 : // src data.
413 : bool mSrcStreamLoading;
414 :
415 : // A specific state that caused us to fallback
416 : PluginSupportState mFallbackReason;
417 :
418 : nsWeakFrame mPrintFrame;
419 :
420 : nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
421 : };
422 :
423 : #endif
|