// Go down shadow layer tree and apply transformations for scrollable layers. static void TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader, nsIFrame* aFrame, Layer* aLayer, const ViewTransform& aTransform) { ShadowLayer* shadow = aLayer->AsShadowLayer(); shadow->SetShadowClipRect(aLayer->GetClipRect()); shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); const FrameMetrics* metrics = GetFrameMetrics(aLayer); gfx3DMatrix shadowTransform; ViewTransform layerTransform = aTransform; if (metrics && metrics->IsScrollable()) { const ViewID scrollId = metrics->mScrollId; const nsContentView* view = aFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); NS_ABORT_IF_FALSE(view, "Array of views should be consistent with layer tree"); const gfx3DMatrix& currentTransform = aLayer->GetTransform(); ViewTransform viewTransform = ComputeShadowTreeTransform( aFrame, aFrameLoader, metrics, view->GetViewConfig(), 1 / (GetXScale(currentTransform)*layerTransform.mXScale), 1 / (GetYScale(currentTransform)*layerTransform.mYScale) ); // Apply the layer's own transform *before* the view transform shadowTransform = gfx3DMatrix(viewTransform) * currentTransform; if (metrics->IsRootScrollable()) { layerTransform.mTranslation = viewTransform.mTranslation; // Apply the root frame translation *before* we do the rest of the transforms. nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder); shadowTransform = shadowTransform * gfx3DMatrix::Translation(float(rootFrameOffset.x), float(rootFrameOffset.y), 0.0); layerTransform.mXScale *= GetXScale(currentTransform); layerTransform.mYScale *= GetYScale(currentTransform); } } else { shadowTransform = aLayer->GetTransform(); } if (aLayer->GetIsFixedPosition() && !aLayer->GetParent()->GetIsFixedPosition()) { ReverseTranslate(shadowTransform, layerTransform); const nsIntRect* clipRect = shadow->GetShadowClipRect(); if (clipRect) { nsIntRect transformedClipRect(*clipRect); transformedClipRect.MoveBy(shadowTransform._41, shadowTransform._42); shadow->SetShadowClipRect(&transformedClipRect); } } shadow->SetShadowTransform(shadowTransform); for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { TransformShadowTree(aBuilder, aFrameLoader, aFrame, child, layerTransform); } }
bool Axis::ScaleWillOverscrollBothSides(float aScale) { const FrameMetrics& metrics = GetFrameMetrics(); CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale); CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale; return GetRectLength(cssCompositionBounds) - GetRectLength(metrics.GetExpandedScrollableRect()) > COORDINATE_EPSILON; }
void ContainerLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs) { aAttrs = ContainerLayerAttributes(GetFrameMetrics(), mScrollHandoffParentId, mPreXScale, mPreYScale, mInheritedXScale, mInheritedYScale, mBackgroundColor); }
// Use shadow layer tree to build display list for the browser's frame. static void BuildListForLayer(Layer* aLayer, nsFrameLoader* aRootFrameLoader, const gfx3DMatrix& aTransform, nsDisplayListBuilder* aBuilder, nsDisplayList& aShadowTree, nsIFrame* aSubdocFrame) { const FrameMetrics* metrics = GetFrameMetrics(aLayer); gfx3DMatrix transform; if (metrics && metrics->IsScrollable()) { const ViewID scrollId = metrics->mScrollId; // We need to figure out the bounds of the scrollable region using the // shadow layer tree from the remote process. The metrics viewport is // defined based on all the transformations of its parent layers and // the scale of the current layer. // Calculate transform for this layer. nsContentView* view = aRootFrameLoader->GetCurrentRemoteFrame()->GetContentView(scrollId); // XXX why don't we include aLayer->GetTransform() in the inverse-scale here? // This seems wrong, but it doesn't seem to cause bugs! gfx3DMatrix applyTransform = ComputeShadowTreeTransform( aSubdocFrame, aRootFrameLoader, metrics, view->GetViewConfig(), 1 / GetXScale(aTransform), 1 / GetYScale(aTransform)); transform = applyTransform * aLayer->GetTransform() * aTransform; // As mentioned above, bounds calculation also depends on the scale // of this layer. gfx3DMatrix tmpTransform = aTransform; Scale(tmpTransform, GetXScale(applyTransform), GetYScale(applyTransform)); // Calculate rect for this layer based on aTransform. nsRect bounds; { nscoord auPerDevPixel = aSubdocFrame->PresContext()->AppUnitsPerDevPixel(); bounds = metrics->mViewport.ToAppUnits(auPerDevPixel); ApplyTransform(bounds, tmpTransform, auPerDevPixel); } aShadowTree.AppendToTop( new (aBuilder) nsDisplayRemoteShadow(aBuilder, aSubdocFrame, bounds, scrollId)); } else { transform = aLayer->GetTransform() * aTransform; } for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { BuildListForLayer(child, aRootFrameLoader, transform, aBuilder, aShadowTree, aSubdocFrame); } }
AsyncPanZoomController* ContainerLayer::GetAsyncPanZoomController() const { #ifdef DEBUG if (mAPZC) { MOZ_ASSERT(GetFrameMetrics().IsScrollable()); } #endif return mAPZC; }
bool Axis::SampleSnapBack(const TimeDuration& aDelta) { // Apply spring physics to the snap-back as time goes on. // Note: this method of sampling isn't perfectly smooth, as it assumes // a constant velocity over 'aDelta', instead of an accelerating velocity. // (The way we applying friction to flings has the same issue.) // Hooke's law with damping: // F = -kx - bv // where // k is a constant related to the stiffness of the spring // The larger the constant, the stiffer the spring. // x is the displacement of the end of the spring from its equilibrium // In our scenario, it's the amount of overscroll on the axis. // b is a constant that provides damping (friction) // v is the velocity of the point at the end of the spring // See http://gafferongames.com/game-physics/spring-physics/ const float kSpringStiffness = gfxPrefs::APZOverscrollSnapBackSpringStiffness(); const float kSpringFriction = gfxPrefs::APZOverscrollSnapBackSpringFriction(); const float kMass = gfxPrefs::APZOverscrollSnapBackMass(); float force = -1 * kSpringStiffness * mOverscroll - kSpringFriction * mVelocity; float acceleration = force / kMass; mVelocity += acceleration * aDelta.ToMilliseconds(); float screenDisplacement = mVelocity * aDelta.ToMilliseconds(); float cssDisplacement = screenDisplacement / GetFrameMetrics().GetZoom().scale; if (mOverscroll > 0) { if (cssDisplacement > 0) { NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!"); return false; } mOverscroll = std::max(mOverscroll + cssDisplacement, 0.0f); // Overscroll relieved, do not continue animation. if (mOverscroll == 0.f) { mVelocity = 0; return false; } return true; } else if (mOverscroll < 0) { if (cssDisplacement < 0) { NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!"); return false; } mOverscroll = std::min(mOverscroll + cssDisplacement, 0.0f); // Overscroll relieved, do not continue animation. if (mOverscroll == 0.f) { mVelocity = 0; return false; } return true; } // No overscroll on this axis, do not continue animation. return false; }
CSSCoord Axis::ClampOriginToScrollableRect(CSSCoord aOrigin) const { CSSToParentLayerScale zoom = GetScaleForAxis(GetFrameMetrics().GetZoom()); ParentLayerCoord origin = aOrigin * zoom; ParentLayerCoord result; if (origin < GetPageStart()) { result = GetPageStart(); } else if (origin + GetCompositionLength() > GetPageEnd()) { result = GetPageEnd() - GetCompositionLength(); } else { return aOrigin; } return result / zoom; }
CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const { // Internally, do computations in ParentLayer coordinates *before* the scale // is applied. CSSToParentLayerScale zoom = GetFrameMetrics().GetZoom().ToScaleFactor(); ParentLayerCoord focus = aFocus * zoom; ParentLayerCoord originAfterScale = (GetOrigin() + focus) - (focus / aScale); bool both = ScaleWillOverscrollBothSides(aScale); bool minus = GetPageStart() - originAfterScale > COORDINATE_EPSILON; bool plus = (originAfterScale + (GetCompositionLength() / aScale)) - GetPageEnd() > COORDINATE_EPSILON; if ((minus && plus) || both) { // If we ever reach here it's a bug in the client code. MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount"); return 0; } if (minus) { return (originAfterScale - GetPageStart()) / zoom; } if (plus) { return (originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd()) / zoom; } return 0; }
ParentLayerCoord Axis::GetCompositionLength() const { return GetRectLength(GetFrameMetrics().GetCompositionBounds()); }
CSSCoord Axis::GetPageLength() const { CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect(); return GetRectLength(pageRect); }
CSSCoord Axis::GetPageStart() const { CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect(); return GetRectOffset(pageRect); }
CSSCoord Axis::GetCompositionLength() const { return GetRectLength(GetFrameMetrics().CalculateCompositedRectInCssPixels()); }
CSSCoord Axis::GetOrigin() const { CSSPoint origin = GetFrameMetrics().GetScrollOffset(); return GetPointOffset(origin); }
bool Axis::ScaleWillOverscrollBothSides(float aScale) const { const FrameMetrics& metrics = GetFrameMetrics(); ParentLayerRect screenCompositionBounds = metrics.GetCompositionBounds() / ParentLayerToParentLayerScale(aScale); return GetRectLength(screenCompositionBounds) - GetPageLength() > COORDINATE_EPSILON; }
ParentLayerCoord Axis::GetPageLength() const { ParentLayerRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() * GetFrameMetrics().GetZoom(); return GetRectLength(pageRect); }
void AsyncPanZoomController::UpdateViewportSize(int aWidth, int aHeight) { MonitorAutoLock mon(mMonitor); FrameMetrics metrics = GetFrameMetrics(); metrics.mViewport = nsIntRect(0, 0, aWidth, aHeight); mFrameMetrics = metrics; }
ParentLayerCoord Axis::GetOrigin() const { ParentLayerPoint origin = GetFrameMetrics().GetScrollOffset() * GetFrameMetrics().GetZoom(); return GetPointOffset(origin); }
void AsyncPanZoomController::UpdateViewportSize(int width, int height) { ReentrantMonitorAutoEnter mon(mReentrantMonitor); FrameMetrics metrics = GetFrameMetrics(); metrics.mViewport = nsIntRect(0, 0, width, height); SetFrameMetrics(metrics); }