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