void ScrollAnimatorCompositorCoordinator::compositorAnimationFinished( int groupId) { if (m_compositorAnimationGroupId != groupId) return; m_compositorAnimationId = 0; m_compositorAnimationGroupId = 0; switch (m_runState) { case RunState::Idle: case RunState::PostAnimationCleanup: case RunState::RunningOnMainThread: ASSERT_NOT_REACHED(); break; case RunState::WaitingToSendToCompositor: break; case RunState::RunningOnCompositor: case RunState::RunningOnCompositorButNeedsUpdate: case RunState::RunningOnCompositorButNeedsTakeover: case RunState::WaitingToCancelOnCompositor: m_runState = RunState::PostAnimationCleanup; // Get serviced the next time compositor updates are allowed. if (scrollableArea()) scrollableArea()->registerForAnimation(); else resetAnimationState(); } }
bool ScrollAnimatorCompositorCoordinator::reattachCompositorPlayerIfNeeded( CompositorAnimationTimeline* timeline) { bool reattached = false; int compositorAnimationAttachedToLayerId = 0; if (scrollableArea()->layerForScrolling()) compositorAnimationAttachedToLayerId = scrollableArea()->layerForScrolling()->platformLayer()->id(); if (compositorAnimationAttachedToLayerId != m_compositorAnimationAttachedToLayerId) { if (m_compositorPlayer && timeline) { // Detach from old layer (if any). if (m_compositorAnimationAttachedToLayerId) { if (m_compositorPlayer->isLayerAttached()) m_compositorPlayer->detachLayer(); timeline->playerDestroyed(*this); } // Attach to new layer (if any). if (compositorAnimationAttachedToLayerId) { ASSERT(!m_compositorPlayer->isLayerAttached()); timeline->playerAttached(*this); m_compositorPlayer->attachLayer( scrollableArea()->layerForScrolling()->platformLayer()); reattached = true; } m_compositorAnimationAttachedToLayerId = compositorAnimationAttachedToLayerId; } } return reattached; }
void ScrollableAreaPainter::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect) { float deviceScaleFactor = blink::deviceScaleFactor(scrollableArea().box().frame()); RefPtr<Image> resizeCornerImage; IntSize cornerResizerSize; if (deviceScaleFactor >= 2) { DEFINE_STATIC_REF(Image, resizeCornerImageHiRes, (Image::loadPlatformResource("textAreaResizeCorner@2x"))); resizeCornerImage = resizeCornerImageHiRes; cornerResizerSize = resizeCornerImage->size(); cornerResizerSize.scale(0.5f); } else { DEFINE_STATIC_REF(Image, resizeCornerImageLoRes, (Image::loadPlatformResource("textAreaResizeCorner"))); resizeCornerImage = resizeCornerImageLoRes; cornerResizerSize = resizeCornerImage->size(); } if (scrollableArea().box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { context->save(); context->translate(resizerCornerRect.x() + cornerResizerSize.width(), resizerCornerRect.y() + resizerCornerRect.height() - cornerResizerSize.height()); context->scale(-1.0, 1.0); context->drawImage(resizeCornerImage.get(), IntRect(IntPoint(), cornerResizerSize)); context->restore(); return; } IntRect imageRect(resizerCornerRect.maxXMaxYCorner() - cornerResizerSize, cornerResizerSize); context->drawImage(resizeCornerImage.get(), imageRect); }
void ScrollAnimatorCompositorCoordinator::cancelAnimation() { switch (m_runState) { case RunState::Idle: case RunState::WaitingToCancelOnCompositor: case RunState::PostAnimationCleanup: break; case RunState::RunningOnCompositorButNeedsTakeover: case RunState::WaitingToSendToCompositor: if (m_compositorAnimationId) { // We still have a previous animation running on the compositor. m_runState = RunState::WaitingToCancelOnCompositor; } else { resetAnimationState(); } break; case RunState::RunningOnMainThread: m_runState = RunState::PostAnimationCleanup; break; case RunState::RunningOnCompositorButNeedsUpdate: case RunState::RunningOnCompositor: m_runState = RunState::WaitingToCancelOnCompositor; // Get serviced the next time compositor updates are allowed. scrollableArea()->registerForAnimation(); } }
void ScrollAnimator::tickAnimation(double monotonicTime) { if (m_runState != RunState::RunningOnMainThread) return; TRACE_EVENT0("blink", "ScrollAnimator::tickAnimation"); double elapsedTime = monotonicTime - m_startTime; bool isFinished = (elapsedTime > m_animationCurve->duration()); FloatPoint offset = isFinished ? m_animationCurve->targetValue() : m_animationCurve->getValue(elapsedTime); offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset)); m_currentPosX = offset.x(); m_currentPosY = offset.y(); if (isFinished) resetAnimationState(); else scrollableArea()->scheduleAnimation(); TRACE_EVENT0("blink", "ScrollAnimator::notifyPositionChanged"); notifyPositionChanged(); }
bool ScrollableAreaPainter::overflowControlsIntersectRect(const IntRect& localRect) const { const IntRect borderBox = scrollableArea().box().pixelSnappedBorderBoxRect(); if (scrollableArea().rectForHorizontalScrollbar(borderBox).intersects(localRect)) return true; if (scrollableArea().rectForVerticalScrollbar(borderBox).intersects(localRect)) return true; if (scrollableArea().scrollCornerRect().intersects(localRect)) return true; if (scrollableArea().resizerCornerRect(borderBox, ResizerForPointer).intersects(localRect)) return true; return false; }
void ScrollAnimatorCompositorCoordinator::removeAnimation() { if (m_compositorPlayer) { if (m_compositorPlayer->isLayerAttached()) m_compositorPlayer->removeAnimation(m_compositorAnimationId); } else { if (GraphicsLayer* layer = scrollableArea()->layerForScrolling()) layer->removeAnimation(m_compositorAnimationId); } }
bool ScrollAnimator::registerAndScheduleAnimation() { scrollableArea()->registerForAnimation(); if (!m_scrollableArea->scheduleAnimation()) { scrollToOffsetWithoutAnimation(m_targetOffset); resetAnimationState(); return false; } return true; }
void ScrollableAreaPainter::paintScrollCorner(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) { IntRect absRect = scrollableArea().scrollCornerRect(); if (absRect.isEmpty()) return; absRect.moveBy(paintOffset); if (scrollableArea().scrollCorner()) { if (!absRect.intersects(damageRect)) return; ScrollbarPainter::paintIntoRect(scrollableArea().scrollCorner(), context, paintOffset, LayoutRect(absRect)); return; } if (!RuntimeEnabledFeatures::slimmingPaintEnabled() && !absRect.intersects(damageRect)) return; // We don't want to paint white if we have overlay scrollbars, since we need // to see what is behind it. if (scrollableArea().hasOverlayScrollbars()) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, scrollableArea().box(), DisplayItem::ScrollbarCorner)) return; LayoutObjectDrawingRecorder recorder(*context, scrollableArea().box(), DisplayItem::ScrollbarCorner, absRect); context->fillRect(absRect, Color::white); }
bool ScrollAnimatorCompositorCoordinator::addAnimation( PassOwnPtr<CompositorAnimation> animation) { if (m_compositorPlayer) { if (m_compositorPlayer->isLayerAttached()) { m_compositorPlayer->addAnimation(animation.leakPtr()); return true; } } else { return scrollableArea()->layerForScrolling()->addAnimation(animation); } return false; }
void ScrollableAreaPainter::paintResizer(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect) { if (scrollableArea().box().style()->resize() == RESIZE_NONE) return; IntRect absRect = scrollableArea().resizerCornerRect(scrollableArea().box().pixelSnappedBorderBoxRect(), ResizerForPointer); if (absRect.isEmpty()) return; absRect.moveBy(paintOffset); if (scrollableArea().resizer()) { if (!absRect.intersects(damageRect)) return; ScrollbarPainter::paintIntoRect(scrollableArea().resizer(), context, paintOffset, LayoutRect(absRect)); return; } if (!RuntimeEnabledFeatures::slimmingPaintEnabled() && !absRect.intersects(damageRect)) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*context, scrollableArea().box(), DisplayItem::Resizer)) return; LayoutObjectDrawingRecorder recorder(*context, scrollableArea().box(), DisplayItem::Resizer, absRect); drawPlatformResizerImage(context, absRect); // Draw a frame around the resizer (1px grey line) if there are any scrollbars present. // Clipping will exclude the right and bottom edges of this frame. if (!scrollableArea().hasOverlayScrollbars() && scrollableArea().hasScrollbar()) { GraphicsContextStateSaver stateSaver(*context); context->clip(absRect); IntRect largerCorner = absRect; largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1)); context->setStrokeColor(Color(217, 217, 217)); context->setStrokeThickness(1.0f); context->setFillColor(Color::transparent); context->drawRect(largerCorner); } }
ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta) { if (!m_scrollableArea->scrollAnimatorEnabled()) return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta); TRACE_EVENT0("blink", "ScrollAnimator::scroll"); // FIXME: get the type passed in. MouseWheel could also be by line, but should still have different // animation parameters than the keyboard. Parameters parameters; switch (granularity) { case ScrollByDocument: case ScrollByLine: case ScrollByPage: case ScrollByPixel: parameters = parametersForScrollGranularity(granularity); break; case ScrollByPrecisePixel: return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta); } // If the individual input setting is disabled, bail. if (!parameters.m_isEnabled) return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta); // This is an animatable scroll. Set the animation in motion using the appropriate parameters. float scrollableSize = static_cast<float>(m_scrollableArea->scrollSize(orientation)); PerAxisData& data = (orientation == VerticalScrollbar) ? m_verticalData : m_horizontalData; bool needToScroll = data.updateDataFromParameters(step, delta, scrollableSize, WTF::monotonicallyIncreasingTime(), ¶meters); float unusedDelta = needToScroll ? delta - (data.m_desiredPosition - *data.m_currentPosition) : delta; if (needToScroll && !animationTimerActive()) { m_startTime = data.m_startTime; animationWillStart(); animationTimerFired(); scrollableArea()->registerForAnimation(); } return ScrollResultOneDimensional(needToScroll, unusedDelta); }
void ScrollAnimatorCompositorCoordinator::takeoverCompositorAnimation() { switch (m_runState) { case RunState::Idle: case RunState::WaitingToCancelOnCompositor: case RunState::PostAnimationCleanup: case RunState::RunningOnCompositorButNeedsTakeover: case RunState::WaitingToSendToCompositor: case RunState::RunningOnMainThread: break; case RunState::RunningOnCompositorButNeedsUpdate: case RunState::RunningOnCompositor: // We call abortAnimation that makes changes to the animation running on // the compositor. Thus, this function should only be called when in // CompositingClean state. abortAnimation(); m_runState = RunState::RunningOnCompositorButNeedsTakeover; // Get serviced the next time compositor updates are allowed. scrollableArea()->registerForAnimation(); } }
void ScrollAnimatorNone::startNextTimer() { if (scrollableArea()->scheduleAnimation()) m_animationActive = true; }
void ScrollableAreaPainter::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. if (!scrollableArea().box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; if (paintingOverlayControls) adjustedPaintOffset = scrollableArea().cachedOverlayScrollbarOffset(); IntRect localDamageRect = damageRect; localDamageRect.moveBy(-adjustedPaintOffset); // Overlay scrollbars paint in a second pass through the layer tree so that they will paint // on top of everything else. If this is the normal painting pass, paintingOverlayControls // will be false, and we should just tell the root layer that there are overlay scrollbars // that need to be painted. That will cause the second pass through the layer tree to run, // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the // second pass doesn't need to re-enter the LayoutTree to get it right. if (scrollableArea().hasOverlayScrollbars() && !paintingOverlayControls) { scrollableArea().setCachedOverlayScrollbarOffset(paintOffset); // It's not necessary to do the second pass if the scrollbars paint into layers. if ((scrollableArea().horizontalScrollbar() && scrollableArea().layerForHorizontalScrollbar()) || (scrollableArea().verticalScrollbar() && scrollableArea().layerForVerticalScrollbar())) return; if (!overflowControlsIntersectRect(localDamageRect)) return; LayoutView* layoutView = scrollableArea().box().view(); DeprecatedPaintLayer* paintingRoot = scrollableArea().layer()->enclosingLayerWithCompositedDeprecatedPaintLayerMapping(IncludeSelf); if (!paintingRoot) paintingRoot = layoutView->layer(); paintingRoot->setContainsDirtyOverlayScrollbars(true); return; } // This check is required to avoid painting custom CSS scrollbars twice. if (paintingOverlayControls && !scrollableArea().hasOverlayScrollbars()) return; { if (scrollableArea().horizontalScrollbar() && !scrollableArea().layerForHorizontalScrollbar()) { TransformRecorder translateRecorder(*context, *scrollableArea().horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); scrollableArea().horizontalScrollbar()->paint(context, localDamageRect); } if (scrollableArea().verticalScrollbar() && !scrollableArea().layerForVerticalScrollbar()) { TransformRecorder translateRecorder(*context, *scrollableArea().verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); scrollableArea().verticalScrollbar()->paint(context, localDamageRect); } } if (scrollableArea().layerForScrollCorner()) return; // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the // edge of the box. paintScrollCorner(context, adjustedPaintOffset, damageRect); // Paint our resizer last, since it sits on top of the scroll corner. paintResizer(context, adjustedPaintOffset, damageRect); }
void ScrollAnimatorNone::updateVisibleLengths() { m_horizontalData.updateVisibleLength(scrollableArea()->visibleWidth()); m_verticalData.updateVisibleLength(scrollableArea()->visibleHeight()); }
FloatPoint ScrollAnimatorCompositorCoordinator::blinkOffsetFromCompositorOffset(FloatPoint offset) { offset.moveBy(-scrollableArea()->scrollOrigin()); return offset; }