Index: third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp |
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp |
index 8f4b977c9200c3206e84f955a3d162b784f50cb3..58f9146b733d5b52d510069d37aca1c583b60abe 100644 |
--- a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp |
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp |
@@ -18,6 +18,7 @@ namespace blink { |
namespace { |
+using testing::_; |
using testing::Return; |
class MockScrollableArea : public NoBaseWillBeGarbageCollectedFinalized<MockScrollableArea>, public ScrollableArea { |
@@ -32,12 +33,15 @@ public: |
MOCK_CONST_METHOD1(scrollSize, int(ScrollbarOrientation)); |
MOCK_CONST_METHOD0(isScrollCornerVisible, bool()); |
MOCK_CONST_METHOD0(scrollCornerRect, IntRect()); |
+ MOCK_CONST_METHOD0(horizontalScrollbar, Scrollbar*()); |
+ MOCK_CONST_METHOD0(verticalScrollbar, Scrollbar*()); |
MOCK_METHOD0(scrollControlWasSetNeedsPaintInvalidation, void()); |
MOCK_CONST_METHOD0(enclosingScrollableArea, ScrollableArea*()); |
MOCK_CONST_METHOD1(visibleContentRect, IntRect(IncludeScrollbarsInRect)); |
MOCK_CONST_METHOD0(contentsSize, IntSize()); |
MOCK_CONST_METHOD0(scrollableAreaBoundingBox, IntRect()); |
MOCK_CONST_METHOD0(layerForHorizontalScrollbar, GraphicsLayer*()); |
+ MOCK_CONST_METHOD0(layerForVerticalScrollbar, GraphicsLayer*()); |
bool userInputScrollable(ScrollbarOrientation) const override { return true; } |
bool scrollbarsCanBeActive () const override { return true; } |
@@ -51,6 +55,10 @@ public: |
bool scrollAnimatorEnabled() const override { return false; } |
int pageStep(ScrollbarOrientation) const override { return 0; } |
+ using ScrollableArea::horizontalScrollbarNeedsPaintInvalidation; |
+ using ScrollableArea::verticalScrollbarNeedsPaintInvalidation; |
+ using ScrollableArea::clearNeedsPaintInvalidationForScrollControls; |
+ |
DEFINE_INLINE_VIRTUAL_TRACE() |
{ |
ScrollableArea::trace(visitor); |
@@ -142,6 +150,7 @@ namespace { |
class ScrollbarThemeWithMockInvalidation : public ScrollbarThemeMock { |
public: |
MOCK_CONST_METHOD0(shouldRepaintAllPartsOnInvalidation, bool()); |
+ MOCK_CONST_METHOD3(invalidateOnThumbPositionChange, ScrollbarPart(const ScrollbarThemeClient&, float, float)); |
}; |
} // namespace |
@@ -163,18 +172,20 @@ TEST_F(ScrollableAreaTest, ScrollbarTrackAndThumbRepaint) |
scrollbar->setThumbNeedsRepaint(false); |
EXPECT_FALSE(scrollbar->trackNeedsRepaint()); |
EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); |
- scrollbar->setNeedsPaintInvalidation(); |
+ scrollbar->setNeedsPaintInvalidation(ThumbPart); |
EXPECT_TRUE(scrollbar->trackNeedsRepaint()); |
EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); |
+ // When not all parts are repainted on invalidation, |
+ // setNeedsPaintInvalidation sets repaint bits only on the requested parts. |
EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); |
scrollbar->setTrackNeedsRepaint(false); |
scrollbar->setThumbNeedsRepaint(false); |
EXPECT_FALSE(scrollbar->trackNeedsRepaint()); |
EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); |
- scrollbar->setNeedsPaintInvalidation(); |
+ scrollbar->setNeedsPaintInvalidation(ThumbPart); |
EXPECT_FALSE(scrollbar->trackNeedsRepaint()); |
- EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); |
+ EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); |
// Forced GC in order to finalize objects depending on the mock object. |
Heap::collectAllGarbage(); |
@@ -210,4 +221,98 @@ TEST_F(ScrollableAreaTest, ScrollbarGraphicsLayerInvalidation) |
EXPECT_TRUE(graphicsLayer.hasTrackedPaintInvalidations()); |
} |
+TEST_F(ScrollableAreaTest, InvalidatesNonCompositedScrollbarsWhenThumbMoves) |
+{ |
+ ScrollbarThemeWithMockInvalidation theme; |
+ OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(IntPoint(100, 100)); |
+ RefPtrWillBeRawPtr<Scrollbar> horizontalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), HorizontalScrollbar, RegularScrollbar, &theme); |
+ RefPtrWillBeRawPtr<Scrollbar> verticalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), VerticalScrollbar, RegularScrollbar, &theme); |
+ EXPECT_CALL(*scrollableArea, horizontalScrollbar()).WillRepeatedly(Return(horizontalScrollbar.get())); |
+ EXPECT_CALL(*scrollableArea, verticalScrollbar()).WillRepeatedly(Return(verticalScrollbar.get())); |
+ |
+ // Regardless of whether the theme invalidates any parts, non-composited |
+ // scrollbars have to be repainted if the thumb moves. |
+ EXPECT_CALL(*scrollableArea, layerForHorizontalScrollbar()).WillRepeatedly(Return(nullptr)); |
+ EXPECT_CALL(*scrollableArea, layerForVerticalScrollbar()).WillRepeatedly(Return(nullptr)); |
+ ASSERT_FALSE(scrollableArea->hasLayerForVerticalScrollbar()); |
+ ASSERT_FALSE(scrollableArea->hasLayerForHorizontalScrollbar()); |
+ EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); |
+ EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillRepeatedly(Return(NoPart)); |
+ |
+ // A scroll in each direction should only invalidate one scrollbar. |
+ scrollableArea->setScrollPosition(DoublePoint(0, 50), ProgrammaticScroll); |
+ EXPECT_FALSE(scrollableArea->horizontalScrollbarNeedsPaintInvalidation()); |
+ EXPECT_TRUE(scrollableArea->verticalScrollbarNeedsPaintInvalidation()); |
+ scrollableArea->clearNeedsPaintInvalidationForScrollControls(); |
+ scrollableArea->setScrollPosition(DoublePoint(50, 50), ProgrammaticScroll); |
+ EXPECT_TRUE(scrollableArea->horizontalScrollbarNeedsPaintInvalidation()); |
+ EXPECT_FALSE(scrollableArea->verticalScrollbarNeedsPaintInvalidation()); |
+ scrollableArea->clearNeedsPaintInvalidationForScrollControls(); |
+ |
+ // Forced GC in order to finalize objects depending on the mock object. |
+ Heap::collectAllGarbage(); |
+} |
+ |
+ |
+TEST_F(ScrollableAreaTest, InvalidatesCompositedScrollbarsIfPartsNeedRepaint) |
+{ |
+ ScrollbarThemeWithMockInvalidation theme; |
+ OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(IntPoint(100, 100)); |
+ RefPtrWillBeRawPtr<Scrollbar> horizontalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), HorizontalScrollbar, RegularScrollbar, &theme); |
+ horizontalScrollbar->setTrackNeedsRepaint(false); |
+ horizontalScrollbar->setThumbNeedsRepaint(false); |
+ RefPtrWillBeRawPtr<Scrollbar> verticalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), VerticalScrollbar, RegularScrollbar, &theme); |
+ verticalScrollbar->setTrackNeedsRepaint(false); |
+ verticalScrollbar->setThumbNeedsRepaint(false); |
+ EXPECT_CALL(*scrollableArea, horizontalScrollbar()).WillRepeatedly(Return(horizontalScrollbar.get())); |
+ EXPECT_CALL(*scrollableArea, verticalScrollbar()).WillRepeatedly(Return(verticalScrollbar.get())); |
+ |
+ // Composited scrollbars only need repainting when parts become invalid |
+ // (e.g. if the track changes appearance when the thumb reaches the end). |
+ MockGraphicsLayerClient graphicsLayerClient; |
+ MockGraphicsLayer layerForHorizontalScrollbar(&graphicsLayerClient); |
+ layerForHorizontalScrollbar.setDrawsContent(true); |
+ layerForHorizontalScrollbar.setSize(FloatSize(10, 10)); |
+ MockGraphicsLayer layerForVerticalScrollbar(&graphicsLayerClient); |
+ layerForVerticalScrollbar.setDrawsContent(true); |
+ layerForVerticalScrollbar.setSize(FloatSize(10, 10)); |
+ EXPECT_CALL(*scrollableArea, layerForHorizontalScrollbar()).WillRepeatedly(Return(&layerForHorizontalScrollbar)); |
+ EXPECT_CALL(*scrollableArea, layerForVerticalScrollbar()).WillRepeatedly(Return(&layerForVerticalScrollbar)); |
+ ASSERT_TRUE(scrollableArea->hasLayerForHorizontalScrollbar()); |
+ ASSERT_TRUE(scrollableArea->hasLayerForVerticalScrollbar()); |
+ EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); |
+ |
+ // First, we'll scroll horizontally, and the theme will require repainting |
+ // the back button (i.e. the track). |
+ EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillOnce(Return(BackButtonStartPart)); |
+ scrollableArea->setScrollPosition(DoublePoint(50, 0), ProgrammaticScroll); |
+ EXPECT_TRUE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_FALSE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_TRUE(horizontalScrollbar->trackNeedsRepaint()); |
+ EXPECT_FALSE(horizontalScrollbar->thumbNeedsRepaint()); |
+ layerForHorizontalScrollbar.resetTrackedPaintInvalidations(); |
+ horizontalScrollbar->setTrackNeedsRepaint(false); |
+ |
+ // Next, we'll scroll vertically, but invalidate the thumb. |
+ EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillOnce(Return(ThumbPart)); |
+ scrollableArea->setScrollPosition(DoublePoint(50, 50), ProgrammaticScroll); |
+ EXPECT_FALSE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_TRUE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_FALSE(verticalScrollbar->trackNeedsRepaint()); |
+ EXPECT_TRUE(verticalScrollbar->thumbNeedsRepaint()); |
+ layerForVerticalScrollbar.resetTrackedPaintInvalidations(); |
+ verticalScrollbar->setThumbNeedsRepaint(false); |
+ |
+ // Next we'll scroll in both, but the thumb position moving requires no |
+ // invalidations. |
+ EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).Times(2).WillRepeatedly(Return(NoPart)); |
+ scrollableArea->setScrollPosition(DoublePoint(70, 70), ProgrammaticScroll); |
+ EXPECT_FALSE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_FALSE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); |
+ EXPECT_FALSE(horizontalScrollbar->trackNeedsRepaint()); |
+ EXPECT_FALSE(horizontalScrollbar->thumbNeedsRepaint()); |
+ EXPECT_FALSE(verticalScrollbar->trackNeedsRepaint()); |
+ EXPECT_FALSE(verticalScrollbar->thumbNeedsRepaint()); |
+} |
+ |
} // namespace blink |