SampledAPZCState.cpp (5041B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "SampledAPZCState.h" 8 #include "APZUtils.h" 9 10 namespace mozilla { 11 namespace layers { 12 13 SampledAPZCState::SampledAPZCState() {} 14 15 SampledAPZCState::SampledAPZCState(const FrameMetrics& aMetrics) 16 : mLayoutViewport(aMetrics.GetLayoutViewport()), 17 mVisualScrollOffset(aMetrics.GetVisualScrollOffset()), 18 mZoom(aMetrics.GetZoom()) { 19 RemoveFractionalAsyncDelta(); 20 } 21 22 SampledAPZCState::SampledAPZCState( 23 const FrameMetrics& aMetrics, Maybe<CompositionPayload>&& aPayload, 24 APZScrollGeneration aGeneration, 25 std::vector<CompositorScrollUpdate>&& aUpdates) 26 : mLayoutViewport(aMetrics.GetLayoutViewport()), 27 mVisualScrollOffset(aMetrics.GetVisualScrollOffset()), 28 mZoom(aMetrics.GetZoom()), 29 mScrollPayload(std::move(aPayload)), 30 mGeneration(aGeneration), 31 mUpdates(std::move(aUpdates)) { 32 RemoveFractionalAsyncDelta(); 33 } 34 35 bool SampledAPZCState::operator==(const SampledAPZCState& aOther) const { 36 // The payload doesn't factor into equality, that just comes along for 37 // the ride. 38 // The compositor scroll updates also do not factor into equality. 39 // We can think of those as not describing the current state, but the 40 // process by which we got from the previous state to this one. 41 // The FrameMetrics constructor of SampledAPZCState does not initialize 42 // mUpdates, so we can't rely on them always being present. 43 return mLayoutViewport.IsEqualEdges(aOther.mLayoutViewport) && 44 mVisualScrollOffset == aOther.mVisualScrollOffset && 45 mZoom == aOther.mZoom; 46 } 47 48 bool SampledAPZCState::operator!=(const SampledAPZCState& aOther) const { 49 return !(*this == aOther); 50 } 51 52 Maybe<CompositionPayload> SampledAPZCState::TakeScrollPayload() { 53 return std::move(mScrollPayload); 54 } 55 56 void SampledAPZCState::UpdateScrollProperties(const FrameMetrics& aMetrics) { 57 mLayoutViewport = aMetrics.GetLayoutViewport(); 58 mVisualScrollOffset = aMetrics.GetVisualScrollOffset(); 59 } 60 61 void SampledAPZCState::UpdateScrollPropertiesWithRelativeDelta( 62 const FrameMetrics& aMetrics, const CSSPoint& aRelativeDelta) { 63 mVisualScrollOffset += aRelativeDelta; 64 KeepLayoutViewportEnclosingVisualViewport(aMetrics); 65 } 66 67 void SampledAPZCState::UpdateZoomProperties(const FrameMetrics& aMetrics) { 68 mZoom = aMetrics.GetZoom(); 69 } 70 71 void SampledAPZCState::ClampVisualScrollOffset(const FrameMetrics& aMetrics) { 72 // Make sure that we use the local mZoom to do these calculations, because the 73 // one on aMetrics might be newer. 74 CSSRect scrollRange = FrameMetrics::CalculateScrollRange( 75 aMetrics.GetScrollableRect(), aMetrics.GetCompositionBounds(), mZoom); 76 mVisualScrollOffset = scrollRange.ClampPoint(mVisualScrollOffset); 77 78 KeepLayoutViewportEnclosingVisualViewport(aMetrics); 79 } 80 81 void SampledAPZCState::ZoomBy(float aScale) { mZoom.scale *= aScale; } 82 83 void SampledAPZCState::RemoveFractionalAsyncDelta() { 84 // This function is a performance hack. With non-WebRender, having small 85 // fractional deltas between the layout offset and scroll offset on 86 // container layers can trigger the creation of a temporary surface during 87 // composition, because it produces a non-integer translation that doesn't 88 // play well with layer clips. So we detect the case where the delta is 89 // uselessly small (0.01 parentlayer pixels or less) and tweak the sampled 90 // scroll offset to eliminate it. By doing this here at sample time rather 91 // than elsewhere in the pipeline we are least likely to break assumptions 92 // and invariants elsewhere in the code, since sampling effectively takes 93 // a snapshot of APZ state (decoupling it from APZ assumptions) and provides 94 // it as an input to the compositor (so all compositor state should be 95 // internally consistent based on this input). 96 // TODO(bug 1889267): Now that we use WebRender everywhere, can this hack be 97 // removed? 98 if (mLayoutViewport.TopLeft() == mVisualScrollOffset) { 99 return; 100 } 101 const ParentLayerCoord EPSILON = 0.01; 102 ParentLayerPoint paintedOffset = mLayoutViewport.TopLeft() * mZoom; 103 ParentLayerPoint asyncOffset = mVisualScrollOffset * mZoom; 104 if (FuzzyEqualsAdditive(paintedOffset.x, asyncOffset.x, EPSILON) && 105 FuzzyEqualsAdditive(paintedOffset.y, asyncOffset.y, EPSILON)) { 106 mVisualScrollOffset = mLayoutViewport.TopLeft(); 107 } 108 } 109 110 void SampledAPZCState::KeepLayoutViewportEnclosingVisualViewport( 111 const FrameMetrics& aMetrics) { 112 FrameMetrics::KeepLayoutViewportEnclosingVisualViewport( 113 CSSRect(mVisualScrollOffset, 114 FrameMetrics::CalculateCompositedSizeInCssPixels( 115 aMetrics.GetCompositionBounds(), mZoom)), 116 aMetrics.GetScrollableRect(), mLayoutViewport); 117 } 118 119 } // namespace layers 120 } // namespace mozilla