Source code

Revision control

Other Tools

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 "mozilla/layers/AndroidDynamicToolbarAnimator.h"
8
9
#include <cmath>
10
#include <utility>
11
12
#include "APZCTreeManager.h"
13
#include "FrameMetrics.h"
14
#include "mozilla/EventForwards.h"
15
#include "mozilla/FloatingPoint.h"
16
#include "mozilla/MathAlgorithms.h"
17
#include "mozilla/StaticPrefs_browser.h"
18
#include "mozilla/Unused.h"
19
#include "mozilla/gfx/2D.h"
20
#include "mozilla/gfx/Types.h"
21
#include "mozilla/layers/APZThreadUtils.h"
22
#include "mozilla/layers/AsyncCompositionManager.h"
23
#include "mozilla/layers/CompositorBridgeParent.h"
24
#include "mozilla/layers/CompositorOGL.h"
25
#include "mozilla/layers/CompositorThread.h"
26
#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
27
#include "mozilla/layers/UiCompositorControllerParent.h"
28
29
namespace {
30
31
// Internal flags and constants
32
static const float ANIMATION_DURATION =
33
0.15f; // How many seconds the complete animation should span
34
static const int32_t MOVE_TOOLBAR_DOWN =
35
1; // Multiplier to move the toolbar down
36
static const int32_t MOVE_TOOLBAR_UP = -1; // Multiplier to move the toolbar up
37
static const float SHRINK_FACTOR =
38
0.95f; // Amount to shrink the either the full content for small pages or
39
// the amount left See: PageTooSmallEnsureToolbarVisible()
40
} // namespace
41
42
namespace mozilla {
43
namespace layers {
44
45
AndroidDynamicToolbarAnimator::AndroidDynamicToolbarAnimator(
46
APZCTreeManager* aApz)
47
: mRootLayerTreeId{0},
48
mApz(aApz)
49
// Read/Write Compositor Thread, Read only Controller thread
50
,
51
mToolbarState(eToolbarVisible),
52
mPinnedFlags(0)
53
// Controller thread only
54
,
55
mControllerScrollingRootContent(false),
56
mControllerDragThresholdReached(false),
57
mControllerCancelTouchTracking(false),
58
mControllerDragChangedDirection(false),
59
mControllerResetOnNextMove(false),
60
mControllerStartTouch(0),
61
mControllerPreviousTouch(0),
62
mControllerTotalDistance(0),
63
mControllerMaxToolbarHeight(0),
64
mControllerToolbarHeight(0),
65
mControllerSurfaceHeight(0),
66
mControllerCompositionHeight(0),
67
mControllerRootScrollY(0.0f),
68
mControllerLastDragDirection(0),
69
mControllerTouchCount(0),
70
mControllerLastEventTimeStamp(0),
71
mControllerState(eNothingPending)
72
// Compositor thread only
73
,
74
mCompositorShutdown(false),
75
mCompositorAnimationDeferred(false),
76
mCompositorAnimationStarted(false),
77
mCompositorReceivedFirstPaint(false),
78
mCompositorWaitForPageResize(false),
79
mCompositorToolbarShowRequested(false),
80
mCompositorSendResponseForSnapshotUpdate(false),
81
mCompositorAnimationStyle(eAnimate),
82
mCompositorMaxToolbarHeight(0),
83
mCompositorToolbarHeight(0),
84
mCompositorSurfaceHeight(0),
85
mCompositorAnimationDirection(0),
86
mCompositorAnimationStartHeight(0) {}
87
88
void AndroidDynamicToolbarAnimator::Initialize(LayersId aRootLayerTreeId) {
89
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
90
mRootLayerTreeId = aRootLayerTreeId;
91
RefPtr<UiCompositorControllerParent> uiController =
92
UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
93
MOZ_ASSERT(uiController);
94
uiController->RegisterAndroidDynamicToolbarAnimator(this);
95
96
// Send queued messages that were posted before Initialize() was called.
97
for (QueuedMessage* message = mCompositorQueuedMessages.getFirst();
98
message != nullptr; message = message->getNext()) {
99
uiController->ToolbarAnimatorMessageFromCompositor(message->mMessage);
100
}
101
mCompositorQueuedMessages.clear();
102
}
103
104
void AndroidDynamicToolbarAnimator::ClearTreeManager() {
105
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
106
mApz = nullptr;
107
}
108
109
static bool GetTouchY(MultiTouchInput& multiTouch, ScreenIntCoord* value) {
110
MOZ_ASSERT(value);
111
if (multiTouch.mTouches.Length() == 1) {
112
*value = multiTouch.mTouches[0].mScreenPoint.y;
113
return true;
114
}
115
116
return false;
117
}
118
119
nsEventStatus AndroidDynamicToolbarAnimator::ReceiveInputEvent(
120
const RefPtr<APZCTreeManager>& aApz, InputData& aEvent,
121
const ScreenPoint& aScrollOffset) {
122
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
123
124
mControllerRootScrollY = aScrollOffset.y;
125
126
// Only process and adjust touch events. Wheel events (aka scroll events) are
127
// adjusted in the NativePanZoomController
128
if (aEvent.mInputType != MULTITOUCH_INPUT) {
129
return nsEventStatus_eIgnore;
130
}
131
132
MultiTouchInput& multiTouch = aEvent.AsMultiTouchInput();
133
134
if (PageTooSmallEnsureToolbarVisible()) {
135
TranslateTouchEvent(multiTouch);
136
return nsEventStatus_eIgnore;
137
}
138
139
switch (multiTouch.mType) {
140
case MultiTouchInput::MULTITOUCH_START:
141
mControllerTouchCount = multiTouch.mTouches.Length();
142
break;
143
case MultiTouchInput::MULTITOUCH_END:
144
case MultiTouchInput::MULTITOUCH_CANCEL:
145
mControllerTouchCount -= multiTouch.mTouches.Length();
146
break;
147
case MultiTouchInput::MULTITOUCH_MOVE:
148
break;
149
}
150
151
if (mControllerTouchCount > 1) {
152
mControllerResetOnNextMove = true;
153
}
154
155
ScreenIntCoord currentTouch = 0;
156
157
if (mPinnedFlags || !GetTouchY(multiTouch, &currentTouch)) {
158
TranslateTouchEvent(multiTouch);
159
return nsEventStatus_eIgnore;
160
}
161
162
// Only the return value from ProcessTouchDelta should
163
// change status to nsEventStatus_eConsumeNoDefault
164
nsEventStatus status = nsEventStatus_eIgnore;
165
166
const StaticToolbarState currentToolbarState = mToolbarState;
167
switch (multiTouch.mType) {
168
case MultiTouchInput::MULTITOUCH_START:
169
mControllerCancelTouchTracking = false;
170
mControllerStartTouch = mControllerPreviousTouch = currentTouch;
171
// We don't want to stop the animation if we are near the bottom of the
172
// page.
173
if (!ScrollOffsetNearBottom() &&
174
(currentToolbarState == eToolbarAnimating)) {
175
StopCompositorAnimation();
176
}
177
break;
178
case MultiTouchInput::MULTITOUCH_MOVE: {
179
CheckForResetOnNextMove(currentTouch);
180
if ((mControllerState != eAnimationStartPending) &&
181
(mControllerState != eAnimationStopPending) &&
182
(currentToolbarState != eToolbarAnimating) &&
183
!mControllerCancelTouchTracking) {
184
// Don't move the toolbar if we are near the page bottom
185
// and the toolbar is not in transition
186
if (ScrollOffsetNearBottom() && !ToolbarInTransition()) {
187
ShowToolbarIfNotVisible(currentToolbarState);
188
break;
189
}
190
191
ScreenIntCoord delta = currentTouch - mControllerPreviousTouch;
192
mControllerPreviousTouch = currentTouch;
193
mControllerTotalDistance += delta;
194
if (delta != 0) {
195
ScreenIntCoord direction =
196
(delta > 0 ? MOVE_TOOLBAR_DOWN : MOVE_TOOLBAR_UP);
197
if (mControllerLastDragDirection &&
198
(direction != mControllerLastDragDirection)) {
199
mControllerDragChangedDirection = true;
200
}
201
mControllerLastDragDirection = direction;
202
}
203
// NOTE: StaticPrefs::browser_ui_scroll_toolbar_threshold() returns a
204
// percentage as an int32_t. So multiply it by 0.01f to convert.
205
const uint32_t dragThreshold = Abs(std::lround(
206
0.01f * StaticPrefs::browser_ui_scroll_toolbar_threshold() *
207
mControllerCompositionHeight));
208
if ((Abs(mControllerTotalDistance.value) > dragThreshold) &&
209
(delta != 0)) {
210
mControllerDragThresholdReached = true;
211
status = ProcessTouchDelta(aApz, currentToolbarState, delta,
212
multiTouch.mTime);
213
}
214
mControllerLastEventTimeStamp = multiTouch.mTime;
215
}
216
break;
217
}
218
case MultiTouchInput::MULTITOUCH_END:
219
case MultiTouchInput::MULTITOUCH_CANCEL:
220
// last finger was lifted
221
if (mControllerTouchCount == 0) {
222
HandleTouchEnd(currentToolbarState, currentTouch);
223
}
224
break;
225
}
226
227
TranslateTouchEvent(multiTouch);
228
229
return status;
230
}
231
232
void AndroidDynamicToolbarAnimator::SetMaxToolbarHeight(
233
ScreenIntCoord aHeight) {
234
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
235
UpdateControllerToolbarHeight(aHeight, aHeight);
236
mCompositorMaxToolbarHeight = aHeight;
237
UpdateCompositorToolbarHeight(aHeight);
238
}
239
240
void AndroidDynamicToolbarAnimator::SetPinned(bool aPinned, int32_t aReason) {
241
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
242
MOZ_ASSERT(aReason < 32);
243
uint32_t bit = 0x01 << aReason;
244
uint32_t current = mPinnedFlags;
245
if (aPinned) {
246
mPinnedFlags = current | bit;
247
} else {
248
mPinnedFlags = current & (~bit);
249
}
250
}
251
252
ScreenIntCoord AndroidDynamicToolbarAnimator::GetMaxToolbarHeight() const {
253
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
254
return mCompositorMaxToolbarHeight;
255
}
256
257
ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentToolbarHeight() const {
258
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
259
return mCompositorToolbarHeight;
260
}
261
262
ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentContentOffset() const {
263
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
264
if (mCompositorAnimationStarted && (mToolbarState == eToolbarAnimating)) {
265
return 0;
266
}
267
268
return mCompositorToolbarHeight;
269
}
270
271
ScreenIntCoord AndroidDynamicToolbarAnimator::GetCurrentSurfaceHeight() const {
272
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
273
return mCompositorSurfaceHeight;
274
}
275
276
ScreenIntCoord AndroidDynamicToolbarAnimator::GetCompositionHeight() const {
277
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
278
return mCompositorCompositionSize.height;
279
}
280
281
void AndroidDynamicToolbarAnimator::SetScrollingRootContent() {
282
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
283
mControllerScrollingRootContent = true;
284
}
285
286
void AndroidDynamicToolbarAnimator::ToolbarAnimatorMessageFromUI(
287
int32_t aMessage) {
288
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
289
switch (aMessage) {
290
case STATIC_TOOLBAR_NEEDS_UPDATE:
291
break;
292
case STATIC_TOOLBAR_READY:
293
break;
294
case TOOLBAR_HIDDEN:
295
// If the toolbar is animating, then it is already unlocked.
296
if (mToolbarState != eToolbarAnimating) {
297
mToolbarState = eToolbarUnlocked;
298
if (mCompositorAnimationDeferred) {
299
StartCompositorAnimation(
300
mCompositorAnimationDirection, mCompositorAnimationStyle,
301
mCompositorToolbarHeight, mCompositorWaitForPageResize);
302
}
303
} else {
304
// Animation already running so just make sure it is going the right
305
// direction.
306
StartCompositorAnimation(MOVE_TOOLBAR_UP, mCompositorAnimationStyle,
307
mCompositorToolbarHeight,
308
mCompositorWaitForPageResize);
309
}
310
break;
311
case TOOLBAR_VISIBLE:
312
// If we are currently animating, let the animation finish.
313
if (mToolbarState != eToolbarAnimating) {
314
mToolbarState = eToolbarVisible;
315
}
316
break;
317
case TOOLBAR_SHOW:
318
break;
319
case FIRST_PAINT:
320
break;
321
case REQUEST_SHOW_TOOLBAR_IMMEDIATELY:
322
NotifyControllerPendingAnimation(MOVE_TOOLBAR_DOWN, eImmediate);
323
break;
324
case REQUEST_SHOW_TOOLBAR_ANIMATED:
325
NotifyControllerPendingAnimation(MOVE_TOOLBAR_DOWN, eAnimate);
326
break;
327
case REQUEST_HIDE_TOOLBAR_IMMEDIATELY:
328
NotifyControllerPendingAnimation(MOVE_TOOLBAR_UP, eImmediate);
329
break;
330
case REQUEST_HIDE_TOOLBAR_ANIMATED:
331
NotifyControllerPendingAnimation(MOVE_TOOLBAR_UP, eAnimate);
332
break;
333
case TOOLBAR_SNAPSHOT_FAILED:
334
mToolbarState = eToolbarVisible;
335
NotifyControllerSnapshotFailed();
336
break;
337
default:
338
break;
339
}
340
}
341
342
bool AndroidDynamicToolbarAnimator::UpdateAnimation(
343
const TimeStamp& aCurrentFrame) {
344
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
345
if ((mToolbarState != eToolbarAnimating) || mCompositorShutdown) {
346
return false;
347
}
348
349
CompositorBridgeParent* parent =
350
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
351
mRootLayerTreeId);
352
if (!parent) {
353
return false;
354
}
355
MOZ_ASSERT(mApz); // because parent is non-null
356
357
AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
358
if (!manager) {
359
return false;
360
}
361
362
if (mCompositorSurfaceHeight != mCompositorCompositionSize.height) {
363
// Waiting for the composition to resize
364
if (mCompositorWaitForPageResize && mCompositorAnimationStarted) {
365
mCompositorWaitForPageResize = false;
366
} else {
367
return true;
368
}
369
} else if (!mCompositorAnimationStarted) {
370
mApz->AdjustScrollForSurfaceShift(
371
ScreenPoint(0.0f, (float)(-mCompositorToolbarHeight)));
372
manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
373
mCompositorAnimationStarted = true;
374
mCompositorReceivedFirstPaint = false;
375
mCompositorToolbarShowRequested = false;
376
// Reset the start time so the toolbar does not jump on the first animation
377
// frame
378
mCompositorAnimationStartTimeStamp = aCurrentFrame;
379
// Since the delta time for this frame will be zero. Just return, the
380
// animation will start on the next frame.
381
return true;
382
}
383
384
bool continueAnimating = true;
385
386
if (mCompositorAnimationStyle == eImmediate) {
387
if (mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) {
388
mCompositorToolbarHeight = mCompositorMaxToolbarHeight;
389
} else if (mCompositorAnimationDirection == MOVE_TOOLBAR_UP) {
390
mCompositorToolbarHeight = 0;
391
}
392
} else if (mCompositorAnimationStyle == eAnimate) {
393
const float rate =
394
((float)mCompositorMaxToolbarHeight) / ANIMATION_DURATION;
395
float deltaTime =
396
(aCurrentFrame - mCompositorAnimationStartTimeStamp).ToSeconds();
397
// This animation was started in the future!
398
if (deltaTime < 0.0f) {
399
deltaTime = 0.0f;
400
}
401
mCompositorToolbarHeight =
402
mCompositorAnimationStartHeight +
403
((int32_t)(rate * deltaTime) * mCompositorAnimationDirection);
404
}
405
406
if ((mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) &&
407
(mCompositorToolbarHeight >= mCompositorMaxToolbarHeight)) {
408
// if the toolbar is being animated and the page is at the end, the
409
// animation needs to wait for the page to resize before ending the
410
// animation so that the page may be scrolled
411
if (!mCompositorReceivedFirstPaint && mCompositorWaitForPageResize) {
412
continueAnimating = true;
413
} else {
414
continueAnimating = false;
415
mToolbarState = eToolbarVisible;
416
}
417
// Make sure we only send one show request per animation
418
if (!mCompositorToolbarShowRequested) {
419
PostMessage(TOOLBAR_SHOW);
420
mCompositorToolbarShowRequested = true;
421
}
422
mCompositorToolbarHeight = mCompositorMaxToolbarHeight;
423
} else if ((mCompositorAnimationDirection == MOVE_TOOLBAR_UP) &&
424
(mCompositorToolbarHeight <= 0)) {
425
continueAnimating = false;
426
mToolbarState = eToolbarUnlocked;
427
mCompositorToolbarHeight = 0;
428
}
429
430
if (continueAnimating) {
431
manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
432
} else {
433
if (mCompositorAnimationDirection == MOVE_TOOLBAR_DOWN) {
434
if (!mCompositorReceivedFirstPaint) {
435
mApz->AdjustScrollForSurfaceShift(
436
ScreenPoint(0.0f, (float)mCompositorMaxToolbarHeight));
437
}
438
manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
439
} else {
440
manager->SetFixedLayerMargins(0, 0);
441
}
442
}
443
444
if (!continueAnimating) {
445
NotifyControllerAnimationStopped(mCompositorToolbarHeight);
446
} else {
447
UpdateControllerToolbarHeight(mCompositorToolbarHeight);
448
}
449
450
return continueAnimating;
451
}
452
453
void AndroidDynamicToolbarAnimator::FirstPaint() {
454
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
455
mCompositorReceivedFirstPaint = true;
456
}
457
458
void AndroidDynamicToolbarAnimator::UpdateRootFrameMetrics(
459
const FrameMetrics& aMetrics) {
460
CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(
461
aMetrics.GetZoom().ToScaleFactor(),
462
PixelCastJustification::ScreenIsParentLayerForRoot);
463
ScreenPoint scrollOffset = aMetrics.GetScrollOffset() * scale;
464
CSSRect cssPageRect = aMetrics.GetScrollableRect();
465
466
UpdateFrameMetrics(scrollOffset, scale, cssPageRect);
467
}
468
469
void AndroidDynamicToolbarAnimator::
470
MaybeUpdateCompositionSizeAndRootFrameMetrics(
471
const FrameMetrics& aMetrics) {
472
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
473
CSSToScreenScale scale = ViewTargetAs<ScreenPixel>(
474
aMetrics.GetZoom().ToScaleFactor(),
475
PixelCastJustification::ScreenIsParentLayerForRoot);
476
ScreenIntSize size =
477
ScreenIntSize::Round(aMetrics.GetRootCompositionSize() * scale);
478
479
if (mCompositorCompositionSize == size) {
480
return;
481
}
482
483
ScreenIntSize prevSize = mCompositorCompositionSize;
484
mCompositorCompositionSize = size;
485
486
// The width has changed so the static snapshot needs to be updated
487
if ((prevSize.width != size.width) && (mToolbarState == eToolbarUnlocked)) {
488
// No need to set mCompositorSendResponseForSnapshotUpdate. If it is already
489
// true we don't want to change it.
490
PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
491
}
492
493
if (prevSize.height != size.height) {
494
UpdateControllerCompositionHeight(size.height);
495
UpdateFixedLayerMargins();
496
}
497
498
UpdateRootFrameMetrics(aMetrics);
499
}
500
501
void AndroidDynamicToolbarAnimator::AdoptToolbarPixels(
502
mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize) {
503
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
504
mCompositorToolbarPixels = Some(std::move(aMem));
505
mCompositorToolbarPixelsSize = aSize;
506
}
507
508
void AndroidDynamicToolbarAnimator::UpdateToolbarSnapshotTexture(
509
CompositorOGL* gl) {
510
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
511
// if the compositor has shutdown, do not create any new rendering objects.
512
if (mCompositorShutdown) {
513
return;
514
}
515
516
if (mCompositorToolbarPixels) {
517
RefPtr<gfx::DataSourceSurface> surface =
518
gfx::Factory::CreateWrappingDataSourceSurface(
519
mCompositorToolbarPixels.ref().get<uint8_t>(),
520
mCompositorToolbarPixelsSize.width * 4,
521
gfx::IntSize(mCompositorToolbarPixelsSize.width,
522
mCompositorToolbarPixelsSize.height),
523
gfx::SurfaceFormat::B8G8R8A8);
524
525
if (!mCompositorToolbarTexture) {
526
mCompositorToolbarTexture = gl->CreateDataTextureSource();
527
mCompositorToolbarEffect = nullptr;
528
}
529
530
if (!mCompositorToolbarTexture->Update(surface)) {
531
// Upload failed!
532
mCompositorToolbarTexture = nullptr;
533
}
534
535
RefPtr<UiCompositorControllerParent> uiController =
536
UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
537
uiController->DeallocShmem(mCompositorToolbarPixels.ref());
538
mCompositorToolbarPixels.reset();
539
// Send notification that texture is ready after the current composition has
540
// completed.
541
if (mCompositorToolbarTexture && mCompositorSendResponseForSnapshotUpdate) {
542
mCompositorSendResponseForSnapshotUpdate = false;
543
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
544
"AndroidDynamicToolbarAnimator::PostToolbarReady", this,
545
&AndroidDynamicToolbarAnimator::PostToolbarReady));
546
}
547
}
548
}
549
550
Effect* AndroidDynamicToolbarAnimator::GetToolbarEffect() {
551
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
552
// if the compositor has shutdown, do not create any new rendering objects.
553
if (mCompositorShutdown) {
554
return nullptr;
555
}
556
557
if (mCompositorToolbarTexture) {
558
if (!mCompositorToolbarEffect) {
559
mCompositorToolbarEffect = new EffectRGB(mCompositorToolbarTexture, true,
560
gfx::SamplingFilter::LINEAR);
561
}
562
563
float ratioVisible =
564
(float)mCompositorToolbarHeight / (float)mCompositorMaxToolbarHeight;
565
mCompositorToolbarEffect->mTextureCoords.y = 1.0f - ratioVisible;
566
mCompositorToolbarEffect->mTextureCoords.height = ratioVisible;
567
}
568
569
return mCompositorToolbarEffect.get();
570
}
571
572
void AndroidDynamicToolbarAnimator::Shutdown() {
573
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
574
mCompositorShutdown = true;
575
mCompositorToolbarEffect = nullptr;
576
mCompositorToolbarTexture = nullptr;
577
mCompositorQueuedMessages.clear();
578
if (mCompositorToolbarPixels) {
579
RefPtr<UiCompositorControllerParent> uiController =
580
UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
581
uiController->DeallocShmem(mCompositorToolbarPixels.ref());
582
mCompositorToolbarPixels.reset();
583
}
584
}
585
586
nsEventStatus AndroidDynamicToolbarAnimator::ProcessTouchDelta(
587
const RefPtr<APZCTreeManager>& aApz,
588
StaticToolbarState aCurrentToolbarState, ScreenIntCoord aDelta,
589
uint32_t aTimeStamp) {
590
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
591
MOZ_ASSERT(aApz);
592
nsEventStatus status = nsEventStatus_eIgnore;
593
594
const bool tryingToHideToolbar = aDelta < 0;
595
596
if (tryingToHideToolbar && !mControllerScrollingRootContent) {
597
// This prevent the toolbar from hiding if a subframe is being scrolled up.
598
// The toolbar will always become visible regardless what is being scrolled
599
// down.
600
return status;
601
}
602
603
if (aCurrentToolbarState == eToolbarVisible) {
604
if (tryingToHideToolbar && (mControllerState != eUnlockPending)) {
605
mCompositorSendResponseForSnapshotUpdate = true;
606
PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
607
mControllerState = eUnlockPending;
608
}
609
return status;
610
}
611
612
if (aCurrentToolbarState != eToolbarUnlocked) {
613
return status;
614
}
615
616
if ((mControllerState != eUnlockPending) &&
617
(mControllerState != eNothingPending)) {
618
return status;
619
}
620
621
mControllerState = eNothingPending;
622
if ((tryingToHideToolbar && (mControllerToolbarHeight > 0)) ||
623
(!tryingToHideToolbar &&
624
(mControllerToolbarHeight < mControllerMaxToolbarHeight))) {
625
ScreenIntCoord deltaRemainder = 0;
626
mControllerToolbarHeight += aDelta;
627
if (tryingToHideToolbar && (mControllerToolbarHeight <= 0)) {
628
deltaRemainder = mControllerToolbarHeight;
629
mControllerToolbarHeight = 0;
630
} else if (!tryingToHideToolbar &&
631
(mControllerToolbarHeight >= mControllerMaxToolbarHeight)) {
632
deltaRemainder = mControllerToolbarHeight - mControllerMaxToolbarHeight;
633
mControllerToolbarHeight = mControllerMaxToolbarHeight;
634
mControllerState = eShowPending;
635
PostMessage(TOOLBAR_SHOW);
636
}
637
638
UpdateCompositorToolbarHeight(mControllerToolbarHeight);
639
RequestComposite();
640
// If there was no delta left over, the event was completely consumed.
641
if (deltaRemainder == 0) {
642
status = nsEventStatus_eConsumeNoDefault;
643
}
644
645
uint32_t timeDelta = aTimeStamp - mControllerLastEventTimeStamp;
646
if (mControllerLastEventTimeStamp && timeDelta && aDelta) {
647
// we can't use mApz because we're on the controller thread, so we have
648
// the caller provide a RefPtr to the same underlying object, which should
649
// be safe to use.
650
aApz->ProcessDynamicToolbarMovement(mControllerLastEventTimeStamp,
651
aTimeStamp, (float)aDelta);
652
}
653
}
654
655
return status;
656
}
657
658
void AndroidDynamicToolbarAnimator::HandleTouchEnd(
659
StaticToolbarState aCurrentToolbarState, ScreenIntCoord aCurrentTouch) {
660
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
661
// If there was no move before the reset flag was set and the touch ended,
662
// check for it here. if mControllerResetOnNextMove is true, it will be set to
663
// false here
664
CheckForResetOnNextMove(aCurrentTouch);
665
int32_t direction = mControllerLastDragDirection;
666
mControllerLastDragDirection = 0;
667
bool isRoot = mControllerScrollingRootContent;
668
mControllerScrollingRootContent = false;
669
bool dragChangedDirection = mControllerDragChangedDirection;
670
mControllerDragChangedDirection = false;
671
672
// If the drag direction changed and the toolbar is partially visible, hide in
673
// the direction with the least distance to travel.
674
if (dragChangedDirection && ToolbarInTransition()) {
675
direction = ((float)mControllerToolbarHeight /
676
(float)mControllerMaxToolbarHeight) < 0.5f
677
? MOVE_TOOLBAR_UP
678
: MOVE_TOOLBAR_DOWN;
679
}
680
681
// If the last touch didn't have a drag direction, use start of touch to find
682
// direction
683
if (!direction) {
684
if (mControllerToolbarHeight == mControllerMaxToolbarHeight) {
685
direction = MOVE_TOOLBAR_DOWN;
686
} else if (mControllerToolbarHeight == 0) {
687
direction = MOVE_TOOLBAR_UP;
688
} else {
689
direction =
690
((aCurrentTouch - mControllerStartTouch) > 0 ? MOVE_TOOLBAR_DOWN
691
: MOVE_TOOLBAR_UP);
692
}
693
// If there still isn't a direction, default to show just to be safe
694
if (!direction) {
695
direction = MOVE_TOOLBAR_DOWN;
696
}
697
}
698
mControllerStartTouch = 0;
699
mControllerPreviousTouch = 0;
700
mControllerTotalDistance = 0;
701
bool dragThresholdReached = mControllerDragThresholdReached;
702
mControllerDragThresholdReached = false;
703
mControllerLastEventTimeStamp = 0;
704
bool cancelTouchTracking = mControllerCancelTouchTracking;
705
mControllerCancelTouchTracking = false;
706
707
// Animation is in progress, bail out.
708
if (aCurrentToolbarState == eToolbarAnimating) {
709
return;
710
}
711
712
// Received a UI thread request to show or hide the snapshot during a touch.
713
// This overrides the touch event so just return.
714
if (cancelTouchTracking) {
715
return;
716
}
717
718
// The drag threshold has not been reach and the toolbar is either completely
719
// visible or completely hidden.
720
if (!dragThresholdReached && !ToolbarInTransition()) {
721
ShowToolbarIfNotVisible(aCurrentToolbarState);
722
return;
723
}
724
725
// The toolbar is already where it needs to be so just return.
726
if (((direction == MOVE_TOOLBAR_DOWN) &&
727
(mControllerToolbarHeight == mControllerMaxToolbarHeight)) ||
728
((direction == MOVE_TOOLBAR_UP) && (mControllerToolbarHeight == 0))) {
729
ShowToolbarIfNotVisible(aCurrentToolbarState);
730
return;
731
}
732
733
// Don't animate up if not scrolling root content. Even though
734
// ShowToolbarIfNotVisible checks if snapshot toolbar is completely visible
735
// before showing, we don't want to enter this if block if the snapshot
736
// toolbar isn't completely visible to avoid early return.
737
if (!isRoot && ((direction == MOVE_TOOLBAR_UP) &&
738
(mControllerToolbarHeight == mControllerMaxToolbarHeight))) {
739
ShowToolbarIfNotVisible(aCurrentToolbarState);
740
return;
741
}
742
743
if (ScrollOffsetNearBottom()) {
744
if (ToolbarInTransition()) {
745
// Toolbar is partially visible so make it visible since we are near the
746
// end of the page
747
direction = MOVE_TOOLBAR_DOWN;
748
} else {
749
// Don't start an animation if near the bottom of page and toolbar is
750
// completely visible or hidden
751
ShowToolbarIfNotVisible(aCurrentToolbarState);
752
return;
753
}
754
}
755
756
StartCompositorAnimation(direction, eAnimate, mControllerToolbarHeight,
757
ScrollOffsetNearBottom());
758
}
759
760
void AndroidDynamicToolbarAnimator::PostMessage(int32_t aMessage) {
761
// if the root layer tree id is zero then Initialize() has not been called yet
762
// so queue the message until Initialize() is called.
763
if (!mRootLayerTreeId.IsValid()) {
764
QueueMessage(aMessage);
765
return;
766
}
767
768
RefPtr<UiCompositorControllerParent> uiController =
769
UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
770
if (!uiController) {
771
// Looks like IPC may be shutdown.
772
return;
773
}
774
775
// ToolbarAnimatorMessageFromCompositor may be called from any thread.
776
uiController->ToolbarAnimatorMessageFromCompositor(aMessage);
777
}
778
779
void AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight(
780
ScreenIntCoord aHeight) {
781
if (!CompositorThreadHolder::IsInCompositorThread()) {
782
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<ScreenIntCoord>(
783
"AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight", this,
784
&AndroidDynamicToolbarAnimator::UpdateCompositorToolbarHeight,
785
aHeight));
786
return;
787
}
788
789
mCompositorToolbarHeight = aHeight;
790
UpdateFixedLayerMargins();
791
}
792
793
void AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight(
794
ScreenIntCoord aHeight, ScreenIntCoord aMaxHeight) {
795
if (!APZThreadUtils::IsControllerThread()) {
796
APZThreadUtils::RunOnControllerThread(
797
NewRunnableMethod<ScreenIntCoord, ScreenIntCoord>(
798
"AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight",
799
this, &AndroidDynamicToolbarAnimator::UpdateControllerToolbarHeight,
800
aHeight, aMaxHeight));
801
return;
802
}
803
804
mControllerToolbarHeight = aHeight;
805
if (aMaxHeight >= 0) {
806
mControllerMaxToolbarHeight = aMaxHeight;
807
}
808
}
809
810
void AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight(
811
ScreenIntCoord aHeight) {
812
if (!APZThreadUtils::IsControllerThread()) {
813
APZThreadUtils::RunOnControllerThread(NewRunnableMethod<ScreenIntCoord>(
814
"AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight", this,
815
&AndroidDynamicToolbarAnimator::UpdateControllerSurfaceHeight,
816
aHeight));
817
return;
818
}
819
820
mControllerSurfaceHeight = aHeight;
821
}
822
823
void AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight(
824
ScreenIntCoord aHeight) {
825
if (!APZThreadUtils::IsControllerThread()) {
826
APZThreadUtils::RunOnControllerThread(NewRunnableMethod<ScreenIntCoord>(
827
"AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight",
828
this, &AndroidDynamicToolbarAnimator::UpdateControllerCompositionHeight,
829
aHeight));
830
return;
831
}
832
833
mControllerCompositionHeight = aHeight;
834
}
835
836
// Ensures the margin for the fixed layers match the position of the toolbar
837
void AndroidDynamicToolbarAnimator::UpdateFixedLayerMargins() {
838
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
839
if (mCompositorShutdown) {
840
return;
841
}
842
CompositorBridgeParent* parent =
843
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
844
mRootLayerTreeId);
845
if (parent) {
846
ScreenIntCoord surfaceHeight = parent->GetEGLSurfaceSize().height;
847
if (surfaceHeight != mCompositorSurfaceHeight) {
848
mCompositorSurfaceHeight = surfaceHeight;
849
UpdateControllerSurfaceHeight(mCompositorSurfaceHeight);
850
}
851
AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
852
if (manager) {
853
if ((mToolbarState == eToolbarAnimating) && mCompositorAnimationStarted) {
854
manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
855
} else {
856
manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
857
}
858
}
859
}
860
}
861
862
void AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation(
863
int32_t aDirection, AnimationStyle aAnimationStyle) {
864
if (!APZThreadUtils::IsControllerThread()) {
865
APZThreadUtils::RunOnControllerThread(
866
NewRunnableMethod<int32_t, AnimationStyle>(
867
"AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation",
868
this,
869
&AndroidDynamicToolbarAnimator::NotifyControllerPendingAnimation,
870
aDirection, aAnimationStyle));
871
return;
872
}
873
874
mControllerCancelTouchTracking = true;
875
876
// If the toolbar is already where it needs to be, just abort the request.
877
if (((mControllerToolbarHeight == mControllerMaxToolbarHeight) &&
878
(aDirection == MOVE_TOOLBAR_DOWN)) ||
879
((mControllerToolbarHeight == 0) && (aDirection == MOVE_TOOLBAR_UP))) {
880
// We received a show request but the real toolbar is hidden, so tell it to
881
// show now.
882
if ((aDirection == MOVE_TOOLBAR_DOWN) &&
883
(mToolbarState == eToolbarUnlocked)) {
884
PostMessage(TOOLBAR_SHOW);
885
}
886
return;
887
}
888
889
// NOTE: StartCompositorAnimation will set mControllerState to
890
// eAnimationStartPending
891
StartCompositorAnimation(aDirection, aAnimationStyle,
892
mControllerToolbarHeight, ScrollOffsetNearBottom());
893
MOZ_ASSERT(mControllerState == eAnimationStartPending);
894
}
895
896
void AndroidDynamicToolbarAnimator::StartCompositorAnimation(
897
int32_t aDirection, AnimationStyle aAnimationStyle, ScreenIntCoord aHeight,
898
bool aWaitForPageResize) {
899
if (!CompositorThreadHolder::IsInCompositorThread()) {
900
mControllerState = eAnimationStartPending;
901
CompositorThreadHolder::Loop()->PostTask(
902
NewRunnableMethod<int32_t, AnimationStyle, ScreenIntCoord, bool>(
903
"AndroidDynamicToolbarAnimator::StartCompositorAnimation", this,
904
&AndroidDynamicToolbarAnimator::StartCompositorAnimation,
905
aDirection, aAnimationStyle, aHeight, aWaitForPageResize));
906
return;
907
}
908
909
MOZ_ASSERT(aDirection == MOVE_TOOLBAR_UP || aDirection == MOVE_TOOLBAR_DOWN);
910
911
const StaticToolbarState initialToolbarState = mToolbarState;
912
mCompositorAnimationDirection = aDirection;
913
mCompositorAnimationStartHeight = mCompositorToolbarHeight = aHeight;
914
mCompositorAnimationStyle = aAnimationStyle;
915
mCompositorWaitForPageResize = aWaitForPageResize;
916
// If the snapshot is not unlocked, request the UI thread update the snapshot
917
// and defer animation until it has been unlocked
918
if ((initialToolbarState != eToolbarUnlocked) &&
919
(initialToolbarState != eToolbarAnimating)) {
920
mCompositorAnimationDeferred = true;
921
mCompositorSendResponseForSnapshotUpdate = true;
922
PostMessage(STATIC_TOOLBAR_NEEDS_UPDATE);
923
} else {
924
// Toolbar is either unlocked or already animating so animation may begin
925
// immediately
926
mCompositorAnimationDeferred = false;
927
mToolbarState = eToolbarAnimating;
928
if (initialToolbarState != eToolbarAnimating) {
929
mCompositorAnimationStarted = false;
930
}
931
// Let the controller know we are starting an animation so it may clear the
932
// AnimationStartPending flag.
933
NotifyControllerAnimationStarted();
934
// Only reset the time stamp and start compositor animation if not already
935
// animating.
936
if (initialToolbarState != eToolbarAnimating) {
937
if (mApz) {
938
mCompositorAnimationStartTimeStamp = mApz->GetFrameTime();
939
}
940
// Kick the compositor to start the animation if we aren't already
941
// animating.
942
RequestComposite();
943
}
944
}
945
}
946
947
void AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted() {
948
if (!APZThreadUtils::IsControllerThread()) {
949
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
950
"AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted", this,
951
&AndroidDynamicToolbarAnimator::NotifyControllerAnimationStarted));
952
return;
953
}
954
955
// It is possible there was a stop request after the start request so only set
956
// to NothingPending if start is what were are still waiting for.
957
if (mControllerState == eAnimationStartPending) {
958
mControllerState = eNothingPending;
959
}
960
}
961
962
void AndroidDynamicToolbarAnimator::StopCompositorAnimation() {
963
if (!CompositorThreadHolder::IsInCompositorThread()) {
964
mControllerState = eAnimationStopPending;
965
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
966
"AndroidDynamicToolbarAnimator::StopCompositorAnimation", this,
967
&AndroidDynamicToolbarAnimator::StopCompositorAnimation));
968
return;
969
}
970
971
if (mToolbarState == eToolbarAnimating) {
972
if (mCompositorAnimationStarted) {
973
mCompositorAnimationStarted = false;
974
CompositorBridgeParent* parent =
975
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
976
mRootLayerTreeId);
977
if (parent) {
978
AsyncCompositionManager* manager =
979
parent->GetCompositionManager(nullptr);
980
if (manager) {
981
MOZ_ASSERT(mApz);
982
mApz->AdjustScrollForSurfaceShift(
983
ScreenPoint(0.0f, (float)(mCompositorToolbarHeight)));
984
RequestComposite();
985
}
986
}
987
}
988
mToolbarState = eToolbarUnlocked;
989
}
990
991
NotifyControllerAnimationStopped(mCompositorToolbarHeight);
992
}
993
994
void AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped(
995
ScreenIntCoord aHeight) {
996
if (!APZThreadUtils::IsControllerThread()) {
997
APZThreadUtils::RunOnControllerThread(NewRunnableMethod<ScreenIntCoord>(
998
"AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped", this,
999
&AndroidDynamicToolbarAnimator::NotifyControllerAnimationStopped,
1000
aHeight));
1001
return;
1002
}
1003
1004
if (mControllerState == eAnimationStopPending) {
1005
mControllerState = eNothingPending;
1006
}
1007
1008
mControllerToolbarHeight = aHeight;
1009
RequestComposite();
1010
}
1011
1012
void AndroidDynamicToolbarAnimator::RequestComposite() {
1013
if (!CompositorThreadHolder::IsInCompositorThread()) {
1014
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod(
1015
"AndroidDynamicToolbarAnimator::RequestComposite", this,
1016
&AndroidDynamicToolbarAnimator::RequestComposite));
1017
return;
1018
}
1019
1020
if (mCompositorShutdown) {
1021
return;
1022
}
1023
1024
CompositorBridgeParent* parent =
1025
CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(
1026
mRootLayerTreeId);
1027
if (parent) {
1028
AsyncCompositionManager* manager = parent->GetCompositionManager(nullptr);
1029
if (manager) {
1030
if ((mToolbarState == eToolbarAnimating) && mCompositorAnimationStarted) {
1031
manager->SetFixedLayerMargins(mCompositorToolbarHeight, 0);
1032
} else {
1033
manager->SetFixedLayerMargins(0, GetFixedLayerMarginsBottom());
1034
}
1035
parent->Invalidate();
1036
parent->ScheduleComposition();
1037
}
1038
}
1039
}
1040
1041
void AndroidDynamicToolbarAnimator::PostToolbarReady() {
1042
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1043
RequestComposite();
1044
// Notify the UI thread the static toolbar is being rendered so the real
1045
// toolbar needs to be hidden. Once the TOOLBAR_HIDDEN message is
1046
// received, a pending animation may start or the toolbar snapshot may be
1047
// translated.
1048
PostMessage(STATIC_TOOLBAR_READY);
1049
if (mToolbarState != eToolbarAnimating) {
1050
mToolbarState = eToolbarUpdated;
1051
} else {
1052
// The compositor is already animating the toolbar so no need to defer.
1053
mCompositorAnimationDeferred = false;
1054
}
1055
}
1056
1057
void AndroidDynamicToolbarAnimator::UpdateFrameMetrics(
1058
ScreenPoint aScrollOffset, CSSToScreenScale aScale, CSSRect aCssPageRect) {
1059
if (!APZThreadUtils::IsControllerThread()) {
1060
APZThreadUtils::RunOnControllerThread(
1061
NewRunnableMethod<ScreenPoint, CSSToScreenScale, CSSRect>(
1062
"AndroidDynamicToolbarAnimator::UpdateFrameMetrics", this,
1063
&AndroidDynamicToolbarAnimator::UpdateFrameMetrics, aScrollOffset,
1064
aScale, aCssPageRect));
1065
return;
1066
}
1067
1068
mControllerRootScrollY = aScrollOffset.y;
1069
1070
if (mControllerFrameMetrics.Update(aScrollOffset, aScale, aCssPageRect)) {
1071
if (FuzzyEqualsMultiplicative(
1072
mControllerFrameMetrics.mPageRect.YMost(),
1073
mControllerCompositionHeight +
1074
mControllerFrameMetrics.mScrollOffset.y) &&
1075
(mControllerFrameMetrics.mPageRect.YMost() >
1076
(mControllerSurfaceHeight * 2)) &&
1077
(mControllerToolbarHeight != mControllerMaxToolbarHeight) &&
1078
!mPinnedFlags) {
1079
// The end of the page has been reached, the page is twice the height of
1080
// the visible height, and the toolbar is not completely visible so
1081
// animate it into view.
1082
StartCompositorAnimation(MOVE_TOOLBAR_DOWN, eAnimate,
1083
mControllerToolbarHeight,
1084
/* wait for page resize */ true);
1085
}
1086
RefPtr<UiCompositorControllerParent> uiController =
1087
UiCompositorControllerParent::GetFromRootLayerTreeId(mRootLayerTreeId);
1088
MOZ_ASSERT(uiController);
1089
CompositorThreadHolder::Loop()->PostTask(
1090
NewRunnableMethod<ScreenPoint, CSSToScreenScale>(
1091
"UiCompositorControllerParent::SendRootFrameMetrics", uiController,
1092
&UiCompositorControllerParent::SendRootFrameMetrics, aScrollOffset,
1093
aScale));
1094
}
1095
}
1096
1097
bool AndroidDynamicToolbarAnimator::PageTooSmallEnsureToolbarVisible() {
1098
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
1099
// if the page is too small then the toolbar can not be hidden
1100
if ((float)mControllerSurfaceHeight >=
1101
(mControllerFrameMetrics.mPageRect.YMost() * SHRINK_FACTOR)) {
1102
if (!mPinnedFlags) {
1103
// If the toolbar is partial hidden, show it.
1104
if (mControllerToolbarHeight != mControllerMaxToolbarHeight) {
1105
StartCompositorAnimation(MOVE_TOOLBAR_DOWN, eImmediate,
1106
mControllerToolbarHeight,
1107
/* wait for page resize */ true);
1108
} else {
1109
// If the static snapshot is visible, then make sure the real toolbar is
1110
// visible
1111
ShowToolbarIfNotVisible(mToolbarState);
1112
}
1113
}
1114
return true;
1115
}
1116
1117
return false;
1118
}
1119
1120
void AndroidDynamicToolbarAnimator::ShowToolbarIfNotVisible(
1121
StaticToolbarState aCurrentToolbarState) {
1122
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
1123
if ((mControllerToolbarHeight == mControllerMaxToolbarHeight) &&
1124
(aCurrentToolbarState != eToolbarVisible) &&
1125
(mControllerState != eShowPending)) {
1126
mControllerState = eShowPending;
1127
PostMessage(TOOLBAR_SHOW);
1128
}
1129
}
1130
1131
bool AndroidDynamicToolbarAnimator::FrameMetricsState::Update(
1132
const ScreenPoint& aScrollOffset, const CSSToScreenScale& aScale,
1133
const CSSRect& aCssPageRect) {
1134
if (!FuzzyEqualsMultiplicative(aScrollOffset.x, mScrollOffset.x) ||
1135
!FuzzyEqualsMultiplicative(aScrollOffset.y, mScrollOffset.y) ||
1136
!FuzzyEqualsMultiplicative(aScale.scale, mScale.scale) ||
1137
!FuzzyEqualsMultiplicative(aCssPageRect.width, mCssPageRect.width) ||
1138
!FuzzyEqualsMultiplicative(aCssPageRect.height, mCssPageRect.height) ||
1139
!FuzzyEqualsMultiplicative(aCssPageRect.x, mCssPageRect.x) ||
1140
!FuzzyEqualsMultiplicative(aCssPageRect.y, mCssPageRect.y)) {
1141
mScrollOffset = aScrollOffset;
1142
mScale = aScale;
1143
mCssPageRect = aCssPageRect;
1144
mPageRect = mCssPageRect * mScale;
1145
return true;
1146
}
1147
1148
return false;
1149
}
1150
1151
void AndroidDynamicToolbarAnimator::TranslateTouchEvent(
1152
MultiTouchInput& aTouchEvent) {
1153
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
1154
if (mControllerToolbarHeight > 0) {
1155
aTouchEvent.Translate(ScreenPoint(0.0f, -(float)mControllerToolbarHeight));
1156
}
1157
}
1158
1159
ScreenIntCoord AndroidDynamicToolbarAnimator::GetFixedLayerMarginsBottom() {
1160
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1161
return mCompositorToolbarHeight -
1162
(mCompositorSurfaceHeight - mCompositorCompositionSize.height);
1163
}
1164
1165
void AndroidDynamicToolbarAnimator::NotifyControllerSnapshotFailed() {
1166
if (!APZThreadUtils::IsControllerThread()) {
1167
APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
1168
"AndroidDynamicToolbarAnimator::NotifyControllerSnapshotFailed", this,
1169
&AndroidDynamicToolbarAnimator::NotifyControllerSnapshotFailed));
1170
return;
1171
}
1172
1173
mControllerToolbarHeight = 0;
1174
mControllerState = eNothingPending;
1175
UpdateCompositorToolbarHeight(mControllerToolbarHeight);
1176
}
1177
1178
void AndroidDynamicToolbarAnimator::CheckForResetOnNextMove(
1179
ScreenIntCoord aCurrentTouch) {
1180
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
1181
if (mControllerResetOnNextMove) {
1182
mControllerTotalDistance = 0;
1183
mControllerLastDragDirection = 0;
1184
mControllerStartTouch = mControllerPreviousTouch = aCurrentTouch;
1185
mControllerDragThresholdReached = false;
1186
mControllerResetOnNextMove = false;
1187
}
1188
}
1189
1190
bool AndroidDynamicToolbarAnimator::ScrollOffsetNearBottom() const {
1191
MOZ_ASSERT(APZThreadUtils::IsControllerThread());
1192
// Twice the toolbar's height is considered near the bottom of the page.
1193
if ((mControllerToolbarHeight * 2) >=
1194
(mControllerFrameMetrics.mPageRect.YMost() -
1195
(mControllerRootScrollY + ScreenCoord(mControllerCompositionHeight)))) {
1196
return true;
1197
}
1198
return false;
1199
}
1200
1201
bool AndroidDynamicToolbarAnimator::ToolbarInTransition() {
1202
if (APZThreadUtils::IsControllerThread()) {
1203
return (mControllerToolbarHeight != mControllerMaxToolbarHeight) &&
1204
(mControllerToolbarHeight != 0);
1205
}
1206
1207
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1208
return (mCompositorToolbarHeight != mCompositorMaxToolbarHeight) &&
1209
(mCompositorToolbarHeight != 0);
1210
}
1211
1212
void AndroidDynamicToolbarAnimator::QueueMessage(int32_t aMessage) {
1213
if (!CompositorThreadHolder::IsInCompositorThread()) {
1214
CompositorThreadHolder::Loop()->PostTask(NewRunnableMethod<int32_t>(
1215
"AndroidDynamicToolbarAnimator::QueueMessage", this,
1216
&AndroidDynamicToolbarAnimator::QueueMessage, aMessage));
1217
return;
1218
}
1219
1220
// If the root layer tree id is no longer zero, Initialize() was called before
1221
// QueueMessage was processed so just post the message now.
1222
if (mRootLayerTreeId.IsValid()) {
1223
PostMessage(aMessage);
1224
return;
1225
}
1226
1227
mCompositorQueuedMessages.insertBack(new QueuedMessage(aMessage));
1228
}
1229
1230
} // namespace layers
1231
} // namespace mozilla