1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: sw=2 ts=8 et :
3 : */
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at:
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * The Mozilla Foundation
21 : * Portions created by the Initial Developer are Copyright (C) 2010
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Chris Jones <jones.chris.g@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "mozilla/layers/ShadowLayersParent.h"
42 :
43 : #include "BasicLayers.h"
44 : #include "LayerManagerOGL.h"
45 : #ifdef MOZ_ENABLE_D3D9_LAYER
46 : #include "LayerManagerD3D9.h"
47 : #endif //MOZ_ENABLE_D3D9_LAYER
48 : #include "RenderFrameParent.h"
49 :
50 : #include "gfx3DMatrix.h"
51 : #include "nsFrameLoader.h"
52 : #include "nsViewportFrame.h"
53 : #include "nsSubDocumentFrame.h"
54 : #include "nsIObserver.h"
55 :
56 : typedef nsContentView::ViewConfig ViewConfig;
57 : using namespace mozilla::layers;
58 :
59 : namespace mozilla {
60 : namespace layout {
61 :
62 : typedef FrameMetrics::ViewID ViewID;
63 : typedef RenderFrameParent::ViewMap ViewMap;
64 :
65 : // Represents (affine) transforms that are calculated from a content view.
66 0 : struct ViewTransform {
67 0 : ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1)
68 : : mTranslation(aTranslation)
69 : , mXScale(aXScale)
70 0 : , mYScale(aYScale)
71 0 : {}
72 :
73 0 : operator gfx3DMatrix() const
74 : {
75 : return
76 0 : gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1) *
77 0 : gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0);
78 : }
79 :
80 : nsIntPoint mTranslation;
81 : float mXScale;
82 : float mYScale;
83 : };
84 :
85 : // Matrix helpers
86 : // For our simple purposes, these helpers apply to 2D affine transformations
87 : // that can be represented by a scale and a translation. This makes the math
88 : // much easier because we only expect the diagonals and the translation
89 : // coordinates of the matrix to be non-zero.
90 :
91 0 : static double GetXScale(const gfx3DMatrix& aTransform)
92 : {
93 0 : return aTransform._11;
94 : }
95 :
96 0 : static double GetYScale(const gfx3DMatrix& aTransform)
97 : {
98 0 : return aTransform._22;
99 : }
100 :
101 0 : static void Scale(gfx3DMatrix& aTransform, double aXScale, double aYScale)
102 : {
103 0 : aTransform._11 *= aXScale;
104 0 : aTransform._22 *= aYScale;
105 0 : }
106 :
107 0 : static void ReverseTranslate(gfx3DMatrix& aTransform, ViewTransform& aViewTransform)
108 : {
109 0 : aTransform._41 -= aViewTransform.mTranslation.x / aViewTransform.mXScale;
110 0 : aTransform._42 -= aViewTransform.mTranslation.y / aViewTransform.mYScale;
111 0 : }
112 :
113 :
114 0 : static void ApplyTransform(nsRect& aRect,
115 : gfx3DMatrix& aTransform,
116 : nscoord auPerDevPixel)
117 : {
118 0 : aRect.x = aRect.x * aTransform._11 + aTransform._41 * auPerDevPixel;
119 0 : aRect.y = aRect.y * aTransform._22 + aTransform._42 * auPerDevPixel;
120 0 : aRect.width = aRect.width * aTransform._11;
121 0 : aRect.height = aRect.height * aTransform._22;
122 0 : }
123 :
124 : static void
125 0 : AssertInTopLevelChromeDoc(ContainerLayer* aContainer,
126 : nsIFrame* aContainedFrame)
127 : {
128 0 : NS_ASSERTION(
129 : (aContainer->Manager()->GetBackendType() != LayerManager::LAYERS_BASIC) ||
130 : (aContainedFrame->GetNearestWidget() ==
131 : static_cast<BasicLayerManager*>(aContainer->Manager())->GetRetainerWidget()),
132 : "Expected frame to be in top-level chrome document");
133 0 : }
134 :
135 : // Return view for given ID in aArray, NULL if not found.
136 : static nsContentView*
137 0 : FindViewForId(const ViewMap& aMap, ViewID aId)
138 : {
139 0 : ViewMap::const_iterator iter = aMap.find(aId);
140 0 : return iter != aMap.end() ? iter->second : NULL;
141 : }
142 :
143 : static const FrameMetrics*
144 0 : GetFrameMetrics(Layer* aLayer)
145 : {
146 0 : ContainerLayer* container = aLayer->AsContainerLayer();
147 0 : return container ? &container->GetFrameMetrics() : NULL;
148 : }
149 :
150 : static nsIntPoint
151 0 : GetRootFrameOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder)
152 : {
153 0 : nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
154 :
155 : // Offset to the content rect in case we have borders or padding
156 : nsPoint frameOffset =
157 0 : (aBuilder->ToReferenceFrame(aContainerFrame->GetParent()) +
158 0 : aContainerFrame->GetContentRect().TopLeft());
159 :
160 0 : return frameOffset.ToNearestPixels(auPerDevPixel);
161 : }
162 :
163 : // Compute the transform of the shadow tree contained by
164 : // |aContainerFrame| to widget space. We transform because the
165 : // subprocess layer manager renders to a different top-left than where
166 : // the shadow tree is drawn here and because a scale can be set on the
167 : // shadow tree.
168 : static ViewTransform
169 0 : ComputeShadowTreeTransform(nsIFrame* aContainerFrame,
170 : nsFrameLoader* aRootFrameLoader,
171 : const FrameMetrics* aMetrics,
172 : const ViewConfig& aConfig,
173 : float aTempScaleX = 1.0,
174 : float aTempScaleY = 1.0)
175 : {
176 : // |aMetrics->mViewportScrollOffset| The frame's scroll offset when it was
177 : // painted, in content document pixels.
178 : // |aConfig.mScrollOffset| What our user expects, or wants, the
179 : // frame scroll offset to be in chrome
180 : // document app units.
181 : //
182 : // So we set a compensating translation that moves the content document
183 : // pixels to where the user wants them to be.
184 : //
185 0 : nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
186 : nsIntPoint scrollOffset =
187 0 : aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
188 : // metricsScrollOffset is in layer coordinates.
189 0 : nsIntPoint metricsScrollOffset = aMetrics->mViewportScrollOffset;
190 :
191 0 : if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) {
192 : // Only use asynchronous scrolling if it is enabled and there is a
193 : // displayport defined. It is useful to have a scroll layer that is
194 : // synchronously scrolled for identifying a scroll area before it is
195 : // being actively scrolled.
196 : nsIntPoint scrollCompensation(
197 : (scrollOffset.x / aTempScaleX - metricsScrollOffset.x) * aConfig.mXScale,
198 0 : (scrollOffset.y / aTempScaleY - metricsScrollOffset.y) * aConfig.mYScale);
199 :
200 0 : return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale);
201 : } else {
202 0 : return ViewTransform(nsIntPoint(0, 0), 1, 1);
203 : }
204 : }
205 :
206 : // Use shadow layer tree to build display list for the browser's frame.
207 : static void
208 0 : BuildListForLayer(Layer* aLayer,
209 : nsFrameLoader* aRootFrameLoader,
210 : const gfx3DMatrix& aTransform,
211 : nsDisplayListBuilder* aBuilder,
212 : nsDisplayList& aShadowTree,
213 : nsIFrame* aSubdocFrame)
214 : {
215 0 : const FrameMetrics* metrics = GetFrameMetrics(aLayer);
216 :
217 0 : gfx3DMatrix transform;
218 :
219 0 : if (metrics && metrics->IsScrollable()) {
220 0 : const ViewID scrollId = metrics->mScrollId;
221 :
222 : // We need to figure out the bounds of the scrollable region using the
223 : // shadow layer tree from the remote process. The metrics viewport is
224 : // defined based on all the transformations of its parent layers and
225 : // the scale of the current layer.
226 :
227 : // Calculate transform for this layer.
228 : nsContentView* view =
229 0 : aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
230 : // XXX why don't we include aLayer->GetTransform() in the inverse-scale here?
231 : // This seems wrong, but it doesn't seem to cause bugs!
232 : gfx3DMatrix applyTransform = ComputeShadowTreeTransform(
233 : aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(),
234 0 : 1 / GetXScale(aTransform), 1 / GetYScale(aTransform));
235 0 : transform = applyTransform * aLayer->GetTransform() * aTransform;
236 :
237 : // As mentioned above, bounds calculation also depends on the scale
238 : // of this layer.
239 0 : gfx3DMatrix tmpTransform = aTransform;
240 0 : Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform));
241 :
242 : // Calculate rect for this layer based on aTransform.
243 0 : nsRect bounds;
244 : {
245 0 : nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel();
246 0 : bounds = metrics->mViewport.ToAppUnits(auPerDevPixel);
247 0 : ApplyTransform(bounds, tmpTransform, auPerDevPixel);
248 :
249 : }
250 :
251 : aShadowTree.AppendToTop(
252 0 : new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId));
253 :
254 : } else {
255 0 : transform = aLayer->GetTransform() * aTransform;
256 : }
257 :
258 0 : for (Layer* child = aLayer->GetFirstChild(); child;
259 : child = child->GetNextSibling()) {
260 : BuildListForLayer(child, aRootFrameLoader, transform,
261 0 : aBuilder, aShadowTree, aSubdocFrame);
262 : }
263 0 : }
264 :
265 : // Go down shadow layer tree and apply transformations for scrollable layers.
266 : static void
267 0 : TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
268 : nsIFrame* aFrame, Layer* aLayer,
269 : const ViewTransform& aTransform,
270 : float aTempScaleDiffX = 1.0,
271 : float aTempScaleDiffY = 1.0)
272 : {
273 0 : ShadowLayer* shadow = aLayer->AsShadowLayer();
274 0 : shadow->SetShadowClipRect(aLayer->GetClipRect());
275 0 : shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
276 :
277 0 : const FrameMetrics* metrics = GetFrameMetrics(aLayer);
278 :
279 0 : gfx3DMatrix shadowTransform = aLayer->GetTransform();
280 0 : ViewTransform layerTransform = aTransform;
281 :
282 0 : if (metrics && metrics->IsScrollable()) {
283 0 : const ViewID scrollId = metrics->mScrollId;
284 : const nsContentView* view =
285 0 : aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId);
286 0 : NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree");
287 0 : const gfx3DMatrix& currentTransform = aLayer->GetTransform();
288 :
289 0 : const ViewConfig& config = view->GetViewConfig();
290 : // With temporary scale we should compensate translation
291 : // using temporary scale value
292 0 : aTempScaleDiffX *= GetXScale(shadowTransform) * config.mXScale;
293 0 : aTempScaleDiffY *= GetYScale(shadowTransform) * config.mYScale;
294 : ViewTransform viewTransform = ComputeShadowTreeTransform(
295 : aFrame, aFrameLoader, metrics, view->GetViewConfig(),
296 : aTempScaleDiffX, aTempScaleDiffY
297 0 : );
298 :
299 : // Apply the layer's own transform *before* the view transform
300 0 : shadowTransform = gfx3DMatrix(viewTransform) * currentTransform;
301 :
302 0 : layerTransform = viewTransform;
303 0 : if (metrics->IsRootScrollable()) {
304 : // Apply the root frame translation *before* we do the rest of the transforms.
305 0 : nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder);
306 : shadowTransform = shadowTransform *
307 0 : gfx3DMatrix::Translation(float(rootFrameOffset.x), float(rootFrameOffset.y), 0.0);
308 : }
309 : }
310 :
311 0 : if (aLayer->GetIsFixedPosition() &&
312 0 : !aLayer->GetParent()->GetIsFixedPosition()) {
313 0 : ReverseTranslate(shadowTransform, layerTransform);
314 0 : const nsIntRect* clipRect = shadow->GetShadowClipRect();
315 0 : if (clipRect) {
316 0 : nsIntRect transformedClipRect(*clipRect);
317 0 : transformedClipRect.MoveBy(shadowTransform._41, shadowTransform._42);
318 0 : shadow->SetShadowClipRect(&transformedClipRect);
319 : }
320 : }
321 :
322 0 : shadow->SetShadowTransform(shadowTransform);
323 0 : for (Layer* child = aLayer->GetFirstChild();
324 : child; child = child->GetNextSibling()) {
325 : TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform,
326 0 : aTempScaleDiffX, aTempScaleDiffY);
327 : }
328 0 : }
329 :
330 : static void
331 0 : ClearContainer(ContainerLayer* aContainer)
332 : {
333 0 : while (Layer* layer = aContainer->GetFirstChild()) {
334 0 : aContainer->RemoveChild(layer);
335 : }
336 0 : }
337 :
338 : // Return true iff |aManager| is a "temporary layer manager". They're
339 : // used for small software rendering tasks, like drawWindow. That's
340 : // currently implemented by a BasicLayerManager without a backing
341 : // widget, and hence in non-retained mode.
342 : static bool
343 0 : IsTempLayerManager(LayerManager* aManager)
344 : {
345 0 : return (LayerManager::LAYERS_BASIC == aManager->GetBackendType() &&
346 0 : !static_cast<BasicLayerManager*>(aManager)->IsRetained());
347 : }
348 :
349 : // Recursively create a new array of scrollables, preserving any scrollables
350 : // that are still in the layer tree.
351 : //
352 : // aXScale and aYScale are used to calculate any values that need to be in
353 : // chrome-document CSS pixels and aren't part of the rendering loop, such as
354 : // the initial scroll offset for a new view.
355 : static void
356 0 : BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
357 : nsFrameLoader* aFrameLoader, Layer* aLayer,
358 : float aXScale = 1, float aYScale = 1,
359 : float aAccConfigXScale = 1, float aAccConfigYScale = 1)
360 : {
361 0 : ContainerLayer* container = aLayer->AsContainerLayer();
362 0 : if (!container)
363 0 : return;
364 0 : const FrameMetrics metrics = container->GetFrameMetrics();
365 0 : const ViewID scrollId = metrics.mScrollId;
366 0 : const gfx3DMatrix transform = aLayer->GetTransform();
367 0 : aXScale *= GetXScale(transform);
368 0 : aYScale *= GetYScale(transform);
369 :
370 0 : if (metrics.IsScrollable()) {
371 : nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent()
372 0 : ->PresContext()->AppUnitsPerDevPixel();
373 0 : nsContentView* view = FindViewForId(oldContentViews, scrollId);
374 0 : if (view) {
375 : // View already exists. Be sure to propagate scales for any values
376 : // that need to be calculated something in chrome-doc CSS pixels.
377 0 : ViewConfig config = view->GetViewConfig();
378 0 : aXScale *= config.mXScale;
379 0 : aYScale *= config.mYScale;
380 0 : view->mFrameLoader = aFrameLoader;
381 : // If scale has changed, then we should update
382 : // current scroll offset to new scaled value
383 0 : if (aAccConfigXScale != view->mParentScaleX ||
384 : aAccConfigYScale != view->mParentScaleY) {
385 0 : float xscroll = 0, yscroll = 0;
386 0 : view->GetScrollX(&xscroll);
387 0 : view->GetScrollY(&yscroll);
388 0 : xscroll = xscroll * (aAccConfigXScale / view->mParentScaleX);
389 0 : yscroll = yscroll * (aAccConfigYScale / view->mParentScaleY);
390 0 : view->ScrollTo(xscroll, yscroll);
391 0 : view->mParentScaleX = aAccConfigXScale;
392 0 : view->mParentScaleY = aAccConfigYScale;
393 : }
394 : // Collect only config scale values for scroll compensation
395 0 : aAccConfigXScale *= config.mXScale;
396 0 : aAccConfigYScale *= config.mYScale;
397 : } else {
398 : // View doesn't exist, so generate one. We start the view scroll offset at
399 : // the same position as the framemetric's scroll offset from the layer.
400 : // The default scale is 1, so no need to propagate scale down.
401 0 : ViewConfig config;
402 : config.mScrollOffset = nsPoint(
403 0 : NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.x, auPerDevPixel) * aXScale,
404 0 : NSIntPixelsToAppUnits(metrics.mViewportScrollOffset.y, auPerDevPixel) * aYScale);
405 0 : view = new nsContentView(aFrameLoader, scrollId, config);
406 0 : view->mParentScaleX = aAccConfigXScale;
407 0 : view->mParentScaleY = aAccConfigYScale;
408 : }
409 :
410 : view->mViewportSize = nsSize(
411 0 : NSIntPixelsToAppUnits(metrics.mViewport.width, auPerDevPixel) * aXScale,
412 0 : NSIntPixelsToAppUnits(metrics.mViewport.height, auPerDevPixel) * aYScale);
413 : view->mContentSize = nsSize(
414 0 : NSIntPixelsToAppUnits(metrics.mContentSize.width, auPerDevPixel) * aXScale,
415 0 : NSIntPixelsToAppUnits(metrics.mContentSize.height, auPerDevPixel) * aYScale);
416 :
417 0 : newContentViews[scrollId] = view;
418 : }
419 :
420 0 : for (Layer* child = aLayer->GetFirstChild();
421 : child; child = child->GetNextSibling()) {
422 : BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child,
423 0 : aXScale, aYScale, aAccConfigXScale, aAccConfigYScale);
424 : }
425 : }
426 :
427 : static void
428 0 : BuildBackgroundPatternFor(ContainerLayer* aContainer,
429 : ContainerLayer* aShadowRoot,
430 : const ViewConfig& aConfig,
431 : const gfxRGBA& aColor,
432 : LayerManager* aManager,
433 : nsIFrame* aFrame)
434 : {
435 0 : ShadowLayer* shadowRoot = aShadowRoot->AsShadowLayer();
436 0 : gfxMatrix t;
437 0 : if (!shadowRoot->GetShadowTransform().Is2D(&t)) {
438 0 : return;
439 : }
440 :
441 : // Get the rect bounding the shadow content, transformed into the
442 : // same space as |aFrame|
443 0 : nsIntRect contentBounds = shadowRoot->GetShadowVisibleRegion().GetBounds();
444 : gfxRect contentVis(contentBounds.x, contentBounds.y,
445 0 : contentBounds.width, contentBounds.height);
446 0 : gfxRect localContentVis(t.Transform(contentVis));
447 : // Round *in* here because this area is punched out of the background
448 0 : localContentVis.RoundIn();
449 0 : nsIntRect localIntContentVis(localContentVis.X(), localContentVis.Y(),
450 0 : localContentVis.Width(), localContentVis.Height());
451 :
452 : // Get the frame's rect
453 0 : nscoord auPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
454 0 : nsIntRect frameRect = aFrame->GetRect().ToOutsidePixels(auPerDevPixel);
455 :
456 : // If the shadow tree covers the frame rect, don't bother building
457 : // the background, it wouldn't be visible
458 0 : if (localIntContentVis.Contains(frameRect)) {
459 0 : return;
460 : }
461 0 : nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
462 0 : layer->SetColor(aColor);
463 :
464 : // The visible area of the background is the frame's area minus the
465 : // content area
466 0 : nsIntRegion bgRgn(frameRect);
467 0 : bgRgn.Sub(bgRgn, localIntContentVis);
468 0 : bgRgn.MoveBy(-frameRect.TopLeft());
469 0 : layer->SetVisibleRegion(bgRgn);
470 :
471 0 : aContainer->InsertAfter(layer, nsnull);
472 : }
473 :
474 0 : RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader)
475 : : mFrameLoader(aFrameLoader)
476 : , mFrameLoaderDestroyed(false)
477 0 : , mBackgroundColor(gfxRGBA(1, 1, 1))
478 : {
479 0 : if (aFrameLoader) {
480 0 : mContentViews[FrameMetrics::ROOT_SCROLL_ID] =
481 0 : new nsContentView(aFrameLoader, FrameMetrics::ROOT_SCROLL_ID);
482 : }
483 0 : }
484 :
485 0 : RenderFrameParent::~RenderFrameParent()
486 0 : {}
487 :
488 : void
489 0 : RenderFrameParent::Destroy()
490 : {
491 0 : size_t numChildren = ManagedPLayersParent().Length();
492 0 : NS_ABORT_IF_FALSE(0 == numChildren || 1 == numChildren,
493 : "render frame must only have 0 or 1 layer manager");
494 :
495 0 : if (numChildren) {
496 : ShadowLayersParent* layers =
497 0 : static_cast<ShadowLayersParent*>(ManagedPLayersParent()[0]);
498 0 : layers->Destroy();
499 : }
500 :
501 0 : mFrameLoaderDestroyed = true;
502 0 : }
503 :
504 : nsContentView*
505 0 : RenderFrameParent::GetContentView(ViewID aId)
506 : {
507 0 : return FindViewForId(mContentViews, aId);
508 : }
509 :
510 : void
511 0 : RenderFrameParent::ContentViewScaleChanged(nsContentView* aView)
512 : {
513 : // Since the scale has changed for a view, it and its descendents need their
514 : // shadow-space attributes updated. It's easiest to rebuild the view map.
515 0 : BuildViewMap();
516 0 : }
517 :
518 : void
519 0 : RenderFrameParent::ShadowLayersUpdated()
520 : {
521 0 : mFrameLoader->SetCurrentRemoteFrame(this);
522 :
523 : // View map must only contain views that are associated with the current
524 : // shadow layer tree. We must always update the map when shadow layers
525 : // are updated.
526 0 : BuildViewMap();
527 :
528 0 : nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent();
529 0 : if (!docFrame) {
530 : // Bad, but nothing we can do about it (XXX/cjones: or is there?
531 : // maybe bug 589337?). When the new frame is created, we'll
532 : // probably still be the current render frame and will get to draw
533 : // our content then. Or, we're shutting down and this update goes
534 : // to /dev/null.
535 0 : return;
536 : }
537 :
538 : // FIXME/cjones: we should collect the rects/regions updated for
539 : // Painted*Layer() calls and pass that region to here, then only
540 : // invalidate that rect
541 : //
542 : // We pass INVALIDATE_NO_THEBES_LAYERS here because we're
543 : // invalidating the <browser> on behalf of its counterpart in the
544 : // content process. Not only do we not need to invalidate the
545 : // shadow layers, things would just break if we did --- we have no
546 : // way to repaint shadow layers from this process.
547 0 : nsRect rect = nsRect(nsPoint(0, 0), docFrame->GetRect().Size());
548 0 : docFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
549 : }
550 :
551 : already_AddRefed<Layer>
552 0 : RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
553 : nsIFrame* aFrame,
554 : LayerManager* aManager,
555 : const nsIntRect& aVisibleRect)
556 : {
557 0 : NS_ABORT_IF_FALSE(aFrame,
558 : "makes no sense to have a shadow tree without a frame");
559 0 : NS_ABORT_IF_FALSE(!mContainer ||
560 : IsTempLayerManager(aManager) ||
561 : mContainer->Manager() == aManager,
562 : "retaining manager changed out from under us ... HELP!");
563 :
564 0 : if (mContainer && mContainer->Manager() != aManager) {
565 : // This can happen if aManager is a "temporary" manager, or if the
566 : // widget's layer manager changed out from under us. We need to
567 : // FIXME handle the former case somehow, probably with an API to
568 : // draw a manager's subtree. The latter is bad bad bad, but the
569 : // the NS_ABORT_IF_FALSE() above will flag it. Returning NULL
570 : // here will just cause the shadow subtree not to be rendered.
571 0 : return nsnull;
572 : }
573 :
574 0 : if (mContainer) {
575 0 : ClearContainer(mContainer);
576 : }
577 :
578 0 : ContainerLayer* shadowRoot = GetRootLayer();
579 0 : if (!shadowRoot) {
580 0 : mContainer = nsnull;
581 0 : return nsnull;
582 : }
583 :
584 0 : NS_ABORT_IF_FALSE(!shadowRoot || shadowRoot->Manager() == aManager,
585 : "retaining manager changed out from under us ... HELP!");
586 :
587 : // Wrap the shadow layer tree in mContainer.
588 0 : if (!mContainer) {
589 0 : mContainer = aManager->CreateContainerLayer();
590 : }
591 0 : NS_ABORT_IF_FALSE(!mContainer->GetFirstChild(),
592 : "container of shadow tree shouldn't have a 'root' here");
593 :
594 0 : mContainer->InsertAfter(shadowRoot, nsnull);
595 :
596 0 : AssertInTopLevelChromeDoc(mContainer, aFrame);
597 0 : ViewTransform transform;
598 0 : TransformShadowTree(aBuilder, mFrameLoader, aFrame, shadowRoot, transform);
599 0 : mContainer->SetClipRect(nsnull);
600 :
601 0 : if (mFrameLoader->AsyncScrollEnabled()) {
602 0 : const nsContentView* view = GetContentView(FrameMetrics::ROOT_SCROLL_ID);
603 : BuildBackgroundPatternFor(mContainer,
604 : shadowRoot,
605 : view->GetViewConfig(),
606 : mBackgroundColor,
607 0 : aManager, aFrame);
608 : }
609 0 : mContainer->SetVisibleRegion(aVisibleRect);
610 :
611 0 : return nsRefPtr<Layer>(mContainer).forget();
612 : }
613 :
614 : void
615 0 : RenderFrameParent::OwnerContentChanged(nsIContent* aContent)
616 : {
617 0 : NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent,
618 : "Don't build new map if owner is same!");
619 0 : BuildViewMap();
620 0 : }
621 :
622 : void
623 0 : RenderFrameParent::ActorDestroy(ActorDestroyReason why)
624 : {
625 0 : if (mFrameLoader && mFrameLoader->GetCurrentRemoteFrame() == this) {
626 : // XXX this might cause some weird issues ... we'll just not
627 : // redraw the part of the window covered by this until the "next"
628 : // remote frame has a layer-tree transaction. For
629 : // why==NormalShutdown, we'll definitely want to do something
630 : // better, especially as nothing guarantees another Update() from
631 : // the "next" remote layer tree.
632 0 : mFrameLoader->SetCurrentRemoteFrame(nsnull);
633 : }
634 0 : mFrameLoader = nsnull;
635 0 : }
636 :
637 : PLayersParent*
638 0 : RenderFrameParent::AllocPLayers(LayerManager::LayersBackend* aBackendType)
639 : {
640 0 : if (!mFrameLoader || mFrameLoaderDestroyed) {
641 0 : *aBackendType = LayerManager::LAYERS_NONE;
642 0 : return nsnull;
643 : }
644 0 : LayerManager* lm = GetLayerManager();
645 0 : ShadowLayerManager* slm = lm->AsShadowManager();
646 0 : if (!slm) {
647 0 : *aBackendType = LayerManager::LAYERS_NONE;
648 0 : return nsnull;
649 : }
650 0 : *aBackendType = lm->GetBackendType();
651 0 : return new ShadowLayersParent(slm, this);
652 : }
653 :
654 : bool
655 0 : RenderFrameParent::DeallocPLayers(PLayersParent* aLayers)
656 : {
657 0 : delete aLayers;
658 0 : return true;
659 : }
660 :
661 : void
662 0 : RenderFrameParent::BuildViewMap()
663 : {
664 0 : ViewMap newContentViews;
665 : // BuildViewMap assumes we have a primary frame, which may not be the case.
666 0 : if (GetRootLayer() && mFrameLoader->GetPrimaryFrameOfOwningContent()) {
667 : // Some of the content views in our hash map may no longer be active. To
668 : // tag them as inactive and to remove any chance of them using a dangling
669 : // pointer, we set mContentView to NULL.
670 : //
671 : // BuildViewMap will restore mFrameLoader if the content view is still
672 : // in our hash table.
673 :
674 0 : for (ViewMap::const_iterator iter = mContentViews.begin();
675 0 : iter != mContentViews.end();
676 : ++iter) {
677 0 : iter->second->mFrameLoader = NULL;
678 : }
679 :
680 0 : mozilla::layout::BuildViewMap(mContentViews, newContentViews, mFrameLoader, GetRootLayer());
681 : }
682 :
683 : // Here, we guarantee that *only* the root view is preserved in
684 : // case we couldn't build a new view map above. This is important because
685 : // the content view map should only contain the root view and content
686 : // views that are present in the layer tree.
687 0 : if (newContentViews.empty()) {
688 0 : newContentViews[FrameMetrics::ROOT_SCROLL_ID] =
689 0 : FindViewForId(mContentViews, FrameMetrics::ROOT_SCROLL_ID);
690 : }
691 :
692 0 : mContentViews = newContentViews;
693 0 : }
694 :
695 : LayerManager*
696 0 : RenderFrameParent::GetLayerManager() const
697 : {
698 0 : nsIDocument* doc = mFrameLoader->OwnerDoc();
699 0 : return doc->GetShell()->GetLayerManager();
700 : }
701 :
702 : ShadowLayersParent*
703 0 : RenderFrameParent::GetShadowLayers() const
704 : {
705 0 : const nsTArray<PLayersParent*>& shadowParents = ManagedPLayersParent();
706 0 : NS_ABORT_IF_FALSE(shadowParents.Length() <= 1,
707 : "can only support at most 1 ShadowLayersParent");
708 0 : return (shadowParents.Length() == 1) ?
709 0 : static_cast<ShadowLayersParent*>(shadowParents[0]) : nsnull;
710 : }
711 :
712 : ContainerLayer*
713 0 : RenderFrameParent::GetRootLayer() const
714 : {
715 0 : ShadowLayersParent* shadowLayers = GetShadowLayers();
716 0 : return shadowLayers ? shadowLayers->GetRoot() : nsnull;
717 : }
718 :
719 : NS_IMETHODIMP
720 0 : RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder,
721 : nsSubDocumentFrame* aFrame,
722 : const nsRect& aDirtyRect,
723 : const nsDisplayListSet& aLists)
724 : {
725 : // We're the subdoc for <browser remote="true"> and it has
726 : // painted content. Display its shadow layer tree.
727 0 : nsDisplayList shadowTree;
728 0 : ContainerLayer* container = GetRootLayer();
729 0 : if (aBuilder->IsForEventDelivery() && container) {
730 0 : nsRect bounds = aFrame->EnsureInnerView()->GetBounds();
731 : ViewTransform offset =
732 0 : ViewTransform(GetRootFrameOffset(aFrame, aBuilder), 1, 1);
733 : BuildListForLayer(container, mFrameLoader, offset,
734 0 : aBuilder, shadowTree, aFrame);
735 : } else {
736 : shadowTree.AppendToTop(
737 0 : new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this));
738 : }
739 :
740 : // Clip the shadow layers to subdoc bounds
741 0 : nsPoint offset = aFrame->GetOffsetToCrossDoc(aBuilder->ReferenceFrame());
742 0 : nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset;
743 :
744 : return aLists.Content()->AppendNewToTop(
745 : new (aBuilder) nsDisplayClip(aBuilder, aFrame, &shadowTree,
746 0 : bounds));
747 : }
748 :
749 : } // namespace layout
750 : } // namespace mozilla
751 :
752 : already_AddRefed<Layer>
753 0 : nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
754 : LayerManager* aManager,
755 : const ContainerParameters& aContainerParameters)
756 : {
757 0 : PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
758 0 : nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
759 0 : nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect);
760 0 : return layer.forget();
761 : }
762 :
763 :
764 : void
765 0 : nsDisplayRemoteShadow::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
766 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
767 : {
768 : // If we are here, then rects have intersected.
769 : //
770 : // XXX I think iframes and divs can be rounded like anything else but we don't
771 : // cover that case here.
772 : //
773 0 : if (aState->mShadows) {
774 0 : aState->mShadows->AppendElement(mId);
775 : }
776 0 : }
|