/src/mozilla-central/layout/ipc/RenderFrameParent.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "base/basictypes.h" |
8 | | |
9 | | #include "BasicLayers.h" |
10 | | #include "gfxPrefs.h" |
11 | | #include "mozilla/BrowserElementParent.h" |
12 | | #include "mozilla/EventForwards.h" // for Modifiers |
13 | | #include "mozilla/ViewportFrame.h" |
14 | | #include "mozilla/dom/ContentChild.h" |
15 | | #include "mozilla/dom/ContentParent.h" |
16 | | #include "mozilla/dom/Element.h" |
17 | | #include "mozilla/dom/TabChild.h" |
18 | | #include "mozilla/dom/TabParent.h" |
19 | | #include "mozilla/layers/CompositorBridgeParent.h" |
20 | | #include "mozilla/layers/LayerTransactionParent.h" |
21 | | #include "nsContentUtils.h" |
22 | | #include "nsFocusManager.h" |
23 | | #include "nsFrameLoader.h" |
24 | | #include "nsIObserver.h" |
25 | | #include "nsStyleStructInlines.h" |
26 | | #include "nsSubDocumentFrame.h" |
27 | | #include "nsView.h" |
28 | | #include "RenderFrameParent.h" |
29 | | #include "mozilla/gfx/GPUProcessManager.h" |
30 | | #include "mozilla/layers/LayerManagerComposite.h" |
31 | | #include "mozilla/layers/CompositorBridgeChild.h" |
32 | | #include "mozilla/layers/WebRenderLayerManager.h" |
33 | | #include "mozilla/layers/WebRenderScrollData.h" |
34 | | #include "mozilla/webrender/WebRenderAPI.h" |
35 | | #include "ClientLayerManager.h" |
36 | | #include "FrameLayerBuilder.h" |
37 | | |
38 | | using namespace mozilla::dom; |
39 | | using namespace mozilla::gfx; |
40 | | using namespace mozilla::layers; |
41 | | |
42 | | namespace mozilla { |
43 | | namespace layout { |
44 | | |
45 | | typedef FrameMetrics::ViewID ViewID; |
46 | | |
47 | | /** |
48 | | * Gets the layer-pixel offset of aContainerFrame's content rect top-left |
49 | | * from the nearest display item reference frame (which we assume will be inducing |
50 | | * a ContainerLayer). |
51 | | */ |
52 | | static LayoutDeviceIntPoint |
53 | | GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder) |
54 | 0 | { |
55 | 0 | nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); |
56 | 0 |
|
57 | 0 | // Offset to the content rect in case we have borders or padding |
58 | 0 | // Note that aContainerFrame could be a reference frame itself, so |
59 | 0 | // we need to be careful here to ensure that we call ToReferenceFrame |
60 | 0 | // on aContainerFrame and not its parent. |
61 | 0 | nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) + |
62 | 0 | aContainerFrame->GetContentRectRelativeToSelf().TopLeft(); |
63 | 0 |
|
64 | 0 | return LayoutDeviceIntPoint::FromAppUnitsToNearest(frameOffset, auPerDevPixel); |
65 | 0 | } |
66 | | |
67 | | // Return true iff |aManager| is a "temporary layer manager". They're |
68 | | // used for small software rendering tasks, like drawWindow. That's |
69 | | // currently implemented by a BasicLayerManager without a backing |
70 | | // widget, and hence in non-retained mode. |
71 | | inline static bool |
72 | | IsTempLayerManager(LayerManager* aManager) |
73 | 0 | { |
74 | 0 | return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() && |
75 | 0 | !static_cast<BasicLayerManager*>(aManager)->IsRetained()); |
76 | 0 | } |
77 | | |
78 | | static already_AddRefed<LayerManager> |
79 | | GetLayerManager(nsFrameLoader* aFrameLoader) |
80 | 0 | { |
81 | 0 | if (nsIContent* content = aFrameLoader->GetOwnerContent()) { |
82 | 0 | RefPtr<LayerManager> lm = nsContentUtils::LayerManagerForContent(content); |
83 | 0 | if (lm) { |
84 | 0 | return lm.forget(); |
85 | 0 | } |
86 | 0 | } |
87 | 0 | |
88 | 0 | nsIDocument* doc = aFrameLoader->GetOwnerDoc(); |
89 | 0 | if (!doc) { |
90 | 0 | return nullptr; |
91 | 0 | } |
92 | 0 | return nsContentUtils::LayerManagerForDocument(doc); |
93 | 0 | } |
94 | | |
95 | | RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader) |
96 | | : mLayersId{0} |
97 | | , mLayersConnected(false) |
98 | | , mFrameLoader(aFrameLoader) |
99 | | , mFrameLoaderDestroyed(false) |
100 | | , mAsyncPanZoomEnabled(false) |
101 | | , mInitted(false) |
102 | 0 | { |
103 | 0 | mInitted = Init(aFrameLoader); |
104 | 0 | } |
105 | | |
106 | | RenderFrameParent::~RenderFrameParent() |
107 | 0 | {} |
108 | | |
109 | | bool |
110 | | RenderFrameParent::Init(nsFrameLoader* aFrameLoader) |
111 | 0 | { |
112 | 0 | if (mInitted || !aFrameLoader) { |
113 | 0 | return false; |
114 | 0 | } |
115 | 0 | |
116 | 0 | mFrameLoader = aFrameLoader; |
117 | 0 |
|
118 | 0 | RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader); |
119 | 0 |
|
120 | 0 | mAsyncPanZoomEnabled = lm && lm->AsyncPanZoomEnabled(); |
121 | 0 |
|
122 | 0 | TabParent* browser = TabParent::GetFrom(mFrameLoader); |
123 | 0 | if (XRE_IsParentProcess()) { |
124 | 0 | PCompositorBridgeChild* compositor = nullptr; |
125 | 0 | if (lm) { |
126 | 0 | compositor = lm->GetCompositorBridgeChild(); |
127 | 0 | } |
128 | 0 |
|
129 | 0 | // Our remote frame will push layers updates to the compositor, |
130 | 0 | // and we'll keep an indirect reference to that tree. |
131 | 0 | GPUProcessManager* gpm = GPUProcessManager::Get(); |
132 | 0 | mLayersConnected = gpm->AllocateAndConnectLayerTreeId( |
133 | 0 | compositor, |
134 | 0 | browser->Manager()->AsContentParent()->OtherPid(), |
135 | 0 | &mLayersId, |
136 | 0 | &mCompositorOptions); |
137 | 0 | } else if (XRE_IsContentProcess()) { |
138 | 0 | ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId); |
139 | 0 | mLayersConnected = CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId, &mCompositorOptions); |
140 | 0 | } |
141 | 0 |
|
142 | 0 | mInitted = true; |
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | bool |
147 | | RenderFrameParent::IsInitted() |
148 | 0 | { |
149 | 0 | return mInitted; |
150 | 0 | } |
151 | | |
152 | | void |
153 | | RenderFrameParent::Destroy() |
154 | 0 | { |
155 | 0 | mFrameLoaderDestroyed = true; |
156 | 0 | mLayerManager = nullptr; |
157 | 0 | } |
158 | | |
159 | | already_AddRefed<Layer> |
160 | | RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, |
161 | | nsIFrame* aFrame, |
162 | | LayerManager* aManager, |
163 | | nsDisplayItem* aItem, |
164 | | const ContainerLayerParameters& aContainerParameters) |
165 | 0 | { |
166 | 0 | MOZ_ASSERT(aFrame, |
167 | 0 | "makes no sense to have a shadow tree without a frame"); |
168 | 0 | MOZ_ASSERT(!mContainer || |
169 | 0 | IsTempLayerManager(aManager) || |
170 | 0 | mContainer->Manager() == aManager, |
171 | 0 | "retaining manager changed out from under us ... HELP!"); |
172 | 0 |
|
173 | 0 | if (IsTempLayerManager(aManager) || |
174 | 0 | (mContainer && mContainer->Manager() != aManager)) { |
175 | 0 | // This can happen if aManager is a "temporary" manager, or if the |
176 | 0 | // widget's layer manager changed out from under us. We need to |
177 | 0 | // FIXME handle the former case somehow, probably with an API to |
178 | 0 | // draw a manager's subtree. The latter is bad bad bad, but the the |
179 | 0 | // MOZ_ASSERT() above will flag it. Returning nullptr here will just |
180 | 0 | // cause the shadow subtree not to be rendered. |
181 | 0 | if (!aContainerParameters.mForEventsAndPluginsOnly) { |
182 | 0 | NS_WARNING("Remote iframe not rendered"); |
183 | 0 | } |
184 | 0 | return nullptr; |
185 | 0 | } |
186 | 0 |
|
187 | 0 | if (!mLayersId.IsValid()) { |
188 | 0 | return nullptr; |
189 | 0 | } |
190 | 0 | |
191 | 0 | RefPtr<Layer> layer = |
192 | 0 | (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); |
193 | 0 | if (!layer) { |
194 | 0 | layer = aManager->CreateRefLayer(); |
195 | 0 | } |
196 | 0 | if (!layer) { |
197 | 0 | // Probably a temporary layer manager that doesn't know how to |
198 | 0 | // use ref layers. |
199 | 0 | return nullptr; |
200 | 0 | } |
201 | 0 | static_cast<RefLayer*>(layer.get())->SetReferentId(mLayersId); |
202 | 0 | LayoutDeviceIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); |
203 | 0 | // We can only have an offset if we're a child of an inactive |
204 | 0 | // container, but our display item is LAYER_ACTIVE_FORCE which |
205 | 0 | // forces all layers above to be active. |
206 | 0 | MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint()); |
207 | 0 | gfx::Matrix4x4 m = gfx::Matrix4x4::Translation(offset.x, offset.y, 0.0); |
208 | 0 | // Remote content can't be repainted by us, so we multiply down |
209 | 0 | // the resolution that our container expects onto our container. |
210 | 0 | m.PreScale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0); |
211 | 0 | layer->SetBaseTransform(m); |
212 | 0 |
|
213 | 0 | return layer.forget(); |
214 | 0 | } |
215 | | |
216 | | LayerManager* |
217 | | RenderFrameParent::AttachLayerManager() |
218 | 0 | { |
219 | 0 | RefPtr<LayerManager> lm; |
220 | 0 | if (mFrameLoader) { |
221 | 0 | lm = GetLayerManager(mFrameLoader); |
222 | 0 | } |
223 | 0 |
|
224 | 0 | // Perhaps the document containing this frame currently has no presentation? |
225 | 0 | if (lm && lm->GetCompositorBridgeChild() && lm != mLayerManager) { |
226 | 0 | mLayersConnected = lm->GetCompositorBridgeChild()->SendAdoptChild(mLayersId); |
227 | 0 | FrameLayerBuilder::InvalidateAllLayers(lm); |
228 | 0 | } |
229 | 0 |
|
230 | 0 | mLayerManager = lm.forget(); |
231 | 0 | return mLayerManager; |
232 | 0 | } |
233 | | |
234 | | void |
235 | | RenderFrameParent::OwnerContentChanged(nsIContent* aContent) |
236 | 0 | { |
237 | 0 | MOZ_ASSERT(!mFrameLoader || mFrameLoader->GetOwnerContent() == aContent, |
238 | 0 | "Don't build new map if owner is same!"); |
239 | 0 |
|
240 | 0 | Unused << AttachLayerManager(); |
241 | 0 | } |
242 | | |
243 | | void |
244 | | RenderFrameParent::ActorDestroy(ActorDestroyReason why) |
245 | 0 | { |
246 | 0 | if (mLayersId.IsValid()) { |
247 | 0 | if (XRE_IsParentProcess()) { |
248 | 0 | GPUProcessManager::Get()->UnmapLayerTreeId(mLayersId, OtherPid()); |
249 | 0 | } else if (XRE_IsContentProcess()) { |
250 | 0 | TabParent* browser = TabParent::GetFrom(mFrameLoader); |
251 | 0 | ContentChild::GetSingleton()->SendDeallocateLayerTreeId(browser->Manager()->ChildID(), mLayersId); |
252 | 0 | } |
253 | 0 | } |
254 | 0 |
|
255 | 0 | mFrameLoader = nullptr; |
256 | 0 | mLayerManager = nullptr; |
257 | 0 | } |
258 | | |
259 | | mozilla::ipc::IPCResult |
260 | | RenderFrameParent::RecvNotifyCompositorTransaction() |
261 | 0 | { |
262 | 0 | TriggerRepaint(); |
263 | 0 | return IPC_OK(); |
264 | 0 | } |
265 | | |
266 | | void |
267 | | RenderFrameParent::TriggerRepaint() |
268 | 0 | { |
269 | 0 | nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent(); |
270 | 0 | if (!docFrame) { |
271 | 0 | // Bad, but nothing we can do about it (XXX/cjones: or is there? |
272 | 0 | // maybe bug 589337?). When the new frame is created, we'll |
273 | 0 | // probably still be the current render frame and will get to draw |
274 | 0 | // our content then. Or, we're shutting down and this update goes |
275 | 0 | // to /dev/null. |
276 | 0 | return; |
277 | 0 | } |
278 | 0 | |
279 | 0 | docFrame->InvalidateLayer(DisplayItemType::TYPE_REMOTE); |
280 | 0 | } |
281 | | |
282 | | void |
283 | | RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
284 | | nsSubDocumentFrame* aFrame, |
285 | | const nsDisplayListSet& aLists) |
286 | 0 | { |
287 | 0 | // We're the subdoc for <browser remote="true"> and it has |
288 | 0 | // painted content. Display its shadow layer tree. |
289 | 0 | DisplayListClipState::AutoSaveRestore clipState(aBuilder); |
290 | 0 |
|
291 | 0 | nsPoint offset = aBuilder->ToReferenceFrame(aFrame); |
292 | 0 | nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset; |
293 | 0 | clipState.ClipContentDescendants(bounds); |
294 | 0 |
|
295 | 0 | aLists.Content()->AppendToTop( |
296 | 0 | MakeDisplayItem<nsDisplayRemote>(aBuilder, aFrame)); |
297 | 0 | } |
298 | | |
299 | | void |
300 | | RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier) |
301 | 0 | { |
302 | 0 | RefPtr<LayerManager> lm = mFrameLoader ? GetLayerManager(mFrameLoader) : nullptr; |
303 | 0 | // Perhaps the document containing this frame currently has no presentation? |
304 | 0 | if (lm) { |
305 | 0 | *aTextureFactoryIdentifier = lm->GetTextureFactoryIdentifier(); |
306 | 0 | } else { |
307 | 0 | *aTextureFactoryIdentifier = TextureFactoryIdentifier(); |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | | void |
312 | | RenderFrameParent::TakeFocusForClickFromTap() |
313 | 0 | { |
314 | 0 | nsIFocusManager* fm = nsFocusManager::GetFocusManager(); |
315 | 0 | if (!fm) { |
316 | 0 | return; |
317 | 0 | } |
318 | 0 | RefPtr<Element> element = mFrameLoader->GetOwnerContent(); |
319 | 0 | if (!element) { |
320 | 0 | return; |
321 | 0 | } |
322 | 0 | fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE | |
323 | 0 | nsIFocusManager::FLAG_BYTOUCH | |
324 | 0 | nsIFocusManager::FLAG_NOSCROLL); |
325 | 0 | } |
326 | | |
327 | | void |
328 | | RenderFrameParent::EnsureLayersConnected(CompositorOptions* aCompositorOptions) |
329 | 0 | { |
330 | 0 | RefPtr<LayerManager> lm = GetLayerManager(mFrameLoader); |
331 | 0 | if (!lm) { |
332 | 0 | return; |
333 | 0 | } |
334 | 0 | |
335 | 0 | if (!lm->GetCompositorBridgeChild()) { |
336 | 0 | return; |
337 | 0 | } |
338 | 0 | |
339 | 0 | mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildRecreated(mLayersId, &mCompositorOptions); |
340 | 0 | *aCompositorOptions = mCompositorOptions; |
341 | 0 | } |
342 | | |
343 | | } // namespace layout |
344 | | } // namespace mozilla |
345 | | |
346 | | nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder, |
347 | | nsSubDocumentFrame* aFrame) |
348 | | : nsDisplayItem(aBuilder, aFrame) |
349 | | , mEventRegionsOverride(EventRegionsOverride::NoOverride) |
350 | 0 | { |
351 | 0 | bool frameIsPointerEventsNone = |
352 | 0 | aFrame->StyleUI()->GetEffectivePointerEvents(aFrame) == |
353 | 0 | NS_STYLE_POINTER_EVENTS_NONE; |
354 | 0 | if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) { |
355 | 0 | mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion; |
356 | 0 | } |
357 | 0 | if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(aFrame->PresShell())) { |
358 | 0 | mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent; |
359 | 0 | } |
360 | 0 | } |
361 | | |
362 | | bool |
363 | | nsDisplayRemote::HasDeletedFrame() const |
364 | 0 | { |
365 | 0 | // RenderFrameParent might change without invalidating nsSubDocumentFrame. |
366 | 0 | return !GetRenderFrameParent() || nsDisplayItem::HasDeletedFrame(); |
367 | 0 | } |
368 | | |
369 | | already_AddRefed<Layer> |
370 | | nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder, |
371 | | LayerManager* aManager, |
372 | | const ContainerLayerParameters& aContainerParameters) |
373 | 0 | { |
374 | 0 | MOZ_ASSERT(GetRenderFrameParent()); |
375 | 0 |
|
376 | 0 | RefPtr<Layer> layer = |
377 | 0 | GetRenderFrameParent()->BuildLayer(aBuilder, mFrame, aManager, |
378 | 0 | this, aContainerParameters); |
379 | 0 |
|
380 | 0 | if (layer && layer->AsRefLayer()) { |
381 | 0 | layer->AsRefLayer()->SetEventRegionsOverride(mEventRegionsOverride); |
382 | 0 | } |
383 | 0 | return layer.forget(); |
384 | 0 | } |
385 | | |
386 | | bool |
387 | | nsDisplayRemote::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder, |
388 | | mozilla::wr::IpcResourceUpdateQueue& aResources, |
389 | | const StackingContextHelper& aSc, |
390 | | mozilla::layers::WebRenderLayerManager* aManager, |
391 | | nsDisplayListBuilder* aDisplayListBuilder) |
392 | 0 | { |
393 | 0 | mOffset = mozilla::layout::GetContentRectLayerOffset(mFrame, aDisplayListBuilder); |
394 | 0 |
|
395 | 0 | mozilla::LayoutDeviceRect rect = mozilla::LayoutDeviceRect::FromAppUnits( |
396 | 0 | mFrame->GetContentRectRelativeToSelf(), mFrame->PresContext()->AppUnitsPerDevPixel()); |
397 | 0 | rect += mOffset; |
398 | 0 |
|
399 | 0 | aBuilder.PushIFrame(mozilla::wr::ToRoundedLayoutRect(rect), |
400 | 0 | !BackfaceIsHidden(), |
401 | 0 | mozilla::wr::AsPipelineId(GetRemoteLayersId()), |
402 | 0 | /*ignoreMissingPipelines*/ true); |
403 | 0 |
|
404 | 0 | return true; |
405 | 0 | } |
406 | | |
407 | | bool |
408 | | nsDisplayRemote::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData, |
409 | | mozilla::layers::WebRenderLayerScrollData* aLayerData) |
410 | 0 | { |
411 | 0 | if (aLayerData) { |
412 | 0 | aLayerData->SetReferentId(GetRemoteLayersId()); |
413 | 0 | aLayerData->SetTransform(mozilla::gfx::Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0)); |
414 | 0 | aLayerData->SetEventRegionsOverride(mEventRegionsOverride); |
415 | 0 | } |
416 | 0 | return true; |
417 | 0 | } |
418 | | |
419 | | LayersId |
420 | | nsDisplayRemote::GetRemoteLayersId() const |
421 | 0 | { |
422 | 0 | MOZ_ASSERT(GetRenderFrameParent()); |
423 | 0 | return GetRenderFrameParent()->GetLayersId(); |
424 | 0 | } |
425 | | |
426 | | mozilla::layout::RenderFrameParent* |
427 | | nsDisplayRemote::GetRenderFrameParent() const |
428 | 0 | { |
429 | 0 | return static_cast<nsSubDocumentFrame*>(Frame())->GetRenderFrameParent(); |
430 | 0 | } |