5fded5c44aac942793171f296ca204479bb8327e
[WebKit-https.git] / WebCore / platform / gtk / ScrollViewGtk.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 
4  * Copyright (C) 2007 Holger Hans Peter Freyther
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
28  */
29
30 #include "config.h"
31 #include "ScrollView.h"
32
33 #include "FloatRect.h"
34 #include "Frame.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "IntRect.h"
38 #include "NotImplemented.h"
39 #include "PlatformMouseEvent.h"
40 #include "PlatformWheelEvent.h"
41 #include "PlatformScrollBar.h"
42 #include "Page.h"
43 #include "RenderLayer.h"
44
45 #include <gdk/gdk.h>
46 #include <gtk/gtk.h>
47
48 using namespace std;
49
50 namespace WebCore {
51
52 class ScrollViewScrollbar : public PlatformScrollbar {
53 public:
54     ScrollViewScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
55
56 protected:
57     void geometryChanged();
58 };
59
60 class ScrollView::ScrollViewPrivate : public ScrollbarClient
61 {
62 public:
63     ScrollViewPrivate(ScrollView* _view)
64         : view(_view)
65         , hasStaticBackground(false)
66         , scrollbarsSuppressed(false)
67         , vScrollbarMode(ScrollbarAuto)
68         , hScrollbarMode(ScrollbarAuto)
69         , inUpdateScrollbars(false)
70         , horizontalAdjustment(0)
71         , verticalAdjustment(0)
72     {}
73
74     ~ScrollViewPrivate()
75     {
76         setHasHorizontalScrollbar(false);
77         setHasVerticalScrollbar(false);
78
79         if (horizontalAdjustment) {
80             g_signal_handlers_disconnect_by_func(G_OBJECT(horizontalAdjustment), (gpointer)ScrollViewPrivate::adjustmentChanged, this);
81             g_object_unref(horizontalAdjustment);
82         }
83
84         if (verticalAdjustment) {
85             g_signal_handlers_disconnect_by_func(G_OBJECT(verticalAdjustment), (gpointer)ScrollViewPrivate::adjustmentChanged, this);
86             g_object_unref(verticalAdjustment);
87         }
88     }
89
90     void scrollBackingStore(const IntSize& scrollDelta);
91  
92     void setHasHorizontalScrollbar(bool hasBar);
93     void setHasVerticalScrollbar(bool hasBar);
94
95     virtual void valueChanged(Scrollbar*);
96     virtual IntRect windowClipRect() const;
97
98     static void adjustmentChanged(GtkAdjustment*, gpointer);
99
100     ScrollView* view;
101     bool hasStaticBackground;
102     bool scrollbarsSuppressed;
103     ScrollbarMode vScrollbarMode;
104     ScrollbarMode hScrollbarMode;
105     RefPtr<ScrollViewScrollbar> vBar;
106     RefPtr<ScrollViewScrollbar> hBar;
107     IntSize scrollOffset;
108     IntSize contentsSize;
109     IntSize viewPortSize;
110     bool inUpdateScrollbars;
111     HashSet<Widget*> children;
112     GtkAdjustment* horizontalAdjustment;
113     GtkAdjustment* verticalAdjustment;
114 };
115
116 ScrollViewScrollbar::ScrollViewScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
117     : PlatformScrollbar(client, orientation, size)
118 {
119 }
120
121 void ScrollViewScrollbar::geometryChanged()
122 {
123     if (!parent())
124         return;
125
126     ASSERT(parent()->isFrameView());
127
128     FrameView* frameView = static_cast<FrameView*>(parent());
129     IntRect windowRect = IntRect(frameView->convertToContainingWindow(frameGeometry().location()), frameGeometry().size());
130     GtkAllocation allocation = { windowRect.x(), windowRect.y(), windowRect.width(), windowRect.height() };
131     gtk_widget_size_allocate(gtkWidget(), &allocation);
132 }
133
134 void ScrollView::ScrollViewPrivate::setHasHorizontalScrollbar(bool hasBar)
135 {
136     if (Scrollbar::hasPlatformScrollbars()) {
137         if (hasBar && !hBar && !horizontalAdjustment) {
138             hBar = new ScrollViewScrollbar(this, HorizontalScrollbar, RegularScrollbar);
139             view->addChild(hBar.get());
140         } else if (!hasBar && hBar) {
141             view->removeChild(hBar.get());
142             hBar = 0;
143         }
144     }
145 }
146
147 void ScrollView::ScrollViewPrivate::setHasVerticalScrollbar(bool hasBar)
148 {
149     if (Scrollbar::hasPlatformScrollbars()) {
150         if (hasBar && !vBar && !verticalAdjustment) {
151             vBar = new ScrollViewScrollbar(this, VerticalScrollbar, RegularScrollbar);
152             view->addChild(vBar.get());
153         } else if (!hasBar && vBar) {
154             view->removeChild(vBar.get());
155             vBar = 0;
156         }
157     }
158 }
159
160
161 void ScrollView::ScrollViewPrivate::scrollBackingStore(const IntSize& scrollDelta)
162 {
163     // Since scrolling is double buffered, we will be blitting the scroll view's intersection
164     // with the clip rect every time to keep it smooth.
165     IntRect clipRect = view->windowClipRect();
166     IntRect scrollViewRect = view->convertToContainingWindow(IntRect(0, 0, view->visibleWidth(), view->visibleHeight()));
167
168     IntRect updateRect = clipRect;
169     updateRect.intersect(scrollViewRect);
170
171     //FIXME update here?
172
173     if (!hasStaticBackground) // The main frame can just blit the WebView window
174        // FIXME: Find a way to blit subframes without blitting overlapping content
175        view->scrollBackingStore(-scrollDelta.width(), -scrollDelta.height(), scrollViewRect, clipRect);
176     else  {
177        // We need to go ahead and repaint the entire backing store.  Do it now before moving the
178        // plugins.
179        view->addToDirtyRegion(updateRect);
180        view->updateBackingStore();
181     }
182
183     view->geometryChanged();
184
185     // Now update the window (which should do nothing but a blit of the backing store's updateRect and so should
186     // be very fast).
187     view->update();
188 }
189
190 void ScrollView::ScrollViewPrivate::adjustmentChanged(GtkAdjustment* adjustment, gpointer _that)
191 {
192     ScrollViewPrivate* that = reinterpret_cast<ScrollViewPrivate*>(_that);
193
194     // Figure out if we really moved.
195     IntSize newOffset = that->scrollOffset;
196     if (adjustment == that->horizontalAdjustment)
197         newOffset.setWidth(static_cast<int>(gtk_adjustment_get_value(adjustment)));
198     else if (adjustment == that->verticalAdjustment)
199         newOffset.setHeight(static_cast<int>(gtk_adjustment_get_value(adjustment)));
200
201     IntSize scrollDelta = newOffset - that->scrollOffset;
202     if (scrollDelta == IntSize())
203         return;
204     that->scrollOffset = newOffset;
205
206     if (that->scrollbarsSuppressed)
207         return;
208
209     that->scrollBackingStore(scrollDelta);
210     static_cast<FrameView*>(that->view)->frame()->sendScrollEvent();
211 }
212
213 void ScrollView::ScrollViewPrivate::valueChanged(Scrollbar* bar)
214 {
215     // Figure out if we really moved.
216     IntSize newOffset = scrollOffset;
217     if (bar) {
218         if (bar == hBar)
219             newOffset.setWidth(bar->value());
220         else if (bar == vBar)
221             newOffset.setHeight(bar->value());
222     }
223     IntSize scrollDelta = newOffset - scrollOffset;
224     if (scrollDelta == IntSize())
225         return;
226     scrollOffset = newOffset;
227
228     if (scrollbarsSuppressed)
229         return;
230
231     scrollBackingStore(scrollDelta);
232     static_cast<FrameView*>(view)->frame()->sendScrollEvent();
233 }
234
235 IntRect ScrollView::ScrollViewPrivate::windowClipRect() const
236 {
237     return static_cast<const FrameView*>(view)->windowClipRect(false);
238 }
239
240 ScrollView::ScrollView()
241     : m_data(new ScrollViewPrivate(this))
242 {}
243
244 ScrollView::~ScrollView()
245 {
246     delete m_data;
247 }
248
249 /*  
250  * The following is assumed:
251  *   (hadj && vadj) || (!hadj && !vadj)
252  */ 
253 void ScrollView::setGtkAdjustments(GtkAdjustment* hadj, GtkAdjustment* vadj)
254 {
255     ASSERT(!hadj == !vadj);
256
257     if (m_data->horizontalAdjustment) {
258         g_signal_handlers_disconnect_by_func(G_OBJECT(m_data->horizontalAdjustment), (gpointer)ScrollViewPrivate::adjustmentChanged, m_data);
259         g_signal_handlers_disconnect_by_func(G_OBJECT(m_data->verticalAdjustment), (gpointer)ScrollViewPrivate::adjustmentChanged, m_data);
260         g_object_unref(m_data->horizontalAdjustment);
261         g_object_unref(m_data->verticalAdjustment);
262     }
263
264     m_data->horizontalAdjustment = hadj;
265     m_data->verticalAdjustment = vadj;
266
267     if (m_data->horizontalAdjustment) {
268         g_signal_connect(m_data->horizontalAdjustment, "value-changed", G_CALLBACK(ScrollViewPrivate::adjustmentChanged), m_data);
269         g_signal_connect(m_data->verticalAdjustment, "value-changed", G_CALLBACK(ScrollViewPrivate::adjustmentChanged), m_data);
270
271         /*
272          * disable the scrollbars (if we have any) as the GtkAdjustment over
273          */
274         m_data->setHasVerticalScrollbar(false);
275         m_data->setHasHorizontalScrollbar(false);
276
277         g_object_ref(m_data->horizontalAdjustment);
278         gtk_object_sink(GTK_OBJECT(m_data->horizontalAdjustment));
279         g_object_ref(m_data->verticalAdjustment);
280         gtk_object_sink(GTK_OBJECT(m_data->verticalAdjustment));
281     }
282
283     updateScrollbars(m_data->scrollOffset);
284 }
285
286 void ScrollView::updateContents(const IntRect& updateRect, bool now)
287 {
288     if (updateRect.isEmpty())
289         return;
290
291     IntPoint windowPoint = contentsToWindow(updateRect.location());
292     IntRect containingWindowRect = updateRect;
293     containingWindowRect.setLocation(windowPoint);
294
295     GdkRectangle rect = { containingWindowRect.x(),
296                           containingWindowRect.y(),
297                           containingWindowRect.width(),
298                           containingWindowRect.height() };
299     GdkWindow* window = GTK_WIDGET(containingWindow())->window;
300
301     if (window)
302         gdk_window_invalidate_rect(window, &rect, true);
303
304     // Cache the dirty spot.
305     addToDirtyRegion(containingWindowRect);
306
307     if (now && window)
308         gdk_window_process_updates(window, true);
309 }
310
311 void ScrollView::update()
312 {
313     ASSERT(containingWindow());
314
315     GdkRectangle rect = { 0, 0, m_data->contentsSize.width(), m_data->contentsSize.height() };
316     gdk_window_invalidate_rect(GTK_WIDGET(containingWindow())->window, &rect, true);
317 }
318
319 int ScrollView::visibleWidth() const
320 {
321     return width() - (m_data->vBar ? m_data->vBar->width() : 0);
322 }
323
324 int ScrollView::visibleHeight() const
325 {
326     return height() - (m_data->hBar ? m_data->hBar->height() : 0);
327 }
328
329 // Region of the content currently visible in the viewport in the content view's coordinate system.
330 FloatRect ScrollView::visibleContentRect() const
331 {
332     return FloatRect(contentsX(), contentsY(), visibleWidth(), visibleHeight());
333 }
334
335 FloatRect ScrollView::visibleContentRectConsideringExternalScrollers() const
336 {
337     // external scrollers not supported for now
338     return visibleContentRect();
339 }
340
341 void ScrollView::setContentsPos(int newX, int newY)
342 {
343     int dx = newX - contentsX();
344     int dy = newY - contentsY();
345     scrollBy(dx, dy);
346 }
347
348 void ScrollView::resizeContents(int w, int h)
349 {
350     IntSize newSize(w, h);
351     if (m_data->contentsSize == newSize)
352         return;
353
354     m_data->contentsSize = newSize;
355     updateScrollbars(m_data->scrollOffset);
356 }
357
358 int ScrollView::contentsX() const
359 {
360     return scrollOffset().width();
361 }
362
363 int ScrollView::contentsY() const
364 {
365     return scrollOffset().height();
366 }
367
368 int ScrollView::contentsWidth() const
369 {
370     return m_data->contentsSize.width();
371 }
372
373 int ScrollView::contentsHeight() const
374 {
375     return m_data->contentsSize.height();
376 }
377
378 IntSize ScrollView::scrollOffset() const
379 {
380     return m_data->scrollOffset;
381 }
382
383 IntSize ScrollView::maximumScroll() const
384 {
385     IntSize delta = (m_data->contentsSize - IntSize(visibleWidth(), visibleHeight())) - scrollOffset();
386     delta.clampNegativeToZero();
387     return delta;
388 }
389
390 void ScrollView::scrollBy(int dx, int dy)
391 {
392     IntSize scrollOffset = m_data->scrollOffset;
393     IntSize newScrollOffset = scrollOffset + IntSize(dx, dy).shrunkTo(maximumScroll());
394     newScrollOffset.clampNegativeToZero();
395  
396     if (newScrollOffset == scrollOffset)
397         return;
398
399     updateScrollbars(newScrollOffset);
400 }
401
402 ScrollbarMode ScrollView::hScrollbarMode() const
403 {
404     return m_data->hScrollbarMode;
405 }
406
407 ScrollbarMode ScrollView::vScrollbarMode() const
408 {
409     return m_data->vScrollbarMode;
410 }
411
412 void ScrollView::suppressScrollbars(bool suppressed, bool repaintOnSuppress)
413 {
414     m_data->scrollbarsSuppressed = suppressed;
415     if (repaintOnSuppress)
416         updateScrollbars(m_data->scrollOffset);
417 }
418
419 void ScrollView::setHScrollbarMode(ScrollbarMode newMode)
420 {
421     if (m_data->hScrollbarMode != newMode) {
422         m_data->hScrollbarMode = newMode;
423         updateScrollbars(m_data->scrollOffset);
424     }
425 }
426
427 void ScrollView::setVScrollbarMode(ScrollbarMode newMode)
428 {
429     if (m_data->vScrollbarMode != newMode) {
430         m_data->vScrollbarMode = newMode;
431         updateScrollbars(m_data->scrollOffset);
432     }
433 }
434
435 void ScrollView::setScrollbarsMode(ScrollbarMode newMode)
436 {
437     m_data->hScrollbarMode = m_data->vScrollbarMode = newMode;
438     updateScrollbars(m_data->scrollOffset);
439 }
440
441 void ScrollView::setStaticBackground(bool flag)
442 {
443     m_data->hasStaticBackground = flag;
444 }
445
446 void ScrollView::setFrameGeometry(const IntRect& newGeometry)
447 {
448     ASSERT(isFrameView());
449     IntRect oldGeometry = frameGeometry();
450     Widget::setFrameGeometry(newGeometry);
451
452     if (newGeometry == oldGeometry)
453         return;
454     if (newGeometry.width() != oldGeometry.width() || newGeometry.height() != oldGeometry.height()) {
455         updateScrollbars(m_data->scrollOffset);
456         static_cast<FrameView*>(this)->setNeedsLayout();
457     }
458
459     geometryChanged();
460 }
461
462 void ScrollView::addChild(Widget* child)
463
464     child->setParent(this);
465     child->setContainingWindow(containingWindow());
466     m_data->children.add(child);
467
468     if (child->gtkWidget())
469         gtk_container_add(GTK_CONTAINER(containingWindow()), child->gtkWidget());
470 }
471
472 void ScrollView::removeChild(Widget* child)
473 {
474     child->setParent(0);
475     m_data->children.remove(child);
476
477     if (child->gtkWidget() && GTK_WIDGET(containingWindow()) == GTK_WIDGET(child->gtkWidget())->parent)
478         gtk_container_remove(GTK_CONTAINER(containingWindow()), child->gtkWidget());
479 }
480
481 void ScrollView::scrollRectIntoViewRecursively(const IntRect& r)
482 {
483     IntPoint p(max(0, r.x()), max(0, r.y()));
484     ScrollView* view = this;
485     while (view) {
486         view->setContentsPos(p.x(), p.y());
487         p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height());
488         view = static_cast<ScrollView*>(view->parent());
489     }
490 }
491
492 bool ScrollView::inWindow() const
493 {
494     notImplemented();
495     return true;
496 }
497
498 void ScrollView::wheelEvent(PlatformWheelEvent& e)
499 {
500     // Determine how much we want to scroll.  If we can move at all, we will accept the event.
501     IntSize maxScrollDelta = maximumScroll();
502     if ((e.deltaX() < 0 && maxScrollDelta.width() > 0) ||
503         (e.deltaX() > 0 && scrollOffset().width() > 0) ||
504         (e.deltaY() < 0 && maxScrollDelta.height() > 0) ||
505         (e.deltaY() > 0 && scrollOffset().height() > 0))
506         e.accept();
507
508     scrollBy(e.deltaX() * LINE_STEP, e.deltaY() * LINE_STEP);
509 }
510
511 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
512 {
513     // Don't allow re-entrancy into this function.
514     if (m_data->inUpdateScrollbars)
515         return;
516
517     // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
518     // In the end, FrameView should just merge with ScrollView.
519     if (static_cast<const FrameView*>(this)->frame()->prohibitsScrolling())
520         return;
521
522     m_data->inUpdateScrollbars = true;
523
524     bool hasVerticalScrollbar = m_data->vBar;
525     bool hasHorizontalScrollbar = m_data->hBar;
526     bool oldHasVertical = hasVerticalScrollbar;
527     bool oldHasHorizontal = hasHorizontalScrollbar;
528     ScrollbarMode hScroll = m_data->hScrollbarMode;
529     ScrollbarMode vScroll = m_data->vScrollbarMode;
530
531     const int cVerticalWidth = PlatformScrollbar::verticalScrollbarWidth();
532     const int cHorizontalHeight = PlatformScrollbar::horizontalScrollbarHeight();
533
534     for (int pass = 0; pass < 2; pass++) {
535         bool scrollsVertically;
536         bool scrollsHorizontally;
537
538         if (!m_data->scrollbarsSuppressed && (hScroll == ScrollbarAuto || vScroll == ScrollbarAuto)) {
539             // Do a layout if pending before checking if scrollbars are needed.
540             if (hasVerticalScrollbar != oldHasVertical || hasHorizontalScrollbar != oldHasHorizontal)
541                 static_cast<FrameView*>(this)->layout();
542              
543             scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() > height());
544             if (scrollsVertically)
545                 scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() + cVerticalWidth > width());
546             else {
547                 scrollsHorizontally = (hScroll == ScrollbarAlwaysOn) || (hScroll == ScrollbarAuto && contentsWidth() > width());
548                 if (scrollsHorizontally)
549                     scrollsVertically = (vScroll == ScrollbarAlwaysOn) || (vScroll == ScrollbarAuto && contentsHeight() + cHorizontalHeight > height());
550             }
551         }
552         else {
553             scrollsHorizontally = (hScroll == ScrollbarAuto) ? hasHorizontalScrollbar : (hScroll == ScrollbarAlwaysOn);
554             scrollsVertically = (vScroll == ScrollbarAuto) ? hasVerticalScrollbar : (vScroll == ScrollbarAlwaysOn);
555         }
556         
557         if (hasVerticalScrollbar != scrollsVertically) {
558             m_data->setHasVerticalScrollbar(scrollsVertically);
559             hasVerticalScrollbar = scrollsVertically;
560         }
561
562         if (hasHorizontalScrollbar != scrollsHorizontally) {
563             m_data->setHasHorizontalScrollbar(scrollsHorizontally);
564             hasHorizontalScrollbar = scrollsHorizontally;
565         }
566     }
567
568     // Set up the range (and page step/line step).
569     IntSize maxScrollPosition(contentsWidth() - visibleWidth(), contentsHeight() - visibleHeight());
570     IntSize scroll = desiredOffset.shrunkTo(maxScrollPosition);
571     scroll.clampNegativeToZero();
572
573     if (m_data->horizontalAdjustment) {
574         m_data->horizontalAdjustment->page_size = visibleWidth();
575         m_data->horizontalAdjustment->step_increment = visibleWidth() / 10.0;
576         m_data->horizontalAdjustment->page_increment = visibleWidth() * 0.9;
577         m_data->horizontalAdjustment->upper = contentsWidth();
578         gtk_adjustment_changed(m_data->horizontalAdjustment);
579
580         if (m_data->scrollOffset.width() != scroll.width()) {
581             m_data->horizontalAdjustment->value = scroll.width();
582             gtk_adjustment_value_changed(m_data->horizontalAdjustment);
583         } 
584     } else if (m_data->hBar) {
585         int clientWidth = visibleWidth();
586         m_data->hBar->setEnabled(contentsWidth() > clientWidth);
587         int pageStep = (clientWidth - PAGE_KEEP);
588         if (pageStep < 0) pageStep = clientWidth;
589         IntRect oldRect(m_data->hBar->frameGeometry());
590         IntRect hBarRect = IntRect(0,
591                                    height() - m_data->hBar->height(),
592                                    width() - (m_data->vBar ? m_data->vBar->width() : 0),
593                                    m_data->hBar->height());
594         m_data->hBar->setRect(hBarRect);
595         if (!m_data->scrollbarsSuppressed && oldRect != m_data->hBar->frameGeometry())
596             m_data->hBar->invalidate();
597
598         if (m_data->scrollbarsSuppressed)
599             m_data->hBar->setSuppressInvalidation(true);
600         m_data->hBar->setSteps(LINE_STEP, pageStep);
601         m_data->hBar->setProportion(clientWidth, contentsWidth());
602         m_data->hBar->setValue(scroll.width());
603         if (m_data->scrollbarsSuppressed)
604             m_data->hBar->setSuppressInvalidation(false); 
605     } 
606
607     if (m_data->verticalAdjustment) {
608         m_data->verticalAdjustment->page_size = visibleHeight();
609         m_data->verticalAdjustment->step_increment = visibleHeight() / 10.0;
610         m_data->verticalAdjustment->page_increment = visibleHeight() * 0.9;
611         m_data->verticalAdjustment->upper = contentsHeight();
612         gtk_adjustment_changed(m_data->verticalAdjustment);
613
614         if (m_data->scrollOffset.height() != scroll.height()) {
615             m_data->verticalAdjustment->value = scroll.height();
616             gtk_adjustment_value_changed(m_data->verticalAdjustment);
617         }
618     } else if (m_data->vBar) {
619         int clientHeight = visibleHeight();
620         m_data->vBar->setEnabled(contentsHeight() > clientHeight);
621         int pageStep = (clientHeight - PAGE_KEEP);
622         if (pageStep < 0) pageStep = clientHeight;
623         IntRect oldRect(m_data->vBar->frameGeometry());
624         IntRect vBarRect = IntRect(width() - m_data->vBar->width(), 
625                                    0,
626                                    m_data->vBar->width(),
627                                    height() - (m_data->hBar ? m_data->hBar->height() : 0));
628         m_data->vBar->setRect(vBarRect);
629         if (!m_data->scrollbarsSuppressed && oldRect != m_data->vBar->frameGeometry())
630             m_data->vBar->invalidate();
631
632         if (m_data->scrollbarsSuppressed)
633             m_data->vBar->setSuppressInvalidation(true);
634         m_data->vBar->setSteps(LINE_STEP, pageStep);
635         m_data->vBar->setProportion(clientHeight, contentsHeight());
636         m_data->vBar->setValue(scroll.height());
637         if (m_data->scrollbarsSuppressed)
638             m_data->vBar->setSuppressInvalidation(false);
639     }
640
641     if (oldHasVertical != (m_data->vBar != 0) || oldHasHorizontal != (m_data->hBar != 0))
642         geometryChanged();
643
644     // See if our offset has changed in a situation where we might not have scrollbars.
645     // This can happen when editing a body with overflow:hidden and scrolling to reveal selection.
646     // It can also happen when maximizing a window that has scrollbars (but the new maximized result
647     // does not).
648     IntSize scrollDelta = scroll - m_data->scrollOffset;
649     if (scrollDelta != IntSize()) {
650        m_data->scrollOffset = scroll;
651        m_data->scrollBackingStore(scrollDelta);
652     }
653  
654     m_data->inUpdateScrollbars = false;
655 }
656
657 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
658
659     IntPoint viewPoint = convertFromContainingWindow(windowPoint);
660     return viewPoint + scrollOffset();
661 }
662
663 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
664 {
665     IntPoint viewPoint = contentsPoint - scrollOffset();
666     return convertToContainingWindow(viewPoint);  
667 }
668
669 PlatformScrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent)
670
671     IntPoint viewPoint = convertFromContainingWindow(mouseEvent.pos());
672     if (m_data->hBar && m_data->hBar->frameGeometry().contains(viewPoint))
673         return m_data->hBar.get();
674     if (m_data->vBar && m_data->vBar->frameGeometry().contains(viewPoint))
675         return m_data->vBar.get();
676     return 0;
677 }
678
679 IntPoint ScrollView::convertChildToSelf(const Widget* child, const IntPoint& point) const
680 {
681     IntPoint newPoint = point;
682     if (child != m_data->hBar && child != m_data->vBar)
683         newPoint = point - scrollOffset();
684     return Widget::convertChildToSelf(child, newPoint);
685 }
686
687 IntPoint ScrollView::convertSelfToChild(const Widget* child, const IntPoint& point) const
688 {
689     IntPoint newPoint = point;
690     if (child != m_data->hBar && child != m_data->vBar)
691         newPoint = point + scrollOffset();
692     return Widget::convertSelfToChild(child, newPoint);
693 }
694
695 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
696 {
697     // FIXME: This code is here so we don't have to fork FrameView.h/.cpp.
698     // In the end, FrameView should just merge with ScrollView.
699     ASSERT(isFrameView());
700
701     if (context->paintingDisabled())
702         return;
703
704     IntRect documentDirtyRect = rect;
705     documentDirtyRect.intersect(frameGeometry());
706
707     context->save();
708
709     context->translate(x(), y());
710     documentDirtyRect.move(-x(), -y());
711
712     context->translate(-contentsX(), -contentsY());
713     documentDirtyRect.move(contentsX(), contentsY());
714
715     context->clip(enclosingIntRect(visibleContentRect()));
716     static_cast<const FrameView*>(this)->frame()->paint(context, documentDirtyRect);
717     context->restore();
718
719     // Now paint the scrollbars.
720     if (!m_data->scrollbarsSuppressed && (m_data->hBar || m_data->vBar)) {
721         context->save();
722         IntRect scrollViewDirtyRect = rect;
723         scrollViewDirtyRect.intersect(frameGeometry());
724         context->translate(x(), y());
725         scrollViewDirtyRect.move(-x(), -y());
726         if (m_data->hBar)
727             m_data->hBar->paint(context, scrollViewDirtyRect);
728         if (m_data->vBar)
729             m_data->vBar->paint(context, scrollViewDirtyRect);
730
731         /*
732          * FIXME: TODO: Check if that works with RTL
733          */
734         // Fill the scroll corner with white.
735         IntRect hCorner;
736         if (m_data->hBar && width() - m_data->hBar->width() > 0) {
737             hCorner = IntRect(m_data->hBar->width(),
738                               height() - m_data->hBar->height(),
739                               width() - m_data->hBar->width(),
740                               m_data->hBar->height());
741             if (hCorner.intersects(scrollViewDirtyRect))
742                 context->fillRect(hCorner, Color::white);
743         }
744
745         if (m_data->vBar && height() - m_data->vBar->height() > 0) {
746             IntRect vCorner(width() - m_data->vBar->width(),
747                             m_data->vBar->height(),
748                             m_data->vBar->width(),
749                             height() - m_data->vBar->height());
750             if (vCorner != hCorner && vCorner.intersects(scrollViewDirtyRect))
751                 context->fillRect(vCorner, Color::white);
752         }
753
754         context->restore();
755     }
756 }
757
758 /*
759  * update children but nor our scrollbars. They should not scroll when
760  * we scroll our content.
761  */
762 void ScrollView::geometryChanged() const
763 {
764     HashSet<Widget*>::const_iterator end = m_data->children.end();
765     for (HashSet<Widget*>::const_iterator current = m_data->children.begin(); current != end; ++current)
766         (*current)->geometryChanged();
767 }
768
769 void ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
770 {
771     if  ((direction == ScrollUp || direction == ScrollDown) && m_data->vBar)
772         m_data->vBar->scroll(direction, granularity);
773     else if (m_data->hBar)
774         m_data->hBar->scroll(direction, granularity);
775 }
776
777 void ScrollView::addToDirtyRegion(const IntRect& containingWindowRect)
778 {
779     ASSERT(isFrameView());
780     const FrameView* frameView = static_cast<const FrameView*>(this);
781     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
782     if (!page)
783         return;
784     page->chrome()->addToDirtyRegion(containingWindowRect);
785 }
786
787 void ScrollView::scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect)
788 {
789     ASSERT(isFrameView());
790     const FrameView* frameView = static_cast<const FrameView*>(this);
791     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
792     if (!page)
793         return;
794     page->chrome()->scrollBackingStore(dx, dy, scrollViewRect, clipRect);
795 }
796
797 void ScrollView::updateBackingStore()
798 {
799     ASSERT(isFrameView());
800     const FrameView* frameView = static_cast<const FrameView*>(this);
801     Page* page = frameView->frame() ? frameView->frame()->page() : 0;
802     if (!page)
803         return;
804     page->chrome()->updateBackingStore();
805 }
806
807 HashSet<Widget*>* ScrollView::children() const
808 {
809     return &m_data->children;
810 }
811
812 }