WebCore/platform/ScrollView.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  * 1. Redistributions of source code must retain the above copyright
       
     8  *    notice, this list of conditions and the following disclaimer.
       
     9  * 2. Redistributions in binary form must reproduce the above copyright
       
    10  *    notice, this list of conditions and the following disclaimer in the
       
    11  *    documentation and/or other materials provided with the distribution.
       
    12  *
       
    13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    24  */
       
    25 
       
    26 #include "config.h"
       
    27 #include "ScrollView.h"
       
    28 
       
    29 #include "GraphicsContext.h"
       
    30 #include "HostWindow.h"
       
    31 #include "PlatformMouseEvent.h"
       
    32 #include "PlatformWheelEvent.h"
       
    33 #include "Scrollbar.h"
       
    34 #include "ScrollbarTheme.h"
       
    35 #include <wtf/StdLibExtras.h>
       
    36 
       
    37 
       
    38 using std::max;
       
    39 
       
    40 namespace WebCore {
       
    41 
       
    42 ScrollView::ScrollView()
       
    43     : m_horizontalScrollbarMode(ScrollbarAuto)
       
    44     , m_verticalScrollbarMode(ScrollbarAuto)
       
    45     , m_horizontalScrollbarLock(false)
       
    46     , m_verticalScrollbarLock(false)
       
    47     , m_prohibitsScrolling(false)
       
    48     , m_canBlitOnScroll(true)
       
    49     , m_scrollbarsAvoidingResizer(0)
       
    50     , m_scrollbarsSuppressed(false)
       
    51     , m_inUpdateScrollbars(false)
       
    52     , m_updateScrollbarsPass(0)
       
    53     , m_drawPanScrollIcon(false)
       
    54     , m_useFixedLayout(false)
       
    55     , m_paintsEntireContents(false)
       
    56 {
       
    57     platformInit();
       
    58 }
       
    59 
       
    60 ScrollView::~ScrollView()
       
    61 {
       
    62     platformDestroy();
       
    63 }
       
    64 
       
    65 void ScrollView::addChild(PassRefPtr<Widget> prpChild) 
       
    66 {
       
    67     Widget* child = prpChild.get();
       
    68     ASSERT(child != this && !child->parent());
       
    69     child->setParent(this);
       
    70     m_children.add(prpChild);
       
    71     if (child->platformWidget())
       
    72         platformAddChild(child);
       
    73 }
       
    74 
       
    75 void ScrollView::removeChild(Widget* child)
       
    76 {
       
    77     ASSERT(child->parent() == this);
       
    78     child->setParent(0);
       
    79     m_children.remove(child);
       
    80     if (child->platformWidget())
       
    81         platformRemoveChild(child);
       
    82 }
       
    83 
       
    84 void ScrollView::setHasHorizontalScrollbar(bool hasBar)
       
    85 {
       
    86     if (hasBar && avoidScrollbarCreation())
       
    87         return;
       
    88 
       
    89     if (hasBar && !m_horizontalScrollbar) {
       
    90         m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
       
    91         addChild(m_horizontalScrollbar.get());
       
    92         m_horizontalScrollbar->styleChanged();
       
    93     } else if (!hasBar && m_horizontalScrollbar) {
       
    94         removeChild(m_horizontalScrollbar.get());
       
    95         m_horizontalScrollbar = 0;
       
    96     }
       
    97 }
       
    98 
       
    99 void ScrollView::setHasVerticalScrollbar(bool hasBar)
       
   100 {
       
   101     if (hasBar && avoidScrollbarCreation())
       
   102         return;
       
   103 
       
   104     if (hasBar && !m_verticalScrollbar) {
       
   105         m_verticalScrollbar = createScrollbar(VerticalScrollbar);
       
   106         addChild(m_verticalScrollbar.get());
       
   107         m_verticalScrollbar->styleChanged();
       
   108     } else if (!hasBar && m_verticalScrollbar) {
       
   109         removeChild(m_verticalScrollbar.get());
       
   110         m_verticalScrollbar = 0;
       
   111     }
       
   112 }
       
   113 
       
   114 #if !PLATFORM(GTK)
       
   115 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
       
   116 {
       
   117     return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
       
   118 }
       
   119 
       
   120 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
       
   121                                    bool horizontalLock, bool verticalLock)
       
   122 {
       
   123     bool needsUpdate = false;
       
   124 
       
   125     if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
       
   126         m_horizontalScrollbarMode = horizontalMode;
       
   127         needsUpdate = true;
       
   128     }
       
   129 
       
   130     if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
       
   131         m_verticalScrollbarMode = verticalMode;
       
   132         needsUpdate = true;
       
   133     }
       
   134 
       
   135     if (horizontalLock)
       
   136         setHorizontalScrollbarLock();
       
   137 
       
   138     if (verticalLock)
       
   139         setVerticalScrollbarLock();
       
   140 
       
   141     if (!needsUpdate)
       
   142         return;
       
   143 
       
   144     if (platformWidget())
       
   145         platformSetScrollbarModes();
       
   146     else
       
   147         updateScrollbars(scrollOffset());
       
   148 }
       
   149 #endif
       
   150 
       
   151 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
       
   152 {
       
   153     if (platformWidget()) {
       
   154         platformScrollbarModes(horizontalMode, verticalMode);
       
   155         return;
       
   156     }
       
   157     horizontalMode = m_horizontalScrollbarMode;
       
   158     verticalMode = m_verticalScrollbarMode;
       
   159 }
       
   160 
       
   161 void ScrollView::setCanHaveScrollbars(bool canScroll)
       
   162 {
       
   163     ScrollbarMode newHorizontalMode;
       
   164     ScrollbarMode newVerticalMode;
       
   165     
       
   166     scrollbarModes(newHorizontalMode, newVerticalMode);
       
   167     
       
   168     if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
       
   169         newVerticalMode = ScrollbarAuto;
       
   170     else if (!canScroll)
       
   171         newVerticalMode = ScrollbarAlwaysOff;
       
   172     
       
   173     if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
       
   174         newHorizontalMode = ScrollbarAuto;
       
   175     else if (!canScroll)
       
   176         newHorizontalMode = ScrollbarAlwaysOff;
       
   177     
       
   178     setScrollbarModes(newHorizontalMode, newVerticalMode);
       
   179 }
       
   180 
       
   181 void ScrollView::setCanBlitOnScroll(bool b)
       
   182 {
       
   183     if (platformWidget()) {
       
   184         platformSetCanBlitOnScroll(b);
       
   185         return;
       
   186     }
       
   187 
       
   188     m_canBlitOnScroll = b;
       
   189 }
       
   190 
       
   191 bool ScrollView::canBlitOnScroll() const
       
   192 {
       
   193     if (platformWidget())
       
   194         return platformCanBlitOnScroll();
       
   195 
       
   196     return m_canBlitOnScroll;
       
   197 }
       
   198 
       
   199 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
       
   200 {
       
   201     m_paintsEntireContents = paintsEntireContents;
       
   202 }
       
   203 
       
   204 #if !PLATFORM(GTK)
       
   205 IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
       
   206 {
       
   207     if (platformWidget())
       
   208         return platformVisibleContentRect(includeScrollbars);
       
   209     return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
       
   210                    IntSize(max(0, width() - (verticalScrollbar() && !includeScrollbars ? verticalScrollbar()->width() : 0)), 
       
   211                            max(0, height() - (horizontalScrollbar() && !includeScrollbars ? horizontalScrollbar()->height() : 0))));
       
   212 }
       
   213 #endif
       
   214 
       
   215 int ScrollView::layoutWidth() const
       
   216 {
       
   217     return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleWidth() : m_fixedLayoutSize.width();
       
   218 }
       
   219 
       
   220 int ScrollView::layoutHeight() const
       
   221 {
       
   222     return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleHeight() : m_fixedLayoutSize.height();
       
   223 }
       
   224 
       
   225 IntSize ScrollView::fixedLayoutSize() const
       
   226 {
       
   227     return m_fixedLayoutSize;
       
   228 }
       
   229 
       
   230 void ScrollView::setFixedLayoutSize(const IntSize& newSize)
       
   231 {
       
   232     if (fixedLayoutSize() == newSize)
       
   233         return;
       
   234     m_fixedLayoutSize = newSize;
       
   235     updateScrollbars(scrollOffset());
       
   236 }
       
   237 
       
   238 bool ScrollView::useFixedLayout() const
       
   239 {
       
   240     return m_useFixedLayout;
       
   241 }
       
   242 
       
   243 void ScrollView::setUseFixedLayout(bool enable)
       
   244 {
       
   245     if (useFixedLayout() == enable)
       
   246         return;
       
   247     m_useFixedLayout = enable;
       
   248     updateScrollbars(scrollOffset());
       
   249 }
       
   250 
       
   251 IntSize ScrollView::contentsSize() const
       
   252 {
       
   253     if (platformWidget())
       
   254         return platformContentsSize();
       
   255     return m_contentsSize;
       
   256 }
       
   257 
       
   258 void ScrollView::setContentsSize(const IntSize& newSize)
       
   259 {
       
   260     if (contentsSize() == newSize)
       
   261         return;
       
   262     m_contentsSize = newSize;
       
   263     if (platformWidget())
       
   264         platformSetContentsSize();
       
   265     else
       
   266         updateScrollbars(scrollOffset());
       
   267 }
       
   268 
       
   269 IntPoint ScrollView::maximumScrollPosition() const
       
   270 {
       
   271     IntSize maximumOffset = contentsSize() - visibleContentRect().size();
       
   272     maximumOffset.clampNegativeToZero();
       
   273     return IntPoint(maximumOffset.width(), maximumOffset.height());
       
   274 }
       
   275 
       
   276 void ScrollView::valueChanged(Scrollbar* scrollbar)
       
   277 {
       
   278     // Figure out if we really moved.
       
   279     IntSize newOffset = m_scrollOffset;
       
   280     if (scrollbar) {
       
   281         if (scrollbar->orientation() == HorizontalScrollbar)
       
   282             newOffset.setWidth(scrollbar->value());
       
   283         else if (scrollbar->orientation() == VerticalScrollbar)
       
   284             newOffset.setHeight(scrollbar->value());
       
   285     }
       
   286 
       
   287     IntSize scrollDelta = newOffset - m_scrollOffset;
       
   288     if (scrollDelta == IntSize())
       
   289         return;
       
   290     m_scrollOffset = newOffset;
       
   291 
       
   292     if (scrollbarsSuppressed())
       
   293         return;
       
   294 
       
   295     repaintFixedElementsAfterScrolling();
       
   296     scrollContents(scrollDelta);
       
   297 }
       
   298 
       
   299 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
       
   300 {
       
   301     if (prohibitsScrolling())
       
   302         return;
       
   303 
       
   304     if (platformWidget()) {
       
   305         platformSetScrollPosition(scrollPoint);
       
   306         return;
       
   307     }
       
   308 
       
   309     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
       
   310     newScrollPosition.clampNegativeToZero();
       
   311 
       
   312     if (newScrollPosition == scrollPosition())
       
   313         return;
       
   314 
       
   315     updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
       
   316 }
       
   317 
       
   318 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
       
   319 {
       
   320     if (platformWidget())
       
   321         return platformScroll(direction, granularity);
       
   322 
       
   323     if (direction == ScrollUp || direction == ScrollDown) {
       
   324         if (m_verticalScrollbar)
       
   325             return m_verticalScrollbar->scroll(direction, granularity);
       
   326     } else {
       
   327         if (m_horizontalScrollbar)
       
   328             return m_horizontalScrollbar->scroll(direction, granularity);
       
   329     }
       
   330     return false;
       
   331 }
       
   332 
       
   333 static const unsigned cMaxUpdateScrollbarsPass = 2;
       
   334 
       
   335 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
       
   336 {
       
   337     if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
       
   338         return;
       
   339 
       
   340     // If we came in here with the view already needing a layout, then go ahead and do that
       
   341     // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
       
   342     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
       
   343     if (!m_scrollbarsSuppressed) {
       
   344         m_inUpdateScrollbars = true;
       
   345         visibleContentsResized();
       
   346         m_inUpdateScrollbars = false;
       
   347     }
       
   348 
       
   349     bool hasHorizontalScrollbar = m_horizontalScrollbar;
       
   350     bool hasVerticalScrollbar = m_verticalScrollbar;
       
   351     
       
   352     bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
       
   353     bool newHasVerticalScrollbar = hasVerticalScrollbar;
       
   354    
       
   355     ScrollbarMode hScroll = m_horizontalScrollbarMode;
       
   356     ScrollbarMode vScroll = m_verticalScrollbarMode;
       
   357 
       
   358     if (hScroll != ScrollbarAuto)
       
   359         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
       
   360     if (vScroll != ScrollbarAuto)
       
   361         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
       
   362 
       
   363     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
       
   364         if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
       
   365             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
       
   366         if (hasVerticalScrollbar != newHasVerticalScrollbar)
       
   367             setHasVerticalScrollbar(newHasVerticalScrollbar);
       
   368     } else {
       
   369         bool sendContentResizedNotification = false;
       
   370         
       
   371         IntSize docSize = contentsSize();
       
   372         IntSize frameSize = frameRect().size();
       
   373 
       
   374         if (hScroll == ScrollbarAuto) {
       
   375             newHasHorizontalScrollbar = docSize.width() > visibleWidth();
       
   376             if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
       
   377                 newHasHorizontalScrollbar = false;
       
   378         }
       
   379         if (vScroll == ScrollbarAuto) {
       
   380             newHasVerticalScrollbar = docSize.height() > visibleHeight();
       
   381             if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
       
   382                 newHasVerticalScrollbar = false;
       
   383         }
       
   384 
       
   385         // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
       
   386         // try to both gain/lose a scrollbar in the same pass.
       
   387         if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
       
   388             newHasVerticalScrollbar = false;
       
   389         if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
       
   390             newHasHorizontalScrollbar = false;
       
   391 
       
   392         if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
       
   393             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
       
   394             sendContentResizedNotification = true;
       
   395         }
       
   396 
       
   397         if (hasVerticalScrollbar != newHasVerticalScrollbar) {
       
   398             setHasVerticalScrollbar(newHasVerticalScrollbar);
       
   399             sendContentResizedNotification = true;
       
   400         }
       
   401 
       
   402         if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
       
   403             m_updateScrollbarsPass++;
       
   404             contentsResized();
       
   405             visibleContentsResized();
       
   406             IntSize newDocSize = contentsSize();
       
   407             if (newDocSize == docSize) {
       
   408                 // The layout with the new scroll state had no impact on
       
   409                 // the document's overall size, so updateScrollbars didn't get called.
       
   410                 // Recur manually.
       
   411                 updateScrollbars(desiredOffset);
       
   412             }
       
   413             m_updateScrollbarsPass--;
       
   414         }
       
   415     }
       
   416     
       
   417     // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
       
   418     // doing it multiple times).
       
   419     if (m_updateScrollbarsPass)
       
   420         return;
       
   421 
       
   422     m_inUpdateScrollbars = true;
       
   423     IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
       
   424     IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
       
   425     scroll.clampNegativeToZero();
       
   426  
       
   427     if (m_horizontalScrollbar) {
       
   428         int clientWidth = visibleWidth();
       
   429         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
       
   430         int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
       
   431         IntRect oldRect(m_horizontalScrollbar->frameRect());
       
   432         IntRect hBarRect = IntRect(0,
       
   433                                    height() - m_horizontalScrollbar->height(),
       
   434                                    width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
       
   435                                    m_horizontalScrollbar->height());
       
   436         m_horizontalScrollbar->setFrameRect(hBarRect);
       
   437         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
       
   438             m_horizontalScrollbar->invalidate();
       
   439 
       
   440         if (m_scrollbarsSuppressed)
       
   441             m_horizontalScrollbar->setSuppressInvalidation(true);
       
   442         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
       
   443         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
       
   444         m_horizontalScrollbar->setValue(scroll.width());
       
   445         if (m_scrollbarsSuppressed)
       
   446             m_horizontalScrollbar->setSuppressInvalidation(false); 
       
   447     } 
       
   448 
       
   449     if (m_verticalScrollbar) {
       
   450         int clientHeight = visibleHeight();
       
   451         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
       
   452         int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
       
   453         IntRect oldRect(m_verticalScrollbar->frameRect());
       
   454         IntRect vBarRect = IntRect(width() - m_verticalScrollbar->width(), 
       
   455                                    0,
       
   456                                    m_verticalScrollbar->width(),
       
   457                                    height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
       
   458         m_verticalScrollbar->setFrameRect(vBarRect);
       
   459         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
       
   460             m_verticalScrollbar->invalidate();
       
   461 
       
   462         if (m_scrollbarsSuppressed)
       
   463             m_verticalScrollbar->setSuppressInvalidation(true);
       
   464         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
       
   465         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
       
   466         m_verticalScrollbar->setValue(scroll.height());
       
   467         if (m_scrollbarsSuppressed)
       
   468             m_verticalScrollbar->setSuppressInvalidation(false);
       
   469     }
       
   470 
       
   471     if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) {
       
   472         frameRectsChanged();
       
   473         updateScrollCorner();
       
   474     }
       
   475 
       
   476     // See if our offset has changed in a situation where we might not have scrollbars.
       
   477     // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
       
   478     // It can also happen when maximizing a window that has scrollbars (but the new maximized result
       
   479     // does not).
       
   480     IntSize scrollDelta = scroll - m_scrollOffset;
       
   481     if (scrollDelta != IntSize()) {
       
   482        m_scrollOffset = scroll;
       
   483        scrollContents(scrollDelta);
       
   484     }
       
   485 
       
   486     m_inUpdateScrollbars = false;
       
   487 }
       
   488 
       
   489 const int panIconSizeLength = 16;
       
   490 
       
   491 void ScrollView::scrollContents(const IntSize& scrollDelta)
       
   492 {
       
   493     if (!hostWindow())
       
   494         return;
       
   495 
       
   496     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
       
   497     // with the clip rect every time to keep it smooth.
       
   498     IntRect clipRect = windowClipRect();
       
   499     IntRect scrollViewRect = convertToContainingWindow(IntRect(0, 0, visibleWidth(), visibleHeight()));
       
   500     IntRect updateRect = clipRect;
       
   501     updateRect.intersect(scrollViewRect);
       
   502 
       
   503     // Invalidate the window (not the backing store).
       
   504     hostWindow()->invalidateWindow(updateRect, false /*immediate*/);
       
   505 
       
   506     if (m_drawPanScrollIcon) {
       
   507         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
       
   508         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
       
   509         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
       
   510         panScrollIconDirtyRect.intersect(clipRect);
       
   511         hostWindow()->invalidateContentsAndWindow(panScrollIconDirtyRect, false /*immediate*/);
       
   512     }
       
   513 
       
   514     if (canBlitOnScroll()) { // The main frame can just blit the WebView window
       
   515         // FIXME: Find a way to scroll subframes with this faster path
       
   516         if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
       
   517             hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
       
   518     } else { 
       
   519        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
       
   520        // windowed plugins.
       
   521        hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
       
   522     }
       
   523 
       
   524     // This call will move children with native widgets (plugins) and invalidate them as well.
       
   525     frameRectsChanged();
       
   526 
       
   527     // Now blit the backingstore into the window which should be very fast.
       
   528     hostWindow()->invalidateWindow(IntRect(), true);
       
   529 }
       
   530 
       
   531 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
       
   532 {
       
   533     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
       
   534     return true;
       
   535 }
       
   536 
       
   537 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
       
   538 {
       
   539     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
       
   540     return viewPoint + scrollOffset();
       
   541 }
       
   542 
       
   543 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
       
   544 {
       
   545     IntPoint viewPoint = contentsPoint - scrollOffset();
       
   546     return convertToContainingWindow(viewPoint);  
       
   547 }
       
   548 
       
   549 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
       
   550 {
       
   551     IntRect viewRect = convertFromContainingWindow(windowRect);
       
   552     viewRect.move(scrollOffset());
       
   553     return viewRect;
       
   554 }
       
   555 
       
   556 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
       
   557 {
       
   558     IntRect viewRect = contentsRect;
       
   559     viewRect.move(-scrollOffset());
       
   560     return convertToContainingWindow(viewRect);
       
   561 }
       
   562 
       
   563 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
       
   564 {
       
   565     if (platformWidget())
       
   566         return platformContentsToScreen(rect);
       
   567     if (!hostWindow())
       
   568         return IntRect();
       
   569     return hostWindow()->windowToScreen(contentsToWindow(rect));
       
   570 }
       
   571 
       
   572 IntPoint ScrollView::screenToContents(const IntPoint& point) const
       
   573 {
       
   574     if (platformWidget())
       
   575         return platformScreenToContents(point);
       
   576     if (!hostWindow())
       
   577         return IntPoint();
       
   578     return windowToContents(hostWindow()->screenToWindow(point));
       
   579 }
       
   580 
       
   581 bool ScrollView::containsScrollbarsAvoidingResizer() const
       
   582 {
       
   583     return !m_scrollbarsAvoidingResizer;
       
   584 }
       
   585 
       
   586 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
       
   587 {
       
   588     int oldCount = m_scrollbarsAvoidingResizer;
       
   589     m_scrollbarsAvoidingResizer += overlapDelta;
       
   590     if (parent())
       
   591         parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
       
   592     else if (!scrollbarsSuppressed()) {
       
   593         // If we went from n to 0 or from 0 to n and we're the outermost view,
       
   594         // we need to invalidate the windowResizerRect(), since it will now need to paint
       
   595         // differently.
       
   596         if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
       
   597             (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
       
   598             invalidateRect(windowResizerRect());
       
   599     }
       
   600 }
       
   601 
       
   602 void ScrollView::setParent(ScrollView* parentView)
       
   603 {
       
   604     if (parentView == parent())
       
   605         return;
       
   606 
       
   607     if (m_scrollbarsAvoidingResizer && parent())
       
   608         parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
       
   609 
       
   610     Widget::setParent(parentView);
       
   611 
       
   612     if (m_scrollbarsAvoidingResizer && parent())
       
   613         parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
       
   614 }
       
   615 
       
   616 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
       
   617 {
       
   618     if (suppressed == m_scrollbarsSuppressed)
       
   619         return;
       
   620 
       
   621     m_scrollbarsSuppressed = suppressed;
       
   622 
       
   623     if (platformWidget())
       
   624         platformSetScrollbarsSuppressed(repaintOnUnsuppress);
       
   625     else if (repaintOnUnsuppress && !suppressed) {
       
   626         if (m_horizontalScrollbar)
       
   627             m_horizontalScrollbar->invalidate();
       
   628         if (m_verticalScrollbar)
       
   629             m_verticalScrollbar->invalidate();
       
   630 
       
   631         // Invalidate the scroll corner too on unsuppress.
       
   632         invalidateRect(scrollCornerRect());
       
   633     }
       
   634 }
       
   635 
       
   636 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
       
   637 {
       
   638     if (platformWidget())
       
   639         return 0;
       
   640 
       
   641     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
       
   642     if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint))
       
   643         return m_horizontalScrollbar.get();
       
   644     if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint))
       
   645         return m_verticalScrollbar.get();
       
   646     return 0;
       
   647 }
       
   648 
       
   649 void ScrollView::wheelEvent(PlatformWheelEvent& e)
       
   650 {
       
   651     // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
       
   652 #if PLATFORM(WX)
       
   653     if (!canHaveScrollbars()) {
       
   654 #else
       
   655     if (!canHaveScrollbars() || platformWidget()) {
       
   656 #endif
       
   657         return;
       
   658     }
       
   659 
       
   660     // Determine how much we want to scroll.  If we can move at all, we will accept the event.
       
   661     IntSize maxScrollDelta = maximumScrollPosition() - scrollPosition();
       
   662     if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
       
   663         (e.deltaX() > 0 && scrollOffset().width() > 0) ||
       
   664         (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
       
   665         (e.deltaY() > 0 && scrollOffset().height() > 0)) {
       
   666         e.accept();
       
   667         float deltaX = e.deltaX();
       
   668         float deltaY = e.deltaY();
       
   669         if (e.granularity() == ScrollByPageWheelEvent) {
       
   670             ASSERT(deltaX == 0);
       
   671             bool negative = deltaY < 0;
       
   672             deltaY = max(max<int>(visibleHeight() * Scrollbar::minFractionToStepWhenPaging(), visibleHeight() - Scrollbar::maxOverlapBetweenPages()), 1);
       
   673             if (negative)
       
   674                 deltaY = -deltaY;
       
   675         }
       
   676         scrollBy(IntSize(-deltaX, -deltaY));
       
   677     }
       
   678 }
       
   679 
       
   680 void ScrollView::setFrameRect(const IntRect& newRect)
       
   681 {
       
   682     IntRect oldRect = frameRect();
       
   683     
       
   684     if (newRect == oldRect)
       
   685         return;
       
   686 
       
   687     Widget::setFrameRect(newRect);
       
   688 
       
   689     if (platformWidget())
       
   690         return;
       
   691     
       
   692     if (newRect.width() != oldRect.width() || newRect.height() != oldRect.height()) {
       
   693         updateScrollbars(m_scrollOffset);
       
   694         if (!m_useFixedLayout)
       
   695             contentsResized();
       
   696     }
       
   697 
       
   698     frameRectsChanged();
       
   699 }
       
   700 
       
   701 void ScrollView::frameRectsChanged()
       
   702 {
       
   703     if (platformWidget())
       
   704         return;
       
   705 
       
   706     HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
       
   707     for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
       
   708         (*current)->frameRectsChanged();
       
   709 }
       
   710 
       
   711 void ScrollView::repaintContentRectangle(const IntRect& rect, bool now)
       
   712 {
       
   713     IntRect paintRect = rect;
       
   714     if (!paintsEntireContents())
       
   715         paintRect.intersect(visibleContentRect());
       
   716     if (paintRect.isEmpty())
       
   717         return;
       
   718 
       
   719     if (platformWidget()) {
       
   720         platformRepaintContentRectangle(paintRect, now);
       
   721         return;
       
   722     }
       
   723 
       
   724     if (hostWindow())
       
   725         hostWindow()->invalidateContentsAndWindow(contentsToWindow(paintRect), now /*immediate*/);
       
   726 }
       
   727 
       
   728 IntRect ScrollView::scrollCornerRect() const
       
   729 {
       
   730     IntRect cornerRect;
       
   731     
       
   732     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
       
   733         cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
       
   734                                  height() - m_horizontalScrollbar->height(),
       
   735                                  width() - m_horizontalScrollbar->width(),
       
   736                                  m_horizontalScrollbar->height()));
       
   737     }
       
   738 
       
   739     if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
       
   740         cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
       
   741                                  m_verticalScrollbar->height(),
       
   742                                  m_verticalScrollbar->width(),
       
   743                                  height() - m_verticalScrollbar->height()));
       
   744     }
       
   745     
       
   746     return cornerRect;
       
   747 }
       
   748 
       
   749 void ScrollView::updateScrollCorner()
       
   750 {
       
   751 }
       
   752 
       
   753 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
       
   754 {
       
   755     ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect);
       
   756 }
       
   757 
       
   758 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
       
   759 {
       
   760     if (m_horizontalScrollbar)
       
   761         m_horizontalScrollbar->paint(context, rect);
       
   762     if (m_verticalScrollbar)
       
   763         m_verticalScrollbar->paint(context, rect);
       
   764 
       
   765     paintScrollCorner(context, scrollCornerRect());
       
   766 }
       
   767 
       
   768 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
       
   769 {
       
   770     static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
       
   771     context->drawImage(panScrollIcon, DeviceColorSpace, m_panScrollIconPoint);
       
   772 }
       
   773 
       
   774 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
       
   775 {
       
   776     if (platformWidget()) {
       
   777         Widget::paint(context, rect);
       
   778         return;
       
   779     }
       
   780 
       
   781     if (context->paintingDisabled() && !context->updatingControlTints())
       
   782         return;
       
   783 
       
   784     IntRect documentDirtyRect = rect;
       
   785     documentDirtyRect.intersect(frameRect());
       
   786 
       
   787     context->save();
       
   788 
       
   789     context->translate(x(), y());
       
   790     documentDirtyRect.move(-x(), -y());
       
   791 
       
   792     context->translate(-scrollX(), -scrollY());
       
   793     documentDirtyRect.move(scrollX(), scrollY());
       
   794 
       
   795     context->clip(visibleContentRect());
       
   796 
       
   797     paintContents(context, documentDirtyRect);
       
   798 
       
   799     context->restore();
       
   800 
       
   801     // Now paint the scrollbars.
       
   802     if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
       
   803         context->save();
       
   804         IntRect scrollViewDirtyRect = rect;
       
   805         scrollViewDirtyRect.intersect(frameRect());
       
   806         context->translate(x(), y());
       
   807         scrollViewDirtyRect.move(-x(), -y());
       
   808 
       
   809         paintScrollbars(context, scrollViewDirtyRect);
       
   810 
       
   811         context->restore();
       
   812     }
       
   813 
       
   814     // Paint the panScroll Icon
       
   815     if (m_drawPanScrollIcon)
       
   816         paintPanScrollIcon(context);
       
   817 }
       
   818 
       
   819 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
       
   820 {
       
   821     if (!scrollbarCornerPresent())
       
   822         return false;
       
   823 
       
   824     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
       
   825 
       
   826     if (m_horizontalScrollbar) {
       
   827         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
       
   828         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
       
   829         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
       
   830 
       
   831         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
       
   832     }
       
   833 
       
   834     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
       
   835     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
       
   836     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
       
   837     
       
   838     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
       
   839 }
       
   840 
       
   841 bool ScrollView::scrollbarCornerPresent() const
       
   842 {
       
   843     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) ||
       
   844            (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
       
   845 }
       
   846 
       
   847 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
       
   848 {
       
   849     // Scrollbars won't be transformed within us
       
   850     IntRect newRect = localRect;
       
   851     newRect.move(scrollbar->x(), scrollbar->y());
       
   852     return newRect;
       
   853 }
       
   854 
       
   855 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
       
   856 {
       
   857     IntRect newRect = parentRect;
       
   858     // Scrollbars won't be transformed within us
       
   859     newRect.move(-scrollbar->x(), -scrollbar->y());
       
   860     return newRect;
       
   861 }
       
   862 
       
   863 // FIXME: test these on windows
       
   864 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
       
   865 {
       
   866     // Scrollbars won't be transformed within us
       
   867     IntPoint newPoint = localPoint;
       
   868     newPoint.move(scrollbar->x(), scrollbar->y());
       
   869     return newPoint;
       
   870 }
       
   871 
       
   872 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
       
   873 {
       
   874     IntPoint newPoint = parentPoint;
       
   875     // Scrollbars won't be transformed within us
       
   876     newPoint.move(-scrollbar->x(), -scrollbar->y());
       
   877     return newPoint;
       
   878 }
       
   879 
       
   880 void ScrollView::setParentVisible(bool visible)
       
   881 {
       
   882     if (isParentVisible() == visible)
       
   883         return;
       
   884     
       
   885     Widget::setParentVisible(visible);
       
   886 
       
   887     if (!isSelfVisible())
       
   888         return;
       
   889         
       
   890     HashSet<RefPtr<Widget> >::iterator end = m_children.end();
       
   891     for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
       
   892         (*it)->setParentVisible(visible);
       
   893 }
       
   894 
       
   895 void ScrollView::show()
       
   896 {
       
   897     if (!isSelfVisible()) {
       
   898         setSelfVisible(true);
       
   899         if (isParentVisible()) {
       
   900             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
       
   901             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
       
   902                 (*it)->setParentVisible(true);
       
   903         }
       
   904     }
       
   905 
       
   906     Widget::show();
       
   907 }
       
   908 
       
   909 void ScrollView::hide()
       
   910 {
       
   911     if (isSelfVisible()) {
       
   912         if (isParentVisible()) {
       
   913             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
       
   914             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
       
   915                 (*it)->setParentVisible(false);
       
   916         }
       
   917         setSelfVisible(false);
       
   918     }
       
   919 
       
   920     Widget::hide();
       
   921 }
       
   922 
       
   923 bool ScrollView::isOffscreen() const
       
   924 {
       
   925     if (platformWidget())
       
   926         return platformIsOffscreen();
       
   927     
       
   928     if (!isVisible())
       
   929         return true;
       
   930     
       
   931     // FIXME: Add a HostWindow::isOffscreen method here.  Since only Mac implements this method
       
   932     // currently, we can add the method when the other platforms decide to implement this concept.
       
   933     return false;
       
   934 }
       
   935 
       
   936 
       
   937 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
       
   938 {
       
   939     if (!hostWindow())
       
   940         return;
       
   941     m_drawPanScrollIcon = true;    
       
   942     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
       
   943     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
       
   944 }
       
   945 
       
   946 void ScrollView::removePanScrollIcon()
       
   947 {
       
   948     if (!hostWindow())
       
   949         return;
       
   950     m_drawPanScrollIcon = false; 
       
   951     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
       
   952 }
       
   953 
       
   954 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(EFL)
       
   955 
       
   956 void ScrollView::platformInit()
       
   957 {
       
   958 }
       
   959 
       
   960 void ScrollView::platformDestroy()
       
   961 {
       
   962 }
       
   963 
       
   964 #endif
       
   965 
       
   966 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC)
       
   967 
       
   968 void ScrollView::platformAddChild(Widget*)
       
   969 {
       
   970 }
       
   971 
       
   972 void ScrollView::platformRemoveChild(Widget*)
       
   973 {
       
   974 }
       
   975 
       
   976 #endif
       
   977 
       
   978 #if !PLATFORM(MAC)
       
   979 
       
   980 void ScrollView::platformSetScrollbarsSuppressed(bool)
       
   981 {
       
   982 }
       
   983 
       
   984 #endif
       
   985 
       
   986 #if !PLATFORM(MAC) && !PLATFORM(WX)
       
   987 
       
   988 void ScrollView::platformSetScrollbarModes()
       
   989 {
       
   990 }
       
   991 
       
   992 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
       
   993 {
       
   994     horizontal = ScrollbarAuto;
       
   995     vertical = ScrollbarAuto;
       
   996 }
       
   997 
       
   998 void ScrollView::platformSetCanBlitOnScroll(bool)
       
   999 {
       
  1000 }
       
  1001 
       
  1002 bool ScrollView::platformCanBlitOnScroll() const
       
  1003 {
       
  1004     return false;
       
  1005 }
       
  1006 
       
  1007 IntRect ScrollView::platformVisibleContentRect(bool) const
       
  1008 {
       
  1009     return IntRect();
       
  1010 }
       
  1011 
       
  1012 IntSize ScrollView::platformContentsSize() const
       
  1013 {
       
  1014     return IntSize();
       
  1015 }
       
  1016 
       
  1017 void ScrollView::platformSetContentsSize()
       
  1018 {
       
  1019 }
       
  1020 
       
  1021 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
       
  1022 {
       
  1023     return rect;
       
  1024 }
       
  1025 
       
  1026 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
       
  1027 {
       
  1028     return point;
       
  1029 }
       
  1030 
       
  1031 void ScrollView::platformSetScrollPosition(const IntPoint&)
       
  1032 {
       
  1033 }
       
  1034 
       
  1035 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
       
  1036 {
       
  1037     return true;
       
  1038 }
       
  1039 
       
  1040 void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/)
       
  1041 {
       
  1042 }
       
  1043 
       
  1044 bool ScrollView::platformIsOffscreen() const
       
  1045 {
       
  1046     return false;
       
  1047 }
       
  1048 
       
  1049 #endif
       
  1050 
       
  1051 }
       
  1052