OSDN Git Service

Merge "Fix text-shadow style when blur is 0px"
[android-x86/external-webkit.git] / WebCore / platform / ScrollView.cpp
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 #if PLATFORM(ANDROID)
270 int ScrollView::actualWidth() const
271 {
272     if (platformWidget())
273         return platformActualWidth();
274     return width();
275 }
276
277 int ScrollView::actualHeight() const
278 {
279     if (platformWidget())
280         return platformActualHeight();
281     return height();
282 }
283
284 int ScrollView::actualScrollX() const
285 {
286     if (platformWidget())
287         return platformActualScrollX();
288     return scrollX();
289 }
290
291 int ScrollView::actualScrollY() const
292 {
293     if (platformWidget())
294         return platformActualScrollY();
295     return scrollY();
296 }
297 #endif
298
299 IntPoint ScrollView::maximumScrollPosition() const
300 {
301     IntSize maximumOffset = contentsSize() - visibleContentRect().size();
302     maximumOffset.clampNegativeToZero();
303     return IntPoint(maximumOffset.width(), maximumOffset.height());
304 }
305
306 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
307 {
308     Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
309     return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
310 }
311
312 void ScrollView::setScrollOffsetFromAnimation(const IntPoint& offset)
313 {
314     if (m_horizontalScrollbar)
315         m_horizontalScrollbar->setValue(offset.x(), Scrollbar::FromScrollAnimator);
316     if (m_verticalScrollbar)
317         m_verticalScrollbar->setValue(offset.y(), Scrollbar::FromScrollAnimator);
318 }
319
320 void ScrollView::valueChanged(Scrollbar* scrollbar)
321 {
322     // Figure out if we really moved.
323     IntSize newOffset = m_scrollOffset;
324     if (scrollbar) {
325         if (scrollbar->orientation() == HorizontalScrollbar)
326             newOffset.setWidth(scrollbar->value());
327         else if (scrollbar->orientation() == VerticalScrollbar)
328             newOffset.setHeight(scrollbar->value());
329     }
330
331     IntSize scrollDelta = newOffset - m_scrollOffset;
332     if (scrollDelta == IntSize())
333         return;
334     m_scrollOffset = newOffset;
335
336     if (scrollbarsSuppressed())
337         return;
338
339     repaintFixedElementsAfterScrolling();
340     scrollContents(scrollDelta);
341 }
342
343 void ScrollView::valueChanged(const IntSize& scrollDelta)
344 {
345     if (scrollbarsSuppressed())
346         return;
347
348     repaintFixedElementsAfterScrolling();
349     scrollContents(scrollDelta);
350 }
351
352 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
353 {
354     if (prohibitsScrolling())
355         return;
356
357     if (platformWidget()) {
358         platformSetScrollPosition(scrollPoint);
359         return;
360     }
361
362     IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
363     newScrollPosition.clampNegativeToZero();
364
365     if (newScrollPosition == scrollPosition())
366         return;
367
368     updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
369 }
370
371 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
372 {
373     if (platformWidget())
374         return platformScroll(direction, granularity);
375
376     if (direction == ScrollUp || direction == ScrollDown) {
377         if (m_verticalScrollbar)
378             return m_verticalScrollbar->scroll(direction, granularity);
379     } else {
380         if (m_horizontalScrollbar)
381             return m_horizontalScrollbar->scroll(direction, granularity);
382     }
383     return false;
384 }
385
386 void ScrollView::windowResizerRectChanged()
387 {
388     if (platformWidget())
389         return;
390
391     updateScrollbars(scrollOffset());
392 }
393
394 static const unsigned cMaxUpdateScrollbarsPass = 2;
395
396 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
397 {
398     if (m_inUpdateScrollbars || prohibitsScrolling() || platformWidget())
399         return;
400
401     // If we came in here with the view already needing a layout, then go ahead and do that
402     // first.  (This will be the common case, e.g., when the page changes due to window resizing for example).
403     // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
404     if (!m_scrollbarsSuppressed) {
405         m_inUpdateScrollbars = true;
406         visibleContentsResized();
407         m_inUpdateScrollbars = false;
408     }
409
410     bool hasHorizontalScrollbar = m_horizontalScrollbar;
411     bool hasVerticalScrollbar = m_verticalScrollbar;
412     
413     bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
414     bool newHasVerticalScrollbar = hasVerticalScrollbar;
415    
416     ScrollbarMode hScroll = m_horizontalScrollbarMode;
417     ScrollbarMode vScroll = m_verticalScrollbarMode;
418
419     if (hScroll != ScrollbarAuto)
420         newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
421     if (vScroll != ScrollbarAuto)
422         newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
423
424     if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
425         if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
426             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
427         if (hasVerticalScrollbar != newHasVerticalScrollbar)
428             setHasVerticalScrollbar(newHasVerticalScrollbar);
429     } else {
430         bool sendContentResizedNotification = false;
431         
432         IntSize docSize = contentsSize();
433         IntSize frameSize = frameRect().size();
434
435         if (hScroll == ScrollbarAuto) {
436             newHasHorizontalScrollbar = docSize.width() > visibleWidth();
437             if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
438                 newHasHorizontalScrollbar = false;
439         }
440         if (vScroll == ScrollbarAuto) {
441             newHasVerticalScrollbar = docSize.height() > visibleHeight();
442             if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
443                 newHasVerticalScrollbar = false;
444         }
445
446         // If we ever turn one scrollbar off, always turn the other one off too.  Never ever
447         // try to both gain/lose a scrollbar in the same pass.
448         if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
449             newHasVerticalScrollbar = false;
450         if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
451             newHasHorizontalScrollbar = false;
452
453         if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
454             setHasHorizontalScrollbar(newHasHorizontalScrollbar);
455             sendContentResizedNotification = true;
456         }
457
458         if (hasVerticalScrollbar != newHasVerticalScrollbar) {
459             setHasVerticalScrollbar(newHasVerticalScrollbar);
460             sendContentResizedNotification = true;
461         }
462
463         if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
464             m_updateScrollbarsPass++;
465             contentsResized();
466             visibleContentsResized();
467             IntSize newDocSize = contentsSize();
468             if (newDocSize == docSize) {
469                 // The layout with the new scroll state had no impact on
470                 // the document's overall size, so updateScrollbars didn't get called.
471                 // Recur manually.
472                 updateScrollbars(desiredOffset);
473             }
474             m_updateScrollbarsPass--;
475         }
476     }
477     
478     // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
479     // doing it multiple times).
480     if (m_updateScrollbarsPass)
481         return;
482
483     m_inUpdateScrollbars = true;
484     IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
485     IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
486     scroll.clampNegativeToZero();
487  
488     if (m_horizontalScrollbar) {
489         int clientWidth = visibleWidth();
490         m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
491         int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
492         IntRect oldRect(m_horizontalScrollbar->frameRect());
493         IntRect hBarRect = IntRect(0,
494                                    height() - m_horizontalScrollbar->height(),
495                                    width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
496                                    m_horizontalScrollbar->height());
497         m_horizontalScrollbar->setFrameRect(hBarRect);
498         if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
499             m_horizontalScrollbar->invalidate();
500
501         if (m_scrollbarsSuppressed)
502             m_horizontalScrollbar->setSuppressInvalidation(true);
503         m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
504         m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
505         m_horizontalScrollbar->setValue(scroll.width(), Scrollbar::NotFromScrollAnimator);
506         if (m_scrollbarsSuppressed)
507             m_horizontalScrollbar->setSuppressInvalidation(false); 
508     } 
509
510     if (m_verticalScrollbar) {
511         int clientHeight = visibleHeight();
512         m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
513         int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
514         IntRect oldRect(m_verticalScrollbar->frameRect());
515         IntRect vBarRect = IntRect(width() - m_verticalScrollbar->width(), 
516                                    0,
517                                    m_verticalScrollbar->width(),
518                                    height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
519         m_verticalScrollbar->setFrameRect(vBarRect);
520         if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
521             m_verticalScrollbar->invalidate();
522
523         if (m_scrollbarsSuppressed)
524             m_verticalScrollbar->setSuppressInvalidation(true);
525         m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
526         m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
527         m_verticalScrollbar->setValue(scroll.height(), Scrollbar::NotFromScrollAnimator);
528         if (m_scrollbarsSuppressed)
529             m_verticalScrollbar->setSuppressInvalidation(false);
530     }
531
532     if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) {
533         frameRectsChanged();
534         updateScrollCorner();
535     }
536
537     // See if our offset has changed in a situation where we might not have scrollbars.
538     // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
539     // It can also happen when maximizing a window that has scrollbars (but the new maximized result
540     // does not).
541     IntSize scrollDelta = scroll - m_scrollOffset;
542     if (scrollDelta != IntSize()) {
543        m_scrollOffset = scroll;
544        valueChanged(scrollDelta);
545     }
546
547     m_inUpdateScrollbars = false;
548 }
549
550 const int panIconSizeLength = 16;
551
552 void ScrollView::scrollContents(const IntSize& scrollDelta)
553 {
554     if (!hostWindow())
555         return;
556
557     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
558     // with the clip rect every time to keep it smooth.
559     IntRect clipRect = windowClipRect();
560     IntRect scrollViewRect = convertToContainingWindow(IntRect(0, 0, visibleWidth(), visibleHeight()));
561     IntRect updateRect = clipRect;
562     updateRect.intersect(scrollViewRect);
563
564     // Invalidate the window (not the backing store).
565     hostWindow()->invalidateWindow(updateRect, false /*immediate*/);
566
567     if (m_drawPanScrollIcon) {
568         int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
569         IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
570         IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
571         panScrollIconDirtyRect.intersect(clipRect);
572         hostWindow()->invalidateContentsAndWindow(panScrollIconDirtyRect, false /*immediate*/);
573     }
574
575     if (canBlitOnScroll()) { // The main frame can just blit the WebView window
576         // FIXME: Find a way to scroll subframes with this faster path
577         if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
578             hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
579     } else { 
580        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
581        // windowed plugins.
582        hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
583     }
584
585     // This call will move children with native widgets (plugins) and invalidate them as well.
586     frameRectsChanged();
587
588     // Now blit the backingstore into the window which should be very fast.
589     hostWindow()->invalidateWindow(IntRect(), true);
590 }
591
592 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
593 {
594     hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
595     return true;
596 }
597
598 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
599 {
600     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
601     return viewPoint + scrollOffset();
602 }
603
604 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
605 {
606     IntPoint viewPoint = contentsPoint - scrollOffset();
607     return convertToContainingWindow(viewPoint);  
608 }
609
610 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
611 {
612     IntRect viewRect = convertFromContainingWindow(windowRect);
613     viewRect.move(scrollOffset());
614     return viewRect;
615 }
616
617 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
618 {
619     IntRect viewRect = contentsRect;
620     viewRect.move(-scrollOffset());
621     return convertToContainingWindow(viewRect);
622 }
623
624 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
625 {
626     if (platformWidget())
627         return platformContentsToScreen(rect);
628     if (!hostWindow())
629         return IntRect();
630     return hostWindow()->windowToScreen(contentsToWindow(rect));
631 }
632
633 IntPoint ScrollView::screenToContents(const IntPoint& point) const
634 {
635     if (platformWidget())
636         return platformScreenToContents(point);
637     if (!hostWindow())
638         return IntPoint();
639     return windowToContents(hostWindow()->screenToWindow(point));
640 }
641
642 bool ScrollView::containsScrollbarsAvoidingResizer() const
643 {
644     return !m_scrollbarsAvoidingResizer;
645 }
646
647 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
648 {
649     int oldCount = m_scrollbarsAvoidingResizer;
650     m_scrollbarsAvoidingResizer += overlapDelta;
651     if (parent())
652         parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
653     else if (!scrollbarsSuppressed()) {
654         // If we went from n to 0 or from 0 to n and we're the outermost view,
655         // we need to invalidate the windowResizerRect(), since it will now need to paint
656         // differently.
657         if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
658             (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
659             invalidateRect(windowResizerRect());
660     }
661 }
662
663 void ScrollView::setParent(ScrollView* parentView)
664 {
665     if (parentView == parent())
666         return;
667
668     if (m_scrollbarsAvoidingResizer && parent())
669         parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
670
671     Widget::setParent(parentView);
672
673     if (m_scrollbarsAvoidingResizer && parent())
674         parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
675 }
676
677 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
678 {
679     if (suppressed == m_scrollbarsSuppressed)
680         return;
681
682     m_scrollbarsSuppressed = suppressed;
683
684     if (platformWidget())
685         platformSetScrollbarsSuppressed(repaintOnUnsuppress);
686     else if (repaintOnUnsuppress && !suppressed) {
687         if (m_horizontalScrollbar)
688             m_horizontalScrollbar->invalidate();
689         if (m_verticalScrollbar)
690             m_verticalScrollbar->invalidate();
691
692         // Invalidate the scroll corner too on unsuppress.
693         invalidateRect(scrollCornerRect());
694     }
695 }
696
697 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
698 {
699     if (platformWidget())
700         return 0;
701
702     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
703     if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint))
704         return m_horizontalScrollbar.get();
705     if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint))
706         return m_verticalScrollbar.get();
707     return 0;
708 }
709
710 void ScrollView::wheelEvent(PlatformWheelEvent& e)
711 {
712     // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
713 #if PLATFORM(WX)
714     if (!canHaveScrollbars()) {
715 #else
716     if (!canHaveScrollbars() || platformWidget()) {
717 #endif
718         return;
719     }
720
721     // Accept the event if we have a scrollbar in that direction and can still
722     // scroll any further.
723     float deltaX = m_horizontalScrollbar ? e.deltaX() : 0;
724     float deltaY = m_verticalScrollbar ? e.deltaY() : 0;
725     IntSize maxScrollDelta = maximumScrollPosition() - scrollPosition();
726     if ((deltaX < 0 && maxScrollDelta.width() > 0)
727         || (deltaX > 0 && scrollOffset().width() > 0)
728         || (deltaY < 0 && maxScrollDelta.height() > 0)
729         || (deltaY > 0 && scrollOffset().height() > 0)) {
730         e.accept();
731         if (e.granularity() == ScrollByPageWheelEvent) {
732             ASSERT(!e.deltaX());
733             bool negative = deltaY < 0;
734             deltaY = max(max(static_cast<float>(visibleHeight()) * Scrollbar::minFractionToStepWhenPaging(), static_cast<float>(visibleHeight() - Scrollbar::maxOverlapBetweenPages())), 1.0f);
735             if (negative)
736                 deltaY = -deltaY;
737         }
738
739         if (deltaY)
740             m_verticalScrollbar->scroll(ScrollUp, ScrollByPixel, deltaY);
741         if (deltaX)
742             m_horizontalScrollbar->scroll(ScrollLeft, ScrollByPixel, deltaX);
743     }
744 }
745
746 void ScrollView::setFrameRect(const IntRect& newRect)
747 {
748     IntRect oldRect = frameRect();
749     
750     if (newRect == oldRect)
751         return;
752
753     Widget::setFrameRect(newRect);
754
755     if (platformWidget())
756         return;
757     
758     if (newRect.width() != oldRect.width() || newRect.height() != oldRect.height()) {
759         updateScrollbars(m_scrollOffset);
760         if (!m_useFixedLayout)
761             contentsResized();
762     }
763
764     frameRectsChanged();
765 }
766
767 void ScrollView::frameRectsChanged()
768 {
769     if (platformWidget())
770         return;
771
772     HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
773     for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
774         (*current)->frameRectsChanged();
775 }
776
777 void ScrollView::repaintContentRectangle(const IntRect& rect, bool now)
778 {
779     IntRect paintRect = rect;
780     if (!paintsEntireContents())
781         paintRect.intersect(visibleContentRect());
782 #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
783     if (rect != paintRect)
784         platformOffscreenContentRectangle(visibleContentRect(), rect);
785 #endif
786     if (paintRect.isEmpty())
787         return;
788     if (platformWidget()) {
789         platformRepaintContentRectangle(paintRect, now);
790         return;
791     }
792
793     if (hostWindow())
794         hostWindow()->invalidateContentsAndWindow(contentsToWindow(paintRect), now /*immediate*/);
795 }
796
797 IntRect ScrollView::scrollCornerRect() const
798 {
799     IntRect cornerRect;
800     
801     if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) {
802         cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
803                                  height() - m_horizontalScrollbar->height(),
804                                  width() - m_horizontalScrollbar->width(),
805                                  m_horizontalScrollbar->height()));
806     }
807
808     if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) {
809         cornerRect.unite(IntRect(width() - m_verticalScrollbar->width(),
810                                  m_verticalScrollbar->height(),
811                                  m_verticalScrollbar->width(),
812                                  height() - m_verticalScrollbar->height()));
813     }
814     
815     return cornerRect;
816 }
817
818 void ScrollView::updateScrollCorner()
819 {
820 }
821
822 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
823 {
824     ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect);
825 }
826
827 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
828 {
829     if (m_horizontalScrollbar)
830         m_horizontalScrollbar->paint(context, rect);
831     if (m_verticalScrollbar)
832         m_verticalScrollbar->paint(context, rect);
833
834     paintScrollCorner(context, scrollCornerRect());
835 }
836
837 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
838 {
839     static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
840     context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, m_panScrollIconPoint);
841 }
842
843 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
844 {
845     if (platformWidget()) {
846         Widget::paint(context, rect);
847         return;
848     }
849
850     if (context->paintingDisabled() && !context->updatingControlTints())
851         return;
852
853     IntRect documentDirtyRect = rect;
854     documentDirtyRect.intersect(frameRect());
855
856     context->save();
857
858     context->translate(x(), y());
859     documentDirtyRect.move(-x(), -y());
860
861     context->translate(-scrollX(), -scrollY());
862     documentDirtyRect.move(scrollX(), scrollY());
863
864     context->clip(visibleContentRect());
865
866     paintContents(context, documentDirtyRect);
867
868     context->restore();
869
870     // Now paint the scrollbars.
871     if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
872         context->save();
873         IntRect scrollViewDirtyRect = rect;
874         scrollViewDirtyRect.intersect(frameRect());
875         context->translate(x(), y());
876         scrollViewDirtyRect.move(-x(), -y());
877
878         paintScrollbars(context, scrollViewDirtyRect);
879
880         context->restore();
881     }
882
883     // Paint the panScroll Icon
884     if (m_drawPanScrollIcon)
885         paintPanScrollIcon(context);
886 }
887
888 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
889 {
890     if (!scrollbarCornerPresent())
891         return false;
892
893     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
894
895     if (m_horizontalScrollbar) {
896         int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
897         int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
898         int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
899
900         return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
901     }
902
903     int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
904     int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
905     int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
906     
907     return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
908 }
909
910 bool ScrollView::scrollbarCornerPresent() const
911 {
912     return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) ||
913            (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0);
914 }
915
916 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
917 {
918     // Scrollbars won't be transformed within us
919     IntRect newRect = localRect;
920     newRect.move(scrollbar->x(), scrollbar->y());
921     return newRect;
922 }
923
924 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
925 {
926     IntRect newRect = parentRect;
927     // Scrollbars won't be transformed within us
928     newRect.move(-scrollbar->x(), -scrollbar->y());
929     return newRect;
930 }
931
932 // FIXME: test these on windows
933 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
934 {
935     // Scrollbars won't be transformed within us
936     IntPoint newPoint = localPoint;
937     newPoint.move(scrollbar->x(), scrollbar->y());
938     return newPoint;
939 }
940
941 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
942 {
943     IntPoint newPoint = parentPoint;
944     // Scrollbars won't be transformed within us
945     newPoint.move(-scrollbar->x(), -scrollbar->y());
946     return newPoint;
947 }
948
949 void ScrollView::setParentVisible(bool visible)
950 {
951     if (isParentVisible() == visible)
952         return;
953     
954     Widget::setParentVisible(visible);
955
956     if (!isSelfVisible())
957         return;
958         
959     HashSet<RefPtr<Widget> >::iterator end = m_children.end();
960     for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
961         (*it)->setParentVisible(visible);
962 }
963
964 void ScrollView::show()
965 {
966     if (!isSelfVisible()) {
967         setSelfVisible(true);
968         if (isParentVisible()) {
969             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
970             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
971                 (*it)->setParentVisible(true);
972         }
973     }
974
975     Widget::show();
976 }
977
978 void ScrollView::hide()
979 {
980     if (isSelfVisible()) {
981         if (isParentVisible()) {
982             HashSet<RefPtr<Widget> >::iterator end = m_children.end();
983             for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
984                 (*it)->setParentVisible(false);
985         }
986         setSelfVisible(false);
987     }
988
989     Widget::hide();
990 }
991
992 bool ScrollView::isOffscreen() const
993 {
994     if (platformWidget())
995         return platformIsOffscreen();
996     
997     if (!isVisible())
998         return true;
999     
1000     // FIXME: Add a HostWindow::isOffscreen method here.  Since only Mac implements this method
1001     // currently, we can add the method when the other platforms decide to implement this concept.
1002     return false;
1003 }
1004
1005
1006 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1007 {
1008     if (!hostWindow())
1009         return;
1010     m_drawPanScrollIcon = true;    
1011     m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1012     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1013 }
1014
1015 void ScrollView::removePanScrollIcon()
1016 {
1017     if (!hostWindow())
1018         return;
1019     m_drawPanScrollIcon = false; 
1020     hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1021 }
1022
1023 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(EFL)
1024
1025 void ScrollView::platformInit()
1026 {
1027 }
1028
1029 void ScrollView::platformDestroy()
1030 {
1031 }
1032
1033 #endif
1034
1035 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(QT) && !PLATFORM(MAC)
1036
1037 void ScrollView::platformAddChild(Widget*)
1038 {
1039 }
1040
1041 void ScrollView::platformRemoveChild(Widget*)
1042 {
1043 }
1044
1045 #endif
1046
1047 #if !PLATFORM(MAC)
1048
1049 void ScrollView::platformSetScrollbarsSuppressed(bool)
1050 {
1051 }
1052
1053 #endif
1054
1055 #if !PLATFORM(MAC) && !PLATFORM(WX)
1056
1057 #if !PLATFORM(ANDROID)
1058 void ScrollView::platformSetScrollbarModes()
1059 {
1060 }
1061
1062 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1063 {
1064     horizontal = ScrollbarAuto;
1065     vertical = ScrollbarAuto;
1066 }
1067 #endif
1068
1069 void ScrollView::platformSetCanBlitOnScroll(bool)
1070 {
1071 }
1072
1073 bool ScrollView::platformCanBlitOnScroll() const
1074 {
1075     return false;
1076 }
1077
1078 #if !PLATFORM(ANDROID)
1079 IntRect ScrollView::platformVisibleContentRect(bool) const
1080 {
1081     return IntRect();
1082 }
1083 #endif
1084
1085 #if !PLATFORM(ANDROID)
1086 IntSize ScrollView::platformContentsSize() const
1087 {
1088     return IntSize();
1089 }
1090 #endif
1091
1092 void ScrollView::platformSetContentsSize()
1093 {
1094 }
1095
1096 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1097 {
1098     return rect;
1099 }
1100
1101 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1102 {
1103     return point;
1104 }
1105
1106 #if !PLATFORM(ANDROID)
1107 void ScrollView::platformSetScrollPosition(const IntPoint&)
1108 {
1109 }
1110 #endif
1111
1112 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1113 {
1114     return true;
1115 }
1116
1117 #if !PLATFORM(ANDROID)
1118 void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/)
1119 {
1120 }
1121
1122 #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
1123 void ScrollView::platformOffscreenContentRectangle(const IntRect& )
1124 {
1125 }
1126 #endif
1127
1128 bool ScrollView::platformIsOffscreen() const
1129 {
1130     return false;
1131 }
1132
1133 #endif
1134 #endif
1135
1136 }
1137