Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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/. */
8 #include "base/basictypes.h"
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"
31 typedef nsContentView::ViewConfig ViewConfig;
32 using namespace mozilla::dom;
33 using namespace mozilla::layers;
35 namespace mozilla {
36 namespace layout {
38 typedef FrameMetrics::ViewID ViewID;
39 typedef RenderFrameParent::ViewMap ViewMap;
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 {}
49 operator gfx3DMatrix() const
50 {
51 return
52 gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) *
53 gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1);
54 }
56 nsIntPoint mTranslation;
57 float mXScale;
58 float mYScale;
59 };
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.
67 static double GetXScale(const gfx3DMatrix& aTransform)
68 {
69 return aTransform._11;
70 }
72 static double GetYScale(const gfx3DMatrix& aTransform)
73 {
74 return aTransform._22;
75 }
77 static void Scale(gfx3DMatrix& aTransform, double aXScale, double aYScale)
78 {
79 aTransform._11 *= aXScale;
80 aTransform._22 *= aYScale;
81 }
83 static void ReverseTranslate(gfx3DMatrix& aTransform, const gfxPoint& aOffset)
84 {
85 aTransform._41 -= aOffset.x;
86 aTransform._42 -= aOffset.y;
87 }
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 }
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 }
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 }
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 }
132 static const FrameMetrics*
133 GetFrameMetrics(Layer* aLayer)
134 {
135 ContainerLayer* container = aLayer->AsContainerLayer();
136 return container ? &container->GetFrameMetrics() : nullptr;
137 }
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();
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());
156 return frameOffset.ToNearestPixels(auPerDevPixel);
157 }
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());
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));
195 return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale);
196 } else {
197 return ViewTransform(nsIntPoint(0, 0), 1, 1);
198 }
199 }
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);
212 gfx3DMatrix transform;
214 if (metrics && metrics->IsScrollable()) {
215 const ViewID scrollId = metrics->GetScrollId();
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.
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;
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));
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 }
247 aShadowTree.AppendToTop(
248 new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId));
250 } else {
251 gfx3DMatrix layerTransform;
252 To3DMatrix(aLayer->GetTransform(), layerTransform);
253 transform = layerTransform * aTransform;
254 }
256 for (Layer* child = aLayer->GetFirstChild(); child;
257 child = child->GetNextSibling()) {
258 BuildListForLayer(child, aRootFrameLoader, transform,
259 aBuilder, aShadowTree, aSubdocFrame);
260 }
261 }
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());
276 const FrameMetrics* metrics = GetFrameMetrics(aLayer);
278 gfx3DMatrix shadowTransform;
279 To3DMatrix(aLayer->GetTransform(), shadowTransform);
280 ViewTransform layerTransform = aTransform;
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);
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 );
300 // Apply the layer's own transform *before* the view transform
301 shadowTransform = gfx3DMatrix(viewTransform) * currentTransform;
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 }
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 }
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);
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 }
350 static void
351 ClearContainer(ContainerLayer* aContainer)
352 {
353 while (Layer* layer = aContainer->GetFirstChild()) {
354 aContainer->RemoveChild(layer);
355 }
356 }
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 }
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);
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 }
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);
442 newContentViews[scrollId] = view;
443 }
445 for (Layer* child = aLayer->GetFirstChild();
446 child; child = child->GetNextSibling()) {
447 BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child,
448 aXScale, aYScale, aAccConfigXScale, aAccConfigYScale);
449 }
450 }
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 }
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());
477 // Get the frame's rect
478 nscoord auPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
479 nsIntRect frameRect = aFrame->GetRect().ToOutsidePixels(auPerDevPixel);
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);
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);
496 aContainer->InsertAfter(layer, nullptr);
497 }
499 already_AddRefed<LayerManager>
500 GetFrom(nsFrameLoader* aFrameLoader)
501 {
502 nsIDocument* doc = aFrameLoader->GetOwnerDoc();
503 return nsContentUtils::LayerManagerForDocument(doc);
504 }
506 class RemoteContentController : public GeckoContentController {
507 public:
508 RemoteContentController(RenderFrameParent* aRenderFrame)
509 : mUILoop(MessageLoop::current())
510 , mRenderFrame(aRenderFrame)
511 , mHaveZoomConstraints(false)
512 { }
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 }
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 }
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 }
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 }
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 }
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 }
618 void ClearRenderFrame() { mRenderFrame = nullptr; }
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 }
639 virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE
640 {
641 MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
642 }
644 virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints)
645 {
646 if (mHaveZoomConstraints && aOutConstraints) {
647 *aOutConstraints = mZoomConstraints;
648 }
649 return mHaveZoomConstraints;
650 }
652 virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion)
653 {
654 if (mTouchSensitiveRegion.IsEmpty())
655 return false;
657 *aOutRegion = CSSRect::FromAppUnits(mTouchSensitiveRegion.GetBounds());
658 return true;
659 }
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 }
678 // Methods used by RenderFrameParent to set fields stored here.
680 void SaveZoomConstraints(const ZoomConstraints& aConstraints)
681 {
682 mHaveZoomConstraints = true;
683 mZoomConstraints = aConstraints;
684 }
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 }
699 MessageLoop* mUILoop;
700 RenderFrameParent* mRenderFrame;
702 bool mHaveZoomConstraints;
703 ZoomConstraints mZoomConstraints;
704 nsRegion mTouchSensitiveRegion;
705 };
707 RenderFrameParent::RenderFrameParent()
708 : mLayersId(0)
709 , mFrameLoaderDestroyed(false)
710 , mBackgroundColor(gfxRGBA(1, 1, 1))
711 {
712 }
714 void
715 RenderFrameParent::Init(nsFrameLoader* aFrameLoader,
716 ScrollingBehavior aScrollingBehavior,
717 TextureFactoryIdentifier* aTextureFactoryIdentifier,
718 uint64_t* aId)
719 {
720 mFrameLoader = aFrameLoader;
722 *aId = 0;
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 }
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 }
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 }
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 }
770 RenderFrameParent::~RenderFrameParent()
771 {}
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");
780 if (numChildren) {
781 LayerTransactionParent* layers =
782 static_cast<LayerTransactionParent*>(ManagedPLayerTransactionParent()[0]);
783 layers->Destroy();
784 }
786 mFrameLoaderDestroyed = true;
787 }
789 nsContentView*
790 RenderFrameParent::GetContentView(ViewID aId)
791 {
792 return FindViewForId(mContentViews, aId);
793 }
795 nsContentView*
796 RenderFrameParent::GetRootContentView()
797 {
798 return FindRootView(mContentViews);
799 }
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 }
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();
820 TriggerRepaint();
821 }
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!");
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 }
850 uint64_t id = GetLayerTreeId();
851 if (0 != id) {
852 MOZ_ASSERT(!GetRootLayer());
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);
878 return layer.forget();
879 }
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 }
888 Layer* shadowRoot = GetRootLayer();
889 if (!shadowRoot) {
890 mContainer = nullptr;
891 return nullptr;
892 }
894 NS_ABORT_IF_FALSE(!shadowRoot || shadowRoot->Manager() == aManager,
895 "retaining manager changed out from under us ... HELP!");
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");
904 mContainer->InsertAfter(shadowRoot, nullptr);
906 AssertInTopLevelChromeDoc(mContainer, aFrame);
907 ViewTransform transform;
908 TransformShadowTree(aBuilder, mFrameLoader, aFrame, shadowRoot, transform);
909 mContainer->SetClipRect(nullptr);
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);
921 return nsRefPtr<Layer>(mContainer).forget();
922 }
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 }
932 void
933 RenderFrameParent::NotifyInputEvent(WidgetInputEvent& aEvent,
934 ScrollableLayerGuid* aOutTargetGuid)
935 {
936 if (GetApzcTreeManager()) {
937 GetApzcTreeManager()->ReceiveInputEvent(aEvent, aOutTargetGuid);
938 }
939 }
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 }
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 }
966 bool
967 RenderFrameParent::RecvNotifyCompositorTransaction()
968 {
969 TriggerRepaint();
970 return true;
971 }
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 }
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 }
999 bool
1000 RenderFrameParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers)
1001 {
1002 static_cast<LayerTransactionParent*>(aLayers)->ReleaseIPDLReference();
1003 return true;
1004 }
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.
1019 for (ViewMap::const_iterator iter = mContentViews.begin();
1020 iter != mContentViews.end();
1021 ++iter) {
1022 iter->second->mFrameLoader = nullptr;
1023 }
1025 mozilla::layout::BuildViewMap(mContentViews, newContentViews, mFrameLoader, GetRootLayer());
1026 }
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 }
1038 mContentViews = newContentViews;
1039 }
1041 void
1042 RenderFrameParent::TriggerRepaint()
1043 {
1044 mFrameLoader->SetCurrentRemoteFrame(this);
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 }
1056 docFrame->InvalidateLayer(nsDisplayItem::TYPE_REMOTE);
1057 }
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 }
1069 uint64_t
1070 RenderFrameParent::GetLayerTreeId() const
1071 {
1072 return mLayersId;
1073 }
1075 Layer*
1076 RenderFrameParent::GetRootLayer() const
1077 {
1078 LayerTransactionParent* shadowLayers = GetShadowLayers();
1079 return shadowLayers ? shadowLayers->GetRoot() : nullptr;
1080 }
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);
1092 nsPoint offset = aBuilder->ToReferenceFrame(aFrame);
1093 nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
1094 clipState.ClipContentDescendants(bounds);
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 }
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 }
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 }
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 }
1147 bool
1148 RenderFrameParent::HitTest(const nsRect& aRect)
1149 {
1150 return mTouchRegion.Contains(aRect);
1151 }
1153 } // namespace layout
1154 } // namespace mozilla
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 }
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 }
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 }