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