| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights
reserved. | |
| 3 * | |
| 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. | |
| 5 * | |
| 6 * Other contributors: | |
| 7 * Robert O'Callahan <roc+@cs.cmu.edu> | |
| 8 * David Baron <dbaron@fas.harvard.edu> | |
| 9 * Christian Biesinger <cbiesinger@web.de> | |
| 10 * Randall Jesup <rjesup@wgate.com> | |
| 11 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> | |
| 12 * Josh Soref <timeless@mac.com> | |
| 13 * Boris Zbarsky <bzbarsky@mit.edu> | |
| 14 * | |
| 15 * This library is free software; you can redistribute it and/or | |
| 16 * modify it under the terms of the GNU Lesser General Public | |
| 17 * License as published by the Free Software Foundation; either | |
| 18 * version 2.1 of the License, or (at your option) any later version. | |
| 19 * | |
| 20 * This library is distributed in the hope that it will be useful, | |
| 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 23 * Lesser General Public License for more details. | |
| 24 * | |
| 25 * You should have received a copy of the GNU Lesser General Public | |
| 26 * License along with this library; if not, write to the Free Software | |
| 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 US
A | |
| 28 * | |
| 29 * Alternatively, the contents of this file may be used under the terms | |
| 30 * of either the Mozilla Public License Version 1.1, found at | |
| 31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public | |
| 32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html | |
| 33 * (the "GPL"), in which case the provisions of the MPL or the GPL are | |
| 34 * applicable instead of those above. If you wish to allow use of your | |
| 35 * version of this file only under the terms of one of those two | |
| 36 * licenses (the MPL or the GPL) and not to allow others to use your | |
| 37 * version of this file under the LGPL, indicate your decision by | |
| 38 * deletingthe provisions above and replace them with the notice and | |
| 39 * other provisions required by the MPL or the GPL, as the case may be. | |
| 40 * If you do not delete the provisions above, a recipient may use your | |
| 41 * version of this file under any of the LGPL, the MPL or the GPL. | |
| 42 */ | |
| 43 | |
| 44 #include "config.h" | |
| 45 #include "core/rendering/RenderLayer.h" | |
| 46 | |
| 47 #include "core/css/PseudoStyleRequest.h" | |
| 48 #include "core/dom/AXObjectCache.h" | |
| 49 #include "core/dom/Node.h" | |
| 50 #include "core/dom/shadow/ShadowRoot.h" | |
| 51 #include "core/editing/FrameSelection.h" | |
| 52 #include "core/frame/FrameView.h" | |
| 53 #include "core/frame/LocalFrame.h" | |
| 54 #include "core/frame/Settings.h" | |
| 55 #include "core/html/HTMLFrameOwnerElement.h" | |
| 56 #include "core/inspector/InspectorInstrumentation.h" | |
| 57 #include "core/layout/LayoutTheme.h" | |
| 58 #include "core/layout/compositing/CompositedLayerMapping.h" | |
| 59 #include "core/layout/compositing/RenderLayerCompositor.h" | |
| 60 #include "core/page/Chrome.h" | |
| 61 #include "core/page/EventHandler.h" | |
| 62 #include "core/page/FocusController.h" | |
| 63 #include "core/page/Page.h" | |
| 64 #include "core/page/scrolling/ScrollingCoordinator.h" | |
| 65 #include "core/rendering/RenderGeometryMap.h" | |
| 66 #include "core/rendering/RenderScrollbar.h" | |
| 67 #include "core/rendering/RenderScrollbarPart.h" | |
| 68 #include "core/rendering/RenderView.h" | |
| 69 #include "platform/PlatformGestureEvent.h" | |
| 70 #include "platform/PlatformMouseEvent.h" | |
| 71 #include "platform/graphics/GraphicsContextStateSaver.h" | |
| 72 #include "platform/graphics/GraphicsLayer.h" | |
| 73 #include "platform/graphics/paint/DrawingRecorder.h" | |
| 74 #include "platform/scroll/ScrollAnimator.h" | |
| 75 #include "platform/scroll/ScrollbarTheme.h" | |
| 76 #include "public/platform/Platform.h" | |
| 77 | |
| 78 namespace blink { | |
| 79 | |
| 80 const int ResizerControlExpandRatioForTouch = 2; | |
| 81 | |
| 82 RenderLayerScrollableArea::RenderLayerScrollableArea(RenderLayer& layer) | |
| 83 : m_layer(layer) | |
| 84 , m_inResizeMode(false) | |
| 85 , m_scrollsOverflow(false) | |
| 86 , m_scrollDimensionsDirty(true) | |
| 87 , m_inOverflowRelayout(false) | |
| 88 , m_nextTopmostScrollChild(0) | |
| 89 , m_topmostScrollChild(0) | |
| 90 , m_needsCompositedScrolling(false) | |
| 91 , m_scrollCorner(nullptr) | |
| 92 , m_resizer(nullptr) | |
| 93 { | |
| 94 ScrollableArea::setConstrainsScrollingToContentEdge(false); | |
| 95 | |
| 96 Node* node = box().node(); | |
| 97 if (node && node->isElementNode()) { | |
| 98 // We save and restore only the scrollOffset as the other scroll values
are recalculated. | |
| 99 Element* element = toElement(node); | |
| 100 m_scrollOffset = element->savedLayerScrollOffset(); | |
| 101 if (!m_scrollOffset.isZero()) | |
| 102 scrollAnimator()->setCurrentPosition(FloatPoint(m_scrollOffset.width
(), m_scrollOffset.height())); | |
| 103 element->setSavedLayerScrollOffset(IntSize()); | |
| 104 } | |
| 105 | |
| 106 updateResizerAreaSet(); | |
| 107 } | |
| 108 | |
| 109 RenderLayerScrollableArea::~RenderLayerScrollableArea() | |
| 110 { | |
| 111 if (inResizeMode() && !box().documentBeingDestroyed()) { | |
| 112 if (LocalFrame* frame = box().frame()) | |
| 113 frame->eventHandler().resizeScrollableAreaDestroyed(); | |
| 114 } | |
| 115 | |
| 116 if (LocalFrame* frame = box().frame()) { | |
| 117 if (FrameView* frameView = frame->view()) { | |
| 118 frameView->removeScrollableArea(this); | |
| 119 frameView->removeAnimatingScrollableArea(this); | |
| 120 } | |
| 121 } | |
| 122 | |
| 123 if (box().frame() && box().frame()->page()) { | |
| 124 if (ScrollingCoordinator* scrollingCoordinator = box().frame()->page()->
scrollingCoordinator()) | |
| 125 scrollingCoordinator->willDestroyScrollableArea(this); | |
| 126 } | |
| 127 | |
| 128 if (!box().documentBeingDestroyed()) { | |
| 129 Node* node = box().node(); | |
| 130 // FIXME: Make setSavedLayerScrollOffset take DoubleSize. crbug.com/4142
83. | |
| 131 if (node && node->isElementNode()) | |
| 132 toElement(node)->setSavedLayerScrollOffset(flooredIntSize(m_scrollOf
fset)); | |
| 133 } | |
| 134 | |
| 135 if (LocalFrame* frame = box().frame()) { | |
| 136 if (FrameView* frameView = frame->view()) | |
| 137 frameView->removeResizerArea(box()); | |
| 138 } | |
| 139 | |
| 140 destroyScrollbar(HorizontalScrollbar); | |
| 141 destroyScrollbar(VerticalScrollbar); | |
| 142 | |
| 143 if (m_scrollCorner) | |
| 144 m_scrollCorner->destroy(); | |
| 145 if (m_resizer) | |
| 146 m_resizer->destroy(); | |
| 147 } | |
| 148 | |
| 149 HostWindow* RenderLayerScrollableArea::hostWindow() const | |
| 150 { | |
| 151 if (Page* page = box().frame()->page()) | |
| 152 return &page->chrome(); | |
| 153 return nullptr; | |
| 154 } | |
| 155 | |
| 156 GraphicsLayer* RenderLayerScrollableArea::layerForScrolling() const | |
| 157 { | |
| 158 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin
g()->scrollingContentsLayer() : 0; | |
| 159 } | |
| 160 | |
| 161 GraphicsLayer* RenderLayerScrollableArea::layerForHorizontalScrollbar() const | |
| 162 { | |
| 163 // See crbug.com/343132. | |
| 164 DisableCompositingQueryAsserts disabler; | |
| 165 | |
| 166 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin
g()->layerForHorizontalScrollbar() : 0; | |
| 167 } | |
| 168 | |
| 169 GraphicsLayer* RenderLayerScrollableArea::layerForVerticalScrollbar() const | |
| 170 { | |
| 171 // See crbug.com/343132. | |
| 172 DisableCompositingQueryAsserts disabler; | |
| 173 | |
| 174 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin
g()->layerForVerticalScrollbar() : 0; | |
| 175 } | |
| 176 | |
| 177 GraphicsLayer* RenderLayerScrollableArea::layerForScrollCorner() const | |
| 178 { | |
| 179 // See crbug.com/343132. | |
| 180 DisableCompositingQueryAsserts disabler; | |
| 181 | |
| 182 return layer()->hasCompositedLayerMapping() ? layer()->compositedLayerMappin
g()->layerForScrollCorner() : 0; | |
| 183 } | |
| 184 | |
| 185 void RenderLayerScrollableArea::invalidateScrollbarRect(Scrollbar* scrollbar, co
nst IntRect& rect) | |
| 186 { | |
| 187 // See crbug.com/343132. | |
| 188 DisableCompositingQueryAsserts disabler; | |
| 189 | |
| 190 if (scrollbar == m_vBar.get()) { | |
| 191 if (GraphicsLayer* layer = layerForVerticalScrollbar()) { | |
| 192 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll); | |
| 193 return; | |
| 194 } | |
| 195 } else { | |
| 196 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { | |
| 197 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll); | |
| 198 return; | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 IntRect scrollRect = rect; | |
| 203 // If we are not yet inserted into the tree, there is no need to issue paint
invaldiations. | |
| 204 if (!box().isRenderView() && !box().parent()) | |
| 205 return; | |
| 206 | |
| 207 if (scrollbar == m_vBar.get()) | |
| 208 scrollRect.move(verticalScrollbarStart(0, box().size().width()), box().b
orderTop()); | |
| 209 else | |
| 210 scrollRect.move(horizontalScrollbarStart(0), box().size().height() - box
().borderBottom() - scrollbar->height()); | |
| 211 | |
| 212 if (scrollRect.isEmpty()) | |
| 213 return; | |
| 214 | |
| 215 LayoutRect paintInvalidationRect = scrollRect; | |
| 216 box().flipForWritingMode(paintInvalidationRect); | |
| 217 | |
| 218 IntRect intRect = pixelSnappedIntRect(paintInvalidationRect); | |
| 219 | |
| 220 if (box().frameView()->isInPerformLayout()) | |
| 221 addScrollbarDamage(scrollbar, intRect); | |
| 222 else | |
| 223 box().invalidatePaintRectangle(intRect); | |
| 224 } | |
| 225 | |
| 226 void RenderLayerScrollableArea::invalidateScrollCornerRect(const IntRect& rect) | |
| 227 { | |
| 228 if (GraphicsLayer* layer = layerForScrollCorner()) { | |
| 229 layer->setNeedsDisplayInRect(rect, PaintInvalidationScroll); | |
| 230 return; | |
| 231 } | |
| 232 | |
| 233 if (m_scrollCorner) | |
| 234 m_scrollCorner->invalidatePaintRectangle(rect); | |
| 235 if (m_resizer) | |
| 236 m_resizer->invalidatePaintRectangle(rect); | |
| 237 } | |
| 238 | |
| 239 bool RenderLayerScrollableArea::shouldUseIntegerScrollOffset() const | |
| 240 { | |
| 241 Frame* frame = box().frame(); | |
| 242 if (frame->settings() && !frame->settings()->preferCompositingToLCDTextEnabl
ed()) | |
| 243 return true; | |
| 244 return false; | |
| 245 } | |
| 246 | |
| 247 bool RenderLayerScrollableArea::isActive() const | |
| 248 { | |
| 249 Page* page = box().frame()->page(); | |
| 250 return page && page->focusController().isActive(); | |
| 251 } | |
| 252 | |
| 253 bool RenderLayerScrollableArea::isScrollCornerVisible() const | |
| 254 { | |
| 255 return !scrollCornerRect().isEmpty(); | |
| 256 } | |
| 257 | |
| 258 static int cornerStart(const RenderStyle* style, int minX, int maxX, int thickne
ss) | |
| 259 { | |
| 260 if (style->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
| 261 return minX + style->borderLeftWidth(); | |
| 262 return maxX - thickness - style->borderRightWidth(); | |
| 263 } | |
| 264 | |
| 265 static IntRect cornerRect(const RenderStyle* style, const Scrollbar* horizontalS
crollbar, const Scrollbar* verticalScrollbar, const IntRect& bounds) | |
| 266 { | |
| 267 int horizontalThickness; | |
| 268 int verticalThickness; | |
| 269 if (!verticalScrollbar && !horizontalScrollbar) { | |
| 270 // FIXME: This isn't right. We need to know the thickness of custom scro
llbars | |
| 271 // even when they don't exist in order to set the resizer square size pr
operly. | |
| 272 horizontalThickness = ScrollbarTheme::theme()->scrollbarThickness(); | |
| 273 verticalThickness = horizontalThickness; | |
| 274 } else if (verticalScrollbar && !horizontalScrollbar) { | |
| 275 horizontalThickness = verticalScrollbar->width(); | |
| 276 verticalThickness = horizontalThickness; | |
| 277 } else if (horizontalScrollbar && !verticalScrollbar) { | |
| 278 verticalThickness = horizontalScrollbar->height(); | |
| 279 horizontalThickness = verticalThickness; | |
| 280 } else { | |
| 281 horizontalThickness = verticalScrollbar->width(); | |
| 282 verticalThickness = horizontalScrollbar->height(); | |
| 283 } | |
| 284 return IntRect(cornerStart(style, bounds.x(), bounds.maxX(), horizontalThick
ness), | |
| 285 bounds.maxY() - verticalThickness - style->borderBottomWidth(), | |
| 286 horizontalThickness, verticalThickness); | |
| 287 } | |
| 288 | |
| 289 | |
| 290 IntRect RenderLayerScrollableArea::scrollCornerRect() const | |
| 291 { | |
| 292 // We have a scrollbar corner when a scrollbar is visible and not filling th
e entire length of the box. | |
| 293 // This happens when: | |
| 294 // (a) A resizer is present and at least one scrollbar is present | |
| 295 // (b) Both scrollbars are present. | |
| 296 bool hasHorizontalBar = horizontalScrollbar(); | |
| 297 bool hasVerticalBar = verticalScrollbar(); | |
| 298 bool hasResizer = box().style()->resize() != RESIZE_NONE; | |
| 299 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar
|| hasVerticalBar))) | |
| 300 return cornerRect(box().style(), horizontalScrollbar(), verticalScrollba
r(), box().pixelSnappedBorderBoxRect()); | |
| 301 return IntRect(); | |
| 302 } | |
| 303 | |
| 304 IntRect RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Sc
rollbar* scrollbar, const IntRect& scrollbarRect) const | |
| 305 { | |
| 306 RenderView* view = box().view(); | |
| 307 if (!view) | |
| 308 return scrollbarRect; | |
| 309 | |
| 310 IntRect rect = scrollbarRect; | |
| 311 rect.move(scrollbarOffset(scrollbar)); | |
| 312 | |
| 313 return view->frameView()->convertFromRenderer(box(), rect); | |
| 314 } | |
| 315 | |
| 316 IntRect RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Sc
rollbar* scrollbar, const IntRect& parentRect) const | |
| 317 { | |
| 318 RenderView* view = box().view(); | |
| 319 if (!view) | |
| 320 return parentRect; | |
| 321 | |
| 322 IntRect rect = view->frameView()->convertToRenderer(box(), parentRect); | |
| 323 rect.move(-scrollbarOffset(scrollbar)); | |
| 324 return rect; | |
| 325 } | |
| 326 | |
| 327 IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const S
crollbar* scrollbar, const IntPoint& scrollbarPoint) const | |
| 328 { | |
| 329 RenderView* view = box().view(); | |
| 330 if (!view) | |
| 331 return scrollbarPoint; | |
| 332 | |
| 333 IntPoint point = scrollbarPoint; | |
| 334 point.move(scrollbarOffset(scrollbar)); | |
| 335 return view->frameView()->convertFromRenderer(box(), point); | |
| 336 } | |
| 337 | |
| 338 IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const S
crollbar* scrollbar, const IntPoint& parentPoint) const | |
| 339 { | |
| 340 RenderView* view = box().view(); | |
| 341 if (!view) | |
| 342 return parentPoint; | |
| 343 | |
| 344 IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint); | |
| 345 | |
| 346 point.move(-scrollbarOffset(scrollbar)); | |
| 347 return point; | |
| 348 } | |
| 349 | |
| 350 int RenderLayerScrollableArea::scrollSize(ScrollbarOrientation orientation) cons
t | |
| 351 { | |
| 352 IntSize scrollDimensions = maximumScrollPosition() - minimumScrollPosition()
; | |
| 353 return (orientation == HorizontalScrollbar) ? scrollDimensions.width() : scr
ollDimensions.height(); | |
| 354 } | |
| 355 | |
| 356 void RenderLayerScrollableArea::setScrollOffset(const IntPoint& newScrollOffset) | |
| 357 { | |
| 358 setScrollOffset(DoublePoint(newScrollOffset)); | |
| 359 } | |
| 360 | |
| 361 void RenderLayerScrollableArea::setScrollOffset(const DoublePoint& newScrollOffs
et) | |
| 362 { | |
| 363 // Ensure that the dimensions will be computed if they need to be (for overf
low:hidden blocks). | |
| 364 if (m_scrollDimensionsDirty) | |
| 365 computeScrollDimensions(); | |
| 366 | |
| 367 if (scrollOffset() == toDoubleSize(newScrollOffset)) | |
| 368 return; | |
| 369 | |
| 370 m_scrollOffset = toDoubleSize(newScrollOffset); | |
| 371 | |
| 372 LocalFrame* frame = box().frame(); | |
| 373 ASSERT(frame); | |
| 374 | |
| 375 RefPtrWillBeRawPtr<FrameView> frameView = box().frameView(); | |
| 376 | |
| 377 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ScrollLayer",
"data", InspectorScrollLayerEvent::data(&box())); | |
| 378 // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeli
ne migrates to tracing. | |
| 379 InspectorInstrumentation::willScrollLayer(&box()); | |
| 380 | |
| 381 // Update the positions of our child layers (if needed as only fixed layers
should be impacted by a scroll). | |
| 382 // We don't update compositing layers, because we need to do a deep update f
rom the compositing ancestor. | |
| 383 if (!frameView->isInPerformLayout()) { | |
| 384 // If we're in the middle of layout, we'll just update layers once layou
t has finished. | |
| 385 layer()->updateLayerPositionsAfterOverflowScroll(); | |
| 386 // Update regions, scrolling may change the clip of a particular region. | |
| 387 frameView->updateAnnotatedRegions(); | |
| 388 frameView->setNeedsUpdateWidgetPositions(); | |
| 389 updateCompositingLayersAfterScroll(); | |
| 390 } | |
| 391 | |
| 392 const RenderLayerModelObject* paintInvalidationContainer = box().containerFo
rPaintInvalidation(); | |
| 393 // The caret rect needs to be invalidated after scrolling | |
| 394 frame->selection().setCaretRectNeedsUpdate(); | |
| 395 | |
| 396 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(layer()->renderer()->previou
sPaintInvalidationRect()); | |
| 397 | |
| 398 quadForFakeMouseMoveEvent = paintInvalidationContainer->localToAbsoluteQuad(
quadForFakeMouseMoveEvent); | |
| 399 frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseM
oveEvent); | |
| 400 | |
| 401 bool requiresPaintInvalidation = true; | |
| 402 | |
| 403 { | |
| 404 // FIXME(420741): Since scrolling depends on compositing state, the scro
ll should be | |
| 405 // deferred until after the compositing update. | |
| 406 DisableCompositingQueryAsserts disabler; | |
| 407 if (box().view()->compositor()->inCompositingMode()) { | |
| 408 bool onlyScrolledCompositedLayers = scrollsOverflow() | |
| 409 && !layer()->hasVisibleNonLayerContent() | |
| 410 && !layer()->hasNonCompositedChild() | |
| 411 && !layer()->hasBlockSelectionGapBounds() | |
| 412 && box().style()->backgroundLayers().attachment() != LocalBackgr
oundAttachment; | |
| 413 | |
| 414 if (usesCompositedScrolling() || onlyScrolledCompositedLayers) | |
| 415 requiresPaintInvalidation = false; | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 // Just schedule a full paint invalidation of our object. | |
| 420 if (requiresPaintInvalidation) | |
| 421 box().setShouldDoFullPaintInvalidation(); | |
| 422 | |
| 423 // Schedule the scroll DOM event. | |
| 424 if (box().node()) | |
| 425 box().node()->document().enqueueScrollEventForNode(box().node()); | |
| 426 | |
| 427 if (AXObjectCache* cache = box().document().existingAXObjectCache()) | |
| 428 cache->handleScrollPositionChanged(&box()); | |
| 429 | |
| 430 InspectorInstrumentation::didScrollLayer(&box()); | |
| 431 } | |
| 432 | |
| 433 IntPoint RenderLayerScrollableArea::scrollPosition() const | |
| 434 { | |
| 435 return IntPoint(flooredIntSize(m_scrollOffset)); | |
| 436 } | |
| 437 | |
| 438 DoublePoint RenderLayerScrollableArea::scrollPositionDouble() const | |
| 439 { | |
| 440 return DoublePoint(m_scrollOffset); | |
| 441 } | |
| 442 | |
| 443 IntPoint RenderLayerScrollableArea::minimumScrollPosition() const | |
| 444 { | |
| 445 return -scrollOrigin(); | |
| 446 } | |
| 447 | |
| 448 IntPoint RenderLayerScrollableArea::maximumScrollPosition() const | |
| 449 { | |
| 450 if (!box().hasOverflowClip()) | |
| 451 return -scrollOrigin(); | |
| 452 return -scrollOrigin() + IntPoint(pixelSnappedScrollWidth(), pixelSnappedScr
ollHeight()) - enclosingIntRect(box().clientBoxRect()).size(); | |
| 453 } | |
| 454 | |
| 455 IntRect RenderLayerScrollableArea::visibleContentRect(IncludeScrollbarsInRect sc
rollbarInclusion) const | |
| 456 { | |
| 457 int verticalScrollbarWidth = 0; | |
| 458 int horizontalScrollbarHeight = 0; | |
| 459 if (scrollbarInclusion == IncludeScrollbars) { | |
| 460 verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->i
sOverlayScrollbar()) ? verticalScrollbar()->width() : 0; | |
| 461 horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollb
ar()->isOverlayScrollbar()) ? horizontalScrollbar()->height() : 0; | |
| 462 } | |
| 463 | |
| 464 return IntRect(IntPoint(scrollXOffset(), scrollYOffset()), | |
| 465 IntSize(max(0, layer()->size().width() - verticalScrollbarWidth), max(0,
layer()->size().height() - horizontalScrollbarHeight))); | |
| 466 } | |
| 467 | |
| 468 int RenderLayerScrollableArea::visibleHeight() const | |
| 469 { | |
| 470 return layer()->size().height(); | |
| 471 } | |
| 472 | |
| 473 int RenderLayerScrollableArea::visibleWidth() const | |
| 474 { | |
| 475 return layer()->size().width(); | |
| 476 } | |
| 477 | |
| 478 IntSize RenderLayerScrollableArea::contentsSize() const | |
| 479 { | |
| 480 return IntSize(scrollWidth(), scrollHeight()); | |
| 481 } | |
| 482 | |
| 483 IntSize RenderLayerScrollableArea::overhangAmount() const | |
| 484 { | |
| 485 return IntSize(); | |
| 486 } | |
| 487 | |
| 488 IntPoint RenderLayerScrollableArea::lastKnownMousePosition() const | |
| 489 { | |
| 490 return box().frame() ? box().frame()->eventHandler().lastKnownMousePosition(
) : IntPoint(); | |
| 491 } | |
| 492 | |
| 493 bool RenderLayerScrollableArea::shouldSuspendScrollAnimations() const | |
| 494 { | |
| 495 RenderView* view = box().view(); | |
| 496 if (!view) | |
| 497 return true; | |
| 498 return view->frameView()->shouldSuspendScrollAnimations(); | |
| 499 } | |
| 500 | |
| 501 bool RenderLayerScrollableArea::scrollbarsCanBeActive() const | |
| 502 { | |
| 503 RenderView* view = box().view(); | |
| 504 if (!view) | |
| 505 return false; | |
| 506 return view->frameView()->scrollbarsCanBeActive(); | |
| 507 } | |
| 508 | |
| 509 IntRect RenderLayerScrollableArea::scrollableAreaBoundingBox() const | |
| 510 { | |
| 511 return box().absoluteBoundingBoxRect(); | |
| 512 } | |
| 513 | |
| 514 void RenderLayerScrollableArea::registerForAnimation() | |
| 515 { | |
| 516 if (LocalFrame* frame = box().frame()) { | |
| 517 if (FrameView* frameView = frame->view()) | |
| 518 frameView->addAnimatingScrollableArea(this); | |
| 519 } | |
| 520 } | |
| 521 | |
| 522 void RenderLayerScrollableArea::deregisterForAnimation() | |
| 523 { | |
| 524 if (LocalFrame* frame = box().frame()) { | |
| 525 if (FrameView* frameView = frame->view()) | |
| 526 frameView->removeAnimatingScrollableArea(this); | |
| 527 } | |
| 528 } | |
| 529 | |
| 530 bool RenderLayerScrollableArea::userInputScrollable(ScrollbarOrientation orienta
tion) const | |
| 531 { | |
| 532 if (box().isIntristicallyScrollable(orientation)) | |
| 533 return true; | |
| 534 | |
| 535 EOverflow overflowStyle = (orientation == HorizontalScrollbar) ? | |
| 536 box().style()->overflowX() : box().style()->overflowY(); | |
| 537 return (overflowStyle == OSCROLL || overflowStyle == OAUTO || overflowStyle
== OOVERLAY); | |
| 538 } | |
| 539 | |
| 540 bool RenderLayerScrollableArea::shouldPlaceVerticalScrollbarOnLeft() const | |
| 541 { | |
| 542 return box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft(); | |
| 543 } | |
| 544 | |
| 545 int RenderLayerScrollableArea::pageStep(ScrollbarOrientation orientation) const | |
| 546 { | |
| 547 int length = (orientation == HorizontalScrollbar) ? | |
| 548 box().pixelSnappedClientWidth() : box().pixelSnappedClientHeight(); | |
| 549 int minPageStep = static_cast<float>(length) * ScrollableArea::minFractionTo
StepWhenPaging(); | |
| 550 int pageStep = max(minPageStep, length - ScrollableArea::maxOverlapBetweenPa
ges()); | |
| 551 | |
| 552 return max(pageStep, 1); | |
| 553 } | |
| 554 | |
| 555 RenderBox& RenderLayerScrollableArea::box() const | |
| 556 { | |
| 557 return *m_layer.renderBox(); | |
| 558 } | |
| 559 | |
| 560 RenderLayer* RenderLayerScrollableArea::layer() const | |
| 561 { | |
| 562 return &m_layer; | |
| 563 } | |
| 564 | |
| 565 LayoutUnit RenderLayerScrollableArea::scrollWidth() const | |
| 566 { | |
| 567 if (m_scrollDimensionsDirty) | |
| 568 const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); | |
| 569 return m_overflowRect.width(); | |
| 570 } | |
| 571 | |
| 572 LayoutUnit RenderLayerScrollableArea::scrollHeight() const | |
| 573 { | |
| 574 if (m_scrollDimensionsDirty) | |
| 575 const_cast<RenderLayerScrollableArea*>(this)->computeScrollDimensions(); | |
| 576 return m_overflowRect.height(); | |
| 577 } | |
| 578 | |
| 579 int RenderLayerScrollableArea::pixelSnappedScrollWidth() const | |
| 580 { | |
| 581 return snapSizeToPixel(scrollWidth(), box().clientLeft() + box().location().
x()); | |
| 582 } | |
| 583 | |
| 584 int RenderLayerScrollableArea::pixelSnappedScrollHeight() const | |
| 585 { | |
| 586 return snapSizeToPixel(scrollHeight(), box().clientTop() + box().location().
y()); | |
| 587 } | |
| 588 | |
| 589 void RenderLayerScrollableArea::computeScrollDimensions() | |
| 590 { | |
| 591 m_scrollDimensionsDirty = false; | |
| 592 | |
| 593 m_overflowRect = box().layoutOverflowRect(); | |
| 594 box().flipForWritingMode(m_overflowRect); | |
| 595 | |
| 596 int scrollableLeftOverflow = m_overflowRect.x() - box().borderLeft() - (box(
).style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft() ? box().verticalScr
ollbarWidth() : 0); | |
| 597 int scrollableTopOverflow = m_overflowRect.y() - box().borderTop(); | |
| 598 setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow)); | |
| 599 } | |
| 600 | |
| 601 void RenderLayerScrollableArea::scrollToOffset(const DoubleSize& scrollOffset, S
crollOffsetClamping clamp, ScrollBehavior scrollBehavior) | |
| 602 { | |
| 603 cancelProgrammaticScrollAnimation(); | |
| 604 DoubleSize newScrollOffset = clamp == ScrollOffsetClamped ? clampScrollOffse
t(scrollOffset) : scrollOffset; | |
| 605 if (newScrollOffset != adjustedScrollOffset()) { | |
| 606 if (scrollBehavior == ScrollBehaviorAuto) | |
| 607 scrollBehavior = box().style()->scrollBehavior(); | |
| 608 DoublePoint origin(scrollOrigin()); | |
| 609 if (scrollBehavior == ScrollBehaviorSmooth) { | |
| 610 // FIXME: Make programmaticallyScrollSmoothlyToOffset take DoublePoi
nt. crbug.com/243871. | |
| 611 programmaticallyScrollSmoothlyToOffset(toFloatPoint(-origin + newScr
ollOffset)); | |
| 612 } else { | |
| 613 // FIXME: Make scrollToOffsetWithoutAnimation take DoublePoint. crbu
g.com/414283. | |
| 614 scrollToOffsetWithoutAnimation(toFloatPoint(-origin + newScrollOffse
t)); | |
| 615 } | |
| 616 } | |
| 617 } | |
| 618 | |
| 619 void RenderLayerScrollableArea::updateAfterLayout() | |
| 620 { | |
| 621 m_scrollDimensionsDirty = true; | |
| 622 DoubleSize originalScrollOffset = adjustedScrollOffset(); | |
| 623 | |
| 624 computeScrollDimensions(); | |
| 625 | |
| 626 // Layout may cause us to be at an invalid scroll position. In this case we
need | |
| 627 // to pull our scroll offsets back to the max (or push them up to the min). | |
| 628 DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); | |
| 629 if (clampedScrollOffset != adjustedScrollOffset()) | |
| 630 scrollToOffset(clampedScrollOffset); | |
| 631 | |
| 632 if (originalScrollOffset != adjustedScrollOffset()) { | |
| 633 DoublePoint origin(scrollOrigin()); | |
| 634 scrollToOffsetWithoutAnimation(toFloatPoint(-origin + adjustedScrollOffs
et())); | |
| 635 } | |
| 636 | |
| 637 bool hasHorizontalOverflow = this->hasHorizontalOverflow(); | |
| 638 bool hasVerticalOverflow = this->hasVerticalOverflow(); | |
| 639 | |
| 640 { | |
| 641 // Hits in compositing/overflow/automatically-opt-into-composited-scroll
ing-after-style-change.html. | |
| 642 DisableCompositingQueryAsserts disabler; | |
| 643 | |
| 644 // overflow:scroll should just enable/disable. | |
| 645 if (box().style()->overflowX() == OSCROLL && horizontalScrollbar()) | |
| 646 horizontalScrollbar()->setEnabled(hasHorizontalOverflow); | |
| 647 if (box().style()->overflowY() == OSCROLL && verticalScrollbar()) | |
| 648 verticalScrollbar()->setEnabled(hasVerticalOverflow); | |
| 649 } | |
| 650 if (hasOverlayScrollbars()) { | |
| 651 if (!scrollSize(HorizontalScrollbar)) | |
| 652 setHasHorizontalScrollbar(false); | |
| 653 if (!scrollSize(VerticalScrollbar)) | |
| 654 setHasVerticalScrollbar(false); | |
| 655 } | |
| 656 // overflow:auto may need to lay out again if scrollbars got added/removed. | |
| 657 bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() &&
(hasHorizontalScrollbar() != hasHorizontalOverflow); | |
| 658 bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (has
VerticalScrollbar() != hasVerticalOverflow); | |
| 659 | |
| 660 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { | |
| 661 if (box().hasAutoHorizontalScrollbar()) | |
| 662 setHasHorizontalScrollbar(hasHorizontalOverflow); | |
| 663 if (box().hasAutoVerticalScrollbar()) | |
| 664 setHasVerticalScrollbar(hasVerticalOverflow); | |
| 665 | |
| 666 if (hasVerticalOverflow || hasHorizontalOverflow) | |
| 667 updateScrollCornerStyle(); | |
| 668 | |
| 669 layer()->updateSelfPaintingLayer(); | |
| 670 | |
| 671 // Force an update since we know the scrollbars have changed things. | |
| 672 if (box().document().hasAnnotatedRegions()) | |
| 673 box().document().setAnnotatedRegionsDirty(true); | |
| 674 | |
| 675 if (box().style()->overflowX() == OAUTO || box().style()->overflowY() ==
OAUTO) { | |
| 676 if (!m_inOverflowRelayout) { | |
| 677 // Our proprietary overflow: overlay value doesn't trigger a lay
out. | |
| 678 m_inOverflowRelayout = true; | |
| 679 SubtreeLayoutScope layoutScope(box()); | |
| 680 layoutScope.setNeedsLayout(&box()); | |
| 681 if (box().isRenderBlock()) { | |
| 682 RenderBlock& block = toRenderBlock(box()); | |
| 683 block.scrollbarsChanged(autoHorizontalScrollBarChanged, auto
VerticalScrollBarChanged); | |
| 684 block.layoutBlock(true); | |
| 685 } else { | |
| 686 box().layout(); | |
| 687 } | |
| 688 m_inOverflowRelayout = false; | |
| 689 } | |
| 690 } | |
| 691 } | |
| 692 | |
| 693 { | |
| 694 // Hits in compositing/overflow/automatically-opt-into-composited-scroll
ing-after-style-change.html. | |
| 695 DisableCompositingQueryAsserts disabler; | |
| 696 | |
| 697 // Set up the range (and page step/line step). | |
| 698 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { | |
| 699 int clientWidth = box().pixelSnappedClientWidth(); | |
| 700 horizontalScrollbar->setProportion(clientWidth, overflowRect().width
()); | |
| 701 } | |
| 702 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { | |
| 703 int clientHeight = box().pixelSnappedClientHeight(); | |
| 704 verticalScrollbar->setProportion(clientHeight, overflowRect().height
()); | |
| 705 } | |
| 706 } | |
| 707 | |
| 708 bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVertica
lOverflow(); | |
| 709 updateScrollableAreaSet(hasOverflow); | |
| 710 | |
| 711 if (hasOverflow) { | |
| 712 DisableCompositingQueryAsserts disabler; | |
| 713 positionOverflowControls(IntSize()); | |
| 714 } | |
| 715 } | |
| 716 | |
| 717 bool RenderLayerScrollableArea::hasHorizontalOverflow() const | |
| 718 { | |
| 719 ASSERT(!m_scrollDimensionsDirty); | |
| 720 | |
| 721 return pixelSnappedScrollWidth() > box().pixelSnappedClientWidth(); | |
| 722 } | |
| 723 | |
| 724 bool RenderLayerScrollableArea::hasVerticalOverflow() const | |
| 725 { | |
| 726 ASSERT(!m_scrollDimensionsDirty); | |
| 727 | |
| 728 return pixelSnappedScrollHeight() > box().pixelSnappedClientHeight(); | |
| 729 } | |
| 730 | |
| 731 bool RenderLayerScrollableArea::hasScrollableHorizontalOverflow() const | |
| 732 { | |
| 733 return hasHorizontalOverflow() && box().scrollsOverflowX(); | |
| 734 } | |
| 735 | |
| 736 bool RenderLayerScrollableArea::hasScrollableVerticalOverflow() const | |
| 737 { | |
| 738 return hasVerticalOverflow() && box().scrollsOverflowY(); | |
| 739 } | |
| 740 | |
| 741 static bool overflowRequiresScrollbar(EOverflow overflow) | |
| 742 { | |
| 743 return overflow == OSCROLL; | |
| 744 } | |
| 745 | |
| 746 static bool overflowDefinesAutomaticScrollbar(EOverflow overflow) | |
| 747 { | |
| 748 return overflow == OAUTO || overflow == OOVERLAY; | |
| 749 } | |
| 750 | |
| 751 // This function returns true if the given box requires overflow scrollbars (as | |
| 752 // opposed to the 'viewport' scrollbars managed by the RenderLayerCompositor). | |
| 753 // FIXME: we should use the same scrolling machinery for both the viewport and | |
| 754 // overflow. Currently, we need to avoid producing scrollbars here if they'll be | |
| 755 // handled externally in the RLC. | |
| 756 static bool canHaveOverflowScrollbars(const RenderBox& box) | |
| 757 { | |
| 758 bool rootLayerScrolls = box.document().settings() && box.document().settings
()->rootLayerScrolls(); | |
| 759 return (rootLayerScrolls || !box.isRenderView()) && box.document().viewportD
efiningElement() != box.node(); | |
| 760 } | |
| 761 | |
| 762 void RenderLayerScrollableArea::updateAfterStyleChange(const RenderStyle* oldSty
le) | |
| 763 { | |
| 764 if (!m_scrollDimensionsDirty) | |
| 765 updateScrollableAreaSet(hasScrollableHorizontalOverflow() || hasScrollab
leVerticalOverflow()); | |
| 766 | |
| 767 if (!canHaveOverflowScrollbars(box())) | |
| 768 return; | |
| 769 | |
| 770 EOverflow overflowX = box().style()->overflowX(); | |
| 771 EOverflow overflowY = box().style()->overflowY(); | |
| 772 | |
| 773 // To avoid doing a relayout in updateScrollbarsAfterLayout, we try to keep
any automatic scrollbar that was already present. | |
| 774 bool needsHorizontalScrollbar = (hasHorizontalScrollbar() && overflowDefines
AutomaticScrollbar(overflowX)) || overflowRequiresScrollbar(overflowX); | |
| 775 bool needsVerticalScrollbar = (hasVerticalScrollbar() && overflowDefinesAuto
maticScrollbar(overflowY)) || overflowRequiresScrollbar(overflowY); | |
| 776 setHasHorizontalScrollbar(needsHorizontalScrollbar); | |
| 777 setHasVerticalScrollbar(needsVerticalScrollbar); | |
| 778 | |
| 779 // With overflow: scroll, scrollbars are always visible but may be disabled. | |
| 780 // When switching to another value, we need to re-enable them (see bug 11985
). | |
| 781 if (needsHorizontalScrollbar && oldStyle && oldStyle->overflowX() == OSCROLL
&& overflowX != OSCROLL) { | |
| 782 ASSERT(hasHorizontalScrollbar()); | |
| 783 m_hBar->setEnabled(true); | |
| 784 } | |
| 785 | |
| 786 if (needsVerticalScrollbar && oldStyle && oldStyle->overflowY() == OSCROLL &
& overflowY != OSCROLL) { | |
| 787 ASSERT(hasVerticalScrollbar()); | |
| 788 m_vBar->setEnabled(true); | |
| 789 } | |
| 790 | |
| 791 // FIXME: Need to detect a swap from custom to native scrollbars (and vice v
ersa). | |
| 792 if (m_hBar) | |
| 793 m_hBar->styleChanged(); | |
| 794 if (m_vBar) | |
| 795 m_vBar->styleChanged(); | |
| 796 | |
| 797 updateScrollCornerStyle(); | |
| 798 updateResizerAreaSet(); | |
| 799 updateResizerStyle(); | |
| 800 } | |
| 801 | |
| 802 bool RenderLayerScrollableArea::updateAfterCompositingChange() | |
| 803 { | |
| 804 layer()->updateScrollingStateAfterCompositingChange(); | |
| 805 const bool layersChanged = m_topmostScrollChild != m_nextTopmostScrollChild; | |
| 806 m_topmostScrollChild = m_nextTopmostScrollChild; | |
| 807 m_nextTopmostScrollChild = nullptr; | |
| 808 return layersChanged; | |
| 809 } | |
| 810 | |
| 811 void RenderLayerScrollableArea::updateAfterOverflowRecalc() | |
| 812 { | |
| 813 computeScrollDimensions(); | |
| 814 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { | |
| 815 int clientWidth = box().pixelSnappedClientWidth(); | |
| 816 horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); | |
| 817 } | |
| 818 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { | |
| 819 int clientHeight = box().pixelSnappedClientHeight(); | |
| 820 verticalScrollbar->setProportion(clientHeight, overflowRect().height()); | |
| 821 } | |
| 822 | |
| 823 bool hasHorizontalOverflow = this->hasHorizontalOverflow(); | |
| 824 bool hasVerticalOverflow = this->hasVerticalOverflow(); | |
| 825 bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() &&
(hasHorizontalScrollbar() != hasHorizontalOverflow); | |
| 826 bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (has
VerticalScrollbar() != hasVerticalOverflow); | |
| 827 if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) | |
| 828 box().setNeedsLayoutAndFullPaintInvalidation(); | |
| 829 } | |
| 830 | |
| 831 DoubleSize RenderLayerScrollableArea::clampScrollOffset(const DoubleSize& scroll
Offset) const | |
| 832 { | |
| 833 int maxX = scrollWidth() - box().pixelSnappedClientWidth(); | |
| 834 int maxY = scrollHeight() - box().pixelSnappedClientHeight(); | |
| 835 | |
| 836 double x = std::max(std::min(scrollOffset.width(), static_cast<double>(maxX)
), 0.0); | |
| 837 double y = std::max(std::min(scrollOffset.height(), static_cast<double>(maxY
)), 0.0); | |
| 838 return DoubleSize(x, y); | |
| 839 } | |
| 840 | |
| 841 IntRect RenderLayerScrollableArea::rectForHorizontalScrollbar(const IntRect& bor
derBoxRect) const | |
| 842 { | |
| 843 if (!m_hBar) | |
| 844 return IntRect(); | |
| 845 | |
| 846 const IntRect& scrollCorner = scrollCornerRect(); | |
| 847 | |
| 848 return IntRect(horizontalScrollbarStart(borderBoxRect.x()), | |
| 849 borderBoxRect.maxY() - box().borderBottom() - m_hBar->height(), | |
| 850 borderBoxRect.width() - (box().borderLeft() + box().borderRight()) - scr
ollCorner.width(), | |
| 851 m_hBar->height()); | |
| 852 } | |
| 853 | |
| 854 IntRect RenderLayerScrollableArea::rectForVerticalScrollbar(const IntRect& borde
rBoxRect) const | |
| 855 { | |
| 856 if (!m_vBar) | |
| 857 return IntRect(); | |
| 858 | |
| 859 const IntRect& scrollCorner = scrollCornerRect(); | |
| 860 | |
| 861 return IntRect(verticalScrollbarStart(borderBoxRect.x(), borderBoxRect.maxX(
)), | |
| 862 borderBoxRect.y() + box().borderTop(), | |
| 863 m_vBar->width(), | |
| 864 borderBoxRect.height() - (box().borderTop() + box().borderBottom()) - sc
rollCorner.height()); | |
| 865 } | |
| 866 | |
| 867 LayoutUnit RenderLayerScrollableArea::verticalScrollbarStart(int minX, int maxX)
const | |
| 868 { | |
| 869 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
| 870 return minX + box().borderLeft(); | |
| 871 return maxX - box().borderRight() - m_vBar->width(); | |
| 872 } | |
| 873 | |
| 874 LayoutUnit RenderLayerScrollableArea::horizontalScrollbarStart(int minX) const | |
| 875 { | |
| 876 int x = minX + box().borderLeft(); | |
| 877 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
| 878 x += m_vBar ? m_vBar->width() : resizerCornerRect(box().pixelSnappedBord
erBoxRect(), ResizerForPointer).width(); | |
| 879 return x; | |
| 880 } | |
| 881 | |
| 882 IntSize RenderLayerScrollableArea::scrollbarOffset(const Scrollbar* scrollbar) c
onst | |
| 883 { | |
| 884 if (scrollbar == m_vBar.get()) | |
| 885 return IntSize(verticalScrollbarStart(0, box().size().width()), box().bo
rderTop()); | |
| 886 | |
| 887 if (scrollbar == m_hBar.get()) | |
| 888 return IntSize(horizontalScrollbarStart(0), box().size().height() - box(
).borderBottom() - scrollbar->height()); | |
| 889 | |
| 890 ASSERT_NOT_REACHED(); | |
| 891 return IntSize(); | |
| 892 } | |
| 893 | |
| 894 static inline RenderObject* rendererForScrollbar(RenderObject& renderer) | |
| 895 { | |
| 896 if (Node* node = renderer.node()) { | |
| 897 if (ShadowRoot* shadowRoot = node->containingShadowRoot()) { | |
| 898 if (shadowRoot->type() == ShadowRoot::UserAgentShadowRoot) | |
| 899 return shadowRoot->host()->renderer(); | |
| 900 } | |
| 901 } | |
| 902 | |
| 903 return &renderer; | |
| 904 } | |
| 905 | |
| 906 PassRefPtrWillBeRawPtr<Scrollbar> RenderLayerScrollableArea::createScrollbar(Scr
ollbarOrientation orientation) | |
| 907 { | |
| 908 RefPtrWillBeRawPtr<Scrollbar> widget = nullptr; | |
| 909 RenderObject* actualRenderer = rendererForScrollbar(box()); | |
| 910 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->st
yle()->hasPseudoStyle(SCROLLBAR); | |
| 911 if (hasCustomScrollbarStyle) { | |
| 912 widget = RenderScrollbar::createCustomScrollbar(this, orientation, actua
lRenderer->node()); | |
| 913 } else { | |
| 914 ScrollbarControlSize scrollbarSize = RegularScrollbar; | |
| 915 if (actualRenderer->style()->hasAppearance()) | |
| 916 scrollbarSize = LayoutTheme::theme().scrollbarControlSizeForPart(act
ualRenderer->style()->appearance()); | |
| 917 widget = Scrollbar::create(this, orientation, scrollbarSize); | |
| 918 if (orientation == HorizontalScrollbar) | |
| 919 didAddScrollbar(widget.get(), HorizontalScrollbar); | |
| 920 else | |
| 921 didAddScrollbar(widget.get(), VerticalScrollbar); | |
| 922 } | |
| 923 box().document().view()->addChild(widget.get()); | |
| 924 return widget.release(); | |
| 925 } | |
| 926 | |
| 927 void RenderLayerScrollableArea::destroyScrollbar(ScrollbarOrientation orientatio
n) | |
| 928 { | |
| 929 RefPtrWillBePersistent<Scrollbar>& scrollbar = orientation == HorizontalScro
llbar ? m_hBar : m_vBar; | |
| 930 if (!scrollbar) | |
| 931 return; | |
| 932 | |
| 933 if (!scrollbar->isCustomScrollbar()) | |
| 934 willRemoveScrollbar(scrollbar.get(), orientation); | |
| 935 | |
| 936 toFrameView(scrollbar->parent())->removeChild(scrollbar.get()); | |
| 937 scrollbar->disconnectFromScrollableArea(); | |
| 938 scrollbar = nullptr; | |
| 939 } | |
| 940 | |
| 941 void RenderLayerScrollableArea::setHasHorizontalScrollbar(bool hasScrollbar) | |
| 942 { | |
| 943 if (hasScrollbar == hasHorizontalScrollbar()) | |
| 944 return; | |
| 945 | |
| 946 if (hasScrollbar) { | |
| 947 // This doesn't hit in any tests, but since the equivalent code in setHa
sVerticalScrollbar | |
| 948 // does, presumably this code does as well. | |
| 949 DisableCompositingQueryAsserts disabler; | |
| 950 m_hBar = createScrollbar(HorizontalScrollbar); | |
| 951 } else { | |
| 952 if (!layerForHorizontalScrollbar()) | |
| 953 m_hBar->invalidate(); | |
| 954 // Otherwise we will remove the layer and just need recompositing. | |
| 955 | |
| 956 destroyScrollbar(HorizontalScrollbar); | |
| 957 } | |
| 958 | |
| 959 // Destroying or creating one bar can cause our scrollbar corner to come and
go. We need to update the opposite scrollbar's style. | |
| 960 if (m_hBar) | |
| 961 m_hBar->styleChanged(); | |
| 962 if (m_vBar) | |
| 963 m_vBar->styleChanged(); | |
| 964 | |
| 965 // Force an update since we know the scrollbars have changed things. | |
| 966 if (box().document().hasAnnotatedRegions()) | |
| 967 box().document().setAnnotatedRegionsDirty(true); | |
| 968 } | |
| 969 | |
| 970 void RenderLayerScrollableArea::setHasVerticalScrollbar(bool hasScrollbar) | |
| 971 { | |
| 972 if (hasScrollbar == hasVerticalScrollbar()) | |
| 973 return; | |
| 974 | |
| 975 if (hasScrollbar) { | |
| 976 // Hits in compositing/overflow/automatically-opt-into-composited-scroll
ing-after-style-change.html | |
| 977 DisableCompositingQueryAsserts disabler; | |
| 978 m_vBar = createScrollbar(VerticalScrollbar); | |
| 979 } else { | |
| 980 if (!layerForVerticalScrollbar()) | |
| 981 m_vBar->invalidate(); | |
| 982 // Otherwise we will remove the layer and just need recompositing. | |
| 983 | |
| 984 destroyScrollbar(VerticalScrollbar); | |
| 985 } | |
| 986 | |
| 987 // Destroying or creating one bar can cause our scrollbar corner to come and
go. We need to update the opposite scrollbar's style. | |
| 988 if (m_hBar) | |
| 989 m_hBar->styleChanged(); | |
| 990 if (m_vBar) | |
| 991 m_vBar->styleChanged(); | |
| 992 | |
| 993 // Force an update since we know the scrollbars have changed things. | |
| 994 if (box().document().hasAnnotatedRegions()) | |
| 995 box().document().setAnnotatedRegionsDirty(true); | |
| 996 } | |
| 997 | |
| 998 int RenderLayerScrollableArea::verticalScrollbarWidth(OverlayScrollbarSizeReleva
ncy relevancy) const | |
| 999 { | |
| 1000 if (!m_vBar || (m_vBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayS
crollbarSize || !m_vBar->shouldParticipateInHitTesting()))) | |
| 1001 return 0; | |
| 1002 return m_vBar->width(); | |
| 1003 } | |
| 1004 | |
| 1005 int RenderLayerScrollableArea::horizontalScrollbarHeight(OverlayScrollbarSizeRel
evancy relevancy) const | |
| 1006 { | |
| 1007 if (!m_hBar || (m_hBar->isOverlayScrollbar() && (relevancy == IgnoreOverlayS
crollbarSize || !m_hBar->shouldParticipateInHitTesting()))) | |
| 1008 return 0; | |
| 1009 return m_hBar->height(); | |
| 1010 } | |
| 1011 | |
| 1012 void RenderLayerScrollableArea::positionOverflowControls(const IntSize& offsetFr
omRoot) | |
| 1013 { | |
| 1014 if (!hasScrollbar() && !box().canResize()) | |
| 1015 return; | |
| 1016 | |
| 1017 const IntRect borderBox = box().pixelSnappedBorderBoxRect(); | |
| 1018 if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { | |
| 1019 IntRect vBarRect = rectForVerticalScrollbar(borderBox); | |
| 1020 vBarRect.move(offsetFromRoot); | |
| 1021 verticalScrollbar->setFrameRect(vBarRect); | |
| 1022 } | |
| 1023 | |
| 1024 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { | |
| 1025 IntRect hBarRect = rectForHorizontalScrollbar(borderBox); | |
| 1026 hBarRect.move(offsetFromRoot); | |
| 1027 horizontalScrollbar->setFrameRect(hBarRect); | |
| 1028 } | |
| 1029 | |
| 1030 const IntRect& scrollCorner = scrollCornerRect(); | |
| 1031 if (m_scrollCorner) | |
| 1032 m_scrollCorner->setFrameRect(scrollCorner); | |
| 1033 | |
| 1034 if (m_resizer) | |
| 1035 m_resizer->setFrameRect(resizerCornerRect(borderBox, ResizerForPointer))
; | |
| 1036 | |
| 1037 // FIXME, this should eventually be removed, once we are certain that compos
ited | |
| 1038 // controls get correctly positioned on a compositor update. For now, conser
vatively | |
| 1039 // leaving this unchanged. | |
| 1040 if (layer()->hasCompositedLayerMapping()) | |
| 1041 layer()->compositedLayerMapping()->positionOverflowControlsLayers(offset
FromRoot); | |
| 1042 } | |
| 1043 | |
| 1044 void RenderLayerScrollableArea::updateScrollCornerStyle() | |
| 1045 { | |
| 1046 if (!m_scrollCorner && !hasScrollbar()) | |
| 1047 return; | |
| 1048 if (!m_scrollCorner && hasOverlayScrollbars()) | |
| 1049 return; | |
| 1050 | |
| 1051 RenderObject* actualRenderer = rendererForScrollbar(box()); | |
| 1052 RefPtr<RenderStyle> corner = box().hasOverflowClip() ? actualRenderer->getUn
cachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), actualRenderer->style())
: PassRefPtr<RenderStyle>(nullptr); | |
| 1053 if (corner) { | |
| 1054 if (!m_scrollCorner) { | |
| 1055 m_scrollCorner = RenderScrollbarPart::createAnonymous(&box().documen
t()); | |
| 1056 m_scrollCorner->setParent(&box()); | |
| 1057 } | |
| 1058 m_scrollCorner->setStyle(corner.release()); | |
| 1059 } else if (m_scrollCorner) { | |
| 1060 m_scrollCorner->destroy(); | |
| 1061 m_scrollCorner = nullptr; | |
| 1062 } | |
| 1063 } | |
| 1064 | |
| 1065 bool RenderLayerScrollableArea::hitTestOverflowControls(HitTestResult& result, c
onst IntPoint& localPoint) | |
| 1066 { | |
| 1067 if (!hasScrollbar() && !box().canResize()) | |
| 1068 return false; | |
| 1069 | |
| 1070 IntRect resizeControlRect; | |
| 1071 if (box().style()->resize() != RESIZE_NONE) { | |
| 1072 resizeControlRect = resizerCornerRect(box().pixelSnappedBorderBoxRect(),
ResizerForPointer); | |
| 1073 if (resizeControlRect.contains(localPoint)) | |
| 1074 return true; | |
| 1075 } | |
| 1076 | |
| 1077 int resizeControlSize = max(resizeControlRect.height(), 0); | |
| 1078 if (m_vBar && m_vBar->shouldParticipateInHitTesting()) { | |
| 1079 LayoutRect vBarRect(verticalScrollbarStart(0, box().size().width()), | |
| 1080 box().borderTop(), | |
| 1081 m_vBar->width(), | |
| 1082 box().size().height() - (box().borderTop() + box().borderBottom()) -
(m_hBar ? m_hBar->height() : resizeControlSize)); | |
| 1083 if (vBarRect.contains(localPoint)) { | |
| 1084 result.setScrollbar(m_vBar.get()); | |
| 1085 return true; | |
| 1086 } | |
| 1087 } | |
| 1088 | |
| 1089 resizeControlSize = max(resizeControlRect.width(), 0); | |
| 1090 if (m_hBar && m_hBar->shouldParticipateInHitTesting()) { | |
| 1091 LayoutRect hBarRect(horizontalScrollbarStart(0), | |
| 1092 box().size().height() - box().borderBottom() - m_hBar->height(), | |
| 1093 box().size().width() - (box().borderLeft() + box().borderRight()) -
(m_vBar ? m_vBar->width() : resizeControlSize), | |
| 1094 m_hBar->height()); | |
| 1095 if (hBarRect.contains(localPoint)) { | |
| 1096 result.setScrollbar(m_hBar.get()); | |
| 1097 return true; | |
| 1098 } | |
| 1099 } | |
| 1100 | |
| 1101 // FIXME: We should hit test the m_scrollCorner and pass it back through the
result. | |
| 1102 | |
| 1103 return false; | |
| 1104 } | |
| 1105 | |
| 1106 IntRect RenderLayerScrollableArea::resizerCornerRect(const IntRect& bounds, Resi
zerHitTestType resizerHitTestType) const | |
| 1107 { | |
| 1108 if (box().style()->resize() == RESIZE_NONE) | |
| 1109 return IntRect(); | |
| 1110 IntRect corner = cornerRect(box().style(), horizontalScrollbar(), verticalSc
rollbar(), bounds); | |
| 1111 | |
| 1112 if (resizerHitTestType == ResizerForTouch) { | |
| 1113 // We make the resizer virtually larger for touch hit testing. With the | |
| 1114 // expanding ratio k = ResizerControlExpandRatioForTouch, we first move | |
| 1115 // the resizer rect (of width w & height h), by (-w * (k-1), -h * (k-1))
, | |
| 1116 // then expand the rect by new_w/h = w/h * k. | |
| 1117 int expandRatio = ResizerControlExpandRatioForTouch - 1; | |
| 1118 corner.move(-corner.width() * expandRatio, -corner.height() * expandRati
o); | |
| 1119 corner.expand(corner.width() * expandRatio, corner.height() * expandRati
o); | |
| 1120 } | |
| 1121 | |
| 1122 return corner; | |
| 1123 } | |
| 1124 | |
| 1125 IntRect RenderLayerScrollableArea::scrollCornerAndResizerRect() const | |
| 1126 { | |
| 1127 IntRect scrollCornerAndResizer = scrollCornerRect(); | |
| 1128 if (scrollCornerAndResizer.isEmpty()) | |
| 1129 scrollCornerAndResizer = resizerCornerRect(box().pixelSnappedBorderBoxRe
ct(), ResizerForPointer); | |
| 1130 return scrollCornerAndResizer; | |
| 1131 } | |
| 1132 | |
| 1133 bool RenderLayerScrollableArea::isPointInResizeControl(const IntPoint& absoluteP
oint, ResizerHitTestType resizerHitTestType) const | |
| 1134 { | |
| 1135 if (!box().canResize()) | |
| 1136 return false; | |
| 1137 | |
| 1138 IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, U
seTransforms)); | |
| 1139 IntRect localBounds(0, 0, box().pixelSnappedWidth(), box().pixelSnappedHeigh
t()); | |
| 1140 return resizerCornerRect(localBounds, resizerHitTestType).contains(localPoin
t); | |
| 1141 } | |
| 1142 | |
| 1143 bool RenderLayerScrollableArea::hitTestResizerInFragments(const LayerFragments&
layerFragments, const HitTestLocation& hitTestLocation) const | |
| 1144 { | |
| 1145 if (!box().canResize()) | |
| 1146 return false; | |
| 1147 | |
| 1148 if (layerFragments.isEmpty()) | |
| 1149 return false; | |
| 1150 | |
| 1151 for (int i = layerFragments.size() - 1; i >= 0; --i) { | |
| 1152 const LayerFragment& fragment = layerFragments.at(i); | |
| 1153 if (fragment.backgroundRect.intersects(hitTestLocation) && resizerCorner
Rect(pixelSnappedIntRect(fragment.layerBounds), ResizerForPointer).contains(hitT
estLocation.roundedPoint())) | |
| 1154 return true; | |
| 1155 } | |
| 1156 | |
| 1157 return false; | |
| 1158 } | |
| 1159 | |
| 1160 void RenderLayerScrollableArea::updateResizerAreaSet() | |
| 1161 { | |
| 1162 LocalFrame* frame = box().frame(); | |
| 1163 if (!frame) | |
| 1164 return; | |
| 1165 FrameView* frameView = frame->view(); | |
| 1166 if (!frameView) | |
| 1167 return; | |
| 1168 if (box().canResize()) | |
| 1169 frameView->addResizerArea(box()); | |
| 1170 else | |
| 1171 frameView->removeResizerArea(box()); | |
| 1172 } | |
| 1173 | |
| 1174 void RenderLayerScrollableArea::updateResizerStyle() | |
| 1175 { | |
| 1176 if (!m_resizer && !box().canResize()) | |
| 1177 return; | |
| 1178 | |
| 1179 RenderObject* actualRenderer = rendererForScrollbar(box()); | |
| 1180 RefPtr<RenderStyle> resizer = box().hasOverflowClip() ? actualRenderer->getU
ncachedPseudoStyle(PseudoStyleRequest(RESIZER), actualRenderer->style()) : PassR
efPtr<RenderStyle>(nullptr); | |
| 1181 if (resizer) { | |
| 1182 if (!m_resizer) { | |
| 1183 m_resizer = RenderScrollbarPart::createAnonymous(&box().document()); | |
| 1184 m_resizer->setParent(&box()); | |
| 1185 } | |
| 1186 m_resizer->setStyle(resizer.release()); | |
| 1187 } else if (m_resizer) { | |
| 1188 m_resizer->destroy(); | |
| 1189 m_resizer = nullptr; | |
| 1190 } | |
| 1191 } | |
| 1192 | |
| 1193 IntSize RenderLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolu
tePoint) const | |
| 1194 { | |
| 1195 // Currently the resize corner is either the bottom right corner or the bott
om left corner. | |
| 1196 // FIXME: This assumes the location is 0, 0. Is this guaranteed to always be
the case? | |
| 1197 IntSize elementSize = layer()->size(); | |
| 1198 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) | |
| 1199 elementSize.setWidth(0); | |
| 1200 IntPoint resizerPoint = IntPoint(elementSize); | |
| 1201 IntPoint localPoint = roundedIntPoint(box().absoluteToLocal(absolutePoint, U
seTransforms)); | |
| 1202 return localPoint - resizerPoint; | |
| 1203 } | |
| 1204 | |
| 1205 void RenderLayerScrollableArea::resize(const PlatformEvent& evt, const LayoutSiz
e& oldOffset) | |
| 1206 { | |
| 1207 // FIXME: This should be possible on generated content but is not right now. | |
| 1208 if (!inResizeMode() || !box().canResize() || !box().node()) | |
| 1209 return; | |
| 1210 | |
| 1211 ASSERT(box().node()->isElementNode()); | |
| 1212 Element* element = toElement(box().node()); | |
| 1213 | |
| 1214 Document& document = element->document(); | |
| 1215 | |
| 1216 IntPoint pos; | |
| 1217 const PlatformGestureEvent* gevt = 0; | |
| 1218 | |
| 1219 switch (evt.type()) { | |
| 1220 case PlatformEvent::MouseMoved: | |
| 1221 if (!document.frame()->eventHandler().mousePressed()) | |
| 1222 return; | |
| 1223 pos = static_cast<const PlatformMouseEvent*>(&evt)->position(); | |
| 1224 break; | |
| 1225 case PlatformEvent::GestureScrollUpdate: | |
| 1226 pos = static_cast<const PlatformGestureEvent*>(&evt)->position(); | |
| 1227 gevt = static_cast<const PlatformGestureEvent*>(&evt); | |
| 1228 pos = gevt->position(); | |
| 1229 pos.move(gevt->deltaX(), gevt->deltaY()); | |
| 1230 break; | |
| 1231 default: | |
| 1232 ASSERT_NOT_REACHED(); | |
| 1233 } | |
| 1234 | |
| 1235 float zoomFactor = box().style()->effectiveZoom(); | |
| 1236 | |
| 1237 IntSize newOffset = offsetFromResizeCorner(document.view()->windowToContents
(pos)); | |
| 1238 newOffset.setWidth(newOffset.width() / zoomFactor); | |
| 1239 newOffset.setHeight(newOffset.height() / zoomFactor); | |
| 1240 | |
| 1241 LayoutSize currentSize = box().size(); | |
| 1242 currentSize.scale(1 / zoomFactor); | |
| 1243 LayoutSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentS
ize); | |
| 1244 element->setMinimumSizeForResizing(minimumSize); | |
| 1245 | |
| 1246 LayoutSize adjustedOldOffset = LayoutSize(oldOffset.width() / zoomFactor, ol
dOffset.height() / zoomFactor); | |
| 1247 if (box().style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) { | |
| 1248 newOffset.setWidth(-newOffset.width()); | |
| 1249 adjustedOldOffset.setWidth(-adjustedOldOffset.width()); | |
| 1250 } | |
| 1251 | |
| 1252 LayoutSize difference((currentSize + newOffset - adjustedOldOffset).expanded
To(minimumSize) - currentSize); | |
| 1253 | |
| 1254 bool isBoxSizingBorder = box().style()->boxSizing() == BORDER_BOX; | |
| 1255 | |
| 1256 EResize resize = box().style()->resize(); | |
| 1257 if (resize != RESIZE_VERTICAL && difference.width()) { | |
| 1258 if (element->isFormControlElement()) { | |
| 1259 // Make implicit margins from the theme explicit (see <http://bugs.w
ebkit.org/show_bug.cgi?id=9547>). | |
| 1260 element->setInlineStyleProperty(CSSPropertyMarginLeft, box().marginL
eft() / zoomFactor, CSSPrimitiveValue::CSS_PX); | |
| 1261 element->setInlineStyleProperty(CSSPropertyMarginRight, box().margin
Right() / zoomFactor, CSSPrimitiveValue::CSS_PX); | |
| 1262 } | |
| 1263 LayoutUnit baseWidth = box().size().width() - (isBoxSizingBorder ? Layou
tUnit() : box().borderAndPaddingWidth()); | |
| 1264 baseWidth = baseWidth / zoomFactor; | |
| 1265 element->setInlineStyleProperty(CSSPropertyWidth, roundToInt(baseWidth +
difference.width()), CSSPrimitiveValue::CSS_PX); | |
| 1266 } | |
| 1267 | |
| 1268 if (resize != RESIZE_HORIZONTAL && difference.height()) { | |
| 1269 if (element->isFormControlElement()) { | |
| 1270 // Make implicit margins from the theme explicit (see <http://bugs.w
ebkit.org/show_bug.cgi?id=9547>). | |
| 1271 element->setInlineStyleProperty(CSSPropertyMarginTop, box().marginTo
p() / zoomFactor, CSSPrimitiveValue::CSS_PX); | |
| 1272 element->setInlineStyleProperty(CSSPropertyMarginBottom, box().margi
nBottom() / zoomFactor, CSSPrimitiveValue::CSS_PX); | |
| 1273 } | |
| 1274 LayoutUnit baseHeight = box().size().height() - (isBoxSizingBorder ? Lay
outUnit() : box().borderAndPaddingHeight()); | |
| 1275 baseHeight = baseHeight / zoomFactor; | |
| 1276 element->setInlineStyleProperty(CSSPropertyHeight, roundToInt(baseHeight
+ difference.height()), CSSPrimitiveValue::CSS_PX); | |
| 1277 } | |
| 1278 | |
| 1279 document.updateLayout(); | |
| 1280 | |
| 1281 // FIXME (Radar 4118564): We should also autoscroll the window as necessary
to keep the point under the cursor in view. | |
| 1282 } | |
| 1283 | |
| 1284 LayoutRect RenderLayerScrollableArea::exposeRect(const LayoutRect& rect, const S
crollAlignment& alignX, const ScrollAlignment& alignY) | |
| 1285 { | |
| 1286 LayoutRect localExposeRect(box().absoluteToLocalQuad(FloatQuad(FloatRect(rec
t)), UseTransforms).boundingBox()); | |
| 1287 localExposeRect.move(-box().borderLeft(), -box().borderTop()); | |
| 1288 LayoutRect layerBounds(0, 0, box().clientWidth(), box().clientHeight()); | |
| 1289 LayoutRect r = ScrollAlignment::getRectToExpose(layerBounds, localExposeRect
, alignX, alignY); | |
| 1290 | |
| 1291 DoubleSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset() +
roundedIntSize(r.location())); | |
| 1292 if (clampedScrollOffset == adjustedScrollOffset()) | |
| 1293 return rect; | |
| 1294 | |
| 1295 DoubleSize oldScrollOffset = adjustedScrollOffset(); | |
| 1296 scrollToOffset(clampedScrollOffset); | |
| 1297 DoubleSize scrollOffsetDifference = adjustedScrollOffset() - oldScrollOffset
; | |
| 1298 localExposeRect.move(-LayoutSize(scrollOffsetDifference)); | |
| 1299 return LayoutRect(box().localToAbsoluteQuad(FloatQuad(FloatRect(localExposeR
ect)), UseTransforms).boundingBox()); | |
| 1300 } | |
| 1301 | |
| 1302 void RenderLayerScrollableArea::updateScrollableAreaSet(bool hasOverflow) | |
| 1303 { | |
| 1304 LocalFrame* frame = box().frame(); | |
| 1305 if (!frame) | |
| 1306 return; | |
| 1307 | |
| 1308 FrameView* frameView = frame->view(); | |
| 1309 if (!frameView) | |
| 1310 return; | |
| 1311 | |
| 1312 // FIXME: Does this need to be fixed later for OOPI? | |
| 1313 bool isVisibleToHitTest = box().visibleToHitTesting(); | |
| 1314 if (HTMLFrameOwnerElement* owner = frame->deprecatedLocalOwner()) | |
| 1315 isVisibleToHitTest &= owner->renderer() && owner->renderer()->visibleToH
itTesting(); | |
| 1316 | |
| 1317 bool didScrollOverflow = m_scrollsOverflow; | |
| 1318 | |
| 1319 m_scrollsOverflow = hasOverflow && isVisibleToHitTest; | |
| 1320 if (didScrollOverflow == scrollsOverflow()) | |
| 1321 return; | |
| 1322 | |
| 1323 if (m_scrollsOverflow) { | |
| 1324 ASSERT(canHaveOverflowScrollbars(box())); | |
| 1325 frameView->addScrollableArea(this); | |
| 1326 } else | |
| 1327 frameView->removeScrollableArea(this); | |
| 1328 } | |
| 1329 | |
| 1330 void RenderLayerScrollableArea::updateCompositingLayersAfterScroll() | |
| 1331 { | |
| 1332 DisableCompositingQueryAsserts disabler; | |
| 1333 RenderLayerCompositor* compositor = box().view()->compositor(); | |
| 1334 if (compositor->inCompositingMode()) { | |
| 1335 if (usesCompositedScrolling()) { | |
| 1336 ASSERT(layer()->hasCompositedLayerMapping()); | |
| 1337 layer()->compositedLayerMapping()->setNeedsGraphicsLayerUpdate(Graph
icsLayerUpdateSubtree); | |
| 1338 compositor->setNeedsCompositingUpdate(CompositingUpdateAfterGeometry
Change); | |
| 1339 } else { | |
| 1340 layer()->setNeedsCompositingInputsUpdate(); | |
| 1341 } | |
| 1342 } | |
| 1343 } | |
| 1344 | |
| 1345 bool RenderLayerScrollableArea::usesCompositedScrolling() const | |
| 1346 { | |
| 1347 // Scroll form controls on the main thread so they exhibit correct touch scr
oll event bubbling | |
| 1348 if (box().isIntristicallyScrollable(VerticalScrollbar) || box().isIntristica
llyScrollable(HorizontalScrollbar)) | |
| 1349 return false; | |
| 1350 | |
| 1351 // See https://codereview.chromium.org/176633003/ for the tests that fail wi
thout this disabler. | |
| 1352 DisableCompositingQueryAsserts disabler; | |
| 1353 return layer()->hasCompositedLayerMapping() && layer()->compositedLayerMappi
ng()->scrollingLayer(); | |
| 1354 } | |
| 1355 | |
| 1356 static bool layerNeedsCompositedScrolling(RenderLayerScrollableArea::LCDTextMode
mode, const RenderLayer* layer) | |
| 1357 { | |
| 1358 if (mode == RenderLayerScrollableArea::ConsiderLCDText && !layer->compositor
()->preferCompositingToLCDTextEnabled()) | |
| 1359 return false; | |
| 1360 | |
| 1361 return layer->scrollsOverflow() | |
| 1362 && !layer->hasDescendantWithClipPath() | |
| 1363 && !layer->hasAncestorWithClipPath() | |
| 1364 && !layer->renderer()->style()->hasBorderRadius(); | |
| 1365 } | |
| 1366 | |
| 1367 void RenderLayerScrollableArea::updateNeedsCompositedScrolling(LCDTextMode mode) | |
| 1368 { | |
| 1369 const bool needsCompositedScrolling = layerNeedsCompositedScrolling(mode, la
yer()); | |
| 1370 if (static_cast<bool>(m_needsCompositedScrolling) != needsCompositedScrollin
g) { | |
| 1371 m_needsCompositedScrolling = needsCompositedScrolling; | |
| 1372 layer()->didUpdateNeedsCompositedScrolling(); | |
| 1373 } | |
| 1374 } | |
| 1375 | |
| 1376 void RenderLayerScrollableArea::setTopmostScrollChild(RenderLayer* scrollChild) | |
| 1377 { | |
| 1378 // We only want to track the topmost scroll child for scrollable areas with | |
| 1379 // overlay scrollbars. | |
| 1380 if (!hasOverlayScrollbars()) | |
| 1381 return; | |
| 1382 m_nextTopmostScrollChild = scrollChild; | |
| 1383 } | |
| 1384 | |
| 1385 } // namespace blink | |
| OLD | NEW |