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