Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "APZCCallbackHelper.h" |
michael@0 | 7 | #include "gfxPrefs.h" // For gfxPrefs::LayersTilesEnabled, LayersTileWidth/Height |
michael@0 | 8 | #include "mozilla/Preferences.h" |
michael@0 | 9 | #include "nsIScrollableFrame.h" |
michael@0 | 10 | #include "nsLayoutUtils.h" |
michael@0 | 11 | #include "nsIDOMElement.h" |
michael@0 | 12 | #include "nsIInterfaceRequestorUtils.h" |
michael@0 | 13 | |
michael@0 | 14 | namespace mozilla { |
michael@0 | 15 | namespace layers { |
michael@0 | 16 | |
michael@0 | 17 | bool |
michael@0 | 18 | APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils, |
michael@0 | 19 | const FrameMetrics& aMetrics) |
michael@0 | 20 | { |
michael@0 | 21 | MOZ_ASSERT(aUtils); |
michael@0 | 22 | |
michael@0 | 23 | uint32_t presShellId; |
michael@0 | 24 | nsresult rv = aUtils->GetPresShellId(&presShellId); |
michael@0 | 25 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 26 | return NS_SUCCEEDED(rv) && aMetrics.mPresShellId == presShellId; |
michael@0 | 27 | } |
michael@0 | 28 | |
michael@0 | 29 | /** |
michael@0 | 30 | * Expands a given rectangle to the next tile boundary. Note, this will |
michael@0 | 31 | * expand the rectangle if it is already on tile boundaries. |
michael@0 | 32 | */ |
michael@0 | 33 | static CSSRect ExpandDisplayPortToTileBoundaries( |
michael@0 | 34 | const CSSRect& aDisplayPort, |
michael@0 | 35 | const CSSToLayerScale& aLayerPixelsPerCSSPixel) |
michael@0 | 36 | { |
michael@0 | 37 | // Convert the given rect to layer coordinates so we can inflate to tile |
michael@0 | 38 | // boundaries (layer space corresponds to texture pixel space here). |
michael@0 | 39 | LayerRect displayPortInLayerSpace = aDisplayPort * aLayerPixelsPerCSSPixel; |
michael@0 | 40 | |
michael@0 | 41 | // Inflate the rectangle by 1 so that we always push to the next tile |
michael@0 | 42 | // boundary. This is desirable to stop from having a rectangle with a |
michael@0 | 43 | // moving origin occasionally being smaller when it coincidentally lines |
michael@0 | 44 | // up to tile boundaries. |
michael@0 | 45 | displayPortInLayerSpace.Inflate(1); |
michael@0 | 46 | |
michael@0 | 47 | // Now nudge the rectangle to the nearest equal or larger tile boundary. |
michael@0 | 48 | int32_t tileWidth = gfxPrefs::LayersTileWidth(); |
michael@0 | 49 | int32_t tileHeight = gfxPrefs::LayersTileHeight(); |
michael@0 | 50 | gfxFloat left = tileWidth * floor(displayPortInLayerSpace.x / tileWidth); |
michael@0 | 51 | gfxFloat right = tileWidth * ceil(displayPortInLayerSpace.XMost() / tileWidth); |
michael@0 | 52 | gfxFloat top = tileHeight * floor(displayPortInLayerSpace.y / tileHeight); |
michael@0 | 53 | gfxFloat bottom = tileHeight * ceil(displayPortInLayerSpace.YMost() / tileHeight); |
michael@0 | 54 | |
michael@0 | 55 | displayPortInLayerSpace = LayerRect(left, top, right - left, bottom - top); |
michael@0 | 56 | CSSRect displayPort = displayPortInLayerSpace / aLayerPixelsPerCSSPixel; |
michael@0 | 57 | |
michael@0 | 58 | return displayPort; |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | static void |
michael@0 | 62 | MaybeAlignAndClampDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics, |
michael@0 | 63 | const CSSPoint& aActualScrollOffset) |
michael@0 | 64 | { |
michael@0 | 65 | // Correct the display-port by the difference between the requested scroll |
michael@0 | 66 | // offset and the resulting scroll offset after setting the requested value. |
michael@0 | 67 | if (!aFrameMetrics.GetUseDisplayPortMargins()) { |
michael@0 | 68 | CSSRect& displayPort = aFrameMetrics.mDisplayPort; |
michael@0 | 69 | displayPort += aFrameMetrics.GetScrollOffset() - aActualScrollOffset; |
michael@0 | 70 | |
michael@0 | 71 | // Expand the display port to the next tile boundaries, if tiled thebes layers |
michael@0 | 72 | // are enabled. |
michael@0 | 73 | if (gfxPrefs::LayersTilesEnabled()) { |
michael@0 | 74 | // We don't use LayersPixelsPerCSSPixel() here as mCumulativeResolution on |
michael@0 | 75 | // this FrameMetrics may be incorrect (and is about to be reset by mZoom). |
michael@0 | 76 | displayPort = |
michael@0 | 77 | ExpandDisplayPortToTileBoundaries(displayPort + aActualScrollOffset, |
michael@0 | 78 | aFrameMetrics.GetZoom() * |
michael@0 | 79 | ScreenToLayerScale(1.0)) |
michael@0 | 80 | - aActualScrollOffset; |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | // Finally, clamp the display port to the expanded scrollable rect. |
michael@0 | 84 | CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect(); |
michael@0 | 85 | displayPort = scrollableRect.Intersect(displayPort + aActualScrollOffset) |
michael@0 | 86 | - aActualScrollOffset; |
michael@0 | 87 | } else { |
michael@0 | 88 | LayerPoint shift = |
michael@0 | 89 | (aFrameMetrics.GetScrollOffset() - aActualScrollOffset) * |
michael@0 | 90 | aFrameMetrics.LayersPixelsPerCSSPixel(); |
michael@0 | 91 | LayerMargin margins = aFrameMetrics.GetDisplayPortMargins(); |
michael@0 | 92 | margins.left -= shift.x; |
michael@0 | 93 | margins.right += shift.x; |
michael@0 | 94 | margins.top -= shift.y; |
michael@0 | 95 | margins.bottom += shift.y; |
michael@0 | 96 | aFrameMetrics.SetDisplayPortMargins(margins); |
michael@0 | 97 | } |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | static void |
michael@0 | 101 | RecenterDisplayPort(mozilla::layers::FrameMetrics& aFrameMetrics) |
michael@0 | 102 | { |
michael@0 | 103 | if (!aFrameMetrics.GetUseDisplayPortMargins()) { |
michael@0 | 104 | CSSSize compositionSize = aFrameMetrics.CalculateCompositedSizeInCssPixels(); |
michael@0 | 105 | aFrameMetrics.mDisplayPort.x = (compositionSize.width - aFrameMetrics.mDisplayPort.width) / 2; |
michael@0 | 106 | aFrameMetrics.mDisplayPort.y = (compositionSize.height - aFrameMetrics.mDisplayPort.height) / 2; |
michael@0 | 107 | } else { |
michael@0 | 108 | LayerMargin margins = aFrameMetrics.GetDisplayPortMargins(); |
michael@0 | 109 | margins.right = margins.left = margins.LeftRight() / 2; |
michael@0 | 110 | margins.top = margins.bottom = margins.TopBottom() / 2; |
michael@0 | 111 | aFrameMetrics.SetDisplayPortMargins(margins); |
michael@0 | 112 | } |
michael@0 | 113 | } |
michael@0 | 114 | |
michael@0 | 115 | static CSSPoint |
michael@0 | 116 | ScrollFrameTo(nsIScrollableFrame* aFrame, const CSSPoint& aPoint, bool& aSuccessOut) |
michael@0 | 117 | { |
michael@0 | 118 | aSuccessOut = false; |
michael@0 | 119 | |
michael@0 | 120 | if (!aFrame) { |
michael@0 | 121 | return aPoint; |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | CSSPoint targetScrollPosition = aPoint; |
michael@0 | 125 | |
michael@0 | 126 | // If the frame is overflow:hidden on a particular axis, we don't want to allow |
michael@0 | 127 | // user-driven scroll on that axis. Simply set the scroll position on that axis |
michael@0 | 128 | // to whatever it already is. Note that this will leave the APZ's async scroll |
michael@0 | 129 | // position out of sync with the gecko scroll position, but APZ can deal with that |
michael@0 | 130 | // (by design). Note also that when we run into this case, even if both axes |
michael@0 | 131 | // have overflow:hidden, we want to set aSuccessOut to true, so that the displayport |
michael@0 | 132 | // follows the async scroll position rather than the gecko scroll position. |
michael@0 | 133 | CSSPoint geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); |
michael@0 | 134 | if (aFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_HIDDEN) { |
michael@0 | 135 | targetScrollPosition.y = geckoScrollPosition.y; |
michael@0 | 136 | } |
michael@0 | 137 | if (aFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) { |
michael@0 | 138 | targetScrollPosition.x = geckoScrollPosition.x; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | // If the scrollable frame is currently in the middle of an async or smooth |
michael@0 | 142 | // scroll then we don't want to interrupt it (see bug 961280). |
michael@0 | 143 | // Also if the scrollable frame got a scroll request from something other than us |
michael@0 | 144 | // since the last layers update, then we don't want to push our scroll request |
michael@0 | 145 | // because we'll clobber that one, which is bad. |
michael@0 | 146 | if (!aFrame->IsProcessingAsyncScroll() && |
michael@0 | 147 | (!aFrame->OriginOfLastScroll() || aFrame->OriginOfLastScroll() == nsGkAtoms::apz)) { |
michael@0 | 148 | aFrame->ScrollToCSSPixelsApproximate(targetScrollPosition, nsGkAtoms::apz); |
michael@0 | 149 | geckoScrollPosition = CSSPoint::FromAppUnits(aFrame->GetScrollPosition()); |
michael@0 | 150 | aSuccessOut = true; |
michael@0 | 151 | } |
michael@0 | 152 | // Return the final scroll position after setting it so that anything that relies |
michael@0 | 153 | // on it can have an accurate value. Note that even if we set it above re-querying it |
michael@0 | 154 | // is a good idea because it may have gotten clamped or rounded. |
michael@0 | 155 | return geckoScrollPosition; |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | void |
michael@0 | 159 | APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils, |
michael@0 | 160 | FrameMetrics& aMetrics) |
michael@0 | 161 | { |
michael@0 | 162 | // Precondition checks |
michael@0 | 163 | MOZ_ASSERT(aUtils); |
michael@0 | 164 | if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { |
michael@0 | 165 | return; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | // Set the scroll port size, which determines the scroll range. For example if |
michael@0 | 169 | // a 500-pixel document is shown in a 100-pixel frame, the scroll port length would |
michael@0 | 170 | // be 100, and gecko would limit the maximum scroll offset to 400 (so as to prevent |
michael@0 | 171 | // overscroll). Note that if the content here was zoomed to 2x, the document would |
michael@0 | 172 | // be 1000 pixels long but the frame would still be 100 pixels, and so the maximum |
michael@0 | 173 | // scroll range would be 900. Therefore this calculation depends on the zoom applied |
michael@0 | 174 | // to the content relative to the container. |
michael@0 | 175 | CSSSize scrollPort = aMetrics.CalculateCompositedSizeInCssPixels(); |
michael@0 | 176 | aUtils->SetScrollPositionClampingScrollPortSize(scrollPort.width, scrollPort.height); |
michael@0 | 177 | |
michael@0 | 178 | // Scroll the window to the desired spot |
michael@0 | 179 | nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); |
michael@0 | 180 | bool scrollUpdated = false; |
michael@0 | 181 | CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); |
michael@0 | 182 | |
michael@0 | 183 | if (!scrollUpdated) { |
michael@0 | 184 | // For whatever reason we couldn't update the scroll offset on the scroll frame, |
michael@0 | 185 | // which means the data APZ used for its displayport calculation is stale. Fall |
michael@0 | 186 | // back to a sane default behaviour. Note that we don't tile-align the recentered |
michael@0 | 187 | // displayport because tile-alignment depends on the scroll position, and the |
michael@0 | 188 | // scroll position here is out of our control. See bug 966507 comment 21 for a |
michael@0 | 189 | // more detailed explanation. |
michael@0 | 190 | RecenterDisplayPort(aMetrics); |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | // Correct the display port due to the difference between mScrollOffset and the |
michael@0 | 194 | // actual scroll offset, possibly align it to tile boundaries (if tiled layers are |
michael@0 | 195 | // enabled), and clamp it to the scrollable rect. |
michael@0 | 196 | MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset); |
michael@0 | 197 | |
michael@0 | 198 | aMetrics.SetScrollOffset(actualScrollOffset); |
michael@0 | 199 | |
michael@0 | 200 | // The mZoom variable on the frame metrics stores the CSS-to-screen scale for this |
michael@0 | 201 | // frame. This scale includes all of the (cumulative) resolutions set on the presShells |
michael@0 | 202 | // from the root down to this frame. However, when setting the resolution, we only |
michael@0 | 203 | // want the piece of the resolution that corresponds to this presShell, rather than |
michael@0 | 204 | // all of the cumulative stuff, so we need to divide out the parent resolutions. |
michael@0 | 205 | // Finally, we multiply by a ScreenToLayerScale of 1.0f because the goal here is to |
michael@0 | 206 | // take the async zoom calculated by the APZC and tell gecko about it (turning it into |
michael@0 | 207 | // a "sync" zoom) which will update the resolution at which the layer is painted. |
michael@0 | 208 | ParentLayerToLayerScale presShellResolution = |
michael@0 | 209 | aMetrics.GetZoom() |
michael@0 | 210 | / aMetrics.mDevPixelsPerCSSPixel |
michael@0 | 211 | / aMetrics.GetParentResolution() |
michael@0 | 212 | * ScreenToLayerScale(1.0f); |
michael@0 | 213 | aUtils->SetResolution(presShellResolution.scale, presShellResolution.scale); |
michael@0 | 214 | |
michael@0 | 215 | // Finally, we set the displayport. |
michael@0 | 216 | nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aMetrics.GetScrollId()); |
michael@0 | 217 | if (!content) { |
michael@0 | 218 | return; |
michael@0 | 219 | } |
michael@0 | 220 | nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content); |
michael@0 | 221 | if (!element) { |
michael@0 | 222 | return; |
michael@0 | 223 | } |
michael@0 | 224 | if (!aMetrics.GetUseDisplayPortMargins()) { |
michael@0 | 225 | aUtils->SetDisplayPortForElement(aMetrics.mDisplayPort.x, |
michael@0 | 226 | aMetrics.mDisplayPort.y, |
michael@0 | 227 | aMetrics.mDisplayPort.width, |
michael@0 | 228 | aMetrics.mDisplayPort.height, |
michael@0 | 229 | element, 0); |
michael@0 | 230 | } else { |
michael@0 | 231 | gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() |
michael@0 | 232 | ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : |
michael@0 | 233 | gfx::IntSize(0, 0); |
michael@0 | 234 | LayerMargin margins = aMetrics.GetDisplayPortMargins(); |
michael@0 | 235 | aUtils->SetDisplayPortMarginsForElement(margins.left, |
michael@0 | 236 | margins.top, |
michael@0 | 237 | margins.right, |
michael@0 | 238 | margins.bottom, |
michael@0 | 239 | alignment.width, |
michael@0 | 240 | alignment.height, |
michael@0 | 241 | element, 0); |
michael@0 | 242 | CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent(); |
michael@0 | 243 | nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 244 | baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 245 | baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 246 | baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); |
michael@0 | 247 | nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); |
michael@0 | 248 | } |
michael@0 | 249 | } |
michael@0 | 250 | |
michael@0 | 251 | void |
michael@0 | 252 | APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent, |
michael@0 | 253 | FrameMetrics& aMetrics) |
michael@0 | 254 | { |
michael@0 | 255 | // Precondition checks |
michael@0 | 256 | MOZ_ASSERT(aContent); |
michael@0 | 257 | if (aMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) { |
michael@0 | 258 | return; |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | nsCOMPtr<nsIDOMWindowUtils> utils = GetDOMWindowUtils(aContent); |
michael@0 | 262 | if (!utils) { |
michael@0 | 263 | return; |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | // We currently do not support zooming arbitrary subframes. They can only |
michael@0 | 267 | // be scrolled, so here we only have to set the scroll position and displayport. |
michael@0 | 268 | |
michael@0 | 269 | nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId()); |
michael@0 | 270 | bool scrollUpdated = false; |
michael@0 | 271 | CSSPoint actualScrollOffset = ScrollFrameTo(sf, aMetrics.GetScrollOffset(), scrollUpdated); |
michael@0 | 272 | |
michael@0 | 273 | nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent); |
michael@0 | 274 | if (element) { |
michael@0 | 275 | if (!scrollUpdated) { |
michael@0 | 276 | RecenterDisplayPort(aMetrics); |
michael@0 | 277 | } |
michael@0 | 278 | MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset); |
michael@0 | 279 | if (!aMetrics.GetUseDisplayPortMargins()) { |
michael@0 | 280 | utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x, |
michael@0 | 281 | aMetrics.mDisplayPort.y, |
michael@0 | 282 | aMetrics.mDisplayPort.width, |
michael@0 | 283 | aMetrics.mDisplayPort.height, |
michael@0 | 284 | element, 0); |
michael@0 | 285 | } else { |
michael@0 | 286 | gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled() |
michael@0 | 287 | ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) : |
michael@0 | 288 | gfx::IntSize(0, 0); |
michael@0 | 289 | LayerMargin margins = aMetrics.GetDisplayPortMargins(); |
michael@0 | 290 | utils->SetDisplayPortMarginsForElement(margins.left, |
michael@0 | 291 | margins.top, |
michael@0 | 292 | margins.right, |
michael@0 | 293 | margins.bottom, |
michael@0 | 294 | alignment.width, |
michael@0 | 295 | alignment.height, |
michael@0 | 296 | element, 0); |
michael@0 | 297 | CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent(); |
michael@0 | 298 | nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 299 | baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 300 | baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), |
michael@0 | 301 | baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); |
michael@0 | 302 | nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); |
michael@0 | 303 | } |
michael@0 | 304 | } |
michael@0 | 305 | |
michael@0 | 306 | aMetrics.SetScrollOffset(actualScrollOffset); |
michael@0 | 307 | } |
michael@0 | 308 | |
michael@0 | 309 | already_AddRefed<nsIDOMWindowUtils> |
michael@0 | 310 | APZCCallbackHelper::GetDOMWindowUtils(const nsIDocument* aDoc) |
michael@0 | 311 | { |
michael@0 | 312 | nsCOMPtr<nsIDOMWindowUtils> utils; |
michael@0 | 313 | nsCOMPtr<nsIDOMWindow> window = aDoc->GetDefaultView(); |
michael@0 | 314 | if (window) { |
michael@0 | 315 | utils = do_GetInterface(window); |
michael@0 | 316 | } |
michael@0 | 317 | return utils.forget(); |
michael@0 | 318 | } |
michael@0 | 319 | |
michael@0 | 320 | already_AddRefed<nsIDOMWindowUtils> |
michael@0 | 321 | APZCCallbackHelper::GetDOMWindowUtils(const nsIContent* aContent) |
michael@0 | 322 | { |
michael@0 | 323 | nsCOMPtr<nsIDOMWindowUtils> utils; |
michael@0 | 324 | nsIDocument* doc = aContent->GetCurrentDoc(); |
michael@0 | 325 | if (doc) { |
michael@0 | 326 | utils = GetDOMWindowUtils(doc); |
michael@0 | 327 | } |
michael@0 | 328 | return utils.forget(); |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | bool |
michael@0 | 332 | APZCCallbackHelper::GetScrollIdentifiers(const nsIContent* aContent, |
michael@0 | 333 | uint32_t* aPresShellIdOut, |
michael@0 | 334 | FrameMetrics::ViewID* aViewIdOut) |
michael@0 | 335 | { |
michael@0 | 336 | if (!aContent || !nsLayoutUtils::FindIDFor(aContent, aViewIdOut)) { |
michael@0 | 337 | return false; |
michael@0 | 338 | } |
michael@0 | 339 | nsCOMPtr<nsIDOMWindowUtils> utils = GetDOMWindowUtils(aContent); |
michael@0 | 340 | return utils && (utils->GetPresShellId(aPresShellIdOut) == NS_OK); |
michael@0 | 341 | } |
michael@0 | 342 | |
michael@0 | 343 | class AcknowledgeScrollUpdateEvent : public nsRunnable |
michael@0 | 344 | { |
michael@0 | 345 | typedef mozilla::layers::FrameMetrics::ViewID ViewID; |
michael@0 | 346 | |
michael@0 | 347 | public: |
michael@0 | 348 | AcknowledgeScrollUpdateEvent(const ViewID& aScrollId, const uint32_t& aScrollGeneration) |
michael@0 | 349 | : mScrollId(aScrollId) |
michael@0 | 350 | , mScrollGeneration(aScrollGeneration) |
michael@0 | 351 | { |
michael@0 | 352 | } |
michael@0 | 353 | |
michael@0 | 354 | NS_IMETHOD Run() { |
michael@0 | 355 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 356 | |
michael@0 | 357 | nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId); |
michael@0 | 358 | if (sf) { |
michael@0 | 359 | sf->ResetOriginIfScrollAtGeneration(mScrollGeneration); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | return NS_OK; |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | protected: |
michael@0 | 366 | ViewID mScrollId; |
michael@0 | 367 | uint32_t mScrollGeneration; |
michael@0 | 368 | }; |
michael@0 | 369 | |
michael@0 | 370 | void |
michael@0 | 371 | APZCCallbackHelper::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId, |
michael@0 | 372 | const uint32_t& aScrollGeneration) |
michael@0 | 373 | { |
michael@0 | 374 | nsCOMPtr<nsIRunnable> r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration); |
michael@0 | 375 | if (!NS_IsMainThread()) { |
michael@0 | 376 | NS_DispatchToMainThread(r1); |
michael@0 | 377 | } else { |
michael@0 | 378 | r1->Run(); |
michael@0 | 379 | } |
michael@0 | 380 | } |
michael@0 | 381 | |
michael@0 | 382 | void |
michael@0 | 383 | APZCCallbackHelper::UpdateCallbackTransform(const FrameMetrics& aApzcMetrics, const FrameMetrics& aActualMetrics) |
michael@0 | 384 | { |
michael@0 | 385 | nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aApzcMetrics.GetScrollId()); |
michael@0 | 386 | if (!content) { |
michael@0 | 387 | return; |
michael@0 | 388 | } |
michael@0 | 389 | CSSPoint scrollDelta = aApzcMetrics.GetScrollOffset() - aActualMetrics.GetScrollOffset(); |
michael@0 | 390 | content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(scrollDelta), |
michael@0 | 391 | nsINode::DeleteProperty<CSSPoint>); |
michael@0 | 392 | } |
michael@0 | 393 | |
michael@0 | 394 | CSSPoint |
michael@0 | 395 | APZCCallbackHelper::ApplyCallbackTransform(const CSSPoint& aInput, const ScrollableLayerGuid& aGuid) |
michael@0 | 396 | { |
michael@0 | 397 | // XXX: technically we need to walk all the way up the layer tree from the layer |
michael@0 | 398 | // represented by |aGuid.mScrollId| up to the root of the layer tree and apply |
michael@0 | 399 | // the input transforms at each level in turn. However, it is quite difficult |
michael@0 | 400 | // to do this given that the structure of the layer tree may be different from |
michael@0 | 401 | // the structure of the content tree. Also it may be impossible to do correctly |
michael@0 | 402 | // at this point because there are other CSS transforms and such interleaved in |
michael@0 | 403 | // between so applying the inputTransforms all in a row at the end may leave |
michael@0 | 404 | // some things transformed improperly. In practice we should rarely hit scenarios |
michael@0 | 405 | // where any of this matters, so I'm skipping it for now and just doing the single |
michael@0 | 406 | // transform for the layer that the input hit. |
michael@0 | 407 | |
michael@0 | 408 | if (aGuid.mScrollId != FrameMetrics::NULL_SCROLL_ID) { |
michael@0 | 409 | nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aGuid.mScrollId); |
michael@0 | 410 | if (content) { |
michael@0 | 411 | void* property = content->GetProperty(nsGkAtoms::apzCallbackTransform); |
michael@0 | 412 | if (property) { |
michael@0 | 413 | CSSPoint delta = (*static_cast<CSSPoint*>(property)); |
michael@0 | 414 | return aInput + delta; |
michael@0 | 415 | } |
michael@0 | 416 | } |
michael@0 | 417 | } |
michael@0 | 418 | return aInput; |
michael@0 | 419 | } |
michael@0 | 420 | |
michael@0 | 421 | nsIntPoint |
michael@0 | 422 | APZCCallbackHelper::ApplyCallbackTransform(const nsIntPoint& aPoint, |
michael@0 | 423 | const ScrollableLayerGuid& aGuid, |
michael@0 | 424 | const CSSToLayoutDeviceScale& aScale) |
michael@0 | 425 | { |
michael@0 | 426 | LayoutDevicePoint point = LayoutDevicePoint(aPoint.x, aPoint.y); |
michael@0 | 427 | point = ApplyCallbackTransform(point / aScale, aGuid) * aScale; |
michael@0 | 428 | LayoutDeviceIntPoint ret = gfx::RoundedToInt(point); |
michael@0 | 429 | return nsIntPoint(ret.x, ret.y); |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | } |
michael@0 | 433 | } |