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