|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * Class for managing loading of a subframe (creation of the docshell, |
|
8 * handling of loads in it, recursion-checking). |
|
9 */ |
|
10 |
|
11 #ifndef nsFrameLoader_h_ |
|
12 #define nsFrameLoader_h_ |
|
13 |
|
14 #include "nsIDocShell.h" |
|
15 #include "nsStringFwd.h" |
|
16 #include "nsIFrameLoader.h" |
|
17 #include "nsPoint.h" |
|
18 #include "nsSize.h" |
|
19 #include "nsIURI.h" |
|
20 #include "nsAutoPtr.h" |
|
21 #include "nsFrameMessageManager.h" |
|
22 #include "mozilla/dom/Element.h" |
|
23 #include "mozilla/Attributes.h" |
|
24 #include "FrameMetrics.h" |
|
25 #include "nsStubMutationObserver.h" |
|
26 |
|
27 class nsIURI; |
|
28 class nsSubDocumentFrame; |
|
29 class nsView; |
|
30 class nsIInProcessContentFrameMessageManager; |
|
31 class AutoResetInShow; |
|
32 class nsITabParent; |
|
33 class nsIDocShellTreeItem; |
|
34 class nsIDocShellTreeOwner; |
|
35 class mozIApplication; |
|
36 |
|
37 namespace mozilla { |
|
38 namespace dom { |
|
39 class ContentParent; |
|
40 class PBrowserParent; |
|
41 class TabParent; |
|
42 struct StructuredCloneData; |
|
43 } |
|
44 |
|
45 namespace layout { |
|
46 class RenderFrameParent; |
|
47 } |
|
48 } |
|
49 |
|
50 #if defined(MOZ_WIDGET_GTK) |
|
51 typedef struct _GtkWidget GtkWidget; |
|
52 #endif |
|
53 #ifdef MOZ_WIDGET_QT |
|
54 class QX11EmbedContainer; |
|
55 #endif |
|
56 |
|
57 /** |
|
58 * Defines a target configuration for this <browser>'s content |
|
59 * document's view. If the content document's actual view |
|
60 * doesn't match this nsIContentView, then on paints its pixels |
|
61 * are transformed to compensate for the difference. |
|
62 * |
|
63 * Used to support asynchronous re-paints of content pixels; see |
|
64 * nsIContentView. |
|
65 */ |
|
66 class nsContentView MOZ_FINAL : public nsIContentView |
|
67 { |
|
68 public: |
|
69 typedef mozilla::layers::FrameMetrics::ViewID ViewID; |
|
70 NS_DECL_ISUPPORTS |
|
71 NS_DECL_NSICONTENTVIEW |
|
72 |
|
73 struct ViewConfig { |
|
74 ViewConfig() |
|
75 : mScrollOffset(0, 0) |
|
76 , mXScale(1.0) |
|
77 , mYScale(1.0) |
|
78 {} |
|
79 |
|
80 // Default copy ctor and operator= are fine |
|
81 |
|
82 bool operator==(const ViewConfig& aOther) const |
|
83 { |
|
84 return (mScrollOffset == aOther.mScrollOffset && |
|
85 mXScale == aOther.mXScale && |
|
86 mYScale == aOther.mYScale); |
|
87 } |
|
88 |
|
89 // This is the scroll offset the <browser> user wishes or expects |
|
90 // its enclosed content document to have. "Scroll offset" here |
|
91 // means the document pixel at pixel (0,0) within the CSS |
|
92 // viewport. If the content document's actual scroll offset |
|
93 // doesn't match |mScrollOffset|, the difference is used to define |
|
94 // a translation transform when painting the content document. |
|
95 nsPoint mScrollOffset; |
|
96 // The scale at which the <browser> user wishes to paint its |
|
97 // enclosed content document. If content-document layers have a |
|
98 // lower or higher resolution than the desired scale, then the |
|
99 // ratio is used to define a scale transform when painting the |
|
100 // content document. |
|
101 float mXScale; |
|
102 float mYScale; |
|
103 }; |
|
104 |
|
105 nsContentView(nsFrameLoader* aFrameLoader, ViewID aScrollId, bool aIsRoot, |
|
106 ViewConfig aConfig = ViewConfig()) |
|
107 : mViewportSize(0, 0) |
|
108 , mContentSize(0, 0) |
|
109 , mParentScaleX(1.0) |
|
110 , mParentScaleY(1.0) |
|
111 , mFrameLoader(aFrameLoader) |
|
112 , mScrollId(aScrollId) |
|
113 , mIsRoot(aIsRoot) |
|
114 , mConfig(aConfig) |
|
115 {} |
|
116 |
|
117 bool IsRoot() const |
|
118 { |
|
119 return mIsRoot; |
|
120 } |
|
121 |
|
122 ViewID GetId() const |
|
123 { |
|
124 return mScrollId; |
|
125 } |
|
126 |
|
127 ViewConfig GetViewConfig() const |
|
128 { |
|
129 return mConfig; |
|
130 } |
|
131 |
|
132 nsSize mViewportSize; |
|
133 nsSize mContentSize; |
|
134 float mParentScaleX; |
|
135 float mParentScaleY; |
|
136 |
|
137 nsFrameLoader* mFrameLoader; // WEAK |
|
138 |
|
139 private: |
|
140 nsresult Update(const ViewConfig& aConfig); |
|
141 |
|
142 ViewID mScrollId; |
|
143 bool mIsRoot; |
|
144 ViewConfig mConfig; |
|
145 }; |
|
146 |
|
147 |
|
148 class nsFrameLoader MOZ_FINAL : public nsIFrameLoader, |
|
149 public nsIContentViewManager, |
|
150 public nsStubMutationObserver, |
|
151 public mozilla::dom::ipc::MessageManagerCallback |
|
152 { |
|
153 friend class AutoResetInShow; |
|
154 typedef mozilla::dom::PBrowserParent PBrowserParent; |
|
155 typedef mozilla::dom::TabParent TabParent; |
|
156 typedef mozilla::layout::RenderFrameParent RenderFrameParent; |
|
157 |
|
158 protected: |
|
159 nsFrameLoader(mozilla::dom::Element* aOwner, bool aNetworkCreated); |
|
160 |
|
161 public: |
|
162 ~nsFrameLoader(); |
|
163 |
|
164 bool AsyncScrollEnabled() const |
|
165 { |
|
166 return !!(mRenderMode & RENDER_MODE_ASYNC_SCROLL); |
|
167 } |
|
168 |
|
169 static nsFrameLoader* Create(mozilla::dom::Element* aOwner, |
|
170 bool aNetworkCreated); |
|
171 |
|
172 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
173 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameLoader, nsIFrameLoader) |
|
174 NS_DECL_NSIFRAMELOADER |
|
175 NS_DECL_NSICONTENTVIEWMANAGER |
|
176 NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED |
|
177 NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI); |
|
178 nsresult ReallyStartLoading(); |
|
179 void Finalize(); |
|
180 nsIDocShell* GetExistingDocShell() { return mDocShell; } |
|
181 mozilla::dom::EventTarget* GetTabChildGlobalAsEventTarget(); |
|
182 nsresult CreateStaticClone(nsIFrameLoader* aDest); |
|
183 |
|
184 /** |
|
185 * MessageManagerCallback methods that we override. |
|
186 */ |
|
187 virtual bool DoLoadFrameScript(const nsAString& aURL, |
|
188 bool aRunInGlobalScope) MOZ_OVERRIDE; |
|
189 virtual bool DoSendAsyncMessage(JSContext* aCx, |
|
190 const nsAString& aMessage, |
|
191 const mozilla::dom::StructuredCloneData& aData, |
|
192 JS::Handle<JSObject *> aCpows, |
|
193 nsIPrincipal* aPrincipal) MOZ_OVERRIDE; |
|
194 virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE; |
|
195 virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE; |
|
196 virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE; |
|
197 |
|
198 /** |
|
199 * Called from the layout frame associated with this frame loader; |
|
200 * this notifies us to hook up with the widget and view. |
|
201 */ |
|
202 bool Show(int32_t marginWidth, int32_t marginHeight, |
|
203 int32_t scrollbarPrefX, int32_t scrollbarPrefY, |
|
204 nsSubDocumentFrame* frame); |
|
205 |
|
206 /** |
|
207 * Called when the margin properties of the containing frame are changed. |
|
208 */ |
|
209 void MarginsChanged(uint32_t aMarginWidth, uint32_t aMarginHeight); |
|
210 |
|
211 /** |
|
212 * Called from the layout frame associated with this frame loader, when |
|
213 * the frame is being torn down; this notifies us that out widget and view |
|
214 * are going away and we should unhook from them. |
|
215 */ |
|
216 void Hide(); |
|
217 |
|
218 nsresult CloneForStatic(nsIFrameLoader* aOriginal); |
|
219 |
|
220 // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation. A |
|
221 // frame loader owner needs to call this, and pass in the two references to |
|
222 // nsRefPtrs for frame loaders that need to be swapped. |
|
223 nsresult SwapWithOtherLoader(nsFrameLoader* aOther, |
|
224 nsRefPtr<nsFrameLoader>& aFirstToSwap, |
|
225 nsRefPtr<nsFrameLoader>& aSecondToSwap); |
|
226 |
|
227 // When IPC is enabled, destroy any associated child process. |
|
228 void DestroyChild(); |
|
229 |
|
230 /** |
|
231 * Return the primary frame for our owning content, or null if it |
|
232 * can't be found. |
|
233 */ |
|
234 nsIFrame* GetPrimaryFrameOfOwningContent() const |
|
235 { |
|
236 return mOwnerContent ? mOwnerContent->GetPrimaryFrame() : nullptr; |
|
237 } |
|
238 |
|
239 /** |
|
240 * Return the document that owns this, or null if we don't have |
|
241 * an owner. |
|
242 */ |
|
243 nsIDocument* GetOwnerDoc() const |
|
244 { return mOwnerContent ? mOwnerContent->OwnerDoc() : nullptr; } |
|
245 |
|
246 PBrowserParent* GetRemoteBrowser(); |
|
247 |
|
248 /** |
|
249 * The "current" render frame is the one on which the most recent |
|
250 * remote layer-tree transaction was executed. If no content has |
|
251 * been drawn yet, or the remote browser doesn't have any drawn |
|
252 * content for whatever reason, return nullptr. The returned render |
|
253 * frame has an associated shadow layer tree. |
|
254 * |
|
255 * Note that the returned render frame might not be a frame |
|
256 * constructed for this->GetURL(). This can happen, e.g., if the |
|
257 * <browser> was just navigated to a new URL, but hasn't painted the |
|
258 * new page yet. A render frame for the previous page may be |
|
259 * returned. (In-process <browser> behaves similarly, and this |
|
260 * behavior seems desirable.) |
|
261 */ |
|
262 RenderFrameParent* GetCurrentRemoteFrame() const |
|
263 { |
|
264 return mCurrentRemoteFrame; |
|
265 } |
|
266 |
|
267 /** |
|
268 * |aFrame| can be null. If non-null, it must be the remote frame |
|
269 * on which the most recent layer transaction completed for this's |
|
270 * <browser>. |
|
271 */ |
|
272 void SetCurrentRemoteFrame(RenderFrameParent* aFrame) |
|
273 { |
|
274 mCurrentRemoteFrame = aFrame; |
|
275 } |
|
276 nsFrameMessageManager* GetFrameMessageManager() { return mMessageManager; } |
|
277 |
|
278 mozilla::dom::Element* GetOwnerContent() { return mOwnerContent; } |
|
279 bool ShouldClipSubdocument() { return mClipSubdocument; } |
|
280 |
|
281 bool ShouldClampScrollPosition() { return mClampScrollPosition; } |
|
282 |
|
283 /** |
|
284 * Tell this FrameLoader to use a particular remote browser. |
|
285 * |
|
286 * This will assert if mRemoteBrowser or mCurrentRemoteFrame is non-null. In |
|
287 * practice, this means you can't have successfully run TryRemoteBrowser() on |
|
288 * this object, which means you can't have called ShowRemoteFrame() or |
|
289 * ReallyStartLoading(). |
|
290 */ |
|
291 void SetRemoteBrowser(nsITabParent* aTabParent); |
|
292 |
|
293 /** |
|
294 * Stashes a detached view on the frame loader. We do this when we're |
|
295 * destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is |
|
296 * being reframed we'll restore the detached view when it's recreated, |
|
297 * otherwise we'll discard the old presentation and set the detached |
|
298 * subdoc view to null. aContainerDoc is the document containing the |
|
299 * the subdoc frame. This enables us to detect when the containing |
|
300 * document has changed during reframe, so we can discard the presentation |
|
301 * in that case. |
|
302 */ |
|
303 void SetDetachedSubdocView(nsView* aDetachedView, |
|
304 nsIDocument* aContainerDoc); |
|
305 |
|
306 /** |
|
307 * Retrieves the detached view and the document containing the view, |
|
308 * as set by SetDetachedSubdocView(). |
|
309 */ |
|
310 nsView* GetDetachedSubdocView(nsIDocument** aContainerDoc) const; |
|
311 |
|
312 /** |
|
313 * Applies a new set of sandbox flags. These are merged with the sandbox |
|
314 * flags from our owning content's owning document with a logical OR, this |
|
315 * ensures that we can only add restrictions and never remove them. |
|
316 */ |
|
317 void ApplySandboxFlags(uint32_t sandboxFlags); |
|
318 |
|
319 void GetURL(nsString& aURL); |
|
320 |
|
321 private: |
|
322 |
|
323 void SetOwnerContent(mozilla::dom::Element* aContent); |
|
324 |
|
325 bool ShouldUseRemoteProcess(); |
|
326 |
|
327 /** |
|
328 * Is this a frameloader for a bona fide <iframe mozbrowser> or |
|
329 * <iframe mozapp>? (I.e., does the frame return true for |
|
330 * nsIMozBrowserFrame::GetReallyIsBrowserOrApp()?) |
|
331 */ |
|
332 bool OwnerIsBrowserOrAppFrame(); |
|
333 |
|
334 /** |
|
335 * Is this a frameloader for a bona fide <iframe mozapp>? (I.e., does the |
|
336 * frame return true for nsIMozBrowserFrame::GetReallyIsApp()?) |
|
337 */ |
|
338 bool OwnerIsAppFrame(); |
|
339 |
|
340 /** |
|
341 * Is this a frame loader for a bona fide <iframe mozbrowser>? |
|
342 */ |
|
343 bool OwnerIsBrowserFrame(); |
|
344 |
|
345 /** |
|
346 * Get our owning element's app manifest URL, or return the empty string if |
|
347 * our owning element doesn't have an app manifest URL. |
|
348 */ |
|
349 void GetOwnerAppManifestURL(nsAString& aOut); |
|
350 |
|
351 /** |
|
352 * Get the app for our frame. This is the app whose manifest is returned by |
|
353 * GetOwnerAppManifestURL. |
|
354 */ |
|
355 already_AddRefed<mozIApplication> GetOwnApp(); |
|
356 |
|
357 /** |
|
358 * Get the app which contains this frame. This is the app associated with |
|
359 * the frame element's principal. |
|
360 */ |
|
361 already_AddRefed<mozIApplication> GetContainingApp(); |
|
362 |
|
363 /** |
|
364 * If we are an IPC frame, set mRemoteFrame. Otherwise, create and |
|
365 * initialize mDocShell. |
|
366 */ |
|
367 nsresult MaybeCreateDocShell(); |
|
368 nsresult EnsureMessageManager(); |
|
369 |
|
370 // Properly retrieves documentSize of any subdocument type. |
|
371 nsresult GetWindowDimensions(nsRect& aRect); |
|
372 |
|
373 // Updates the subdocument position and size. This gets called only |
|
374 // when we have our own in-process DocShell. |
|
375 NS_HIDDEN_(nsresult) UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame); |
|
376 nsresult CheckURILoad(nsIURI* aURI); |
|
377 void FireErrorEvent(); |
|
378 nsresult ReallyStartLoadingInternal(); |
|
379 |
|
380 // Return true if remote browser created; nothing else to do |
|
381 bool TryRemoteBrowser(); |
|
382 |
|
383 // Tell the remote browser that it's now "virtually visible" |
|
384 bool ShowRemoteFrame(const nsIntSize& size, |
|
385 nsSubDocumentFrame *aFrame = nullptr); |
|
386 |
|
387 bool AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, |
|
388 nsIDocShellTreeOwner* aOwner, |
|
389 int32_t aParentType, |
|
390 nsIDocShell* aParentNode); |
|
391 |
|
392 nsIAtom* TypeAttrName() const { |
|
393 return mOwnerContent->IsXUL() ? nsGkAtoms::type : nsGkAtoms::mozframetype; |
|
394 } |
|
395 |
|
396 // Update the permission manager's app-id refcount based on mOwnerContent's |
|
397 // own-or-containing-app. |
|
398 void ResetPermissionManagerStatus(); |
|
399 |
|
400 nsCOMPtr<nsIDocShell> mDocShell; |
|
401 nsCOMPtr<nsIURI> mURIToLoad; |
|
402 mozilla::dom::Element* mOwnerContent; // WEAK |
|
403 |
|
404 // Note: this variable must be modified only by ResetPermissionManagerStatus() |
|
405 uint32_t mAppIdSentToPermissionManager; |
|
406 |
|
407 public: |
|
408 // public because a callback needs these. |
|
409 nsRefPtr<nsFrameMessageManager> mMessageManager; |
|
410 nsCOMPtr<nsIInProcessContentFrameMessageManager> mChildMessageManager; |
|
411 private: |
|
412 // Stores the root view of the subdocument while the subdocument is being |
|
413 // reframed. Used to restore the presentation after reframing. |
|
414 nsView* mDetachedSubdocViews; |
|
415 // Stores the containing document of the frame corresponding to this |
|
416 // frame loader. This is reference is kept valid while the subframe's |
|
417 // presentation is detached and stored in mDetachedSubdocViews. This |
|
418 // enables us to detect whether the frame has moved documents during |
|
419 // a reframe, so that we know not to restore the presentation. |
|
420 nsCOMPtr<nsIDocument> mContainerDocWhileDetached; |
|
421 |
|
422 bool mDepthTooGreat : 1; |
|
423 bool mIsTopLevelContent : 1; |
|
424 bool mDestroyCalled : 1; |
|
425 bool mNeedsAsyncDestroy : 1; |
|
426 bool mInSwap : 1; |
|
427 bool mInShow : 1; |
|
428 bool mHideCalled : 1; |
|
429 // True when the object is created for an element which the parser has |
|
430 // created using NS_FROM_PARSER_NETWORK flag. If the element is modified, |
|
431 // it may lose the flag. |
|
432 bool mNetworkCreated : 1; |
|
433 |
|
434 bool mRemoteBrowserShown : 1; |
|
435 bool mRemoteFrame : 1; |
|
436 bool mClipSubdocument : 1; |
|
437 bool mClampScrollPosition : 1; |
|
438 bool mRemoteBrowserInitialized : 1; |
|
439 bool mObservingOwnerContent : 1; |
|
440 |
|
441 // Backs nsIFrameLoader::{Get,Set}Visible. Visibility state here relates to |
|
442 // whether this frameloader's <iframe mozbrowser> is setVisible(true)'ed, and |
|
443 // doesn't necessarily correlate with docshell/document visibility. |
|
444 bool mVisible : 1; |
|
445 |
|
446 // The ContentParent associated with mRemoteBrowser. This was added as a |
|
447 // strong ref in bug 545237, and we're not sure if we can get rid of it. |
|
448 nsRefPtr<mozilla::dom::ContentParent> mContentParent; |
|
449 RenderFrameParent* mCurrentRemoteFrame; |
|
450 TabParent* mRemoteBrowser; |
|
451 uint64_t mChildID; |
|
452 |
|
453 // See nsIFrameLoader.idl. Short story, if !(mRenderMode & |
|
454 // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in |
|
455 // favor of what content tells. |
|
456 uint32_t mRenderMode; |
|
457 |
|
458 // See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically |
|
459 // forwards some input events to out-of-process content. |
|
460 uint32_t mEventMode; |
|
461 |
|
462 // Indicate if we have sent 'remote-browser-pending'. |
|
463 bool mPendingFrameSent; |
|
464 }; |
|
465 |
|
466 #endif |