1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "platform/scroll/ScrollView.h" 28 29 #include "platform/graphics/GraphicsContextStateSaver.h" 30 #include "platform/graphics/GraphicsLayer.h" 31 #include "platform/HostWindow.h" 32 #include "platform/scroll/ScrollbarTheme.h" 33 #include "wtf/StdLibExtras.h" 34 35 namespace blink { 36 37 ScrollView::ScrollView() 38 : m_horizontalScrollbarMode(ScrollbarAuto) 39 , m_verticalScrollbarMode(ScrollbarAuto) 40 , m_horizontalScrollbarLock(false) 41 , m_verticalScrollbarLock(false) 42 , m_scrollbarsAvoidingResizer(0) 43 , m_scrollbarsSuppressed(false) 44 , m_inUpdateScrollbars(false) 45 , m_drawPanScrollIcon(false) 46 , m_clipsRepaints(true) 47 { 48 } 49 50 ScrollView::~ScrollView() 51 { 52 } 53 54 void ScrollView::addChild(PassRefPtr<Widget> prpChild) 55 { 56 Widget* child = prpChild.get(); 57 ASSERT(child != this && !child->parent()); 58 child->setParent(this); 59 m_children.add(prpChild); 60 } 61 62 void ScrollView::removeChild(Widget* child) 63 { 64 ASSERT(child->parent() == this); 65 child->setParent(0); 66 m_children.remove(child); 67 } 68 69 void ScrollView::setHasHorizontalScrollbar(bool hasBar) 70 { 71 if (hasBar && !m_horizontalScrollbar) { 72 m_horizontalScrollbar = createScrollbar(HorizontalScrollbar); 73 addChild(m_horizontalScrollbar.get()); 74 didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar); 75 m_horizontalScrollbar->styleChanged(); 76 } else if (!hasBar && m_horizontalScrollbar) { 77 willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar); 78 removeChild(m_horizontalScrollbar.get()); 79 m_horizontalScrollbar = nullptr; 80 } 81 } 82 83 void ScrollView::setHasVerticalScrollbar(bool hasBar) 84 { 85 if (hasBar && !m_verticalScrollbar) { 86 m_verticalScrollbar = createScrollbar(VerticalScrollbar); 87 addChild(m_verticalScrollbar.get()); 88 didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar); 89 m_verticalScrollbar->styleChanged(); 90 } else if (!hasBar && m_verticalScrollbar) { 91 willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar); 92 removeChild(m_verticalScrollbar.get()); 93 m_verticalScrollbar = nullptr; 94 } 95 } 96 97 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation) 98 { 99 return Scrollbar::create(this, orientation, RegularScrollbar); 100 } 101 102 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode, 103 bool horizontalLock, bool verticalLock) 104 { 105 bool needsUpdate = false; 106 107 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) { 108 m_horizontalScrollbarMode = horizontalMode; 109 needsUpdate = true; 110 } 111 112 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) { 113 m_verticalScrollbarMode = verticalMode; 114 needsUpdate = true; 115 } 116 117 if (horizontalLock) 118 setHorizontalScrollbarLock(); 119 120 if (verticalLock) 121 setVerticalScrollbarLock(); 122 123 if (!needsUpdate) 124 return; 125 126 updateScrollbars(scrollOffset()); 127 128 if (!layerForScrolling()) 129 return; 130 blink::WebLayer* layer = layerForScrolling()->platformLayer(); 131 if (!layer) 132 return; 133 layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInputScrollable(VerticalScrollbar)); 134 } 135 136 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const 137 { 138 horizontalMode = m_horizontalScrollbarMode; 139 verticalMode = m_verticalScrollbarMode; 140 } 141 142 void ScrollView::setCanHaveScrollbars(bool canScroll) 143 { 144 ScrollbarMode newHorizontalMode; 145 ScrollbarMode newVerticalMode; 146 147 scrollbarModes(newHorizontalMode, newVerticalMode); 148 149 if (canScroll && newVerticalMode == ScrollbarAlwaysOff) 150 newVerticalMode = ScrollbarAuto; 151 else if (!canScroll) 152 newVerticalMode = ScrollbarAlwaysOff; 153 154 if (canScroll && newHorizontalMode == ScrollbarAlwaysOff) 155 newHorizontalMode = ScrollbarAuto; 156 else if (!canScroll) 157 newHorizontalMode = ScrollbarAlwaysOff; 158 159 setScrollbarModes(newHorizontalMode, newVerticalMode); 160 } 161 162 void ScrollView::setClipsRepaints(bool clipsRepaints) 163 { 164 m_clipsRepaints = clipsRepaints; 165 } 166 167 IntSize ScrollView::unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbarInclusion) const 168 { 169 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect().size()) : frameRect().size(); 170 } 171 172 IntSize ScrollView::excludeScrollbars(const IntSize& size) const 173 { 174 int verticalScrollbarWidth = 0; 175 int horizontalScrollbarHeight = 0; 176 177 if (Scrollbar* verticalBar = verticalScrollbar()) 178 verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBar->width() : 0; 179 if (Scrollbar* horizontalBar = horizontalScrollbar()) 180 horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horizontalBar->height() : 0; 181 182 return IntSize(std::max(0, size.width() - verticalScrollbarWidth), 183 std::max(0, size.height() - horizontalScrollbarHeight)); 184 185 } 186 187 IntRect ScrollView::visibleContentRect(IncludeScrollbarsInRect scollbarInclusion) const 188 { 189 FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion); 190 visibleContentSize.scale(1 / visibleContentScaleFactor()); 191 return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize)); 192 } 193 194 IntSize ScrollView::contentsSize() const 195 { 196 return m_contentsSize; 197 } 198 199 void ScrollView::setContentsSize(const IntSize& newSize) 200 { 201 if (contentsSize() == newSize) 202 return; 203 m_contentsSize = newSize; 204 updateScrollbars(scrollOffset()); 205 updateOverhangAreas(); 206 } 207 208 IntPoint ScrollView::maximumScrollPosition() const 209 { 210 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x(), contentsHeight() - visibleHeight() - scrollOrigin().y()); 211 maximumOffset.clampNegativeToZero(); 212 return maximumOffset; 213 } 214 215 IntPoint ScrollView::minimumScrollPosition() const 216 { 217 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y()); 218 } 219 220 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const 221 { 222 if (!constrainsScrollingToContentEdge()) 223 return scrollPoint; 224 225 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition()); 226 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition()); 227 return newScrollPosition; 228 } 229 230 void ScrollView::adjustScrollbarOpacity() 231 { 232 if (m_horizontalScrollbar && layerForHorizontalScrollbar()) { 233 bool isOpaqueScrollbar = !m_horizontalScrollbar->isOverlayScrollbar(); 234 layerForHorizontalScrollbar()->setContentsOpaque(isOpaqueScrollbar); 235 } 236 if (m_verticalScrollbar && layerForVerticalScrollbar()) { 237 bool isOpaqueScrollbar = !m_verticalScrollbar->isOverlayScrollbar(); 238 layerForVerticalScrollbar()->setContentsOpaque(isOpaqueScrollbar); 239 } 240 } 241 242 int ScrollView::scrollSize(ScrollbarOrientation orientation) const 243 { 244 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get(); 245 246 // If no scrollbars are present, the content may still be scrollable. 247 if (!scrollbar) { 248 IntSize scrollSize = m_contentsSize - visibleContentRect().size(); 249 scrollSize.clampNegativeToZero(); 250 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollSize.height(); 251 } 252 253 return scrollbar->totalSize() - scrollbar->visibleSize(); 254 } 255 256 void ScrollView::notifyPageThatContentAreaWillPaint() const 257 { 258 } 259 260 void ScrollView::setScrollOffset(const IntPoint& offset) 261 { 262 scrollTo(toIntSize(adjustScrollPositionWithinRange(offset))); 263 } 264 265 void ScrollView::scrollTo(const IntSize& newOffset) 266 { 267 IntSize scrollDelta = newOffset - m_scrollOffset; 268 if (scrollDelta == IntSize()) 269 return; 270 m_scrollOffset = newOffset; 271 272 if (scrollbarsSuppressed()) 273 return; 274 275 if (isFrameView()) 276 m_pendingScrollDelta += scrollDelta; 277 else 278 scrollContents(scrollDelta); 279 } 280 281 void ScrollView::setScrollPosition(const IntPoint& scrollPoint, ScrollBehavior scrollBehavior) 282 { 283 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); 284 285 if (newScrollPosition == scrollPosition()) 286 return; 287 288 if (scrollBehavior == ScrollBehaviorInstant) 289 updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y())); 290 else 291 programmaticallyScrollSmoothlyToOffset(newScrollPosition); 292 } 293 294 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity) 295 { 296 ScrollDirection physicalDirection = 297 toPhysicalDirection(direction, isVerticalDocument(), isFlippedDocument()); 298 299 return ScrollableArea::scroll(physicalDirection, granularity); 300 } 301 302 IntSize ScrollView::overhangAmount() const 303 { 304 IntSize stretch; 305 306 IntPoint currentScrollPosition = scrollPosition(); 307 IntPoint minScrollPosition = minimumScrollPosition(); 308 IntPoint maxScrollPosition = maximumScrollPosition(); 309 310 if (currentScrollPosition.x() < minScrollPosition.x()) 311 stretch.setWidth(currentScrollPosition.x() - minScrollPosition.x()); 312 if (currentScrollPosition.x() > maxScrollPosition.x()) 313 stretch.setWidth(currentScrollPosition.x() - maxScrollPosition.x()); 314 315 if (currentScrollPosition.y() < minScrollPosition.y()) 316 stretch.setHeight(currentScrollPosition.y() - minScrollPosition.y()); 317 if (currentScrollPosition.y() > maxScrollPosition.y()) 318 stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y()); 319 320 return stretch; 321 } 322 323 void ScrollView::windowResizerRectChanged() 324 { 325 updateScrollbars(scrollOffset()); 326 } 327 328 static bool useOverlayScrollbars() 329 { 330 // FIXME: Need to detect the presence of CSS custom scrollbars, which are non-overlay regardless the ScrollbarTheme. 331 return ScrollbarTheme::theme()->usesOverlayScrollbars(); 332 } 333 334 void ScrollView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOption option) const 335 { 336 bool hasHorizontalScrollbar = m_horizontalScrollbar; 337 bool hasVerticalScrollbar = m_verticalScrollbar; 338 339 newHasHorizontalScrollbar = hasHorizontalScrollbar; 340 newHasVerticalScrollbar = hasVerticalScrollbar; 341 342 ScrollbarMode hScroll = m_horizontalScrollbarMode; 343 ScrollbarMode vScroll = m_verticalScrollbarMode; 344 345 if (hScroll != ScrollbarAuto) 346 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); 347 if (vScroll != ScrollbarAuto) 348 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); 349 350 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) 351 return; 352 353 if (hScroll == ScrollbarAuto) 354 newHasHorizontalScrollbar = docSize.width() > visibleWidth(); 355 if (vScroll == ScrollbarAuto) 356 newHasVerticalScrollbar = docSize.height() > visibleHeight(); 357 358 if (useOverlayScrollbars()) 359 return; 360 361 IntSize fullVisibleSize = visibleContentRect(IncludeScrollbars).size(); 362 363 bool attemptToRemoveScrollbars = (option == FirstPass 364 && docSize.width() <= fullVisibleSize.width() && docSize.height() <= fullVisibleSize.height()); 365 if (attemptToRemoveScrollbars) { 366 if (hScroll == ScrollbarAuto) 367 newHasHorizontalScrollbar = false; 368 if (vScroll == ScrollbarAuto) 369 newHasVerticalScrollbar = false; 370 } 371 372 // If we ever turn one scrollbar off, always turn the other one off too. 373 // Never ever try to both gain/lose a scrollbar in the same pass. 374 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) 375 newHasVerticalScrollbar = false; 376 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) 377 newHasHorizontalScrollbar = false; 378 } 379 380 void ScrollView::updateScrollbarGeometry() 381 { 382 if (m_horizontalScrollbar) { 383 int clientWidth = visibleWidth(); 384 IntRect oldRect(m_horizontalScrollbar->frameRect()); 385 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScrollbar) ? m_verticalScrollbar->width() : 0, 386 height() - m_horizontalScrollbar->height(), 387 width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0), 388 m_horizontalScrollbar->height()); 389 m_horizontalScrollbar->setFrameRect(hBarRect); 390 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect()) 391 m_horizontalScrollbar->invalidate(); 392 393 if (m_scrollbarsSuppressed) 394 m_horizontalScrollbar->setSuppressInvalidation(true); 395 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth); 396 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth()); 397 m_horizontalScrollbar->offsetDidChange(); 398 if (m_scrollbarsSuppressed) 399 m_horizontalScrollbar->setSuppressInvalidation(false); 400 } 401 402 if (m_verticalScrollbar) { 403 int clientHeight = visibleHeight(); 404 IntRect oldRect(m_verticalScrollbar->frameRect()); 405 IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()), 406 0, 407 m_verticalScrollbar->width(), 408 height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0)); 409 m_verticalScrollbar->setFrameRect(vBarRect); 410 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect()) 411 m_verticalScrollbar->invalidate(); 412 413 if (m_scrollbarsSuppressed) 414 m_verticalScrollbar->setSuppressInvalidation(true); 415 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); 416 m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); 417 m_verticalScrollbar->offsetDidChange(); 418 if (m_scrollbarsSuppressed) 419 m_verticalScrollbar->setSuppressInvalidation(false); 420 } 421 } 422 423 bool ScrollView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option) 424 { 425 ASSERT(m_inUpdateScrollbars); 426 427 // If we came in here with the view already needing a layout, then go ahead and do that 428 // first. (This will be the common case, e.g., when the page changes due to window resizing for example). 429 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total. 430 if (!m_scrollbarsSuppressed) 431 scrollbarExistenceDidChange(); 432 433 bool hasHorizontalScrollbar = m_horizontalScrollbar; 434 bool hasVerticalScrollbar = m_verticalScrollbar; 435 436 bool newHasHorizontalScrollbar = false; 437 bool newHasVerticalScrollbar = false; 438 computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar, contentsSize(), option); 439 440 bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalScrollbar || hasVerticalScrollbar != newHasVerticalScrollbar; 441 if (!scrollbarExistenceChanged) 442 return false; 443 444 setHasHorizontalScrollbar(newHasHorizontalScrollbar); 445 setHasVerticalScrollbar(newHasVerticalScrollbar); 446 447 if (m_scrollbarsSuppressed) 448 return true; 449 450 if (!useOverlayScrollbars()) 451 contentsResized(); 452 scrollbarExistenceDidChange(); 453 return true; 454 } 455 456 void ScrollView::updateScrollbars(const IntSize& desiredOffset) 457 { 458 if (scrollbarsDisabled()) { 459 setScrollOffsetFromUpdateScrollbars(desiredOffset); 460 return; 461 } 462 463 if (m_inUpdateScrollbars) 464 return; 465 InUpdateScrollbarsScope inUpdateScrollbarsScope(this); 466 467 IntSize oldVisibleSize = visibleSize(); 468 469 bool scrollbarExistenceChanged = false; 470 int maxUpdateScrollbarsPass = useOverlayScrollbars() || m_scrollbarsSuppressed ? 1 : 3; 471 for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbarsPass; updateScrollbarsPass++) { 472 if (!adjustScrollbarExistence(updateScrollbarsPass ? Incremental : FirstPass)) 473 break; 474 scrollbarExistenceChanged = true; 475 } 476 477 updateScrollbarGeometry(); 478 479 if (scrollbarExistenceChanged) { 480 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed? 481 frameRectsChanged(); 482 positionScrollbarLayers(); 483 updateScrollCorner(); 484 } 485 486 // FIXME: We don't need to do this if we are composited. 487 IntSize newVisibleSize = visibleSize(); 488 if (newVisibleSize.width() > oldVisibleSize.width()) { 489 if (shouldPlaceVerticalScrollbarOnLeft()) 490 invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height())); 491 else 492 invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.width() - oldVisibleSize.width(), newVisibleSize.height())); 493 } 494 if (newVisibleSize.height() > oldVisibleSize.height()) 495 invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width(), newVisibleSize.height() - oldVisibleSize.height())); 496 497 setScrollOffsetFromUpdateScrollbars(desiredOffset); 498 } 499 500 void ScrollView::setScrollOffsetFromUpdateScrollbars(const IntSize& offset) 501 { 502 IntPoint adjustedScrollPosition = IntPoint(offset); 503 504 if (!isRubberBandInProgress()) 505 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollPosition); 506 507 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) { 508 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition); 509 resetScrollOriginChanged(); 510 } 511 } 512 513 const int panIconSizeLength = 16; 514 515 IntRect ScrollView::rectToCopyOnScroll() const 516 { 517 IntRect scrollViewRect = convertToContainingWindow(IntRect((shouldPlaceVerticalScrollbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visibleWidth(), visibleHeight())); 518 if (hasOverlayScrollbars()) { 519 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0; 520 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0; 521 522 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth); 523 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight); 524 } 525 return scrollViewRect; 526 } 527 528 void ScrollView::scrollContentsIfNeeded() 529 { 530 if (m_pendingScrollDelta.isZero()) 531 return; 532 IntSize scrollDelta = m_pendingScrollDelta; 533 m_pendingScrollDelta = IntSize(); 534 scrollContents(scrollDelta); 535 } 536 537 void ScrollView::scrollContents(const IntSize& scrollDelta) 538 { 539 HostWindow* window = hostWindow(); 540 if (!window) 541 return; 542 543 IntRect clipRect = windowClipRect(); 544 IntRect updateRect = clipRect; 545 updateRect.intersect(rectToCopyOnScroll()); 546 547 if (m_drawPanScrollIcon) { 548 // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers. 549 // https://bugs.webkit.org/show_bug.cgi?id=47837 550 int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + std::max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary 551 IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2)); 552 IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation, IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength)); 553 panScrollIconDirtyRect.intersect(clipRect); 554 window->invalidateContentsAndRootView(panScrollIconDirtyRect); 555 } 556 557 if (!scrollContentsFastPath(-scrollDelta)) 558 scrollContentsSlowPath(updateRect); 559 560 // Invalidate the overhang areas if they are visible. 561 updateOverhangAreas(); 562 563 // This call will move children with native widgets (plugins) and invalidate them as well. 564 frameRectsChanged(); 565 } 566 567 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect) 568 { 569 hostWindow()->invalidateContentsForSlowScroll(updateRect); 570 } 571 572 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const 573 { 574 IntPoint viewPoint = convertFromContainingWindow(rootViewPoint); 575 return viewPoint + scrollOffset(); 576 } 577 578 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const 579 { 580 IntPoint viewPoint = contentsPoint - scrollOffset(); 581 return convertToContainingWindow(viewPoint); 582 } 583 584 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const 585 { 586 IntRect viewRect = convertFromContainingWindow(rootViewRect); 587 viewRect.move(scrollOffset()); 588 return viewRect; 589 } 590 591 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const 592 { 593 IntRect viewRect = contentsRect; 594 viewRect.move(-scrollOffset()); 595 return convertToContainingWindow(viewRect); 596 } 597 598 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const 599 { 600 IntPoint viewPoint = convertFromContainingWindow(windowPoint); 601 return viewPoint + scrollOffset(); 602 } 603 604 FloatPoint ScrollView::windowToContents(const FloatPoint& windowPoint) const 605 { 606 FloatPoint viewPoint = convertFromContainingWindow(windowPoint); 607 return viewPoint + scrollOffset(); 608 } 609 610 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const 611 { 612 IntPoint viewPoint = contentsPoint - scrollOffset(); 613 return convertToContainingWindow(viewPoint); 614 } 615 616 IntRect ScrollView::windowToContents(const IntRect& windowRect) const 617 { 618 IntRect viewRect = convertFromContainingWindow(windowRect); 619 viewRect.move(scrollOffset()); 620 return viewRect; 621 } 622 623 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const 624 { 625 IntRect viewRect = contentsRect; 626 viewRect.move(-scrollOffset()); 627 return convertToContainingWindow(viewRect); 628 } 629 630 IntRect ScrollView::contentsToScreen(const IntRect& rect) const 631 { 632 HostWindow* window = hostWindow(); 633 if (!window) 634 return IntRect(); 635 return window->rootViewToScreen(contentsToRootView(rect)); 636 } 637 638 bool ScrollView::containsScrollbarsAvoidingResizer() const 639 { 640 return !m_scrollbarsAvoidingResizer; 641 } 642 643 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta) 644 { 645 int oldCount = m_scrollbarsAvoidingResizer; 646 m_scrollbarsAvoidingResizer += overlapDelta; 647 if (parent()) 648 toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(overlapDelta); 649 else if (!scrollbarsSuppressed()) { 650 // If we went from n to 0 or from 0 to n and we're the outermost view, 651 // we need to invalidate the windowResizerRect(), since it will now need to paint 652 // differently. 653 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) || 654 (oldCount == 0 && m_scrollbarsAvoidingResizer > 0)) 655 invalidateRect(windowResizerRect()); 656 } 657 } 658 659 void ScrollView::setParent(Widget* parentView) 660 { 661 if (parentView == parent()) 662 return; 663 664 if (m_scrollbarsAvoidingResizer && parent()) 665 toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer); 666 667 Widget::setParent(parentView); 668 669 if (m_scrollbarsAvoidingResizer && parent()) 670 toScrollView(parent())->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer); 671 } 672 673 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress) 674 { 675 if (suppressed == m_scrollbarsSuppressed) 676 return; 677 678 m_scrollbarsSuppressed = suppressed; 679 680 if (repaintOnUnsuppress && !suppressed) { 681 if (m_horizontalScrollbar) 682 m_horizontalScrollbar->invalidate(); 683 if (m_verticalScrollbar) 684 m_verticalScrollbar->invalidate(); 685 686 // Invalidate the scroll corner too on unsuppress. 687 invalidateRect(scrollCornerRect()); 688 } 689 } 690 691 Scrollbar* ScrollView::scrollbarAtWindowPoint(const IntPoint& windowPoint) 692 { 693 IntPoint viewPoint = convertFromContainingWindow(windowPoint); 694 return scrollbarAtViewPoint(viewPoint); 695 } 696 697 Scrollbar* ScrollView::scrollbarAtViewPoint(const IntPoint& viewPoint) 698 { 699 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTesting() && m_horizontalScrollbar->frameRect().contains(viewPoint)) 700 return m_horizontalScrollbar.get(); 701 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTesting() && m_verticalScrollbar->frameRect().contains(viewPoint)) 702 return m_verticalScrollbar.get(); 703 return 0; 704 } 705 706 void ScrollView::setFrameRect(const IntRect& newRect) 707 { 708 IntRect oldRect = frameRect(); 709 710 if (newRect == oldRect) 711 return; 712 713 Widget::setFrameRect(newRect); 714 715 updateScrollbars(scrollOffset()); 716 717 frameRectsChanged(); 718 } 719 720 void ScrollView::frameRectsChanged() 721 { 722 HashSet<RefPtr<Widget> >::const_iterator end = m_children.end(); 723 for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current) 724 (*current)->frameRectsChanged(); 725 } 726 727 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar) 728 { 729 if (!graphicsLayer || !scrollbar) 730 return; 731 732 IntRect scrollbarRect = scrollbar->frameRect(); 733 graphicsLayer->setPosition(scrollbarRect.location()); 734 735 if (scrollbarRect.size() == graphicsLayer->size()) 736 return; 737 738 graphicsLayer->setSize(scrollbarRect.size()); 739 740 if (graphicsLayer->hasContentsLayer()) { 741 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scrollbarRect.height())); 742 return; 743 } 744 745 graphicsLayer->setDrawsContent(true); 746 graphicsLayer->setNeedsDisplay(); 747 } 748 749 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect) 750 { 751 if (!graphicsLayer) 752 return; 753 graphicsLayer->setDrawsContent(!cornerRect.isEmpty()); 754 graphicsLayer->setPosition(cornerRect.location()); 755 if (cornerRect.size() != graphicsLayer->size()) 756 graphicsLayer->setNeedsDisplay(); 757 graphicsLayer->setSize(cornerRect.size()); 758 } 759 760 void ScrollView::positionScrollbarLayers() 761 { 762 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar()); 763 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar()); 764 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect()); 765 } 766 767 bool ScrollView::userInputScrollable(ScrollbarOrientation orientation) const 768 { 769 ScrollbarMode mode = (orientation == HorizontalScrollbar) ? 770 m_horizontalScrollbarMode : m_verticalScrollbarMode; 771 772 return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn; 773 } 774 775 bool ScrollView::shouldPlaceVerticalScrollbarOnLeft() const 776 { 777 return false; 778 } 779 780 void ScrollView::contentRectangleForPaintInvalidation(const IntRect& rect) 781 { 782 IntRect paintRect = rect; 783 if (clipsPaintInvalidations()) 784 paintRect.intersect(visibleContentRect()); 785 if (paintRect.isEmpty()) 786 return; 787 788 if (HostWindow* window = hostWindow()) 789 window->invalidateContentsAndRootView(contentsToWindow(paintRect)); 790 } 791 792 IntRect ScrollView::scrollCornerRect() const 793 { 794 IntRect cornerRect; 795 796 if (hasOverlayScrollbars()) 797 return cornerRect; 798 799 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) { 800 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_horizontalScrollbar->width(), 801 height() - m_horizontalScrollbar->height(), 802 width() - m_horizontalScrollbar->width(), 803 m_horizontalScrollbar->height())); 804 } 805 806 if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) { 807 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m_verticalScrollbar->width()), 808 m_verticalScrollbar->height(), 809 m_verticalScrollbar->width(), 810 height() - m_verticalScrollbar->height())); 811 } 812 813 return cornerRect; 814 } 815 816 bool ScrollView::isScrollCornerVisible() const 817 { 818 return !scrollCornerRect().isEmpty(); 819 } 820 821 void ScrollView::scrollbarStyleChanged() 822 { 823 adjustScrollbarOpacity(); 824 contentsResized(); 825 updateScrollbars(scrollOffset()); 826 positionScrollbarLayers(); 827 } 828 829 void ScrollView::updateScrollCorner() 830 { 831 } 832 833 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect) 834 { 835 ScrollbarTheme::theme()->paintScrollCorner(context, cornerRect); 836 } 837 838 void ScrollView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect) 839 { 840 bar->paint(context, rect); 841 } 842 843 void ScrollView::invalidateScrollCornerRect(const IntRect& rect) 844 { 845 invalidateRect(rect); 846 } 847 848 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect) 849 { 850 if (m_horizontalScrollbar && !layerForHorizontalScrollbar()) 851 paintScrollbar(context, m_horizontalScrollbar.get(), rect); 852 if (m_verticalScrollbar && !layerForVerticalScrollbar()) 853 paintScrollbar(context, m_verticalScrollbar.get(), rect); 854 855 if (layerForScrollCorner()) 856 return; 857 paintScrollCorner(context, scrollCornerRect()); 858 } 859 860 void ScrollView::paintPanScrollIcon(GraphicsContext* context) 861 { 862 DEFINE_STATIC_REF(Image, panScrollIcon, (Image::loadPlatformResource("panIcon"))); 863 IntPoint iconGCPoint = m_panScrollIconPoint; 864 if (parent()) 865 iconGCPoint = toScrollView(parent())->windowToContents(iconGCPoint); 866 context->drawImage(panScrollIcon, iconGCPoint); 867 } 868 869 void ScrollView::paint(GraphicsContext* context, const IntRect& rect) 870 { 871 notifyPageThatContentAreaWillPaint(); 872 873 IntRect documentDirtyRect = rect; 874 IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect().size()); 875 documentDirtyRect.intersect(visibleAreaWithoutScrollbars); 876 877 if (!documentDirtyRect.isEmpty()) { 878 GraphicsContextStateSaver stateSaver(*context); 879 880 context->translate(x() - scrollX(), y() - scrollY()); 881 context->clip(visibleContentRect()); 882 883 documentDirtyRect.moveBy(-location() + scrollPosition()); 884 paintContents(context, documentDirtyRect); 885 } 886 887 calculateAndPaintOverhangAreas(context, rect); 888 889 // Now paint the scrollbars. 890 if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) { 891 GraphicsContextStateSaver stateSaver(*context); 892 IntRect scrollViewDirtyRect = rect; 893 IntRect visibleAreaWithScrollbars(location(), visibleContentRect(IncludeScrollbars).size()); 894 scrollViewDirtyRect.intersect(visibleAreaWithScrollbars); 895 context->translate(x(), y()); 896 scrollViewDirtyRect.moveBy(-location()); 897 context->clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size())); 898 899 paintScrollbars(context, scrollViewDirtyRect); 900 } 901 902 // Paint the panScroll Icon 903 if (m_drawPanScrollIcon) 904 paintPanScrollIcon(context); 905 } 906 907 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect) 908 { 909 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()) 910 ? verticalScrollbar()->width() : 0; 911 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()) 912 ? horizontalScrollbar()->height() : 0; 913 914 int physicalScrollY = scrollPosition().y() + scrollOrigin().y(); 915 if (physicalScrollY < 0) { 916 horizontalOverhangRect = frameRect(); 917 horizontalOverhangRect.setHeight(-physicalScrollY); 918 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth); 919 } else if (contentsHeight() && physicalScrollY > contentsHeight() - visibleHeight()) { 920 int height = physicalScrollY - (contentsHeight() - visibleHeight()); 921 horizontalOverhangRect = frameRect(); 922 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight); 923 horizontalOverhangRect.setHeight(height); 924 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - verticalScrollbarWidth); 925 } 926 927 int physicalScrollX = scrollPosition().x() + scrollOrigin().x(); 928 if (physicalScrollX < 0) { 929 verticalOverhangRect.setWidth(-physicalScrollX); 930 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight); 931 verticalOverhangRect.setX(frameRect().x()); 932 if (horizontalOverhangRect.y() == frameRect().y()) 933 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height()); 934 else 935 verticalOverhangRect.setY(frameRect().y()); 936 } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWidth()) { 937 int width = physicalScrollX - (contentsWidth() - visibleWidth()); 938 verticalOverhangRect.setWidth(width); 939 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height() - horizontalScrollbarHeight); 940 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth); 941 if (horizontalOverhangRect.y() == frameRect().y()) 942 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height()); 943 else 944 verticalOverhangRect.setY(frameRect().y()); 945 } 946 } 947 948 void ScrollView::updateOverhangAreas() 949 { 950 HostWindow* window = hostWindow(); 951 if (!window) 952 return; 953 954 IntRect horizontalOverhangRect; 955 IntRect verticalOverhangRect; 956 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect); 957 if (!horizontalOverhangRect.isEmpty()) 958 window->invalidateContentsAndRootView(horizontalOverhangRect); 959 if (!verticalOverhangRect.isEmpty()) 960 window->invalidateContentsAndRootView(verticalOverhangRect); 961 } 962 963 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect) 964 { 965 ScrollbarTheme::theme()->paintOverhangBackground(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect); 966 ScrollbarTheme::theme()->paintOverhangShadows(context, scrollOffset(), horizontalOverhangRect, verticalOverhangRect, dirtyRect); 967 } 968 969 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const IntRect& dirtyRect) 970 { 971 IntRect horizontalOverhangRect; 972 IntRect verticalOverhangRect; 973 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect); 974 975 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect)) 976 paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect); 977 } 978 979 void ScrollView::calculateAndPaintOverhangBackground(GraphicsContext* context, const IntRect& dirtyRect) 980 { 981 IntRect horizontalOverhangRect; 982 IntRect verticalOverhangRect; 983 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect); 984 985 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(verticalOverhangRect)) 986 ScrollbarTheme::theme()->paintOverhangBackground(context, horizontalOverhangRect, verticalOverhangRect, dirtyRect); 987 } 988 989 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint) 990 { 991 if (!scrollbarCornerPresent()) 992 return false; 993 994 IntPoint viewPoint = convertFromContainingWindow(windowPoint); 995 996 if (m_horizontalScrollbar) { 997 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y(); 998 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height(); 999 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width(); 1000 1001 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin; 1002 } 1003 1004 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x(); 1005 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width(); 1006 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height(); 1007 1008 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin; 1009 } 1010 1011 bool ScrollView::scrollbarCornerPresent() const 1012 { 1013 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) 1014 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0); 1015 } 1016 1017 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const 1018 { 1019 // Scrollbars won't be transformed within us 1020 IntRect newRect = localRect; 1021 newRect.moveBy(scrollbar->location()); 1022 return newRect; 1023 } 1024 1025 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const 1026 { 1027 IntRect newRect = parentRect; 1028 // Scrollbars won't be transformed within us 1029 newRect.moveBy(-scrollbar->location()); 1030 return newRect; 1031 } 1032 1033 // FIXME: test these on windows 1034 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const 1035 { 1036 // Scrollbars won't be transformed within us 1037 IntPoint newPoint = localPoint; 1038 newPoint.moveBy(scrollbar->location()); 1039 return newPoint; 1040 } 1041 1042 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const 1043 { 1044 IntPoint newPoint = parentPoint; 1045 // Scrollbars won't be transformed within us 1046 newPoint.moveBy(-scrollbar->location()); 1047 return newPoint; 1048 } 1049 1050 void ScrollView::setParentVisible(bool visible) 1051 { 1052 if (isParentVisible() == visible) 1053 return; 1054 1055 Widget::setParentVisible(visible); 1056 1057 if (!isSelfVisible()) 1058 return; 1059 1060 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); 1061 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it) 1062 (*it)->setParentVisible(visible); 1063 } 1064 1065 void ScrollView::show() 1066 { 1067 if (!isSelfVisible()) { 1068 setSelfVisible(true); 1069 if (isParentVisible()) { 1070 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); 1071 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it) 1072 (*it)->setParentVisible(true); 1073 } 1074 } 1075 1076 Widget::show(); 1077 } 1078 1079 void ScrollView::hide() 1080 { 1081 if (isSelfVisible()) { 1082 if (isParentVisible()) { 1083 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); 1084 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it) 1085 (*it)->setParentVisible(false); 1086 } 1087 setSelfVisible(false); 1088 } 1089 1090 Widget::hide(); 1091 } 1092 1093 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition) 1094 { 1095 HostWindow* window = hostWindow(); 1096 if (!window) 1097 return; 1098 m_drawPanScrollIcon = true; 1099 m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ; 1100 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength))); 1101 } 1102 1103 void ScrollView::removePanScrollIcon() 1104 { 1105 HostWindow* window = hostWindow(); 1106 if (!window) 1107 return; 1108 m_drawPanScrollIcon = false; 1109 window->invalidateContentsAndRootView(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength))); 1110 } 1111 1112 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously) 1113 { 1114 if (scrollOrigin() == origin) 1115 return; 1116 1117 ScrollableArea::setScrollOrigin(origin); 1118 1119 // Update if the scroll origin changes, since our position will be different if the content size did not change. 1120 if (updatePositionAtAll && updatePositionSynchronously) 1121 updateScrollbars(scrollOffset()); 1122 } 1123 1124 } // namespace blink 1125