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