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