michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=8 et : michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "BasicLayers.h" michael@0: #include "gfx3DMatrix.h" michael@0: #ifdef MOZ_ENABLE_D3D9_LAYER michael@0: # include "LayerManagerD3D9.h" michael@0: #endif //MOZ_ENABLE_D3D9_LAYER michael@0: #include "mozilla/BrowserElementParent.h" michael@0: #include "mozilla/dom/TabParent.h" michael@0: #include "mozilla/layers/APZCTreeManager.h" michael@0: #include "mozilla/layers/CompositorParent.h" michael@0: #include "mozilla/layers/LayerTransactionParent.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsFrameLoader.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsSubDocumentFrame.h" michael@0: #include "nsView.h" michael@0: #include "nsViewportFrame.h" michael@0: #include "RenderFrameParent.h" michael@0: #include "mozilla/layers/LayerManagerComposite.h" michael@0: #include "mozilla/layers/CompositorChild.h" michael@0: #include "ClientLayerManager.h" michael@0: michael@0: typedef nsContentView::ViewConfig ViewConfig; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::layers; michael@0: michael@0: namespace mozilla { michael@0: namespace layout { michael@0: michael@0: typedef FrameMetrics::ViewID ViewID; michael@0: typedef RenderFrameParent::ViewMap ViewMap; michael@0: michael@0: // Represents (affine) transforms that are calculated from a content view. michael@0: struct ViewTransform { michael@0: ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1) michael@0: : mTranslation(aTranslation) michael@0: , mXScale(aXScale) michael@0: , mYScale(aYScale) michael@0: {} michael@0: michael@0: operator gfx3DMatrix() const michael@0: { michael@0: return michael@0: gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0) * michael@0: gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1); michael@0: } michael@0: michael@0: nsIntPoint mTranslation; michael@0: float mXScale; michael@0: float mYScale; michael@0: }; michael@0: michael@0: // Matrix helpers michael@0: // For our simple purposes, these helpers apply to 2D affine transformations michael@0: // that can be represented by a scale and a translation. This makes the math michael@0: // much easier because we only expect the diagonals and the translation michael@0: // coordinates of the matrix to be non-zero. michael@0: michael@0: static double GetXScale(const gfx3DMatrix& aTransform) michael@0: { michael@0: return aTransform._11; michael@0: } michael@0: michael@0: static double GetYScale(const gfx3DMatrix& aTransform) michael@0: { michael@0: return aTransform._22; michael@0: } michael@0: michael@0: static void Scale(gfx3DMatrix& aTransform, double aXScale, double aYScale) michael@0: { michael@0: aTransform._11 *= aXScale; michael@0: aTransform._22 *= aYScale; michael@0: } michael@0: michael@0: static void ReverseTranslate(gfx3DMatrix& aTransform, const gfxPoint& aOffset) michael@0: { michael@0: aTransform._41 -= aOffset.x; michael@0: aTransform._42 -= aOffset.y; michael@0: } michael@0: michael@0: michael@0: static void ApplyTransform(nsRect& aRect, michael@0: gfx3DMatrix& aTransform, michael@0: nscoord auPerDevPixel) michael@0: { michael@0: aRect.x = aRect.x * aTransform._11 + aTransform._41 * auPerDevPixel; michael@0: aRect.y = aRect.y * aTransform._22 + aTransform._42 * auPerDevPixel; michael@0: aRect.width = aRect.width * aTransform._11; michael@0: aRect.height = aRect.height * aTransform._22; michael@0: } michael@0: michael@0: static void michael@0: AssertInTopLevelChromeDoc(ContainerLayer* aContainer, michael@0: nsIFrame* aContainedFrame) michael@0: { michael@0: NS_ASSERTION( michael@0: (aContainer->Manager()->GetBackendType() != mozilla::layers::LayersBackend::LAYERS_BASIC) || michael@0: (aContainedFrame->GetNearestWidget() == michael@0: static_cast(aContainer->Manager())->GetRetainerWidget()), michael@0: "Expected frame to be in top-level chrome document"); michael@0: } michael@0: michael@0: // Return view for given ID in aMap, nullptr if not found. michael@0: static nsContentView* michael@0: FindViewForId(const ViewMap& aMap, ViewID aId) michael@0: { michael@0: ViewMap::const_iterator iter = aMap.find(aId); michael@0: return iter != aMap.end() ? iter->second : nullptr; michael@0: } michael@0: michael@0: // Return the root content view in aMap, nullptr if not found. michael@0: static nsContentView* michael@0: FindRootView(const ViewMap& aMap) michael@0: { michael@0: for (ViewMap::const_iterator iter = aMap.begin(), end = aMap.end(); michael@0: iter != end; michael@0: ++iter) { michael@0: if (iter->second->IsRoot()) michael@0: return iter->second; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: static const FrameMetrics* michael@0: GetFrameMetrics(Layer* aLayer) michael@0: { michael@0: ContainerLayer* container = aLayer->AsContainerLayer(); michael@0: return container ? &container->GetFrameMetrics() : nullptr; michael@0: } michael@0: michael@0: /** michael@0: * Gets the layer-pixel offset of aContainerFrame's content rect top-left michael@0: * from the nearest display item reference frame (which we assume will be inducing michael@0: * a ContainerLayer). michael@0: */ michael@0: static nsIntPoint michael@0: GetContentRectLayerOffset(nsIFrame* aContainerFrame, nsDisplayListBuilder* aBuilder) michael@0: { michael@0: nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: michael@0: // Offset to the content rect in case we have borders or padding michael@0: // Note that aContainerFrame could be a reference frame itself, so michael@0: // we need to be careful here to ensure that we call ToReferenceFrame michael@0: // on aContainerFrame and not its parent. michael@0: nsPoint frameOffset = aBuilder->ToReferenceFrame(aContainerFrame) + michael@0: (aContainerFrame->GetContentRect().TopLeft() - aContainerFrame->GetPosition()); michael@0: michael@0: return frameOffset.ToNearestPixels(auPerDevPixel); michael@0: } michael@0: michael@0: // Compute the transform of the shadow tree contained by michael@0: // |aContainerFrame| to widget space. We transform because the michael@0: // subprocess layer manager renders to a different top-left than where michael@0: // the shadow tree is drawn here and because a scale can be set on the michael@0: // shadow tree. michael@0: static ViewTransform michael@0: ComputeShadowTreeTransform(nsIFrame* aContainerFrame, michael@0: nsFrameLoader* aRootFrameLoader, michael@0: const FrameMetrics* aMetrics, michael@0: const ViewConfig& aConfig, michael@0: float aTempScaleX = 1.0, michael@0: float aTempScaleY = 1.0) michael@0: { michael@0: // |aMetrics->mViewportScrollOffset| The frame's scroll offset when it was michael@0: // painted, in content document pixels. michael@0: // |aConfig.mScrollOffset| What our user expects, or wants, the michael@0: // frame scroll offset to be in chrome michael@0: // document app units. michael@0: // michael@0: // So we set a compensating translation that moves the content document michael@0: // pixels to where the user wants them to be. michael@0: // michael@0: nscoord auPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: nsIntPoint scrollOffset = michael@0: aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel); michael@0: LayerIntPoint metricsScrollOffset = RoundedToInt(aMetrics->GetScrollOffsetInLayerPixels()); michael@0: michael@0: if (aRootFrameLoader->AsyncScrollEnabled() && !aMetrics->mDisplayPort.IsEmpty()) { michael@0: // Only use asynchronous scrolling if it is enabled and there is a michael@0: // displayport defined. It is useful to have a scroll layer that is michael@0: // synchronously scrolled for identifying a scroll area before it is michael@0: // being actively scrolled. michael@0: nsIntPoint scrollCompensation( michael@0: (scrollOffset.x / aTempScaleX - metricsScrollOffset.x), michael@0: (scrollOffset.y / aTempScaleY - metricsScrollOffset.y)); michael@0: michael@0: return ViewTransform(-scrollCompensation, aConfig.mXScale, aConfig.mYScale); michael@0: } else { michael@0: return ViewTransform(nsIntPoint(0, 0), 1, 1); michael@0: } michael@0: } michael@0: michael@0: // Use shadow layer tree to build display list for the browser's frame. michael@0: static void michael@0: BuildListForLayer(Layer* aLayer, michael@0: nsFrameLoader* aRootFrameLoader, michael@0: const gfx3DMatrix& aTransform, michael@0: nsDisplayListBuilder* aBuilder, michael@0: nsDisplayList& aShadowTree, michael@0: nsIFrame* aSubdocFrame) michael@0: { michael@0: const FrameMetrics* metrics = GetFrameMetrics(aLayer); michael@0: michael@0: gfx3DMatrix transform; michael@0: michael@0: if (metrics && metrics->IsScrollable()) { michael@0: const ViewID scrollId = metrics->GetScrollId(); michael@0: michael@0: // We need to figure out the bounds of the scrollable region using the michael@0: // shadow layer tree from the remote process. The metrics viewport is michael@0: // defined based on all the transformations of its parent layers and michael@0: // the scale of the current layer. michael@0: michael@0: // Calculate transform for this layer. michael@0: nsContentView* view = michael@0: aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); michael@0: // XXX why don't we include aLayer->GetTransform() in the inverse-scale here? michael@0: // This seems wrong, but it doesn't seem to cause bugs! michael@0: gfx3DMatrix applyTransform = ComputeShadowTreeTransform( michael@0: aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(), michael@0: 1 / GetXScale(aTransform), 1 / GetYScale(aTransform)); michael@0: gfx3DMatrix layerTransform; michael@0: To3DMatrix(aLayer->GetTransform(), layerTransform); michael@0: transform = applyTransform * layerTransform * aTransform; michael@0: michael@0: // As mentioned above, bounds calculation also depends on the scale michael@0: // of this layer. michael@0: gfx3DMatrix tmpTransform = aTransform; michael@0: Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform)); michael@0: michael@0: // Calculate rect for this layer based on aTransform. michael@0: nsRect bounds; michael@0: { michael@0: bounds = CSSRect::ToAppUnits(metrics->mViewport); michael@0: nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: ApplyTransform(bounds, tmpTransform, auPerDevPixel); michael@0: } michael@0: michael@0: aShadowTree.AppendToTop( michael@0: new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId)); michael@0: michael@0: } else { michael@0: gfx3DMatrix layerTransform; michael@0: To3DMatrix(aLayer->GetTransform(), layerTransform); michael@0: transform = layerTransform * aTransform; michael@0: } michael@0: michael@0: for (Layer* child = aLayer->GetFirstChild(); child; michael@0: child = child->GetNextSibling()) { michael@0: BuildListForLayer(child, aRootFrameLoader, transform, michael@0: aBuilder, aShadowTree, aSubdocFrame); michael@0: } michael@0: } michael@0: michael@0: // Go down shadow layer tree and apply transformations for scrollable layers. michael@0: static void michael@0: TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader, michael@0: nsIFrame* aFrame, Layer* aLayer, michael@0: const ViewTransform& aTransform, michael@0: float aTempScaleDiffX = 1.0, michael@0: float aTempScaleDiffY = 1.0) michael@0: { michael@0: LayerComposite* shadow = aLayer->AsLayerComposite(); michael@0: shadow->SetShadowClipRect(aLayer->GetClipRect()); michael@0: shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); michael@0: shadow->SetShadowOpacity(aLayer->GetOpacity()); michael@0: michael@0: const FrameMetrics* metrics = GetFrameMetrics(aLayer); michael@0: michael@0: gfx3DMatrix shadowTransform; michael@0: To3DMatrix(aLayer->GetTransform(), shadowTransform); michael@0: ViewTransform layerTransform = aTransform; michael@0: michael@0: if (metrics && metrics->IsScrollable()) { michael@0: const ViewID scrollId = metrics->GetScrollId(); michael@0: const nsContentView* view = michael@0: aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); michael@0: NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree"); michael@0: gfx3DMatrix currentTransform; michael@0: To3DMatrix(aLayer->GetTransform(), currentTransform); michael@0: michael@0: const ViewConfig& config = view->GetViewConfig(); michael@0: // With temporary scale we should compensate translation michael@0: // using temporary scale value michael@0: aTempScaleDiffX *= GetXScale(shadowTransform) * config.mXScale; michael@0: aTempScaleDiffY *= GetYScale(shadowTransform) * config.mYScale; michael@0: ViewTransform viewTransform = ComputeShadowTreeTransform( michael@0: aFrame, aFrameLoader, metrics, view->GetViewConfig(), michael@0: aTempScaleDiffX, aTempScaleDiffY michael@0: ); michael@0: michael@0: // Apply the layer's own transform *before* the view transform michael@0: shadowTransform = gfx3DMatrix(viewTransform) * currentTransform; michael@0: michael@0: layerTransform = viewTransform; michael@0: if (metrics->IsRootScrollable()) { michael@0: // Apply the translation *before* we do the rest of the transforms. michael@0: nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); michael@0: shadowTransform = shadowTransform * michael@0: gfx3DMatrix::Translation(float(offset.x), float(offset.y), 0.0); michael@0: } michael@0: } michael@0: michael@0: if (aLayer->GetIsFixedPosition() && michael@0: !aLayer->GetParent()->GetIsFixedPosition()) { michael@0: // Alter the shadow transform of fixed position layers in the situation michael@0: // that the view transform's scroll position doesn't match the actual michael@0: // scroll position, due to asynchronous layer scrolling. michael@0: float offsetX = layerTransform.mTranslation.x; michael@0: float offsetY = layerTransform.mTranslation.y; michael@0: ReverseTranslate(shadowTransform, gfxPoint(offsetX, offsetY)); michael@0: const nsIntRect* clipRect = shadow->GetShadowClipRect(); michael@0: if (clipRect) { michael@0: nsIntRect transformedClipRect(*clipRect); michael@0: transformedClipRect.MoveBy(-offsetX, -offsetY); michael@0: shadow->SetShadowClipRect(&transformedClipRect); michael@0: } michael@0: } michael@0: michael@0: // The transform already takes the resolution scale into account. Since we michael@0: // will apply the resolution scale again when computing the effective michael@0: // transform, we must apply the inverse resolution scale here. michael@0: if (ContainerLayer* c = aLayer->AsContainerLayer()) { michael@0: shadowTransform.Scale(1.0f/c->GetPreXScale(), michael@0: 1.0f/c->GetPreYScale(), michael@0: 1); michael@0: } michael@0: shadowTransform.ScalePost(1.0f/aLayer->GetPostXScale(), michael@0: 1.0f/aLayer->GetPostYScale(), michael@0: 1); michael@0: michael@0: gfx::Matrix4x4 realShadowTransform; michael@0: ToMatrix4x4(shadowTransform, realShadowTransform); michael@0: shadow->SetShadowTransform(realShadowTransform); michael@0: for (Layer* child = aLayer->GetFirstChild(); michael@0: child; child = child->GetNextSibling()) { michael@0: TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform, michael@0: aTempScaleDiffX, aTempScaleDiffY); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: ClearContainer(ContainerLayer* aContainer) michael@0: { michael@0: while (Layer* layer = aContainer->GetFirstChild()) { michael@0: aContainer->RemoveChild(layer); michael@0: } michael@0: } michael@0: michael@0: // Return true iff |aManager| is a "temporary layer manager". They're michael@0: // used for small software rendering tasks, like drawWindow. That's michael@0: // currently implemented by a BasicLayerManager without a backing michael@0: // widget, and hence in non-retained mode. michael@0: inline static bool michael@0: IsTempLayerManager(LayerManager* aManager) michael@0: { michael@0: return (mozilla::layers::LayersBackend::LAYERS_BASIC == aManager->GetBackendType() && michael@0: !static_cast(aManager)->IsRetained()); michael@0: } michael@0: michael@0: // Recursively create a new array of scrollables, preserving any scrollables michael@0: // that are still in the layer tree. michael@0: // michael@0: // aXScale and aYScale are used to calculate any values that need to be in michael@0: // chrome-document CSS pixels and aren't part of the rendering loop, such as michael@0: // the initial scroll offset for a new view. michael@0: static void michael@0: BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews, michael@0: nsFrameLoader* aFrameLoader, Layer* aLayer, michael@0: float aXScale = 1, float aYScale = 1, michael@0: float aAccConfigXScale = 1, float aAccConfigYScale = 1) michael@0: { michael@0: ContainerLayer* container = aLayer->AsContainerLayer(); michael@0: if (!container) michael@0: return; michael@0: const FrameMetrics metrics = container->GetFrameMetrics(); michael@0: const ViewID scrollId = metrics.GetScrollId(); michael@0: gfx3DMatrix transform; michael@0: To3DMatrix(aLayer->GetTransform(), transform); michael@0: aXScale *= GetXScale(transform); michael@0: aYScale *= GetYScale(transform); michael@0: michael@0: if (metrics.IsScrollable()) { michael@0: nscoord auPerDevPixel = aFrameLoader->GetPrimaryFrameOfOwningContent() michael@0: ->PresContext()->AppUnitsPerDevPixel(); michael@0: nscoord auPerCSSPixel = auPerDevPixel * metrics.mDevPixelsPerCSSPixel.scale; michael@0: nsContentView* view = FindViewForId(oldContentViews, scrollId); michael@0: if (view) { michael@0: // View already exists. Be sure to propagate scales for any values michael@0: // that need to be calculated something in chrome-doc CSS pixels. michael@0: ViewConfig config = view->GetViewConfig(); michael@0: aXScale *= config.mXScale; michael@0: aYScale *= config.mYScale; michael@0: view->mFrameLoader = aFrameLoader; michael@0: // If scale has changed, then we should update michael@0: // current scroll offset to new scaled value michael@0: if (aAccConfigXScale != view->mParentScaleX || michael@0: aAccConfigYScale != view->mParentScaleY) { michael@0: float xscroll = 0, yscroll = 0; michael@0: view->GetScrollX(&xscroll); michael@0: view->GetScrollY(&yscroll); michael@0: xscroll = xscroll * (aAccConfigXScale / view->mParentScaleX); michael@0: yscroll = yscroll * (aAccConfigYScale / view->mParentScaleY); michael@0: view->ScrollTo(xscroll, yscroll); michael@0: view->mParentScaleX = aAccConfigXScale; michael@0: view->mParentScaleY = aAccConfigYScale; michael@0: } michael@0: // Collect only config scale values for scroll compensation michael@0: aAccConfigXScale *= config.mXScale; michael@0: aAccConfigYScale *= config.mYScale; michael@0: } else { michael@0: // View doesn't exist, so generate one. We start the view scroll offset at michael@0: // the same position as the framemetric's scroll offset from the layer. michael@0: // The default scale is 1, so no need to propagate scale down. michael@0: ViewConfig config; michael@0: config.mScrollOffset = nsPoint( michael@0: NSIntPixelsToAppUnits(metrics.GetScrollOffset().x, auPerCSSPixel) * aXScale, michael@0: NSIntPixelsToAppUnits(metrics.GetScrollOffset().y, auPerCSSPixel) * aYScale); michael@0: view = new nsContentView(aFrameLoader, scrollId, metrics.mIsRoot, config); michael@0: view->mParentScaleX = aAccConfigXScale; michael@0: view->mParentScaleY = aAccConfigYScale; michael@0: } michael@0: michael@0: // I don't know what units mViewportSize is in, hence use ToUnknownRect michael@0: // here to mark the current frontier in type info propagation michael@0: gfx::Rect viewport = metrics.mViewport.ToUnknownRect(); michael@0: view->mViewportSize = nsSize( michael@0: NSIntPixelsToAppUnits(viewport.width, auPerDevPixel) * aXScale, michael@0: NSIntPixelsToAppUnits(viewport.height, auPerDevPixel) * aYScale); michael@0: view->mContentSize = nsSize( michael@0: NSFloatPixelsToAppUnits(metrics.mScrollableRect.width, auPerCSSPixel) * aXScale, michael@0: NSFloatPixelsToAppUnits(metrics.mScrollableRect.height, auPerCSSPixel) * aYScale); michael@0: michael@0: newContentViews[scrollId] = view; michael@0: } michael@0: michael@0: for (Layer* child = aLayer->GetFirstChild(); michael@0: child; child = child->GetNextSibling()) { michael@0: BuildViewMap(oldContentViews, newContentViews, aFrameLoader, child, michael@0: aXScale, aYScale, aAccConfigXScale, aAccConfigYScale); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: BuildBackgroundPatternFor(ContainerLayer* aContainer, michael@0: Layer* aShadowRoot, michael@0: const ViewConfig& aConfig, michael@0: const gfxRGBA& aColor, michael@0: LayerManager* aManager, michael@0: nsIFrame* aFrame) michael@0: { michael@0: LayerComposite* shadowRoot = aShadowRoot->AsLayerComposite(); michael@0: gfx::Matrix t; michael@0: if (!shadowRoot->GetShadowTransform().Is2D(&t)) { michael@0: return; michael@0: } michael@0: michael@0: // Get the rect bounding the shadow content, transformed into the michael@0: // same space as |aFrame| michael@0: nsIntRect contentBounds = shadowRoot->GetShadowVisibleRegion().GetBounds(); michael@0: gfxRect contentVis(contentBounds.x, contentBounds.y, michael@0: contentBounds.width, contentBounds.height); michael@0: gfxRect localContentVis(gfx::ThebesMatrix(t).Transform(contentVis)); michael@0: // Round *in* here because this area is punched out of the background michael@0: localContentVis.RoundIn(); michael@0: nsIntRect localIntContentVis(localContentVis.X(), localContentVis.Y(), michael@0: localContentVis.Width(), localContentVis.Height()); michael@0: michael@0: // Get the frame's rect michael@0: nscoord auPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: nsIntRect frameRect = aFrame->GetRect().ToOutsidePixels(auPerDevPixel); michael@0: michael@0: // If the shadow tree covers the frame rect, don't bother building michael@0: // the background, it wouldn't be visible michael@0: if (localIntContentVis.Contains(frameRect)) { michael@0: return; michael@0: } michael@0: nsRefPtr layer = aManager->CreateColorLayer(); michael@0: layer->SetColor(aColor); michael@0: michael@0: // The visible area of the background is the frame's area minus the michael@0: // content area michael@0: nsIntRegion bgRgn(frameRect); michael@0: bgRgn.Sub(bgRgn, localIntContentVis); michael@0: bgRgn.MoveBy(-frameRect.TopLeft()); michael@0: layer->SetVisibleRegion(bgRgn); michael@0: michael@0: aContainer->InsertAfter(layer, nullptr); michael@0: } michael@0: michael@0: already_AddRefed michael@0: GetFrom(nsFrameLoader* aFrameLoader) michael@0: { michael@0: nsIDocument* doc = aFrameLoader->GetOwnerDoc(); michael@0: return nsContentUtils::LayerManagerForDocument(doc); michael@0: } michael@0: michael@0: class RemoteContentController : public GeckoContentController { michael@0: public: michael@0: RemoteContentController(RenderFrameParent* aRenderFrame) michael@0: : mUILoop(MessageLoop::current()) michael@0: , mRenderFrame(aRenderFrame) michael@0: , mHaveZoomConstraints(false) michael@0: { } michael@0: michael@0: virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE michael@0: { michael@0: // We always need to post requests into the "UI thread" otherwise the michael@0: // requests may get processed out of order. michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::DoRequestContentRepaint, michael@0: aFrameMetrics)); michael@0: } michael@0: michael@0: virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, michael@0: const uint32_t& aScrollGeneration) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: // We have to send this message from the "UI thread" (main michael@0: // thread). michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate, michael@0: aScrollId, aScrollGeneration)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->AcknowledgeScrollUpdate(aScrollId, aScrollGeneration); michael@0: } michael@0: } michael@0: michael@0: virtual void HandleDoubleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: // We have to send this message from the "UI thread" (main michael@0: // thread). michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap, michael@0: aPoint, aModifiers, aGuid)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->HandleDoubleTap(aPoint, aModifiers, aGuid); michael@0: } michael@0: } michael@0: michael@0: virtual void HandleSingleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: // We have to send this message from the "UI thread" (main michael@0: // thread). michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::HandleSingleTap, michael@0: aPoint, aModifiers, aGuid)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->HandleSingleTap(aPoint, aModifiers, aGuid); michael@0: } michael@0: } michael@0: michael@0: virtual void HandleLongTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: // We have to send this message from the "UI thread" (main michael@0: // thread). michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::HandleLongTap, michael@0: aPoint, aModifiers, aGuid)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->HandleLongTap(aPoint, aModifiers, aGuid); michael@0: } michael@0: } michael@0: michael@0: virtual void HandleLongTapUp(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid& aGuid) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: // We have to send this message from the "UI thread" (main michael@0: // thread). michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::HandleLongTapUp, michael@0: aPoint, aModifiers, aGuid)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->HandleLongTapUp(aPoint, aModifiers, aGuid); michael@0: } michael@0: } michael@0: michael@0: void ClearRenderFrame() { mRenderFrame = nullptr; } michael@0: michael@0: virtual void SendAsyncScrollDOMEvent(bool aIsRoot, michael@0: const CSSRect& aContentRect, michael@0: const CSSSize& aContentSize) MOZ_OVERRIDE michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, michael@0: &RemoteContentController::SendAsyncScrollDOMEvent, michael@0: aIsRoot, aContentRect, aContentSize)); michael@0: return; michael@0: } michael@0: if (mRenderFrame && aIsRoot) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect, michael@0: aContentSize); michael@0: } michael@0: } michael@0: michael@0: virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE michael@0: { michael@0: MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs); michael@0: } michael@0: michael@0: virtual bool GetRootZoomConstraints(ZoomConstraints* aOutConstraints) michael@0: { michael@0: if (mHaveZoomConstraints && aOutConstraints) { michael@0: *aOutConstraints = mZoomConstraints; michael@0: } michael@0: return mHaveZoomConstraints; michael@0: } michael@0: michael@0: virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) michael@0: { michael@0: if (mTouchSensitiveRegion.IsEmpty()) michael@0: return false; michael@0: michael@0: *aOutRegion = CSSRect::FromAppUnits(mTouchSensitiveRegion.GetBounds()); michael@0: return true; michael@0: } michael@0: michael@0: virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, michael@0: APZStateChange aChange, michael@0: int aArg) michael@0: { michael@0: if (MessageLoop::current() != mUILoop) { michael@0: mUILoop->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange, michael@0: aGuid, aChange, aArg)); michael@0: return; michael@0: } michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->NotifyAPZStateChange(aGuid.mScrollId, aChange, aArg); michael@0: } michael@0: } michael@0: michael@0: // Methods used by RenderFrameParent to set fields stored here. michael@0: michael@0: void SaveZoomConstraints(const ZoomConstraints& aConstraints) michael@0: { michael@0: mHaveZoomConstraints = true; michael@0: mZoomConstraints = aConstraints; michael@0: } michael@0: michael@0: void SetTouchSensitiveRegion(const nsRegion& aRegion) michael@0: { michael@0: mTouchSensitiveRegion = aRegion; michael@0: } michael@0: private: michael@0: void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics) michael@0: { michael@0: if (mRenderFrame) { michael@0: TabParent* browser = static_cast(mRenderFrame->Manager()); michael@0: browser->UpdateFrame(aFrameMetrics); michael@0: } michael@0: } michael@0: michael@0: MessageLoop* mUILoop; michael@0: RenderFrameParent* mRenderFrame; michael@0: michael@0: bool mHaveZoomConstraints; michael@0: ZoomConstraints mZoomConstraints; michael@0: nsRegion mTouchSensitiveRegion; michael@0: }; michael@0: michael@0: RenderFrameParent::RenderFrameParent() michael@0: : mLayersId(0) michael@0: , mFrameLoaderDestroyed(false) michael@0: , mBackgroundColor(gfxRGBA(1, 1, 1)) michael@0: { michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::Init(nsFrameLoader* aFrameLoader, michael@0: ScrollingBehavior aScrollingBehavior, michael@0: TextureFactoryIdentifier* aTextureFactoryIdentifier, michael@0: uint64_t* aId) michael@0: { michael@0: mFrameLoader = aFrameLoader; michael@0: michael@0: *aId = 0; michael@0: michael@0: nsRefPtr lm = GetFrom(mFrameLoader); michael@0: // Perhaps the document containing this frame currently has no presentation? michael@0: if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { michael@0: *aTextureFactoryIdentifier = michael@0: static_cast(lm.get())->GetTextureFactoryIdentifier(); michael@0: } else { michael@0: *aTextureFactoryIdentifier = TextureFactoryIdentifier(); michael@0: } michael@0: michael@0: if (lm && lm->GetRoot() && lm->GetRoot()->AsContainerLayer()) { michael@0: ViewID rootScrollId = lm->GetRoot()->AsContainerLayer()->GetFrameMetrics().GetScrollId(); michael@0: if (rootScrollId != FrameMetrics::NULL_SCROLL_ID) { michael@0: mContentViews[rootScrollId] = new nsContentView(aFrameLoader, rootScrollId, true); michael@0: } michael@0: } michael@0: michael@0: if (CompositorParent::CompositorLoop()) { michael@0: // Our remote frame will push layers updates to the compositor, michael@0: // and we'll keep an indirect reference to that tree. michael@0: *aId = mLayersId = CompositorParent::AllocateLayerTreeId(); michael@0: if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { michael@0: ClientLayerManager *clientManager = static_cast(lm.get()); michael@0: clientManager->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId); michael@0: } michael@0: if (aScrollingBehavior == ASYNC_PAN_ZOOM) { michael@0: mContentController = new RemoteContentController(this); michael@0: CompositorParent::SetControllerForLayerTree(mLayersId, mContentController); michael@0: } michael@0: } michael@0: // Set a default RenderFrameParent michael@0: mFrameLoader->SetCurrentRemoteFrame(this); michael@0: } michael@0: michael@0: APZCTreeManager* michael@0: RenderFrameParent::GetApzcTreeManager() michael@0: { michael@0: // We can't get a ref to the APZCTreeManager until after the child is michael@0: // created and the static getter knows which CompositorParent is michael@0: // instantiated with this layers ID. That's why try to fetch it when michael@0: // we first need it and cache the result. michael@0: if (!mApzcTreeManager) { michael@0: mApzcTreeManager = CompositorParent::GetAPZCTreeManager(mLayersId); michael@0: } michael@0: return mApzcTreeManager.get(); michael@0: } michael@0: michael@0: RenderFrameParent::~RenderFrameParent() michael@0: {} michael@0: michael@0: void michael@0: RenderFrameParent::Destroy() michael@0: { michael@0: size_t numChildren = ManagedPLayerTransactionParent().Length(); michael@0: NS_ABORT_IF_FALSE(0 == numChildren || 1 == numChildren, michael@0: "render frame must only have 0 or 1 layer manager"); michael@0: michael@0: if (numChildren) { michael@0: LayerTransactionParent* layers = michael@0: static_cast(ManagedPLayerTransactionParent()[0]); michael@0: layers->Destroy(); michael@0: } michael@0: michael@0: mFrameLoaderDestroyed = true; michael@0: } michael@0: michael@0: nsContentView* michael@0: RenderFrameParent::GetContentView(ViewID aId) michael@0: { michael@0: return FindViewForId(mContentViews, aId); michael@0: } michael@0: michael@0: nsContentView* michael@0: RenderFrameParent::GetRootContentView() michael@0: { michael@0: return FindRootView(mContentViews); michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::ContentViewScaleChanged(nsContentView* aView) michael@0: { michael@0: // Since the scale has changed for a view, it and its descendents need their michael@0: // shadow-space attributes updated. It's easiest to rebuild the view map. michael@0: BuildViewMap(); michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, michael@0: const TargetConfig& aTargetConfig, michael@0: bool aIsFirstPaint, michael@0: bool aScheduleComposite) michael@0: { michael@0: // View map must only contain views that are associated with the current michael@0: // shadow layer tree. We must always update the map when shadow layers michael@0: // are updated. michael@0: BuildViewMap(); michael@0: michael@0: TriggerRepaint(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: LayerManager* aManager, michael@0: const nsIntRect& aVisibleRect, michael@0: nsDisplayItem* aItem, michael@0: const ContainerLayerParameters& aContainerParameters) michael@0: { michael@0: NS_ABORT_IF_FALSE(aFrame, michael@0: "makes no sense to have a shadow tree without a frame"); michael@0: NS_ABORT_IF_FALSE(!mContainer || michael@0: IsTempLayerManager(aManager) || michael@0: mContainer->Manager() == aManager, michael@0: "retaining manager changed out from under us ... HELP!"); michael@0: michael@0: if (IsTempLayerManager(aManager) || michael@0: (mContainer && mContainer->Manager() != aManager)) { michael@0: // This can happen if aManager is a "temporary" manager, or if the michael@0: // widget's layer manager changed out from under us. We need to michael@0: // FIXME handle the former case somehow, probably with an API to michael@0: // draw a manager's subtree. The latter is bad bad bad, but the michael@0: // the NS_ABORT_IF_FALSE() above will flag it. Returning nullptr michael@0: // here will just cause the shadow subtree not to be rendered. michael@0: NS_WARNING("Remote iframe not rendered"); michael@0: return nullptr; michael@0: } michael@0: michael@0: uint64_t id = GetLayerTreeId(); michael@0: if (0 != id) { michael@0: MOZ_ASSERT(!GetRootLayer()); michael@0: michael@0: nsRefPtr layer = michael@0: (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); michael@0: if (!layer) { michael@0: layer = aManager->CreateRefLayer(); michael@0: } michael@0: if (!layer) { michael@0: // Probably a temporary layer manager that doesn't know how to michael@0: // use ref layers. michael@0: return nullptr; michael@0: } michael@0: static_cast(layer.get())->SetReferentId(id); michael@0: nsIntPoint offset = GetContentRectLayerOffset(aFrame, aBuilder); michael@0: layer->SetVisibleRegion(aVisibleRect - offset); michael@0: // We can only have an offset if we're a child of an inactive michael@0: // container, but our display item is LAYER_ACTIVE_FORCE which michael@0: // forces all layers above to be active. michael@0: MOZ_ASSERT(aContainerParameters.mOffset == nsIntPoint()); michael@0: gfx::Matrix4x4 m; michael@0: m.Translate(offset.x, offset.y, 0.0); michael@0: // Remote content can't be repainted by us, so we multiply down michael@0: // the resolution that our container expects onto our container. michael@0: m.Scale(aContainerParameters.mXScale, aContainerParameters.mYScale, 1.0); michael@0: layer->SetBaseTransform(m); michael@0: michael@0: return layer.forget(); michael@0: } michael@0: michael@0: if (mContainer) { michael@0: ClearContainer(mContainer); michael@0: mContainer->SetPreScale(1.0f, 1.0f); michael@0: mContainer->SetPostScale(1.0f, 1.0f); michael@0: mContainer->SetInheritedScale(1.0f, 1.0f); michael@0: } michael@0: michael@0: Layer* shadowRoot = GetRootLayer(); michael@0: if (!shadowRoot) { michael@0: mContainer = nullptr; michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_ABORT_IF_FALSE(!shadowRoot || shadowRoot->Manager() == aManager, michael@0: "retaining manager changed out from under us ... HELP!"); michael@0: michael@0: // Wrap the shadow layer tree in mContainer. michael@0: if (!mContainer) { michael@0: mContainer = aManager->CreateContainerLayer(); michael@0: } michael@0: NS_ABORT_IF_FALSE(!mContainer->GetFirstChild(), michael@0: "container of shadow tree shouldn't have a 'root' here"); michael@0: michael@0: mContainer->InsertAfter(shadowRoot, nullptr); michael@0: michael@0: AssertInTopLevelChromeDoc(mContainer, aFrame); michael@0: ViewTransform transform; michael@0: TransformShadowTree(aBuilder, mFrameLoader, aFrame, shadowRoot, transform); michael@0: mContainer->SetClipRect(nullptr); michael@0: michael@0: if (mFrameLoader->AsyncScrollEnabled()) { michael@0: const nsContentView* view = GetRootContentView(); michael@0: BuildBackgroundPatternFor(mContainer, michael@0: shadowRoot, michael@0: view->GetViewConfig(), michael@0: mBackgroundColor, michael@0: aManager, aFrame); michael@0: } michael@0: mContainer->SetVisibleRegion(aVisibleRect); michael@0: michael@0: return nsRefPtr(mContainer).forget(); michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::OwnerContentChanged(nsIContent* aContent) michael@0: { michael@0: NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent, michael@0: "Don't build new map if owner is same!"); michael@0: BuildViewMap(); michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::NotifyInputEvent(WidgetInputEvent& aEvent, michael@0: ScrollableLayerGuid* aOutTargetGuid) michael@0: { michael@0: if (GetApzcTreeManager()) { michael@0: GetApzcTreeManager()->ReceiveInputEvent(aEvent, aOutTargetGuid); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (mLayersId != 0) { michael@0: CompositorParent::DeallocateLayerTreeId(mLayersId); michael@0: if (mContentController) { michael@0: // Stop our content controller from requesting repaints of our michael@0: // content. michael@0: mContentController->ClearRenderFrame(); michael@0: // TODO: notify the compositor? michael@0: } michael@0: } michael@0: michael@0: if (mFrameLoader && mFrameLoader->GetCurrentRemoteFrame() == this) { michael@0: // XXX this might cause some weird issues ... we'll just not michael@0: // redraw the part of the window covered by this until the "next" michael@0: // remote frame has a layer-tree transaction. For michael@0: // why==NormalShutdown, we'll definitely want to do something michael@0: // better, especially as nothing guarantees another Update() from michael@0: // the "next" remote layer tree. michael@0: mFrameLoader->SetCurrentRemoteFrame(nullptr); michael@0: } michael@0: mFrameLoader = nullptr; michael@0: } michael@0: michael@0: bool michael@0: RenderFrameParent::RecvNotifyCompositorTransaction() michael@0: { michael@0: TriggerRepaint(); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: RenderFrameParent::RecvUpdateHitRegion(const nsRegion& aRegion) michael@0: { michael@0: mTouchRegion = aRegion; michael@0: if (mContentController) { michael@0: // Tell the content controller about the touch-sensitive region, so michael@0: // that it can provide it to APZ. This is required for APZ to do michael@0: // correct hit testing for a remote 'mozpasspointerevents' iframe michael@0: // until bug 928833 is fixed. michael@0: mContentController->SetTouchSensitiveRegion(aRegion); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: PLayerTransactionParent* michael@0: RenderFrameParent::AllocPLayerTransactionParent() michael@0: { michael@0: if (!mFrameLoader || mFrameLoaderDestroyed) { michael@0: return nullptr; michael@0: } michael@0: nsRefPtr lm = GetFrom(mFrameLoader); michael@0: LayerTransactionParent* result = new LayerTransactionParent(lm->AsLayerManagerComposite(), this, 0); michael@0: result->AddIPDLReference(); michael@0: return result; michael@0: } michael@0: michael@0: bool michael@0: RenderFrameParent::DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) michael@0: { michael@0: static_cast(aLayers)->ReleaseIPDLReference(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::BuildViewMap() michael@0: { michael@0: ViewMap newContentViews; michael@0: // BuildViewMap assumes we have a primary frame, which may not be the case. michael@0: if (GetRootLayer() && mFrameLoader->GetPrimaryFrameOfOwningContent()) { michael@0: // Some of the content views in our hash map may no longer be active. To michael@0: // tag them as inactive and to remove any chance of them using a dangling michael@0: // pointer, we set mContentView to nullptr. michael@0: // michael@0: // BuildViewMap will restore mFrameLoader if the content view is still michael@0: // in our hash table. michael@0: michael@0: for (ViewMap::const_iterator iter = mContentViews.begin(); michael@0: iter != mContentViews.end(); michael@0: ++iter) { michael@0: iter->second->mFrameLoader = nullptr; michael@0: } michael@0: michael@0: mozilla::layout::BuildViewMap(mContentViews, newContentViews, mFrameLoader, GetRootLayer()); michael@0: } michael@0: michael@0: // Here, we guarantee that *only* the root view is preserved in michael@0: // case we couldn't build a new view map above. This is important because michael@0: // the content view map should only contain the root view and content michael@0: // views that are present in the layer tree. michael@0: if (newContentViews.empty()) { michael@0: nsContentView* rootView = FindRootView(mContentViews); michael@0: if (rootView) michael@0: newContentViews[rootView->GetId()] = rootView; michael@0: } michael@0: michael@0: mContentViews = newContentViews; michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::TriggerRepaint() michael@0: { michael@0: mFrameLoader->SetCurrentRemoteFrame(this); michael@0: michael@0: nsIFrame* docFrame = mFrameLoader->GetPrimaryFrameOfOwningContent(); michael@0: if (!docFrame) { michael@0: // Bad, but nothing we can do about it (XXX/cjones: or is there? michael@0: // maybe bug 589337?). When the new frame is created, we'll michael@0: // probably still be the current render frame and will get to draw michael@0: // our content then. Or, we're shutting down and this update goes michael@0: // to /dev/null. michael@0: return; michael@0: } michael@0: michael@0: docFrame->InvalidateLayer(nsDisplayItem::TYPE_REMOTE); michael@0: } michael@0: michael@0: LayerTransactionParent* michael@0: RenderFrameParent::GetShadowLayers() const michael@0: { michael@0: const InfallibleTArray& shadowParents = ManagedPLayerTransactionParent(); michael@0: NS_ABORT_IF_FALSE(shadowParents.Length() <= 1, michael@0: "can only support at most 1 LayerTransactionParent"); michael@0: return (shadowParents.Length() == 1) ? michael@0: static_cast(shadowParents[0]) : nullptr; michael@0: } michael@0: michael@0: uint64_t michael@0: RenderFrameParent::GetLayerTreeId() const michael@0: { michael@0: return mLayersId; michael@0: } michael@0: michael@0: Layer* michael@0: RenderFrameParent::GetRootLayer() const michael@0: { michael@0: LayerTransactionParent* shadowLayers = GetShadowLayers(); michael@0: return shadowLayers ? shadowLayers->GetRoot() : nullptr; michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::BuildDisplayList(nsDisplayListBuilder* aBuilder, michael@0: nsSubDocumentFrame* aFrame, michael@0: const nsRect& aDirtyRect, michael@0: const nsDisplayListSet& aLists) michael@0: { michael@0: // We're the subdoc for and it has michael@0: // painted content. Display its shadow layer tree. michael@0: DisplayListClipState::AutoSaveRestore clipState(aBuilder); michael@0: michael@0: nsPoint offset = aBuilder->ToReferenceFrame(aFrame); michael@0: nsRect bounds = aFrame->EnsureInnerView()->GetBounds() + offset; michael@0: clipState.ClipContentDescendants(bounds); michael@0: michael@0: Layer* container = GetRootLayer(); michael@0: if (aBuilder->IsForEventDelivery() && container) { michael@0: ViewTransform offset = michael@0: ViewTransform(GetContentRectLayerOffset(aFrame, aBuilder)); michael@0: BuildListForLayer(container, mFrameLoader, offset, michael@0: aBuilder, *aLists.Content(), aFrame); michael@0: } else { michael@0: aLists.Content()->AppendToTop( michael@0: new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::ZoomToRect(uint32_t aPresShellId, ViewID aViewId, michael@0: const CSSRect& aRect) michael@0: { michael@0: if (GetApzcTreeManager()) { michael@0: GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId), michael@0: aRect); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::ContentReceivedTouch(const ScrollableLayerGuid& aGuid, michael@0: bool aPreventDefault) michael@0: { michael@0: if (aGuid.mLayersId != mLayersId) { michael@0: // Guard against bad data from hijacked child processes michael@0: NS_ERROR("Unexpected layers id in ContentReceivedTouch; dropping message..."); michael@0: return; michael@0: } michael@0: if (GetApzcTreeManager()) { michael@0: GetApzcTreeManager()->ContentReceivedTouch(aGuid, aPreventDefault); michael@0: } michael@0: } michael@0: michael@0: void michael@0: RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId, michael@0: ViewID aViewId, michael@0: bool aIsRoot, michael@0: const ZoomConstraints& aConstraints) michael@0: { michael@0: if (mContentController && aIsRoot) { michael@0: mContentController->SaveZoomConstraints(aConstraints); michael@0: } michael@0: if (GetApzcTreeManager()) { michael@0: GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId), michael@0: aConstraints); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: RenderFrameParent::HitTest(const nsRect& aRect) michael@0: { michael@0: return mTouchRegion.Contains(aRect); michael@0: } michael@0: michael@0: } // namespace layout michael@0: } // namespace mozilla michael@0: michael@0: already_AddRefed michael@0: nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder, michael@0: LayerManager* aManager, michael@0: const ContainerLayerParameters& aContainerParameters) michael@0: { michael@0: int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); michael@0: nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel); michael@0: visibleRect += aContainerParameters.mOffset; michael@0: nsRefPtr layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters); michael@0: return layer.forget(); michael@0: } michael@0: michael@0: void michael@0: nsDisplayRemote::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) michael@0: { michael@0: if (mRemoteFrame->HitTest(aRect)) { michael@0: aOutFrames->AppendElement(mFrame); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsDisplayRemoteShadow::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, michael@0: HitTestState* aState, nsTArray *aOutFrames) michael@0: { michael@0: // If we are here, then rects have intersected. michael@0: // michael@0: // XXX I think iframes and divs can be rounded like anything else but we don't michael@0: // cover that case here. michael@0: // michael@0: if (aState->mShadows) { michael@0: aState->mShadows->AppendElement(mId); michael@0: } michael@0: }