WebCore:
[WebKit-https.git] / WebCore / platform / win / ScrollViewWin.cpp
1 /*
2  * Copyright (C) 2006, 2007 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 "Chrome.h"
30 #include "ChromeClient.h"
31 #include "FloatRect.h"
32 #include "Frame.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "IntRect.h"
36 #include "NotImplemented.h"
37 #include "Page.h"
38 #include "PlatformScrollBar.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformWheelEvent.h"
41 #include "RenderTheme.h" 
42 #include "ScrollBar.h"
43 #include <algorithm>
44 #include <winsock2.h>
45 #include <windows.h>
46 #include <wtf/Assertions.h>
47 #include <wtf/HashSet.h>
48
49 using namespace std;
50
51 namespace WebCore {
52
53 class ScrollView::ScrollViewPrivate : public ScrollbarClient {
54 public:
55     ScrollViewPrivate(ScrollView* view)
56         : m_view(view)
57         , m_hasStaticBackground(false)
58         , m_scrollbarsSuppressed(false)
59         , m_inUpdateScrollbars(false)
60         , m_scrollbarsAvoidingResizer(0)
61         , m_vScrollbarMode(ScrollbarAuto)
62         , m_hScrollbarMode(ScrollbarAuto)
63     {
64     }
65
66     ~ScrollViewPrivate()
67     {
68         setHasHorizontalScrollbar(false);
69         setHasVerticalScrollbar(false);
70     }
71
72     void setHasHorizontalScrollbar(bool hasBar);
73     void setHasVerticalScrollbar(bool hasBar);
74
75     virtual void valueChanged(Scrollbar*);
76     virtual IntRect windowClipRect() const;
77
78     void scrollBackingStore(const IntSize& scrollDelta);
79
80     void setAllowsScrolling(bool);
81     bool allowsScrolling() const;
82
83     ScrollView* m_view;
84     IntSize m_scrollOffset;
85     IntSize m_contentsSize;
86     bool m_hasStaticBackground;
87     bool m_scrollbarsSuppressed;
88     bool m_inUpdateScrollbars;
89     int m_scrollbarsAvoidingResizer;
90     ScrollbarMode m_vScrollbarMode;
91     ScrollbarMode m_hScrollbarMode;
92     RefPtr<PlatformScrollbar> m_vBar;
93     RefPtr<PlatformScrollbar> m_hBar;
94     HRGN m_dirtyRegion;
95     HashSet<Widget*> m_children;
96 };
97
98 void ScrollView::ScrollViewPrivate::setHasHorizontalScrollbar(bool hasBar)
99 {
100     if (Scrollbar::hasPlatformScrollbars()) {
101         if (hasBar && !m_hBar) {
102             m_hBar = new PlatformScrollbar(this, HorizontalScrollbar, RegularScrollbar);
103             m_view->addChild(m_hBar.get());
104         } else if (!hasBar && m_hBar) {
105             m_view->removeChild(m_hBar.get());
106             m_hBar = 0;
107         }
108     }
109 }
110
111 void ScrollView::ScrollViewPrivate::setHasVerticalScrollbar(bool hasBar)
112 {
113     if (Scrollbar::hasPlatformScrollbars()) {
114         if (hasBar && !m_vBar) {
115             m_vBar = new PlatformScrollbar(this, VerticalScrollbar, RegularScrollbar);
116             m_view->addChild(m_vBar.get());
117         } else if (!hasBar && m_vBar) {
118             m_view->removeChild(m_vBar.get());
119             m_vBar = 0;
120         }
121     }
122 }
123
124 void ScrollView::ScrollViewPrivate::valueChanged(Scrollbar* bar)
125 {
126     // Figure out if we really moved.
127     IntSize newOffset = m_scrollOffset;
128     if (bar) {
129         if (bar == m_hBar)
130             newOffset.setWidth(bar->value());
131         else if (bar == m_vBar)
132             newOffset.setHeight(bar->value());
133     }
134     IntSize scrollDelta = newOffset - m_scrollOffset;
135     if (scrollDelta == IntSize())
136         return;
137     m_scrollOffset = newOffset;
138
139     if (m_scrollbarsSuppressed)
140         return;
141
142     scrollBackingStore(scrollDelta);
143     static_cast<FrameView*>(m_view)->frame()->sendScrollEvent();
144 }
145
146 void ScrollView::ScrollViewPrivate::scrollBackingStore(const IntSize& scrollDelta)
147 {
148     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
149     // with the clip rect every time to keep it smooth.
150     HWND containingWindowHandle = m_view->containingWindow();
151     IntRect clipRect = m_view->windowClipRect();
152     IntRect scrollViewRect = m_view->convertToContainingWindow(IntRect(0, 0, m_view->visibleWidth(), m_view->visibleHeight()));
153     IntRect updateRect = clipRect;
154     updateRect.intersect(scrollViewRect);
155     RECT r = updateRect;
156     ::InvalidateRect(containingWindowHandle, &r, false);
157
158     if (!m_hasStaticBackground) // The main frame can just blit the WebView window
159        // FIXME: Find a way to blit subframes without blitting overlapping content
160        m_view->scrollBackingStore(-scrollDelta.width(), -scrollDelta.height(), scrollViewRect, clipRect);
161     else  {
162        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
163        // plugins.
164        m_view->addToDirtyRegion(updateRect);
165        m_view->updateBackingStore();
166     }
167
168     // This call will move child HWNDs (plugins) and invalidate them as well.
169     m_view->geometryChanged();
170
171     // Now update the window (which should do nothing but a blit of the backing store's updateRect and so should
172     // be very fast).
173     ::UpdateWindow(containingWindowHandle);
174 }
175
176 void ScrollView::ScrollViewPrivate::setAllowsScrolling(bool flag)
177 {
178     if (flag && m_vScrollbarMode == ScrollbarAlwaysOff)
179         m_vScrollbarMode = ScrollbarAuto;
180     else if (!flag)
181         m_vScrollbarMode = ScrollbarAlwaysOff;
182
183     if (flag && m_hScrollbarMode == ScrollbarAlwaysOff)
184         m_hScrollbarMode = ScrollbarAuto;
185     else if (!flag)
186         m_hScrollbarMode = ScrollbarAlwaysOff;
187
188     m_view->updateScrollbars(m_scrollOffset);
189 }
190
191 bool ScrollView::ScrollViewPrivate::allowsScrolling() const
192 {
193     // Return YES if either horizontal or vertical scrolling is allowed.
194     return m_hScrollbarMode != ScrollbarAlwaysOff || m_vScrollbarMode != ScrollbarAlwaysOff;
195 }
196
197 IntRect ScrollView::ScrollViewPrivate::windowClipRect() const
198 {
199     return static_cast<const FrameView*>(m_view)->windowClipRect(false);
200 }
201
202 ScrollView::ScrollView()
203     : m_data(new ScrollViewPrivate(this))
204 {
205 }
206
207 ScrollView::~ScrollView()
208 {
209     delete m_data;
210 }
211
212 void ScrollView::updateContents(const IntRect& rect, bool now)
213 {
214     if (rect.isEmpty())
215         return;
216
217     IntPoint windowPoint = contentsToWindow(rect.location());
218     IntRect containingWindowRect = rect;
219     containingWindowRect.setLocation(windowPoint);
220
221     RECT containingWindowRectWin = containingWindowRect;
222     HWND containingWindowHandle = containingWindow();
223
224     ::InvalidateRect(containingWindowHandle, &containingWindowRectWin, false);
225
226     // Cache the dirty spot.
227     addToDirtyRegion(containingWindowRect);
228
229     if (now)
230         ::UpdateWindow(containingWindowHandle);
231 }
232
233 void ScrollView::update()
234 {
235     ::UpdateWindow(containingWindow());
236 }
237
238 int ScrollView::visibleWidth() const
239 {
240     return max(0, width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0));
241 }
242
243 int ScrollView::visibleHeight() const
244 {
245     return max(0, height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
246 }
247
248 FloatRect ScrollView::visibleContentRect() const
249 {
250     return FloatRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
251 }
252
253 FloatRect ScrollView::visibleContentRectConsideringExternalScrollers() const
254 {
255     // external scrollers not supported for now
256     return visibleContentRect();
257 }
258
259 void ScrollView::setContentsPos(int newX, int newY)
260 {
261     int dx = newX - contentsX();
262     int dy = newY - contentsY();
263     scrollBy(dx, dy);
264 }
265
266 void ScrollView::resizeContents(int w, int h)
267 {
268     IntSize newContentsSize(w, h);
269     if (m_data->m_contentsSize != newContentsSize) {
270         m_data->m_contentsSize = newContentsSize;
271         updateScrollbars(m_data->m_scrollOffset);
272     }
273 }
274
275 void ScrollView::setFrameGeometry(const IntRect& newGeometry)
276 {
277     IntRect oldGeometry = frameGeometry();
278     Widget::setFrameGeometry(newGeometry);
279
280     if (newGeometry == oldGeometry)
281         return;
282
283     if (newGeometry.width() != oldGeometry.width() || newGeometry.height() != oldGeometry.height()) {
284         updateScrollbars(m_data->m_scrollOffset);
285         static_cast<FrameView*>(this)->setNeedsLayout();
286     }
287
288     geometryChanged();
289 }
290
291 int ScrollView::contentsX() const
292 {
293     return scrollOffset().width();
294 }
295
296 int ScrollView::contentsY() const
297 {
298     return scrollOffset().height();
299 }
300
301 int ScrollView::contentsWidth() const
302 {
303     return m_data->m_contentsSize.width();
304 }
305
306 int ScrollView::contentsHeight() const
307 {
308     return m_data->m_contentsSize.height();
309 }
310
311 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
312 {
313     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
314     return viewPoint + scrollOffset();
315 }
316
317 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
318 {
319     IntPoint viewPoint = contentsPoint - scrollOffset();
320     return convertToContainingWindow(viewPoint);  
321 }
322
323 IntPoint ScrollView::convertChildToSelf(const Widget* child, const IntPoint& point) const
324 {
325     IntPoint newPoint = point;
326     if (child != m_data->m_hBar && child != m_data->m_vBar)
327         newPoint = point - scrollOffset();
328     return Widget::convertChildToSelf(child, newPoint);
329 }
330
331 IntPoint ScrollView::convertSelfToChild(const Widget* child, const IntPoint& point) const
332 {
333     IntPoint newPoint = point;
334     if (child != m_data->m_hBar && child != m_data->m_vBar)
335         newPoint = point + scrollOffset();
336     return Widget::convertSelfToChild(child, newPoint);
337 }
338
339 IntSize ScrollView::scrollOffset() const
340 {
341     return m_data->m_scrollOffset;
342 }
343
344 IntSize ScrollView::maximumScroll() const
345 {
346     IntSize delta = (m_data->m_contentsSize - IntSize(visibleWidth(), visibleHeight())) - scrollOffset();
347     delta.clampNegativeToZero();
348     return delta;
349 }
350
351 void ScrollView::scrollBy(int dx, int dy)
352 {
353     IntSize scrollOffset = m_data->m_scrollOffset;
354     IntSize newScrollOffset = scrollOffset + IntSize(dx, dy).shrunkTo(maximumScroll());
355     newScrollOffset.clampNegativeToZero();
356
357     if (newScrollOffset == scrollOffset)
358         return;
359
360     updateScrollbars(newScrollOffset);
361 }
362
363 void ScrollView::scrollRectIntoViewRecursively(const IntRect& r)
364 {
365     IntPoint p(max(0, r.x()), max(0, r.y()));
366     ScrollView* view = this;
367     while (view) {
368         view->setContentsPos(p.x(), p.y());
369         p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height());
370         view = static_cast<ScrollView*>(view->parent());
371     }
372 }
373
374 WebCore::ScrollbarMode ScrollView::hScrollbarMode() const
375 {
376     return m_data->m_hScrollbarMode;
377 }
378
379 WebCore::ScrollbarMode ScrollView::vScrollbarMode() const
380 {
381     return m_data->m_vScrollbarMode;
382 }
383
384 void ScrollView::suppressScrollbars(bool suppressed, bool repaintOnSuppress)
385 {
386     m_data->m_scrollbarsSuppressed = suppressed;
387     if (repaintOnSuppress && !suppressed) {
388         if (m_data->m_hBar)
389             m_data->m_hBar->invalidate();
390         if (m_data->m_vBar)
391             m_data->m_vBar->invalidate();
392
393         // Invalidate the scroll corner too on unsuppress.
394         IntRect hCorner;
395         if (m_data->m_hBar && width() - m_data->m_hBar->width() > 0) {
396             hCorner = IntRect(m_data->m_hBar->width(),
397                               height() - m_data->m_hBar->height(),
398                               width() - m_data->m_hBar->width(),
399                               m_data->m_hBar->height());
400             invalidateRect(hCorner);
401         }
402
403         if (m_data->m_vBar && height() - m_data->m_vBar->height() > 0) {
404             IntRect vCorner(width() - m_data->m_vBar->width(),
405                             m_data->m_vBar->height(),
406                             m_data->m_vBar->width(),
407                             height() - m_data->m_vBar->height());
408             if (vCorner != hCorner)
409                 invalidateRect(vCorner);
410         }
411     }
412 }
413
414 void ScrollView::setHScrollbarMode(ScrollbarMode newMode)
415 {
416     if (m_data->m_hScrollbarMode != newMode) {
417         m_data->m_hScrollbarMode = newMode;
418         updateScrollbars(m_data->m_scrollOffset);
419     }
420 }
421
422 void ScrollView::setVScrollbarMode(ScrollbarMode newMode)
423 {
424     if (m_data->m_vScrollbarMode != newMode) {
425         m_data->m_vScrollbarMode = newMode;
426         updateScrollbars(m_data->m_scrollOffset);
427     }
428 }
429
430 void ScrollView::setScrollbarsMode(ScrollbarMode newMode)
431 {
432     if (m_data->m_hScrollbarMode != newMode ||
433         m_data->m_vScrollbarMode != newMode) {
434         m_data->m_hScrollbarMode = m_data->m_vScrollbarMode = newMode;
435         updateScrollbars(m_data->m_scrollOffset);
436     }
437 }
438
439 void ScrollView::setStaticBackground(bool flag)
440 {
441     m_data->m_hasStaticBackground = flag;
442 }
443
444 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
445 {
446     // Don't allow re-entrancy into this function.
447     if (m_data->m_inUpdateScrollbars)
448         return;
449
450     // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
451     // In the end, FrameView should just merge with ScrollView.
452     if (static_cast<const FrameView*>(this)->frame()->prohibitsScrolling())
453         return;
454
455     m_data->m_inUpdateScrollbars = true;
456
457     bool hasVerticalScrollbar = m_data->m_vBar;
458     bool hasHorizontalScrollbar = m_data->m_hBar;
459     bool oldHasVertical = hasVerticalScrollbar;
460     bool oldHasHorizontal = hasHorizontalScrollbar;
461     ScrollbarMode hScroll = m_data->m_hScrollbarMode;
462     ScrollbarMode vScroll = m_data->m_vScrollbarMode;
463     
464     const int cVerticalWidth = PlatformScrollbar::verticalScrollbarWidth();
465     const int cHorizontalHeight = PlatformScrollbar::horizontalScrollbarHeight();
466
467     for (int pass = 0; pass < 2; pass++) {
468         bool scrollsVertically;
469         bool scrollsHorizontally;
470
471         if (!m_data->m_scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
472             // Do a layout if pending before checking if scrollbars are needed.
473             if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
474                 static_cast<FrameView*>(this)->layout();
475
476             scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
477             if (scrollsVertically)
478                 scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + cVerticalWidth > width());
479             else {
480                 scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
481                 if (scrollsHorizontally)
482                     scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + cHorizontalHeight > height());
483             }
484         }
485         else {
486             scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
487             scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
488         }
489         
490         if (hasVerticalScrollbar != scrollsVertically) {
491             m_data->setHasVerticalScrollbar(scrollsVertically);
492             hasVerticalScrollbar = scrollsVertically;
493         }
494
495         if (hasHorizontalScrollbar != scrollsHorizontally) {
496             m_data->setHasHorizontalScrollbar(scrollsHorizontally);
497             hasHorizontalScrollbar = scrollsHorizontally;
498         }
499     }
500     
501     // Set up the range (and page step/line step).
502     IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
503     IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
504     scroll.clampNegativeToZero();
505  
506     if (m_data->m_hBar) {
507         int clientWidth = visibleWidth();
508         m_data->m_hBar->setEnabled(contentsWidth() > clientWidth);
509         int pageStep = (clientWidth - PAGE_KEEP);
510         if (pageStep < 0) pageStep = clientWidth;
511         IntRect oldRect(m_data->m_hBar->frameGeometry());
512         IntRect hBarRect = IntRect(0,
513                                    height() - m_data->m_hBar->height(),
514                                    width() - (m_data->m_vBar ? m_data->m_vBar->width() : 0),
515                                    m_data->m_hBar->height());
516         m_data->m_hBar->setRect(hBarRect);
517         if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_hBar->frameGeometry())
518             m_data->m_hBar->invalidate();
519
520         if (m_data->m_scrollbarsSuppressed)
521             m_data->m_hBar->setSuppressInvalidation(true);
522         m_data->m_hBar->setSteps(LINE_STEP, pageStep);
523         m_data->m_hBar->setProportion(clientWidth, contentsWidth());
524         m_data->m_hBar->setValue(scroll.width());
525         if (m_data->m_scrollbarsSuppressed)
526             m_data->m_hBar->setSuppressInvalidation(false); 
527     } 
528
529     if (m_data->m_vBar) {
530         int clientHeight = visibleHeight();
531         m_data->m_vBar->setEnabled(contentsHeight() > clientHeight);
532         int pageStep = (clientHeight - PAGE_KEEP);
533         if (pageStep < 0) pageStep = clientHeight;
534         IntRect oldRect(m_data->m_vBar->frameGeometry());
535         IntRect vBarRect = IntRect(width() - m_data->m_vBar->width(), 
536                                    0,
537                                    m_data->m_vBar->width(),
538                                    height() - (m_data->m_hBar ? m_data->m_hBar->height() : 0));
539         m_data->m_vBar->setRect(vBarRect);
540         if (!m_data->m_scrollbarsSuppressed && oldRect != m_data->m_vBar->frameGeometry())
541             m_data->m_vBar->invalidate();
542
543         if (m_data->m_scrollbarsSuppressed)
544             m_data->m_vBar->setSuppressInvalidation(true);
545         m_data->m_vBar->setSteps(LINE_STEP, pageStep);
546         m_data->m_vBar->setProportion(clientHeight, contentsHeight());
547         m_data->m_vBar->setValue(scroll.height());
548         if (m_data->m_scrollbarsSuppressed)
549             m_data->m_vBar->setSuppressInvalidation(false);
550     }
551
552     if (oldHasVertical != (m_data->m_vBar != 0) || oldHasHorizontal != (m_data->m_hBar != 0))
553         geometryChanged();
554
555     // See if our offset has changed in a situation where we might not have scrollbars.
556     // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
557     // It can also happen when maximizing a window that has scrollbars (but the new maximized result
558     // does not).
559     IntSize scrollDelta = scroll - m_data->m_scrollOffset;
560     if (scrollDelta != IntSize()) {
561        m_data->m_scrollOffset = scroll;
562        m_data->scrollBackingStore(scrollDelta);
563     }
564
565     m_data->m_inUpdateScrollbars = false;
566 }
567
568 PlatformScrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent)
569 {
570     IntPoint viewPoint = convertFromContainingWindow(mouseEvent.pos());
571     if (m_data->m_hBar && m_data->m_hBar->frameGeometry().contains(viewPoint))
572         return m_data->m_hBar.get();
573     if (m_data->m_vBar && m_data->m_vBar->frameGeometry().contains(viewPoint))
574         return m_data->m_vBar.get();
575     return 0;
576 }
577
578 void ScrollView::addChild(Widget* child) 
579
580     child->setParent(this);
581     child->setContainingWindow(containingWindow());
582     m_data->m_children.add(child);
583 }
584
585 void ScrollView::removeChild(Widget* child)
586 {
587     child->setParent(0);
588     m_data->m_children.remove(child);
589 }
590
591 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
592 {
593     // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
594     // In the end, FrameView should just merge with ScrollView.
595     ASSERT(isFrameView());
596
597     if (context->paintingDisabled())
598         return;
599
600     IntRect documentDirtyRect = rect;
601     documentDirtyRect.intersect(frameGeometry());
602
603     context->save();
604
605     context->translate(x(), y());
606     documentDirtyRect.move(-x(), -y());
607
608     context->translate(-contentsX(), -contentsY());
609     documentDirtyRect.move(contentsX(), contentsY());
610
611     context->clip(enclosingIntRect(visibleContentRect()));
612
613     static_cast<const FrameView*>(this)->frame()->paint(context, documentDirtyRect);
614
615     context->restore();
616
617     // Now paint the scrollbars.
618     if (!m_data->m_scrollbarsSuppressed && (m_data->m_hBar || m_data->m_vBar)) {
619         context->save();
620         IntRect scrollViewDirtyRect = rect;
621         scrollViewDirtyRect.intersect(frameGeometry());
622         context->translate(x(), y());
623         scrollViewDirtyRect.move(-x(), -y());
624         if (m_data->m_hBar)
625             m_data->m_hBar->paint(context, scrollViewDirtyRect);
626         if (m_data->m_vBar)
627             m_data->m_vBar->paint(context, scrollViewDirtyRect);
628
629         // Fill the scroll corner with white.
630         IntRect hCorner;
631         if (m_data->m_hBar && width() - m_data->m_hBar->width() > 0) {
632             hCorner = IntRect(m_data->m_hBar->width(),
633                               height() - m_data->m_hBar->height(),
634                               width() - m_data->m_hBar->width(),
635                               m_data->m_hBar->height());
636             if (hCorner.intersects(scrollViewDirtyRect))
637                 context->fillRect(hCorner, Color::white);
638         }
639
640         if (m_data->m_vBar && height() - m_data->m_vBar->height() > 0) {
641             IntRect vCorner(width() - m_data->m_vBar->width(),
642                             m_data->m_vBar->height(),
643                             m_data->m_vBar->width(),
644                             height() - m_data->m_vBar->height());
645             if (vCorner != hCorner && vCorner.intersects(scrollViewDirtyRect))
646                 context->fillRect(vCorner, Color::white);
647         }
648
649         context->restore();
650     }
651 }
652
653 void ScrollView::themeChanged()
654 {
655     PlatformScrollbar::themeChanged();
656     theme()->themeChanged();
657     invalidate();
658 }
659
660 void ScrollView::wheelEvent(PlatformWheelEvent& e)
661 {
662     // Determine how much we want to scroll.  If we can move at all, we will accept the event.
663     IntSize maxScrollDelta = maximumScroll();
664     if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
665         (e.deltaX() > 0 && scrollOffset().width() > 0) ||
666         (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
667         (e.deltaY() > 0 && scrollOffset().height() > 0))
668         e.accept();
669
670     scrollBy(-e.deltaX() * LINE_STEP, -e.deltaY() * LINE_STEP);
671 }
672
673 HashSet<Widget*>* ScrollView::children()
674 {
675     return &(m_data->m_children);
676 }
677
678 void ScrollView::geometryChanged() const
679 {
680     HashSet<Widget*>::const_iterator end = m_data->m_children.end();
681     for (HashSet<Widget*>::const_iterator current = m_data->m_children.begin(); current != end; ++current)
682         (*current)->geometryChanged();
683 }
684
685 void ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
686 {
687     if  ((direction == ScrollUp || direction == ScrollDown) && m_data->m_vBar)
688         m_data->m_vBar->scroll(direction, granularity);
689     else if (m_data->m_hBar)
690         m_data->m_hBar->scroll(direction, granularity);
691 }
692
693 IntRect ScrollView::windowResizerRect()
694 {
695     ASSERT(isFrameView());
696     const FrameView* frameView = static_cast<const FrameView*>(this);
697     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
698     if (!page)
699         return IntRect();
700     return page->chrome()->windowResizerRect();
701 }
702
703 bool ScrollView::resizerOverlapsContent() const
704 {
705     return !m_data->m_scrollbarsAvoidingResizer;
706 }
707
708 void ScrollView::adjustOverlappingScrollbarCount(int overlapDelta)
709 {
710     int oldCount = m_data->m_scrollbarsAvoidingResizer;
711     m_data->m_scrollbarsAvoidingResizer += overlapDelta;
712     if (parent() && parent()->isFrameView())
713         static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(overlapDelta);
714     else if (!m_data->m_scrollbarsSuppressed) {
715         // If we went from n to 0 or from 0 to n and we're the outermost view,
716         // we need to invalidate the windowResizerRect(), since it will now need to paint
717         // differently.
718         if (oldCount > 0 && m_data->m_scrollbarsAvoidingResizer == 0 ||
719             oldCount == 0 && m_data->m_scrollbarsAvoidingResizer > 0)
720             invalidateRect(windowResizerRect());
721     }
722 }
723
724 void ScrollView::setParent(ScrollView* parentView)
725 {
726     if (!parentView && m_data->m_scrollbarsAvoidingResizer && parent() && parent()->isFrameView())
727         static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(false);
728     Widget::setParent(parentView);
729 }
730
731 void ScrollView::addToDirtyRegion(const IntRect& containingWindowRect)
732 {
733     ASSERT(isFrameView());
734     const FrameView* frameView = static_cast<const FrameView*>(this);
735     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
736     if (!page)
737         return;
738     page->chrome()->addToDirtyRegion(containingWindowRect);
739 }
740
741 void ScrollView::scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
742 {
743     ASSERT(isFrameView());
744     const FrameView* frameView = static_cast<const FrameView*>(this);
745     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
746     if (!page)
747         return;
748     page->chrome()->scrollBackingStore(dx, dy, scrollViewRect, clipRect);
749 }
750
751 void ScrollView::updateBackingStore()
752 {
753     ASSERT(isFrameView());
754     const FrameView* frameView = static_cast<const FrameView*>(this);
755     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
756     if (!page)
757         return;
758     page->chrome()->updateBackingStore();
759 }
760
761 void ScrollView::setAllowsScrolling(bool flag)
762 {
763     m_data->setAllowsScrolling(flag);
764 }
765
766 bool ScrollView::allowsScrolling() const
767 {
768     return m_data->allowsScrolling();
769 }
770
771 bool ScrollView::inWindow() const
772 {
773     // Needed for back/forward cache. 
774     notImplemented();
775     return true;
776 }
777
778 } // namespace WebCore