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