|
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 "gfx3DMatrix.h" |
|
12 #ifdef MOZ_ENABLE_D3D9_LAYER |
|
13 # include "LayerManagerD3D9.h" |
|
14 #endif //MOZ_ENABLE_D3D9_LAYER |
|
15 #include "mozilla/BrowserElementParent.h" |
|
16 #include "mozilla/dom/TabParent.h" |
|
17 #include "mozilla/layers/APZCTreeManager.h" |
|
18 #include "mozilla/layers/CompositorParent.h" |
|
19 #include "mozilla/layers/LayerTransactionParent.h" |
|
20 #include "nsContentUtils.h" |
|
21 #include "nsFrameLoader.h" |
|
22 #include "nsIObserver.h" |
|
23 #include "nsSubDocumentFrame.h" |
|
24 #include "nsView.h" |
|
25 #include "nsViewportFrame.h" |
|
26 #include "RenderFrameParent.h" |
|
27 #include "mozilla/layers/LayerManagerComposite.h" |
|
28 #include "mozilla/layers/CompositorChild.h" |
|
29 #include "ClientLayerManager.h" |
|
30 |
|
31 typedef nsContentView::ViewConfig ViewConfig; |
|
32 using namespace mozilla::dom; |
|
33 using namespace mozilla::layers; |
|
34 |
|
35 namespace mozilla { |
|
36 namespace layout { |
|
37 |
|
38 typedef FrameMetrics::ViewID ViewID; |
|
39 typedef RenderFrameParent::ViewMap ViewMap; |
|
40 |
|
41 // Represents (affine) transforms that are calculated from a content view. |
|
42 struct ViewTransform { |
|
43 ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1) |
|
44 : mTranslation(aTranslation) |
|
45 , mXScale(aXScale) |
|
46 , mYScale(aYScale) |
|
47 {} |
|
48 |
|
49 operator gfx3DMatrix() const |
|
50 { |
|
51 return |
|
52 gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) * |
|
53 gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1); |
|
54 } |
|
55 |
|
56 nsIntPoint mTranslation; |
|
57 float mXScale; |
|
58 float mYScale; |
|
59 }; |
|
60 |
|
61 // Matrix helpers |
|
62 // For our simple purposes, these helpers apply to 2D affine transformations |
|
63 // that can be represented by a scale and a translation. This makes the math |
|
64 // much easier because we only expect the diagonals and the translation |
|
65 // coordinates of the matrix to be non-zero. |
|
66 |
|
67 static double GetXScale(const gfx3DMatrix& aTransform) |
|
68 { |
|
69 return aTransform._11; |
|
70 } |
|
71 |
|
72 static double GetYScale(const gfx3DMatrix& aTransform) |
|
73 { |
|
74 return aTransform._22; |
|
75 } |
|
76 |
|
77 static void Scale(gfx3DMatrix& aTransform, double aXScale, double aYScale) |
|
78 { |
|
79 aTransform._11 *= aXScale; |
|
80 aTransform._22 *= aYScale; |
|
81 } |
|
82 |
|
83 static void ReverseTranslate(gfx3DMatrix& aTransform, const gfxPoint& aOffset) |
|
84 { |
|
85 aTransform._41 -= aOffset.x; |
|
86 aTransform._42 -= aOffset.y; |
|
87 } |
|
88 |
|
89 |
|
90 static void ApplyTransform(nsRect& aRect, |
|
91 gfx3DMatrix& aTransform, |
|
92 nscoord auPerDevPixel) |
|
93 { |
|
94 aRect.x = aRect.x * aTransform._11 + aTransform._41 * auPerDevPixel; |
|
95 aRect.y = aRect.y * aTransform._22 + aTransform._42 * auPerDevPixel; |
|
96 aRect.width = aRect.width * aTransform._11; |
|
97 aRect.height = aRect.height * aTransform._22; |
|
98 } |
|
99 |
|
100 static void |
|
101 AssertInTopLevelChromeDoc(ContainerLayer* aContainer, |
|
102 nsIFrame* aContainedFrame) |
|
103 { |
|
104 NS_ASSERTION( |
|
105 (aContainer->Manager()->GetBackendType() != mozilla::layers::LayersBackend::LAYERS_BASIC) || |
|
106 (aContainedFrame->GetNearestWidget() == |
|
107 static_cast<BasicLayerManager*>(aContainer->Manager())->GetRetainerWidget()), |
|
108 "Expected frame to be in top-level chrome document"); |
|
109 } |
|
110 |
|
111 // Return view for given ID in aMap, nullptr if not found. |
|
112 static nsContentView* |
|
113 FindViewForId(const ViewMap& aMap, ViewID aId) |
|
114 { |
|
115 ViewMap::const_iterator iter = aMap.find(aId); |
|
116 return iter != aMap.end() ? iter->second : nullptr; |
|
117 } |
|
118 |
|
119 // Return the root content view in aMap, nullptr if not found. |
|
120 static nsContentView* |
|
121 FindRootView(const ViewMap& aMap) |
|
122 { |
|
123 for (ViewMap::const_iterator iter = aMap.begin(), end = aMap.end(); |
|
124 iter != end; |
|
125 ++iter) { |
|
126 if (iter->second->IsRoot()) |
|
127 return iter->second; |
|
128 } |
|
129 return nullptr; |
|
130 } |
|
131 |
|
132 static const FrameMetrics* |
|
133 GetFrameMetrics(Layer* aLayer) |
|
134 { |
|
135 ContainerLayer* container = aLayer->AsContainerLayer(); |
|
136 return container ? &container->GetFrameMetrics() : nullptr; |
|
137 } |
|
138 |
|
139 /** |
|
140 * Gets the layer-pixel offset of aContainerFrame's content rect top-left |
|
141 * from the nearest display item reference frame (which we assume will be inducing |
|
142 * a ContainerLayer). |
|
143 */ |
|
144 static nsIntPoint |
|
145 GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder) |
|
146 { |
|
147 nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); |
|
148 |
|
149 // Offset to the content rect in case we have borders or padding |
|
150 // Note that aContainerFrame could be a reference frame itself, so |
|
151 // we need to be careful here to ensure that we call ToReferenceFrame |
|
152 // on aContainerFrame and not its parent. |
|
153 nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) + |
|
154 (aContainerFrame->GetContentRect().TopLeft() - aContainerFrame->GetPosition()); |
|
155 |
|
156 return frameOffset.ToNearestPixels(auPerDevPixel); |
|
157 } |
|
158 |
|
159 // Compute the transform of the shadow tree contained by |
|
160 // |aContainerFrame| to widget space. We transform because the |
|
161 // subprocess layer manager renders to a different top-left than where |
|
162 // the shadow tree is drawn here and because a scale can be set on the |
|
163 // shadow tree. |
|
164 static ViewTransform |
|
165 ComputeShadowTreeTransform(nsIFrame* aContainerFrame, |
|
166 nsFrameLoader* aRootFrameLoader, |
|
167 const FrameMetrics* aMetrics, |
|
168 const ViewConfig& aConfig, |
|
169 float aTempScaleX = 1.0, |
|
170 float aTempScaleY = 1.0) |
|
171 { |
|
172 // |aMetrics->mViewportScrollOffset| The frame's scroll offset when it was |
|
173 // painted, in content document pixels. |
|
174 // |aConfig.mScrollOffset| What our user expects, or wants, the |
|
175 // frame scroll offset to be in chrome |
|
176 // document app units. |
|
177 // |
|
178 // So we set a compensating translation that moves the content document |
|
179 // pixels to where the user wants them to be. |
|
180 // |
|
181 nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); |
|
182 nsIntPoint scrollOffset = |
|
183 aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel); |
|
184 LayerIntPoint metricsScrollOffset = RoundedToInt(aMetrics->GetScrollOffsetInLayerPixels()); |
|
185 |
|
186 if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) { |
|
187 // Only use asynchronous scrolling if it is enabled and there is a |
|
188 // displayport defined. It is useful to have a scroll layer that is |
|
189 // synchronously scrolled for identifying a scroll area before it is |
|
190 // being actively scrolled. |
|
191 nsIntPoint scrollCompensation( |
|
192 (scrollOffset.x / aTempScaleX - metricsScrollOffset.x), |
|
193 (scrollOffset.y / aTempScaleY - metricsScrollOffset.y)); |
|
194 |
|
195 return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale); |
|
196 } else { |
|
197 return ViewTransform(nsIntPoint(0, 0), 1, 1); |
|
198 } |
|
199 } |
|
200 |
|
201 // Use shadow layer tree to build display list for the browser's frame. |
|
202 static void |
|
203 BuildListForLayer(Layer* aLayer, |
|
204 nsFrameLoader* aRootFrameLoader, |
|
205 const gfx3DMatrix& aTransform, |
|
206 nsDisplayListBuilder* aBuilder, |
|
207 nsDisplayList& aShadowTree, |
|
208 nsIFrame* aSubdocFrame) |
|
209 { |
|
210 const FrameMetrics* metrics = GetFrameMetrics(aLayer); |
|
211 |
|
212 gfx3DMatrix transform; |
|
213 |
|
214 if (metrics && metrics->IsScrollable()) { |
|
215 const ViewID scrollId = metrics->GetScrollId(); |
|
216 |
|
217 // We need to figure out the bounds of the scrollable region using the |
|
218 // shadow layer tree from the remote process. The metrics viewport is |
|
219 // defined based on all the transformations of its parent layers and |
|
220 // the scale of the current layer. |
|
221 |
|
222 // Calculate transform for this layer. |
|
223 nsContentView* view = |
|
224 aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); |
|
225 // XXX why don't we include aLayer->GetTransform() in the inverse-scale here? |
|
226 // This seems wrong, but it doesn't seem to cause bugs! |
|
227 gfx3DMatrix applyTransform = ComputeShadowTreeTransform( |
|
228 aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(), |
|
229 1 / GetXScale(aTransform), 1 / GetYScale(aTransform)); |
|
230 gfx3DMatrix layerTransform; |
|
231 To3DMatrix(aLayer->GetTransform(), layerTransform); |
|
232 transform = applyTransform * layerTransform * aTransform; |
|
233 |
|
234 // As mentioned above, bounds calculation also depends on the scale |
|
235 // of this layer. |
|
236 gfx3DMatrix tmpTransform = aTransform; |
|
237 Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform)); |
|
238 |
|
239 // Calculate rect for this layer based on aTransform. |
|
240 nsRect bounds; |
|
241 { |
|
242 bounds = CSSRect::ToAppUnits(metrics->mViewport); |
|
243 nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel(); |
|
244 ApplyTransform(bounds, tmpTransform, auPerDevPixel); |
|
245 } |
|
246 |
|
247 aShadowTree.AppendToTop( |
|
248 new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId)); |
|
249 |
|
250 } else { |
|
251 gfx3DMatrix layerTransform; |
|
252 To3DMatrix(aLayer->GetTransform(), layerTransform); |
|
253 transform = layerTransform * aTransform; |
|
254 } |
|
255 |
|
256 for (Layer* child = aLayer->GetFirstChild(); child; |
|
257 child = child->GetNextSibling()) { |
|
258 BuildListForLayer(child, aRootFrameLoader, transform, |
|
259 aBuilder, aShadowTree, aSubdocFrame); |
|
260 } |
|
261 } |
|
262 |
|
263 // Go down shadow layer tree and apply transformations for scrollable layers. |
|
264 static void |
|
265 TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader, |
|
266 nsIFrame* aFrame, Layer* aLayer, |
|
267 const ViewTransform& aTransform, |
|
268 float aTempScaleDiffX = 1.0, |
|
269 float aTempScaleDiffY = 1.0) |
|
270 { |
|
271 LayerComposite* shadow = aLayer->AsLayerComposite(); |
|
272 shadow->SetShadowClipRect(aLayer->GetClipRect()); |
|
273 shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); |
|
274 shadow->SetShadowOpacity(aLayer->GetOpacity()); |
|
275 |
|
276 const FrameMetrics* metrics = GetFrameMetrics(aLayer); |
|
277 |
|
278 gfx3DMatrix shadowTransform; |
|
279 To3DMatrix(aLayer->GetTransform(), shadowTransform); |
|
280 ViewTransform layerTransform = aTransform; |
|
281 |
|
282 if (metrics && metrics->IsScrollable()) { |
|
283 const ViewID scrollId = metrics->GetScrollId(); |
|
284 const nsContentView* view = |
|
285 aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); |
|
286 NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree"); |
|
287 gfx3DMatrix currentTransform; |
|
288 To3DMatrix(aLayer->GetTransform(), currentTransform); |
|
289 |
|
290 const ViewConfig& config = view->GetViewConfig(); |
|
291 // With temporary scale we should compensate translation |
|
292 // using temporary scale value |
|
293 aTempScaleDiffX *= GetXScale(shadowTransform) * config.mXScale; |
|
294 aTempScaleDiffY *= GetYScale(shadowTransform) * config.mYScale; |
|
295 ViewTransform viewTransform = ComputeShadowTreeTransform( |
|
296 aFrame, aFrameLoader, metrics, view->GetViewConfig(), |
|
297 aTempScaleDiffX, aTempScaleDiffY |
|
298 ); |
|
299 |
|
300 // Apply the layer's own transform *before* the view transform |
|
301 shadowTransform = gfx3DMatrix(viewTransform) * currentTransform; |
|
302 |
|
303 layerTransform = viewTransform; |
|
304 if (metrics->IsRootScrollable()) { |
|
305 // Apply the translation *before* we do the rest of the transforms. |
|
306 nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); |
|
307 shadowTransform = shadowTransform * |
|
308 gfx3DMatrix::Translation(float(offset.x), float(offset.y), 0.0); |
|
309 } |
|
310 } |
|
311 |
|
312 if (aLayer->GetIsFixedPosition() && |
|
313 !aLayer->GetParent()->GetIsFixedPosition()) { |
|
314 // Alter the shadow transform of fixed position layers in the situation |
|
315 // that the view transform's scroll position doesn't match the actual |
|
316 // scroll position, due to asynchronous layer scrolling. |
|
317 float offsetX = layerTransform.mTranslation.x; |
|
318 float offsetY = layerTransform.mTranslation.y; |
|
319 ReverseTranslate(shadowTransform, gfxPoint(offsetX, offsetY)); |
|
320 const nsIntRect* clipRect = shadow->GetShadowClipRect(); |
|
321 if (clipRect) { |
|
322 nsIntRect transformedClipRect(*clipRect); |
|
323 transformedClipRect.MoveBy(-offsetX, -offsetY); |
|
324 shadow->SetShadowClipRect(&transformedClipRect); |
|
325 } |
|
326 } |
|
327 |
|
328 // The transform already takes the resolution scale into account. Since we |
|
329 // will apply the resolution scale again when computing the effective |
|
330 // transform, we must apply the inverse resolution scale here. |
|
331 if (ContainerLayer* c = aLayer->AsContainerLayer()) { |
|
332 shadowTransform.Scale(1.0f/c->GetPreXScale(), |
|
333 1.0f/c->GetPreYScale(), |
|
334 1); |
|
335 } |
|
336 shadowTransform.ScalePost(1.0f/aLayer->GetPostXScale(), |
|
337 1.0f/aLayer->GetPostYScale(), |
|
338 1); |
|
339 |
|
340 gfx::Matrix4x4 realShadowTransform; |
|
341 ToMatrix4x4(shadowTransform, realShadowTransform); |
|
342 shadow->SetShadowTransform(realShadowTransform); |
|
343 for (Layer* child = aLayer->GetFirstChild(); |
|
344 child; child = child->GetNextSibling()) { |
|
345 TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform, |
|
346 aTempScaleDiffX, aTempScaleDiffY); |
|
347 } |
|
348 } |
|
349 |
|
350 static void |
|
351 ClearContainer(ContainerLayer* aContainer) |
|
352 { |
|
353 while (Layer* layer = aContainer->GetFirstChild()) { |
|
354 aContainer->RemoveChild(layer); |
|
355 } |
|
356 } |
|
357 |
|
358 // Return true iff |aManager| is a "temporary layer manager". They're |
|
359 // used for small software rendering tasks, like drawWindow. That's |
|
360 // currently implemented by a BasicLayerManager without a backing |
|
361 // widget, and hence in non-retained mode. |
|
362 inline static bool |
|
363 IsTempLayerManager(LayerManager* aManager) |
|
364 { |
|
365 return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() && |
|
366 !static_cast<BasicLayerManager*>(aManager)->IsRetained()); |
|
367 } |
|
368 |
|
369 // Recursively create a new array of scrollables, preserving any scrollables |
|
370 // that are still in the layer tree. |
|
371 // |
|
372 // aXScale and aYScale are used to calculate any values that need to be in |
|
373 // chrome-document CSS pixels and aren't part of the rendering loop, such as |
|
374 // the initial scroll offset for a new view. |
|
375 static void |
|
376 BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews, |
|
377 nsFrameLoader* aFrameLoader, Layer* aLayer, |
|
378 float aXScale = 1, float aYScale = 1, |
|
379 float aAccConfigXScale = 1, float aAccConfigYScale = 1) |
|
380 { |
|
381 ContainerLayer* container = aLayer->AsContainerLayer(); |
|
382 if (!container) |
|
383 return; |
|
384 const FrameMetrics metrics = container->GetFrameMetrics(); |
|
385 const ViewID scrollId = metrics.GetScrollId(); |
|
386 gfx3DMatrix transform; |
|
387 To3DMatrix(aLayer->GetTransform(), transform); |
|
388 aXScale *= GetXScale(transform); |
|
389 aYScale *= GetYScale(transform); |
|
390 |
|
391 if (metrics.IsScrollable()) { |
|
392 nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent() |
|
393 ->PresContext()->AppUnitsPerDevPixel(); |
|
394 nscoord auPerCSSPixel = auPerDevPixel * metrics.mDevPixelsPerCSSPixel.scale; |
|
395 nsContentView* view = FindViewForId(oldContentViews, scrollId); |
|
396 if (view) { |
|
397 // View already exists. Be sure to propagate scales for any values |
|
398 // that need to be calculated something in chrome-doc CSS pixels. |
|
399 ViewConfig config = view->GetViewConfig(); |
|
400 aXScale *= config.mXScale; |
|
401 aYScale *= config.mYScale; |
|
402 view->mFrameLoader = aFrameLoader; |
|
403 // If scale has changed, then we should update |
|
404 // current scroll offset to new scaled value |
|
405 if (aAccConfigXScale != view->mParentScaleX || |
|
406 aAccConfigYScale != view->mParentScaleY) { |
|
407 float xscroll = 0, yscroll = 0; |
|
408 view->GetScrollX(&xscroll); |
|
409 view->GetScrollY(&yscroll); |
|
410 xscroll = xscroll * (aAccConfigXScale / view->mParentScaleX); |
|
411 yscroll = yscroll * (aAccConfigYScale / view->mParentScaleY); |
|
412 view->ScrollTo(xscroll, yscroll); |
|
413 view->mParentScaleX = aAccConfigXScale; |
|
414 view->mParentScaleY = aAccConfigYScale; |
|
415 } |
|
416 // Collect only config scale values for scroll compensation |
|
417 aAccConfigXScale *= config.mXScale; |
|
418 aAccConfigYScale *= config.mYScale; |
|
419 } else { |
|
420 // View doesn't exist, so generate one. We start the view scroll offset at |
|
421 // the same position as the framemetric's scroll offset from the layer. |
|
422 // The default scale is 1, so no need to propagate scale down. |
|
423 ViewConfig config; |
|
424 config.mScrollOffset = nsPoint( |
|
425 NSIntPixelsToAppUnits(metrics.GetScrollOffset().x, auPerCSSPixel) * aXScale, |
|
426 NSIntPixelsToAppUnits(metrics.GetScrollOffset().y, auPerCSSPixel) * aYScale); |
|
427 view = new nsContentView(aFrameLoader, scrollId, metrics.mIsRoot, config); |
|
428 view->mParentScaleX = aAccConfigXScale; |
|
429 view->mParentScaleY = aAccConfigYScale; |
|
430 } |
|
431 |
|
432 // I don't know what units mViewportSize is in, hence use ToUnknownRect |
|
433 // here to mark the current frontier in type info propagation |
|
434 gfx::Rect viewport = metrics.mViewport.ToUnknownRect(); |
|
435 view->mViewportSize = nsSize( |
|
436 NSIntPixelsToAppUnits(viewport.width, auPerDevPixel) * aXScale, |
|
437 NSIntPixelsToAppUnits(viewport.height, auPerDevPixel) * aYScale); |
|
438 view->mContentSize = nsSize( |
|
439 NSFloatPixelsToAppUnits(metrics.mScrollableRect.width, auPerCSSPixel) * aXScale, |
|
440 NSFloatPixelsToAppUnits(metrics.mScrollableRect.height, auPerCSSPixel) * aYScale); |
|
441 |
|
442 newContentViews[scrollId] = view; |
|
443 } |
|
444 |
|
445 for (Layer* child = aLayer->GetFirstChild(); |
|
446 child; child = child->GetNextSibling()) { |
|
447 BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child, |
|
448 aXScale, aYScale, aAccConfigXScale, aAccConfigYScale); |
|
449 } |
|
450 } |
|
451 |
|
452 static void |
|
453 BuildBackgroundPatternFor(ContainerLayer* aContainer, |
|
454 Layer* aShadowRoot, |
|
455 const ViewConfig& aConfig, |
|
456 const gfxRGBA& aColor, |
|
457 LayerManager* aManager, |
|
458 nsIFrame* aFrame) |
|
459 { |
|
460 LayerComposite* shadowRoot = aShadowRoot->AsLayerComposite(); |
|
461 gfx::Matrix t; |
|
462 if (!shadowRoot->GetShadowTransform().Is2D(&t)) { |
|
463 return; |
|
464 } |
|
465 |
|
466 // Get the rect bounding the shadow content, transformed into the |
|
467 // same space as |aFrame| |
|
468 nsIntRect contentBounds = shadowRoot->GetShadowVisibleRegion().GetBounds(); |
|
469 gfxRect contentVis(contentBounds.x, contentBounds.y, |
|
470 contentBounds.width, contentBounds.height); |
|
471 gfxRect localContentVis(gfx::ThebesMatrix(t).Transform(contentVis)); |
|
472 // Round *in* here because this area is punched out of the background |
|
473 localContentVis.RoundIn(); |
|
474 nsIntRect localIntContentVis(localContentVis.X(), localContentVis.Y(), |
|
475 localContentVis.Width(), localContentVis.Height()); |
|
476 |
|
477 // Get the frame's rect |
|
478 nscoord auPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); |
|
479 nsIntRect frameRect = aFrame->GetRect().ToOutsidePixels(auPerDevPixel); |
|
480 |
|
481 // If the shadow tree covers the frame rect, don't bother building |
|
482 // the background, it wouldn't be visible |
|
483 if (localIntContentVis.Contains(frameRect)) { |
|
484 return; |
|
485 } |
|
486 nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer(); |
|
487 layer->SetColor(aColor); |
|
488 |
|
489 // The visible area of the background is the frame's area minus the |
|
490 // content area |
|
491 nsIntRegion bgRgn(frameRect); |
|
492 bgRgn.Sub(bgRgn, localIntContentVis); |
|
493 bgRgn.MoveBy(-frameRect.TopLeft()); |
|
494 layer->SetVisibleRegion(bgRgn); |
|
495 |
|
496 aContainer->InsertAfter(layer, nullptr); |
|
497 } |
|
498 |
|
499 already_AddRefed<LayerManager> |
|
500 GetFrom(nsFrameLoader* aFrameLoader) |
|
501 { |
|
502 nsIDocument* doc = aFrameLoader->GetOwnerDoc(); |
|
503 return nsContentUtils::LayerManagerForDocument(doc); |
|
504 } |
|
505 |
|
506 class RemoteContentController : public GeckoContentController { |
|
507 public: |
|
508 RemoteContentController(RenderFrameParent* aRenderFrame) |
|
509 : mUILoop(MessageLoop::current()) |
|
510 , mRenderFrame(aRenderFrame) |
|
511 , mHaveZoomConstraints(false) |
|
512 { } |
|
513 |
|
514 virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE |
|
515 { |
|
516 // We always need to post requests into the "UI thread" otherwise the |
|
517 // requests may get processed out of order. |
|
518 mUILoop->PostTask( |
|
519 FROM_HERE, |
|
520 NewRunnableMethod(this, &RemoteContentController::DoRequestContentRepaint, |
|
521 aFrameMetrics)); |
|
522 } |
|
523 |
|
524 virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, |
|
525 const uint32_t& aScrollGeneration) MOZ_OVERRIDE |
|
526 { |
|
527 if (MessageLoop::current() != mUILoop) { |
|
528 // We have to send this message from the "UI thread" (main |
|
529 // thread). |
|
530 mUILoop->PostTask( |
|
531 FROM_HERE, |
|
532 NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate, |
|
533 aScrollId, aScrollGeneration)); |
|
534 return; |
|
535 } |
|
536 if (mRenderFrame) { |
|
537 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
538 browser->AcknowledgeScrollUpdate(aScrollId, aScrollGeneration); |
|
539 } |
|
540 } |
|
541 |
|
542 virtual void HandleDoubleTap(const CSSPoint& aPoint, |
|
543 int32_t aModifiers, |
|
544 const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE |
|
545 { |
|
546 if (MessageLoop::current() != mUILoop) { |
|
547 // We have to send this message from the "UI thread" (main |
|
548 // thread). |
|
549 mUILoop->PostTask( |
|
550 FROM_HERE, |
|
551 NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap, |
|
552 aPoint, aModifiers, aGuid)); |
|
553 return; |
|
554 } |
|
555 if (mRenderFrame) { |
|
556 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
557 browser->HandleDoubleTap(aPoint, aModifiers, aGuid); |
|
558 } |
|
559 } |
|
560 |
|
561 virtual void HandleSingleTap(const CSSPoint& aPoint, |
|
562 int32_t aModifiers, |
|
563 const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE |
|
564 { |
|
565 if (MessageLoop::current() != mUILoop) { |
|
566 // We have to send this message from the "UI thread" (main |
|
567 // thread). |
|
568 mUILoop->PostTask( |
|
569 FROM_HERE, |
|
570 NewRunnableMethod(this, &RemoteContentController::HandleSingleTap, |
|
571 aPoint, aModifiers, aGuid)); |
|
572 return; |
|
573 } |
|
574 if (mRenderFrame) { |
|
575 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
576 browser->HandleSingleTap(aPoint, aModifiers, aGuid); |
|
577 } |
|
578 } |
|
579 |
|
580 virtual void HandleLongTap(const CSSPoint& aPoint, |
|
581 int32_t aModifiers, |
|
582 const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE |
|
583 { |
|
584 if (MessageLoop::current() != mUILoop) { |
|
585 // We have to send this message from the "UI thread" (main |
|
586 // thread). |
|
587 mUILoop->PostTask( |
|
588 FROM_HERE, |
|
589 NewRunnableMethod(this, &RemoteContentController::HandleLongTap, |
|
590 aPoint, aModifiers, aGuid)); |
|
591 return; |
|
592 } |
|
593 if (mRenderFrame) { |
|
594 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
595 browser->HandleLongTap(aPoint, aModifiers, aGuid); |
|
596 } |
|
597 } |
|
598 |
|
599 virtual void HandleLongTapUp(const CSSPoint& aPoint, |
|
600 int32_t aModifiers, |
|
601 const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE |
|
602 { |
|
603 if (MessageLoop::current() != mUILoop) { |
|
604 // We have to send this message from the "UI thread" (main |
|
605 // thread). |
|
606 mUILoop->PostTask( |
|
607 FROM_HERE, |
|
608 NewRunnableMethod(this, &RemoteContentController::HandleLongTapUp, |
|
609 aPoint, aModifiers, aGuid)); |
|
610 return; |
|
611 } |
|
612 if (mRenderFrame) { |
|
613 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
614 browser->HandleLongTapUp(aPoint, aModifiers, aGuid); |
|
615 } |
|
616 } |
|
617 |
|
618 void ClearRenderFrame() { mRenderFrame = nullptr; } |
|
619 |
|
620 virtual void SendAsyncScrollDOMEvent(bool aIsRoot, |
|
621 const CSSRect& aContentRect, |
|
622 const CSSSize& aContentSize) MOZ_OVERRIDE |
|
623 { |
|
624 if (MessageLoop::current() != mUILoop) { |
|
625 mUILoop->PostTask( |
|
626 FROM_HERE, |
|
627 NewRunnableMethod(this, |
|
628 &RemoteContentController::SendAsyncScrollDOMEvent, |
|
629 aIsRoot, aContentRect, aContentSize)); |
|
630 return; |
|
631 } |
|
632 if (mRenderFrame && aIsRoot) { |
|
633 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
634 BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect, |
|
635 aContentSize); |
|
636 } |
|
637 } |
|
638 |
|
639 virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE |
|
640 { |
|
641 MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs); |
|
642 } |
|
643 |
|
644 virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints) |
|
645 { |
|
646 if (mHaveZoomConstraints && aOutConstraints) { |
|
647 *aOutConstraints = mZoomConstraints; |
|
648 } |
|
649 return mHaveZoomConstraints; |
|
650 } |
|
651 |
|
652 virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) |
|
653 { |
|
654 if (mTouchSensitiveRegion.IsEmpty()) |
|
655 return false; |
|
656 |
|
657 *aOutRegion = CSSRect::FromAppUnits(mTouchSensitiveRegion.GetBounds()); |
|
658 return true; |
|
659 } |
|
660 |
|
661 virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, |
|
662 APZStateChange aChange, |
|
663 int aArg) |
|
664 { |
|
665 if (MessageLoop::current() != mUILoop) { |
|
666 mUILoop->PostTask( |
|
667 FROM_HERE, |
|
668 NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange, |
|
669 aGuid, aChange, aArg)); |
|
670 return; |
|
671 } |
|
672 if (mRenderFrame) { |
|
673 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
674 browser->NotifyAPZStateChange(aGuid.mScrollId, aChange, aArg); |
|
675 } |
|
676 } |
|
677 |
|
678 // Methods used by RenderFrameParent to set fields stored here. |
|
679 |
|
680 void SaveZoomConstraints(const ZoomConstraints& aConstraints) |
|
681 { |
|
682 mHaveZoomConstraints = true; |
|
683 mZoomConstraints = aConstraints; |
|
684 } |
|
685 |
|
686 void SetTouchSensitiveRegion(const nsRegion& aRegion) |
|
687 { |
|
688 mTouchSensitiveRegion = aRegion; |
|
689 } |
|
690 private: |
|
691 void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics) |
|
692 { |
|
693 if (mRenderFrame) { |
|
694 TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager()); |
|
695 browser->UpdateFrame(aFrameMetrics); |
|
696 } |
|
697 } |
|
698 |
|
699 MessageLoop* mUILoop; |
|
700 RenderFrameParent* mRenderFrame; |
|
701 |
|
702 bool mHaveZoomConstraints; |
|
703 ZoomConstraints mZoomConstraints; |
|
704 nsRegion mTouchSensitiveRegion; |
|
705 }; |
|
706 |
|
707 RenderFrameParent::RenderFrameParent() |
|
708 : mLayersId(0) |
|
709 , mFrameLoaderDestroyed(false) |
|
710 , mBackgroundColor(gfxRGBA(1, 1, 1)) |
|
711 { |
|
712 } |
|
713 |
|
714 void |
|
715 RenderFrameParent::Init(nsFrameLoader* aFrameLoader, |
|
716 ScrollingBehavior aScrollingBehavior, |
|
717 TextureFactoryIdentifier* aTextureFactoryIdentifier, |
|
718 uint64_t* aId) |
|
719 { |
|
720 mFrameLoader = aFrameLoader; |
|
721 |
|
722 *aId = 0; |
|
723 |
|
724 nsRefPtr<LayerManager> lm = GetFrom(mFrameLoader); |
|
725 // Perhaps the document containing this frame currently has no presentation? |
|
726 if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { |
|
727 *aTextureFactoryIdentifier = |
|
728 static_cast<ClientLayerManager*>(lm.get())->GetTextureFactoryIdentifier(); |
|
729 } else { |
|
730 *aTextureFactoryIdentifier = TextureFactoryIdentifier(); |
|
731 } |
|
732 |
|
733 if (lm && lm->GetRoot() && lm->GetRoot()->AsContainerLayer()) { |
|
734 ViewID rootScrollId = lm->GetRoot()->AsContainerLayer()->GetFrameMetrics().GetScrollId(); |
|
735 if (rootScrollId != FrameMetrics::NULL_SCROLL_ID) { |
|
736 mContentViews[rootScrollId] = new nsContentView(aFrameLoader, rootScrollId, true); |
|
737 } |
|
738 } |
|
739 |
|
740 if (CompositorParent::CompositorLoop()) { |
|
741 // Our remote frame will push layers updates to the compositor, |
|
742 // and we'll keep an indirect reference to that tree. |
|
743 *aId = mLayersId = CompositorParent::AllocateLayerTreeId(); |
|
744 if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { |
|
745 ClientLayerManager *clientManager = static_cast<ClientLayerManager*>(lm.get()); |
|
746 clientManager->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId); |
|
747 } |
|
748 if (aScrollingBehavior == ASYNC_PAN_ZOOM) { |
|
749 mContentController = new RemoteContentController(this); |
|
750 CompositorParent::SetControllerForLayerTree(mLayersId, mContentController); |
|
751 } |
|
752 } |
|
753 // Set a default RenderFrameParent |
|
754 mFrameLoader->SetCurrentRemoteFrame(this); |
|
755 } |
|
756 |
|
757 APZCTreeManager* |
|
758 RenderFrameParent::GetApzcTreeManager() |
|
759 { |
|
760 // We can't get a ref to the APZCTreeManager until after the child is |
|
761 // created and the static getter knows which CompositorParent is |
|
762 // instantiated with this layers ID. That's why try to fetch it when |
|
763 // we first need it and cache the result. |
|
764 if (!mApzcTreeManager) { |
|
765 mApzcTreeManager = CompositorParent::GetAPZCTreeManager(mLayersId); |
|
766 } |
|
767 return mApzcTreeManager.get(); |
|
768 } |
|
769 |
|
770 RenderFrameParent::~RenderFrameParent() |
|
771 {} |
|
772 |
|
773 void |
|
774 RenderFrameParent::Destroy() |
|
775 { |
|
776 size_t numChildren = ManagedPLayerTransactionParent().Length(); |
|
777 NS_ABORT_IF_FALSE(0 == numChildren || 1 == numChildren, |
|
778 "render frame must only have 0 or 1 layer manager"); |
|
779 |
|
780 if (numChildren) { |
|
781 LayerTransactionParent* layers = |
|
782 static_cast<LayerTransactionParent*>(ManagedPLayerTransactionParent()[0]); |
|
783 layers->Destroy(); |
|
784 } |
|
785 |
|
786 mFrameLoaderDestroyed = true; |
|
787 } |
|
788 |
|
789 nsContentView* |
|
790 RenderFrameParent::GetContentView(ViewID aId) |
|
791 { |
|
792 return FindViewForId(mContentViews, aId); |
|
793 } |
|
794 |
|
795 nsContentView* |
|
796 RenderFrameParent::GetRootContentView() |
|
797 { |
|
798 return FindRootView(mContentViews); |
|
799 } |
|
800 |
|
801 void |
|
802 RenderFrameParent::ContentViewScaleChanged(nsContentView* aView) |
|
803 { |
|
804 // Since the scale has changed for a view, it and its descendents need their |
|
805 // shadow-space attributes updated. It's easiest to rebuild the view map. |
|
806 BuildViewMap(); |
|
807 } |
|
808 |
|
809 void |
|
810 RenderFrameParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, |
|
811 const TargetConfig& aTargetConfig, |
|
812 bool aIsFirstPaint, |
|
813 bool aScheduleComposite) |
|
814 { |
|
815 // View map must only contain views that are associated with the current |
|
816 // shadow layer tree. We must always update the map when shadow layers |
|
817 // are updated. |
|
818 BuildViewMap(); |
|
819 |
|
820 TriggerRepaint(); |
|
821 } |
|
822 |
|
823 already_AddRefed<Layer> |
|
824 RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, |
|
825 nsIFrame* aFrame, |
|
826 LayerManager* aManager, |
|
827 const nsIntRect& aVisibleRect, |
|
828 nsDisplayItem* aItem, |
|
829 const ContainerLayerParameters& aContainerParameters) |
|
830 { |
|
831 NS_ABORT_IF_FALSE(aFrame, |
|
832 "makes no sense to have a shadow tree without a frame"); |
|
833 NS_ABORT_IF_FALSE(!mContainer || |
|
834 IsTempLayerManager(aManager) || |
|
835 mContainer->Manager() == aManager, |
|
836 "retaining manager changed out from under us ... HELP!"); |
|
837 |
|
838 if (IsTempLayerManager(aManager) || |
|
839 (mContainer && mContainer->Manager() != aManager)) { |
|
840 // This can happen if aManager is a "temporary" manager, or if the |
|
841 // widget's layer manager changed out from under us. We need to |
|
842 // FIXME handle the former case somehow, probably with an API to |
|
843 // draw a manager's subtree. The latter is bad bad bad, but the |
|
844 // the NS_ABORT_IF_FALSE() above will flag it. Returning nullptr |
|
845 // here will just cause the shadow subtree not to be rendered. |
|
846 NS_WARNING("Remote iframe not rendered"); |
|
847 return nullptr; |
|
848 } |
|
849 |
|
850 uint64_t id = GetLayerTreeId(); |
|
851 if (0 != id) { |
|
852 MOZ_ASSERT(!GetRootLayer()); |
|
853 |
|
854 nsRefPtr<Layer> layer = |
|
855 (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); |
|
856 if (!layer) { |
|
857 layer = aManager->CreateRefLayer(); |
|
858 } |
|
859 if (!layer) { |
|
860 // Probably a temporary layer manager that doesn't know how to |
|
861 // use ref layers. |
|
862 return nullptr; |
|
863 } |
|
864 static_cast<RefLayer*>(layer.get())->SetReferentId(id); |
|
865 nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); |
|
866 layer->SetVisibleRegion(aVisibleRect - offset); |
|
867 // We can only have an offset if we're a child of an inactive |
|
868 // container, but our display item is LAYER_ACTIVE_FORCE which |
|
869 // forces all layers above to be active. |
|
870 MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint()); |
|
871 gfx::Matrix4x4 m; |
|
872 m.Translate(offset.x, offset.y, 0.0); |
|
873 // Remote content can't be repainted by us, so we multiply down |
|
874 // the resolution that our container expects onto our container. |
|
875 m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0); |
|
876 layer->SetBaseTransform(m); |
|
877 |
|
878 return layer.forget(); |
|
879 } |
|
880 |
|
881 if (mContainer) { |
|
882 ClearContainer(mContainer); |
|
883 mContainer->SetPreScale(1.0f, 1.0f); |
|
884 mContainer->SetPostScale(1.0f, 1.0f); |
|
885 mContainer->SetInheritedScale(1.0f, 1.0f); |
|
886 } |
|
887 |
|
888 Layer* shadowRoot = GetRootLayer(); |
|
889 if (!shadowRoot) { |
|
890 mContainer = nullptr; |
|
891 return nullptr; |
|
892 } |
|
893 |
|
894 NS_ABORT_IF_FALSE(!shadowRoot || shadowRoot->Manager() == aManager, |
|
895 "retaining manager changed out from under us ... HELP!"); |
|
896 |
|
897 // Wrap the shadow layer tree in mContainer. |
|
898 if (!mContainer) { |
|
899 mContainer = aManager->CreateContainerLayer(); |
|
900 } |
|
901 NS_ABORT_IF_FALSE(!mContainer->GetFirstChild(), |
|
902 "container of shadow tree shouldn't have a 'root' here"); |
|
903 |
|
904 mContainer->InsertAfter(shadowRoot, nullptr); |
|
905 |
|
906 AssertInTopLevelChromeDoc(mContainer, aFrame); |
|
907 ViewTransform transform; |
|
908 TransformShadowTree(aBuilder, mFrameLoader, aFrame, shadowRoot, transform); |
|
909 mContainer->SetClipRect(nullptr); |
|
910 |
|
911 if (mFrameLoader->AsyncScrollEnabled()) { |
|
912 const nsContentView* view = GetRootContentView(); |
|
913 BuildBackgroundPatternFor(mContainer, |
|
914 shadowRoot, |
|
915 view->GetViewConfig(), |
|
916 mBackgroundColor, |
|
917 aManager, aFrame); |
|
918 } |
|
919 mContainer->SetVisibleRegion(aVisibleRect); |
|
920 |
|
921 return nsRefPtr<Layer>(mContainer).forget(); |
|
922 } |
|
923 |
|
924 void |
|
925 RenderFrameParent::OwnerContentChanged(nsIContent* aContent) |
|
926 { |
|
927 NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent, |
|
928 "Don't build new map if owner is same!"); |
|
929 BuildViewMap(); |
|
930 } |
|
931 |
|
932 void |
|
933 RenderFrameParent::NotifyInputEvent(WidgetInputEvent& aEvent, |
|
934 ScrollableLayerGuid* aOutTargetGuid) |
|
935 { |
|
936 if (GetApzcTreeManager()) { |
|
937 GetApzcTreeManager()->ReceiveInputEvent(aEvent, aOutTargetGuid); |
|
938 } |
|
939 } |
|
940 |
|
941 void |
|
942 RenderFrameParent::ActorDestroy(ActorDestroyReason why) |
|
943 { |
|
944 if (mLayersId != 0) { |
|
945 CompositorParent::DeallocateLayerTreeId(mLayersId); |
|
946 if (mContentController) { |
|
947 // Stop our content controller from requesting repaints of our |
|
948 // content. |
|
949 mContentController->ClearRenderFrame(); |
|
950 // TODO: notify the compositor? |
|
951 } |
|
952 } |
|
953 |
|
954 if (mFrameLoader && mFrameLoader->GetCurrentRemoteFrame() == this) { |
|
955 // XXX this might cause some weird issues ... we'll just not |
|
956 // redraw the part of the window covered by this until the "next" |
|
957 // remote frame has a layer-tree transaction. For |
|
958 // why==NormalShutdown, we'll definitely want to do something |
|
959 // better, especially as nothing guarantees another Update() from |
|
960 // the "next" remote layer tree. |
|
961 mFrameLoader->SetCurrentRemoteFrame(nullptr); |
|
962 } |
|
963 mFrameLoader = nullptr; |
|
964 } |
|
965 |
|
966 bool |
|
967 RenderFrameParent::RecvNotifyCompositorTransaction() |
|
968 { |
|
969 TriggerRepaint(); |
|
970 return true; |
|
971 } |
|
972 |
|
973 bool |
|
974 RenderFrameParent::RecvUpdateHitRegion(const nsRegion& aRegion) |
|
975 { |
|
976 mTouchRegion = aRegion; |
|
977 if (mContentController) { |
|
978 // Tell the content controller about the touch-sensitive region, so |
|
979 // that it can provide it to APZ. This is required for APZ to do |
|
980 // correct hit testing for a remote 'mozpasspointerevents' iframe |
|
981 // until bug 928833 is fixed. |
|
982 mContentController->SetTouchSensitiveRegion(aRegion); |
|
983 } |
|
984 return true; |
|
985 } |
|
986 |
|
987 PLayerTransactionParent* |
|
988 RenderFrameParent::AllocPLayerTransactionParent() |
|
989 { |
|
990 if (!mFrameLoader || mFrameLoaderDestroyed) { |
|
991 return nullptr; |
|
992 } |
|
993 nsRefPtr<LayerManager> lm = GetFrom(mFrameLoader); |
|
994 LayerTransactionParent* result = new LayerTransactionParent(lm->AsLayerManagerComposite(), this, 0); |
|
995 result->AddIPDLReference(); |
|
996 return result; |
|
997 } |
|
998 |
|
999 bool |
|
1000 RenderFrameParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) |
|
1001 { |
|
1002 static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference(); |
|
1003 return true; |
|
1004 } |
|
1005 |
|
1006 void |
|
1007 RenderFrameParent::BuildViewMap() |
|
1008 { |
|
1009 ViewMap newContentViews; |
|
1010 // BuildViewMap assumes we have a primary frame, which may not be the case. |
|
1011 if (GetRootLayer() && mFrameLoader->GetPrimaryFrameOfOwningContent()) { |
|
1012 // Some of the content views in our hash map may no longer be active. To |
|
1013 // tag them as inactive and to remove any chance of them using a dangling |
|
1014 // pointer, we set mContentView to nullptr. |
|
1015 // |
|
1016 // BuildViewMap will restore mFrameLoader if the content view is still |
|
1017 // in our hash table. |
|
1018 |
|
1019 for (ViewMap::const_iterator iter = mContentViews.begin(); |
|
1020 iter != mContentViews.end(); |
|
1021 ++iter) { |
|
1022 iter->second->mFrameLoader = nullptr; |
|
1023 } |
|
1024 |
|
1025 mozilla::layout::BuildViewMap(mContentViews, newContentViews, mFrameLoader, GetRootLayer()); |
|
1026 } |
|
1027 |
|
1028 // Here, we guarantee that *only* the root view is preserved in |
|
1029 // case we couldn't build a new view map above. This is important because |
|
1030 // the content view map should only contain the root view and content |
|
1031 // views that are present in the layer tree. |
|
1032 if (newContentViews.empty()) { |
|
1033 nsContentView* rootView = FindRootView(mContentViews); |
|
1034 if (rootView) |
|
1035 newContentViews[rootView->GetId()] = rootView; |
|
1036 } |
|
1037 |
|
1038 mContentViews = newContentViews; |
|
1039 } |
|
1040 |
|
1041 void |
|
1042 RenderFrameParent::TriggerRepaint() |
|
1043 { |
|
1044 mFrameLoader->SetCurrentRemoteFrame(this); |
|
1045 |
|
1046 nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent(); |
|
1047 if (!docFrame) { |
|
1048 // Bad, but nothing we can do about it (XXX/cjones: or is there? |
|
1049 // maybe bug 589337?). When the new frame is created, we'll |
|
1050 // probably still be the current render frame and will get to draw |
|
1051 // our content then. Or, we're shutting down and this update goes |
|
1052 // to /dev/null. |
|
1053 return; |
|
1054 } |
|
1055 |
|
1056 docFrame->InvalidateLayer(nsDisplayItem::TYPE_REMOTE); |
|
1057 } |
|
1058 |
|
1059 LayerTransactionParent* |
|
1060 RenderFrameParent::GetShadowLayers() const |
|
1061 { |
|
1062 const InfallibleTArray<PLayerTransactionParent*>& shadowParents = ManagedPLayerTransactionParent(); |
|
1063 NS_ABORT_IF_FALSE(shadowParents.Length() <= 1, |
|
1064 "can only support at most 1 LayerTransactionParent"); |
|
1065 return (shadowParents.Length() == 1) ? |
|
1066 static_cast<LayerTransactionParent*>(shadowParents[0]) : nullptr; |
|
1067 } |
|
1068 |
|
1069 uint64_t |
|
1070 RenderFrameParent::GetLayerTreeId() const |
|
1071 { |
|
1072 return mLayersId; |
|
1073 } |
|
1074 |
|
1075 Layer* |
|
1076 RenderFrameParent::GetRootLayer() const |
|
1077 { |
|
1078 LayerTransactionParent* shadowLayers = GetShadowLayers(); |
|
1079 return shadowLayers ? shadowLayers->GetRoot() : nullptr; |
|
1080 } |
|
1081 |
|
1082 void |
|
1083 RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
1084 nsSubDocumentFrame* aFrame, |
|
1085 const nsRect& aDirtyRect, |
|
1086 const nsDisplayListSet& aLists) |
|
1087 { |
|
1088 // We're the subdoc for <browser remote="true"> and it has |
|
1089 // painted content. Display its shadow layer tree. |
|
1090 DisplayListClipState::AutoSaveRestore clipState(aBuilder); |
|
1091 |
|
1092 nsPoint offset = aBuilder->ToReferenceFrame(aFrame); |
|
1093 nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset; |
|
1094 clipState.ClipContentDescendants(bounds); |
|
1095 |
|
1096 Layer* container = GetRootLayer(); |
|
1097 if (aBuilder->IsForEventDelivery() && container) { |
|
1098 ViewTransform offset = |
|
1099 ViewTransform(GetContentRectLayerOffset(aFrame, aBuilder)); |
|
1100 BuildListForLayer(container, mFrameLoader, offset, |
|
1101 aBuilder, *aLists.Content(), aFrame); |
|
1102 } else { |
|
1103 aLists.Content()->AppendToTop( |
|
1104 new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this)); |
|
1105 } |
|
1106 } |
|
1107 |
|
1108 void |
|
1109 RenderFrameParent::ZoomToRect(uint32_t aPresShellId, ViewID aViewId, |
|
1110 const CSSRect& aRect) |
|
1111 { |
|
1112 if (GetApzcTreeManager()) { |
|
1113 GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId), |
|
1114 aRect); |
|
1115 } |
|
1116 } |
|
1117 |
|
1118 void |
|
1119 RenderFrameParent::ContentReceivedTouch(const ScrollableLayerGuid& aGuid, |
|
1120 bool aPreventDefault) |
|
1121 { |
|
1122 if (aGuid.mLayersId != mLayersId) { |
|
1123 // Guard against bad data from hijacked child processes |
|
1124 NS_ERROR("Unexpected layers id in ContentReceivedTouch; dropping message..."); |
|
1125 return; |
|
1126 } |
|
1127 if (GetApzcTreeManager()) { |
|
1128 GetApzcTreeManager()->ContentReceivedTouch(aGuid, aPreventDefault); |
|
1129 } |
|
1130 } |
|
1131 |
|
1132 void |
|
1133 RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId, |
|
1134 ViewID aViewId, |
|
1135 bool aIsRoot, |
|
1136 const ZoomConstraints& aConstraints) |
|
1137 { |
|
1138 if (mContentController && aIsRoot) { |
|
1139 mContentController->SaveZoomConstraints(aConstraints); |
|
1140 } |
|
1141 if (GetApzcTreeManager()) { |
|
1142 GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId), |
|
1143 aConstraints); |
|
1144 } |
|
1145 } |
|
1146 |
|
1147 bool |
|
1148 RenderFrameParent::HitTest(const nsRect& aRect) |
|
1149 { |
|
1150 return mTouchRegion.Contains(aRect); |
|
1151 } |
|
1152 |
|
1153 } // namespace layout |
|
1154 } // namespace mozilla |
|
1155 |
|
1156 already_AddRefed<Layer> |
|
1157 nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder, |
|
1158 LayerManager* aManager, |
|
1159 const ContainerLayerParameters& aContainerParameters) |
|
1160 { |
|
1161 int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); |
|
1162 nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel); |
|
1163 visibleRect += aContainerParameters.mOffset; |
|
1164 nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters); |
|
1165 return layer.forget(); |
|
1166 } |
|
1167 |
|
1168 void |
|
1169 nsDisplayRemote::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, |
|
1170 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) |
|
1171 { |
|
1172 if (mRemoteFrame->HitTest(aRect)) { |
|
1173 aOutFrames->AppendElement(mFrame); |
|
1174 } |
|
1175 } |
|
1176 |
|
1177 void |
|
1178 nsDisplayRemoteShadow::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, |
|
1179 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) |
|
1180 { |
|
1181 // If we are here, then rects have intersected. |
|
1182 // |
|
1183 // XXX I think iframes and divs can be rounded like anything else but we don't |
|
1184 // cover that case here. |
|
1185 // |
|
1186 if (aState->mShadows) { |
|
1187 aState->mShadows->AppendElement(mId); |
|
1188 } |
|
1189 } |