#include "config.h"
#include "core/rendering/RenderLayer.h"
+#include "core/accessibility/AXObjectCache.h"
#include "core/css/PseudoStyleRequest.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/editing/FrameSelection.h"
#include "core/rendering/RenderGeometryMap.h"
#include "core/rendering/RenderScrollbar.h"
#include "core/rendering/RenderScrollbarPart.h"
+#include "core/rendering/RenderTheme.h"
#include "core/rendering/RenderView.h"
#include "core/rendering/compositing/CompositedLayerMapping.h"
#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "platform/scroll/ScrollbarTheme.h"
#include "public/platform/Platform.h"
-namespace WebCore {
+namespace blink {
const int ResizerControlExpandRatioForTouch = 2;
, m_scrollsOverflow(false)
, m_scrollDimensionsDirty(true)
, m_inOverflowRelayout(false)
- , m_scrollCorner(0)
- , m_resizer(0)
+ , m_nextTopmostScrollChild(0)
+ , m_topmostScrollChild(0)
+ , m_needsCompositedScrolling(false)
+ , m_scrollCorner(nullptr)
+ , m_resizer(nullptr)
{
ScrollableArea::setConstrainsScrollingToContentEdge(false);
GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const
{
- return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->scrollingContentsLayer() : 0;
+ return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->scrollingContentsLayer() : 0;
}
GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const
// See crbug.com/343132.
DisableCompositingQueryAsserts disabler;
- return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForHorizontalScrollbar() : 0;
+ return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForHorizontalScrollbar() : 0;
}
GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const
// See crbug.com/343132.
DisableCompositingQueryAsserts disabler;
- return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForVerticalScrollbar() : 0;
+ return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForVerticalScrollbar() : 0;
}
GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const
// See crbug.com/343132.
DisableCompositingQueryAsserts disabler;
- return box().hasCompositedLayerMapping() ? box().compositedLayerMapping()->layerForScrollCorner() : 0;
+ return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMapping()->layerForScrollCorner() : 0;
}
void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
IntRect intRect = pixelSnappedIntRect(repaintRect);
- if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && box().frameView()->isInPerformLayout()) {
- if (scrollbar == m_vBar.get()) {
- m_verticalBarDamage = intRect;
- m_hasVerticalBarDamage = true;
- } else {
- m_horizontalBarDamage = intRect;
- m_hasHorizontalBarDamage = true;
- }
-
- } else {
+ if (box().frameView()->isInPerformLayout())
+ addScrollbarDamage(scrollbar, intRect);
+ else
box().invalidatePaintRectangle(intRect);
- }
}
void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect)
// FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
InspectorInstrumentation::willScrollLayer(&box());
+ const RenderLayerModelObject* repaintContainer = box().containerForPaintInvalidation();
+
// Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
// We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
if (!frameView->isInPerformLayout()) {
// If we're in the middle of layout, we'll just update layers once layout has finished.
- layer()->updateLayerPositionsAfterOverflowScroll();
+ layer()->clipper().clearClipRectsIncludingDescendants();
+ box().setPreviousPaintInvalidationRect(box().boundsRectForPaintInvalidation(repaintContainer));
// Update regions, scrolling may change the clip of a particular region.
frameView->updateAnnotatedRegions();
// FIXME: We shouldn't call updateWidgetPositions() here since it might tear down the render tree,
updateCompositingLayersAfterScroll();
}
- const RenderLayerModelObject* repaintContainer = box().containerForPaintInvalidation();
// The caret rect needs to be invalidated after scrolling
frame->selection().setCaretRectNeedsUpdate();
- FloatQuad quadForFakeMouseMoveEvent;
- if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
- quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect());
- else
- quadForFakeMouseMoveEvent = FloatQuad(layer()->repainter().repaintRect());
+ FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previousPaintInvalidationRect());
quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
bool requiresRepaint = true;
- if (box().view()->compositor()->inCompositingMode()) {
+ if (!box().isMarquee() && box().view()->compositor()->inCompositingMode()) {
// Hits in virtual/gpu/fast/canvas/canvas-scroll-path-into-view.html.
DisableCompositingQueryAsserts disabler;
bool onlyScrolledCompositedLayers = scrollsOverflow()
&& !layer()->hasVisibleNonLayerContent()
&& !layer()->hasNonCompositedChild()
&& !layer()->hasBlockSelectionGapBounds()
- && !box().isMarquee();
+ && box().style()->backgroundLayers().attachment() != LocalBackgroundAttachment;
if (usesCompositedScrolling() || onlyScrolledCompositedLayers)
requiresRepaint = false;
// Just schedule a full repaint of our object.
if (requiresRepaint) {
- if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
- if (box().frameView()->isInPerformLayout())
- box().setShouldDoFullPaintInvalidationAfterLayout(true);
- else
- box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->renderer()->previousPaintInvalidationRect()), InvalidationScroll);
- } else {
- box().invalidatePaintUsingContainer(repaintContainer, pixelSnappedIntRect(layer()->repainter().repaintRect()), InvalidationScroll);
- }
+ if (box().frameView()->isInPerformLayout())
+ box().setShouldDoFullPaintInvalidation(true);
+ else
+ box().invalidatePaintUsingContainer(repaintContainer, layer()->renderer()->previousPaintInvalidationRect(), InvalidationScroll);
}
// Schedule the scroll DOM event.
{
if (!box().hasOverflowClip())
return -scrollOrigin();
-
- return -scrollOrigin() + enclosingIntRect(m_overflowRect).size() - enclosingIntRect(box().clientBoxRect()).size();
+ return -scrollOrigin() + IntPoint(pixelSnappedScrollWidth(), pixelSnappedScrollHeight()) - enclosingIntRect(box().clientBoxRect()).size();
}
IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarInclusion) const
return m_overflowRect.height();
}
+int RenderLayerScrollableArea::pixelSnappedScrollWidth() const
+{
+ return snapSizeToPixel(scrollWidth(), box().clientLeft() + box().x());
+}
+
+int RenderLayerScrollableArea::pixelSnappedScrollHeight() const
+{
+ return snapSizeToPixel(scrollHeight(), box().clientTop() + box().y());
+}
+
void RenderLayerScrollableArea::computeScrollDimensions()
{
m_scrollDimensionsDirty = false;
void RenderLayerScrollableArea::updateAfterLayout()
{
- // List box parts handle the scrollbars by themselves so we have nothing to do.
- if (box().style()->appearance() == ListboxPart)
- return;
-
m_scrollDimensionsDirty = true;
IntSize originalScrollOffset = adjustedScrollOffset();
if (box().document().hasAnnotatedRegions())
box().document().setAnnotatedRegionsDirty(true);
- if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled())
- box().paintInvalidationForWholeRenderer();
-
if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) {
if (!m_inOverflowRelayout) {
// Our proprietary overflow: overlay value doesn't trigger a layout.
}
}
- updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow());
+ bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow();
+ updateScrollableAreaSet(hasOverflow);
+
+ if (hasOverflow) {
+ DisableCompositingQueryAsserts disabler;
+ positionOverflowControls(IntSize());
+ }
}
bool RenderLayerScrollableArea::hasHorizontalOverflow() const
{
ASSERT(!m_scrollDimensionsDirty);
- return scrollWidth() > box().clientWidth();
+ return pixelSnappedScrollWidth() > box().pixelSnappedClientWidth();
}
bool RenderLayerScrollableArea::hasVerticalOverflow() const
{
ASSERT(!m_scrollDimensionsDirty);
- return scrollHeight() > box().clientHeight();
+ return pixelSnappedScrollHeight() > box().pixelSnappedClientHeight();
}
bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const
void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldStyle)
{
- // List box parts handle the scrollbars by themselves so we have nothing to do.
- if (box().style()->appearance() == ListboxPart)
- return;
-
// RenderView shouldn't provide scrollbars on its own.
if (box().isRenderView())
return;
updateResizerStyle();
}
-void RenderLayerScrollableArea::updateAfterCompositingChange()
+bool RenderLayerScrollableArea::updateAfterCompositingChange()
{
layer()->updateScrollingStateAfterCompositingChange();
+ const bool layersChanged = m_topmostScrollChild != m_nextTopmostScrollChild;
+ m_topmostScrollChild = m_nextTopmostScrollChild;
+ m_nextTopmostScrollChild = nullptr;
+ return layersChanged;
}
void RenderLayerScrollableArea::updateAfterOverflowRecalc()
if (hasCustomScrollbarStyle) {
widget = RenderScrollbar::createCustomScrollbar(this, orientation, actualRenderer->node());
} else {
- widget = Scrollbar::create(this, orientation, RegularScrollbar);
+ ScrollbarControlSize scrollbarSize = RegularScrollbar;
+ if (actualRenderer->style()->hasAppearance())
+ scrollbarSize = RenderTheme::theme().scrollbarControlSizeForPart(actualRenderer->style()->appearance());
+ widget = Scrollbar::create(this, orientation, scrollbarSize);
if (orientation == HorizontalScrollbar)
didAddScrollbar(widget.get(), HorizontalScrollbar);
else
// FIXME, this should eventually be removed, once we are certain that composited
// controls get correctly positioned on a compositor update. For now, conservatively
// leaving this unchanged.
- if (box().hasCompositedLayerMapping())
- box().compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot);
+ if (layer()->hasCompositedLayerMapping())
+ layer()->compositedLayerMapping()->positionOverflowControlsLayers(offsetFromRoot);
}
void RenderLayerScrollableArea::updateScrollCornerStyle()
m_scrollCorner->setStyle(corner.release());
} else if (m_scrollCorner) {
m_scrollCorner->destroy();
- m_scrollCorner = 0;
+ m_scrollCorner = nullptr;
}
}
RenderView* renderView = box().view();
- RenderLayer* paintingRoot = layer()->enclosingCompositingLayer();
+ RenderLayer* paintingRoot = layer()->enclosingLayerWithCompositedLayerMapping(IncludeSelf);
if (!paintingRoot)
paintingRoot = renderView->layer();
if (!absRect.intersects(damageRect))
return;
- if (context->updatingControlTints()) {
- updateScrollCornerStyle();
- return;
- }
-
if (m_scrollCorner) {
m_scrollCorner->paintIntoRect(context, paintOffset, absRect);
return;
if (!absRect.intersects(damageRect))
return;
- if (context->updatingControlTints()) {
- updateResizerStyle();
- return;
- }
-
if (m_resizer) {
m_resizer->paintIntoRect(context, paintOffset, absRect);
return;
m_resizer->setStyle(resizer.release());
} else if (m_resizer) {
m_resizer->destroy();
- m_resizer = 0;
+ m_resizer = nullptr;
}
}
void RenderLayerScrollableArea::drawPlatformResizerImage(GraphicsContext* context, IntRect resizerCornerRect)
{
- float deviceScaleFactor = WebCore::deviceScaleFactor(box().frame());
+ float deviceScaleFactor = blink::deviceScaleFactor(box().frame());
RefPtr<Image> resizeCornerImage;
IntSize cornerResizerSize;
if (HTMLFrameOwnerElement* owner = frame->deprecatedLocalOwner())
isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToHitTesting();
- bool didNeedCompositedScrolling = needsCompositedScrolling();
-
bool didScrollOverflow = m_scrollsOverflow;
m_scrollsOverflow = hasOverflow && isVisibleToHitTest;
frameView->addScrollableArea(this);
else
frameView->removeScrollableArea(this);
-
- if (didNeedCompositedScrolling != needsCompositedScrolling())
- layer()->didUpdateNeedsCompositedScrolling();
}
void RenderLayerScrollableArea::updateCompositingLayersAfterScroll()
if (compositor->inCompositingMode()) {
if (usesCompositedScrolling()) {
DisableCompositingQueryAsserts disabler;
- ASSERT(box().hasCompositedLayerMapping());
- box().compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
+ ASSERT(layer()->hasCompositedLayerMapping());
+ layer()->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree);
compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange);
} else {
layer()->setNeedsCompositingInputsUpdate();
- compositor->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInputChange);
}
}
}
// See https://codereview.chromium.org/176633003/ for the tests that fail without this disabler.
DisableCompositingQueryAsserts disabler;
- return box().hasCompositedLayerMapping() && box().compositedLayerMapping()->scrollingLayer();
+ return layer()->hasCompositedLayerMapping() && layer()->compositedLayerMapping()->scrollingLayer();
+}
+
+static bool layerNeedsCompositedScrolling(const RenderLayer* layer)
+{
+ return layer->scrollsOverflow()
+ && layer->compositor()->acceleratedCompositingForOverflowScrollEnabled()
+ && !layer->hasDescendantWithClipPath()
+ && !layer->hasAncestorWithClipPath();
}
-bool RenderLayerScrollableArea::needsCompositedScrolling() const
+void RenderLayerScrollableArea::updateNeedsCompositedScrolling()
{
- return scrollsOverflow() && box().view()->compositor()->acceleratedCompositingForOverflowScrollEnabled();
+ const bool needsCompositedScrolling = layerNeedsCompositedScrolling(layer());
+ if (static_cast<bool>(m_needsCompositedScrolling) != needsCompositedScrolling) {
+ m_needsCompositedScrolling = needsCompositedScrolling;
+ layer()->didUpdateNeedsCompositedScrolling();
+ }
+}
+
+void RenderLayerScrollableArea::setTopmostScrollChild(RenderLayer* scrollChild)
+{
+ // We only want to track the topmost scroll child for scrollable areas with
+ // overlay scrollbars.
+ if (!hasOverlayScrollbars())
+ return;
+ m_nextTopmostScrollChild = scrollChild;
}
-} // Namespace WebCore
+} // namespace blink