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