Replace 'i < len-1 && func(i+1)' by 'i+1 < len && func(i+1)'
[profile/ivi/qtbase.git] / src / gui / painting / qbackingstore.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include "qplatformdefs.h"
44
45 #include "qbackingstore_p.h"
46
47 #include <QtCore/qglobal.h>
48 #include <QtCore/qdebug.h>
49 #include <QtCore/qvarlengtharray.h>
50 #include <QtGui/qevent.h>
51 #include <QtGui/qapplication.h>
52 #include <QtGui/qpaintengine.h>
53 #include <QtGui/qgraphicsproxywidget.h>
54
55 #include <private/qwidget_p.h>
56 #include <private/qwindowsurface_raster_p.h>
57 #include <private/qapplication_p.h>
58 #include <private/qpaintengine_raster_p.h>
59 #include <private/qgraphicseffect_p.h>
60
61 #include "qgraphicssystem_p.h"
62
63 #ifdef Q_WS_QWS
64 #include <QtGui/qwsmanager_qws.h>
65 #include <private/qwsmanager_p.h>
66 #endif
67
68 QT_BEGIN_NAMESPACE
69
70 extern QRegion qt_dirtyRegion(QWidget *);
71
72 /*
73    A version of QRect::intersects() that does not normalize the rects.
74 */
75 static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
76 {
77     return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right())
78             && qMax(r1.top(), r2.top()) <= qMin(r1.bottom(), r2.bottom()));
79 }
80
81 /**
82  * Flushes the contents of the \a windowSurface into the screen area of \a widget.
83  * \a tlwOffset is the position of the top level widget relative to the window surface.
84  * \a region is the region to be updated in \a widget coordinates.
85  */
86 static inline void qt_flush(QWidget *widget, const QRegion &region, QWindowSurface *windowSurface,
87                             QWidget *tlw, const QPoint &tlwOffset)
88 {
89     Q_ASSERT(widget);
90     Q_ASSERT(!region.isEmpty());
91     Q_ASSERT(windowSurface);
92     Q_ASSERT(tlw);
93
94 #if !defined(QT_NO_PAINT_DEBUG) && !defined(Q_WS_QWS)
95     // QWS does flush update in QWindowSurface::flush (because it needs to lock the surface etc).
96     static int flushUpdate = qgetenv("QT_FLUSH_UPDATE").toInt();
97     if (flushUpdate > 0)
98         QWidgetBackingStore::showYellowThing(widget, region, flushUpdate * 10, false);
99 #endif
100
101     //The performance hit by doing this should be negligible. However, be aware that
102     //using this FPS when you have > 1 windowsurface can give you inaccurate FPS
103     static bool fpsDebug = qgetenv("QT_DEBUG_FPS").toInt();
104     if (fpsDebug) {
105         static QTime time = QTime::currentTime();
106         static int frames = 0;
107
108         frames++;
109
110         if(time.elapsed() > 5000) {
111             double fps = double(frames * 1000) /time.restart();
112             fprintf(stderr,"FPS: %.1f\n",fps);
113             frames = 0;
114         }
115     }
116     if (widget != tlw)
117         windowSurface->flush(widget, region, tlwOffset + widget->mapTo(tlw, QPoint()));
118     else
119         windowSurface->flush(widget, region, tlwOffset);
120 }
121
122 #ifndef QT_NO_PAINT_DEBUG
123 #ifdef Q_WS_WIN
124 static void showYellowThing_win(QWidget *widget, const QRegion &region, int msec)
125 {
126     HBRUSH brush;
127     static int i = 0;
128     switch (i) {
129     case 0:
130         brush = CreateSolidBrush(RGB(255, 255, 0));
131         break;
132     case 1:
133         brush = CreateSolidBrush(RGB(255, 200, 55));
134         break;
135     case 2:
136         brush = CreateSolidBrush(RGB(200, 255, 55));
137         break;
138     case 3:
139         brush = CreateSolidBrush(RGB(200, 200, 0));
140         break;
141     }
142     i = (i + 1) & 3;
143
144     HDC hdc = widget->getDC();
145
146     const QVector<QRect> &rects = region.rects();
147     foreach (QRect rect, rects) {
148         RECT winRect;
149         SetRect(&winRect, rect.left(), rect.top(), rect.right(), rect.bottom());
150         FillRect(hdc, &winRect, brush);
151     }
152
153     widget->releaseDC(hdc);
154     ::Sleep(msec);
155 }
156 #endif
157
158 void QWidgetBackingStore::showYellowThing(QWidget *widget, const QRegion &toBePainted, int msec, bool unclipped)
159 {
160 #ifdef Q_WS_QWS
161     Q_UNUSED(widget);
162     Q_UNUSED(unclipped);
163     static QWSYellowSurface surface(true);
164     surface.setDelay(msec);
165     surface.flush(widget, toBePainted, QPoint());
166 #else
167     QRegion paintRegion = toBePainted;
168     QRect widgetRect = widget->rect();
169
170     if (!widget->internalWinId()) {
171         QWidget *nativeParent = widget->nativeParentWidget();
172         const QPoint offset = widget->mapTo(nativeParent, QPoint(0, 0));
173         paintRegion.translate(offset);
174         widgetRect.translate(offset);
175         widget = nativeParent;
176     }
177
178 #ifdef Q_WS_WIN
179     Q_UNUSED(unclipped);
180     showYellowThing_win(widget, paintRegion, msec);
181 #else
182     //flags to fool painter
183     bool paintUnclipped = widget->testAttribute(Qt::WA_PaintUnclipped);
184     if (unclipped && !widget->d_func()->paintOnScreen())
185         widget->setAttribute(Qt::WA_PaintUnclipped);
186
187     const bool setFlag = !widget->testAttribute(Qt::WA_WState_InPaintEvent);
188     if (setFlag)
189         widget->setAttribute(Qt::WA_WState_InPaintEvent);
190
191     //setup the engine
192     QPaintEngine *pe = widget->paintEngine();
193     if (pe) {
194         pe->setSystemClip(paintRegion);
195         {
196             QPainter p(widget);
197             p.setClipRegion(paintRegion);
198             static int i = 0;
199             switch (i) {
200             case 0:
201                 p.fillRect(widgetRect, QColor(255,255,0));
202                 break;
203             case 1:
204                 p.fillRect(widgetRect, QColor(255,200,55));
205                 break;
206             case 2:
207                 p.fillRect(widgetRect, QColor(200,255,55));
208                 break;
209             case 3:
210                 p.fillRect(widgetRect, QColor(200,200,0));
211                 break;
212             }
213             i = (i+1) & 3;
214             p.end();
215         }
216     }
217
218     if (setFlag)
219         widget->setAttribute(Qt::WA_WState_InPaintEvent, false);
220
221     //restore
222     widget->setAttribute(Qt::WA_PaintUnclipped, paintUnclipped);
223
224     if (pe)
225         pe->setSystemClip(QRegion());
226
227     QApplication::syncX();
228
229 #if defined(Q_OS_UNIX)
230     ::usleep(1000 * msec);
231 #endif
232 #endif // Q_WS_WIN
233 #endif // Q_WS_QWS
234 }
235
236 bool QWidgetBackingStore::flushPaint(QWidget *widget, const QRegion &rgn)
237 {
238     if (!widget)
239         return false;
240
241     int delay = 0;
242     if (widget->testAttribute(Qt::WA_WState_InPaintEvent)) {
243         static int flushPaintEvent = qgetenv("QT_FLUSH_PAINT_EVENT").toInt();
244         if (!flushPaintEvent)
245             return false;
246         delay = flushPaintEvent;
247     } else {
248         static int flushPaint = qgetenv("QT_FLUSH_PAINT").toInt();
249         if (!flushPaint)
250             return false;
251         delay = flushPaint;
252     }
253
254     QWidgetBackingStore::showYellowThing(widget, rgn, delay * 10, true);
255     return true;
256 }
257
258 void QWidgetBackingStore::unflushPaint(QWidget *widget, const QRegion &rgn)
259 {
260     if (widget->d_func()->paintOnScreen() || rgn.isEmpty())
261         return;
262
263     QWidget *tlw = widget->window();
264     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
265     if (!tlwExtra)
266         return;
267
268     const QPoint offset = widget->mapTo(tlw, QPoint());
269     qt_flush(widget, rgn, tlwExtra->backingStore->windowSurface, tlw, offset);
270 }
271 #endif // QT_NO_PAINT_DEBUG
272
273 /*
274     Moves the whole rect by (dx, dy) in widget's coordinate system.
275     Doesn't generate any updates.
276 */
277 bool QWidgetBackingStore::bltRect(const QRect &rect, int dx, int dy, QWidget *widget)
278 {
279     const QPoint pos(tlwOffset + widget->mapTo(tlw, rect.topLeft()));
280     const QRect tlwRect(QRect(pos, rect.size()));
281     if (fullUpdatePending || dirty.intersects(tlwRect))
282         return false; // We don't want to scroll junk.
283     return windowSurface->scroll(tlwRect, dx, dy);
284 }
285
286 void QWidgetBackingStore::releaseBuffer()
287 {
288     if (windowSurface)
289 #if defined(Q_WS_QPA)
290         windowSurface->resize(QSize());
291 #else
292         windowSurface->setGeometry(QRect());
293 #endif
294 #ifdef Q_BACKINGSTORE_SUBSURFACES
295     for (int i = 0; i < subSurfaces.size(); ++i)
296         subSurfaces.at(i)->setGeometry(QRect());
297 #endif
298 }
299
300 /*!
301     Prepares the window surface to paint a\ toClean region of the \a widget and
302     updates the BeginPaintInfo struct accordingly.
303
304     The \a toClean region might be clipped by the window surface.
305 */
306 void QWidgetBackingStore::beginPaint(QRegion &toClean, QWidget *widget, QWindowSurface *windowSurface,
307                                      BeginPaintInfo *returnInfo, bool toCleanIsInTopLevelCoordinates)
308 {
309 #ifdef Q_WS_QWS
310     QWSWindowSurface *surface = static_cast<QWSWindowSurface *>(windowSurface);
311     QWidget *surfaceWidget = surface->window();
312
313     if (!surface->isValid()) {
314         // this looks strange but it really just releases the surface
315         surface->releaseSurface();
316         // the old window surface is deleted in setWindowSurface, which is
317         // called from QWindowSurface constructor.
318         windowSurface = tlw->d_func()->createDefaultWindowSurface();
319         surface = static_cast<QWSWindowSurface *>(windowSurface);
320         // createDefaultWindowSurface() will set topdata->windowSurface on the
321         // widget to zero. However, if this is a sub-surface, it should point
322         // to the widget's sub windowSurface, so we set that here:
323         if (!surfaceWidget->isWindow())
324             surfaceWidget->d_func()->topData()->windowSurface = windowSurface;
325         surface->setGeometry(topLevelRect());
326         returnInfo->windowSurfaceRecreated = true;
327     }
328
329     const QRegion toCleanUnclipped(toClean);
330
331     if (surfaceWidget->isWindow())
332         tlwOffset = surface->painterOffset();
333 #ifdef Q_BACKINGSTORE_SUBSURFACES
334     else if (toCleanIsInTopLevelCoordinates)
335         toClean &= surface->clipRegion().translated(surfaceWidget->mapTo(tlw, QPoint()));
336     if (!toCleanIsInTopLevelCoordinates && windowSurface == this->windowSurface)
337         toClean &= surface->clipRegion().translated(-widget->mapTo(surfaceWidget, QPoint()));
338 #else
339     toClean &= surface->clipRegion();
340 #endif
341
342     if (toClean.isEmpty()) {
343         if (surfaceWidget->isWindow()) {
344             dirtyFromPreviousSync += toCleanUnclipped;
345             hasDirtyFromPreviousSync = true;
346         }
347
348         returnInfo->nothingToPaint = true;
349         // Nothing to repaint. However, we might have newly exposed areas on the
350         // screen, so we have to make sure those are flushed.
351         flush();
352         return;
353     }
354
355     if (surfaceWidget->isWindow()) {
356         if (toCleanUnclipped != toClean) {
357             dirtyFromPreviousSync += (toCleanUnclipped - surface->clipRegion());
358             hasDirtyFromPreviousSync = true;
359         }
360         if (hasDirtyFromPreviousSync) {
361             dirtyFromPreviousSync -= toClean;
362             hasDirtyFromPreviousSync = !dirtyFromPreviousSync.isEmpty();
363         }
364     }
365
366 #endif // Q_WS_QWS
367
368     Q_UNUSED(widget);
369     Q_UNUSED(toCleanIsInTopLevelCoordinates);
370
371     // Always flush repainted areas.
372     dirtyOnScreen += toClean;
373
374 #if defined(Q_WS_QWS) && !defined(Q_BACKINGSTORE_SUBSURFACES)
375     toClean.translate(tlwOffset);
376 #endif
377
378 #ifdef QT_NO_PAINT_DEBUG
379     windowSurface->beginPaint(toClean);
380 #else
381     returnInfo->wasFlushed = QWidgetBackingStore::flushPaint(tlw, toClean);
382     // Avoid deadlock with QT_FLUSH_PAINT: the server will wait for
383     // the BackingStore lock, so if we hold that, the server will
384     // never release the Communication lock that we are waiting for in
385     // sendSynchronousCommand
386     if (!returnInfo->wasFlushed)
387         windowSurface->beginPaint(toClean);
388 #endif
389
390     Q_UNUSED(returnInfo);
391 }
392
393 void QWidgetBackingStore::endPaint(const QRegion &cleaned, QWindowSurface *windowSurface,
394         BeginPaintInfo *beginPaintInfo)
395 {
396 #ifndef QT_NO_PAINT_DEBUG
397     if (!beginPaintInfo->wasFlushed)
398         windowSurface->endPaint(cleaned);
399     else
400         QWidgetBackingStore::unflushPaint(tlw, cleaned);
401 #else
402     Q_UNUSED(beginPaintInfo);
403     windowSurface->endPaint(cleaned);
404 #endif
405
406 #ifdef Q_BACKINGSTORE_SUBSURFACES
407     flush(static_cast<QWSWindowSurface *>(windowSurface)->window(), windowSurface);
408 #else
409     flush();
410 #endif
411 }
412
413 /*!
414     Returns the region (in top-level coordinates) that needs repaint and/or flush.
415
416     If the widget is non-zero, only the dirty region for the widget is returned
417     and the region will be in widget coordinates.
418 */
419 QRegion QWidgetBackingStore::dirtyRegion(QWidget *widget) const
420 {
421     const bool widgetDirty = widget && widget != tlw;
422     const QRect tlwRect(topLevelRect());
423 #if defined(Q_WS_QPA)
424     const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size());
425 #else
426     const QRect surfaceGeometry(windowSurface->geometry());
427 #endif
428     if (fullUpdatePending || (surfaceGeometry != tlwRect && surfaceGeometry.size() != tlwRect.size())) {
429         if (widgetDirty) {
430             const QRect dirtyTlwRect = QRect(QPoint(), tlwRect.size());
431             const QPoint offset(widget->mapTo(tlw, QPoint()));
432             const QRect dirtyWidgetRect(dirtyTlwRect & widget->rect().translated(offset));
433             return dirtyWidgetRect.translated(-offset);
434         }
435         return QRect(QPoint(), tlwRect.size());
436     }
437
438     // Calculate the region that needs repaint.
439     QRegion r(dirty);
440     for (int i = 0; i < dirtyWidgets.size(); ++i) {
441         QWidget *w = dirtyWidgets.at(i);
442         if (widgetDirty && w != widget && !widget->isAncestorOf(w))
443             continue;
444         r += w->d_func()->dirty.translated(w->mapTo(tlw, QPoint()));
445     }
446
447     // Append the region that needs flush.
448     r += dirtyOnScreen;
449
450     if (dirtyOnScreenWidgets) { // Only in use with native child widgets.
451         for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
452             QWidget *w = dirtyOnScreenWidgets->at(i);
453             if (widgetDirty && w != widget && !widget->isAncestorOf(w))
454                 continue;
455             QWidgetPrivate *wd = w->d_func();
456             Q_ASSERT(wd->needsFlush);
457             r += wd->needsFlush->translated(w->mapTo(tlw, QPoint()));
458         }
459     }
460
461     if (widgetDirty) {
462         // Intersect with the widget geometry and translate to its coordinates.
463         const QPoint offset(widget->mapTo(tlw, QPoint()));
464         r &= widget->rect().translated(offset);
465         r.translate(-offset);
466     }
467     return r;
468 }
469
470 /*!
471     Returns the static content inside the \a parent if non-zero; otherwise the static content
472     for the entire backing store is returned. The content will be clipped to \a withinClipRect
473     if non-empty.
474 */
475 QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &withinClipRect) const
476 {
477     if (!parent && tlw->testAttribute(Qt::WA_StaticContents)) {
478 #if defined(Q_WS_QPA)
479         const QSize surfaceGeometry(windowSurface->size());
480 #else
481         const QRect surfaceGeometry(windowSurface->geometry());
482 #endif
483         QRect surfaceRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
484         if (!withinClipRect.isEmpty())
485             surfaceRect &= withinClipRect;
486         return QRegion(surfaceRect);
487     }
488
489     QRegion region;
490     if (parent && parent->d_func()->children.isEmpty())
491         return region;
492
493     const bool clipToRect = !withinClipRect.isEmpty();
494     const int count = staticWidgets.count();
495     for (int i = 0; i < count; ++i) {
496         QWidget *w = staticWidgets.at(i);
497         QWidgetPrivate *wd = w->d_func();
498         if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty()
499             || !w->isVisible() || (parent && !parent->isAncestorOf(w))) {
500             continue;
501         }
502
503         QRect rect(0, 0, wd->extra->staticContentsSize.width(), wd->extra->staticContentsSize.height());
504         const QPoint offset = w->mapTo(parent ? parent : tlw, QPoint());
505         if (clipToRect)
506             rect &= withinClipRect.translated(-offset);
507         if (rect.isEmpty())
508             continue;
509
510         rect &= wd->clipRect();
511         if (rect.isEmpty())
512             continue;
513
514         QRegion visible(rect);
515         wd->clipToEffectiveMask(visible);
516         if (visible.isEmpty())
517             continue;
518         wd->subtractOpaqueSiblings(visible, 0, /*alsoNonOpaque=*/true);
519
520         visible.translate(offset);
521         region += visible;
522     }
523
524     return region;
525 }
526
527 static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
528 {
529     if (!widget)
530         return;
531
532     if (updateImmediately) {
533         QEvent event(QEvent::UpdateRequest);
534         QApplication::sendEvent(widget, &event);
535     } else {
536         QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
537     }
538 }
539
540 /*!
541     Marks the region of the widget as dirty (if not already marked as dirty) and
542     posts an UpdateRequest event to the top-level widget (if not already posted).
543
544     If updateImmediately is true, the event is sent immediately instead of posted.
545
546     If invalidateBuffer is true, all widgets intersecting with the region will be dirty.
547
548     If the widget paints directly on screen, the event is sent to the widget
549     instead of the top-level widget, and invalidateBuffer is completely ignored.
550
551     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
552 */
553 void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool updateImmediately,
554                                     bool invalidateBuffer)
555 {
556     Q_ASSERT(tlw->d_func()->extra);
557     Q_ASSERT(tlw->d_func()->extra->topextra);
558     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
559     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
560     Q_ASSERT(widget->window() == tlw);
561     Q_ASSERT(!rgn.isEmpty());
562
563 #ifndef QT_NO_GRAPHICSEFFECT
564     widget->d_func()->invalidateGraphicsEffectsRecursively();
565 #endif //QT_NO_GRAPHICSEFFECT
566
567     if (widget->d_func()->paintOnScreen()) {
568         if (widget->d_func()->dirty.isEmpty()) {
569             widget->d_func()->dirty = rgn;
570             sendUpdateRequest(widget, updateImmediately);
571             return;
572         } else if (qt_region_strictContains(widget->d_func()->dirty, widget->rect())) {
573             if (updateImmediately)
574                 sendUpdateRequest(widget, updateImmediately);
575             return; // Already dirty.
576         }
577
578         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
579         widget->d_func()->dirty += rgn;
580         if (!eventAlreadyPosted || updateImmediately)
581             sendUpdateRequest(widget, updateImmediately);
582         return;
583     }
584
585     if (fullUpdatePending) {
586         if (updateImmediately)
587             sendUpdateRequest(tlw, updateImmediately);
588         return;
589     }
590
591     if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) {
592         fullUpdatePending = true;
593         sendUpdateRequest(tlw, updateImmediately);
594         return;
595     }
596
597     const QPoint offset = widget->mapTo(tlw, QPoint());
598     const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
599     if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
600         if (updateImmediately)
601             sendUpdateRequest(tlw, updateImmediately);
602         return; // Already dirty.
603     }
604
605     if (invalidateBuffer) {
606         const bool eventAlreadyPosted = !dirty.isEmpty();
607 #ifndef QT_NO_GRAPHICSEFFECT
608         if (widget->d_func()->graphicsEffect)
609             dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
610         else
611 #endif //QT_NO_GRAPHICSEFFECT
612             dirty += rgn.translated(offset);
613         if (!eventAlreadyPosted || updateImmediately)
614             sendUpdateRequest(tlw, updateImmediately);
615         return;
616     }
617
618     if (dirtyWidgets.isEmpty()) {
619         addDirtyWidget(widget, rgn);
620         sendUpdateRequest(tlw, updateImmediately);
621         return;
622     }
623
624     if (widget->d_func()->inDirtyList) {
625         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect)) {
626 #ifndef QT_NO_GRAPHICSEFFECT
627             if (widget->d_func()->graphicsEffect)
628                 widget->d_func()->dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect());
629             else
630 #endif //QT_NO_GRAPHICSEFFECT
631                 widget->d_func()->dirty += rgn;
632         }
633     } else {
634         addDirtyWidget(widget, rgn);
635     }
636
637     if (updateImmediately)
638         sendUpdateRequest(tlw, updateImmediately);
639 }
640
641 /*!
642     This function is equivalent to calling markDirty(QRegion(rect), ...), but
643     is more efficient as it eliminates QRegion operations/allocations and can
644     use the rect more precisely for additional cut-offs.
645
646     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
647 */
648 void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,
649                                     bool invalidateBuffer)
650 {
651     Q_ASSERT(tlw->d_func()->extra);
652     Q_ASSERT(tlw->d_func()->extra->topextra);
653     Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
654     Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
655     Q_ASSERT(widget->window() == tlw);
656     Q_ASSERT(!rect.isEmpty());
657
658 #ifndef QT_NO_GRAPHICSEFFECT
659     widget->d_func()->invalidateGraphicsEffectsRecursively();
660 #endif //QT_NO_GRAPHICSEFFECT
661
662     if (widget->d_func()->paintOnScreen()) {
663         if (widget->d_func()->dirty.isEmpty()) {
664             widget->d_func()->dirty = QRegion(rect);
665             sendUpdateRequest(widget, updateImmediately);
666             return;
667         } else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
668             if (updateImmediately)
669                 sendUpdateRequest(widget, updateImmediately);
670             return; // Already dirty.
671         }
672
673         const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
674         widget->d_func()->dirty += rect;
675         if (!eventAlreadyPosted || updateImmediately)
676             sendUpdateRequest(widget, updateImmediately);
677         return;
678     }
679
680     if (fullUpdatePending) {
681         if (updateImmediately)
682             sendUpdateRequest(tlw, updateImmediately);
683         return;
684     }
685
686     if (!windowSurface->hasFeature(QWindowSurface::PartialUpdates)) {
687         fullUpdatePending = true;
688         sendUpdateRequest(tlw, updateImmediately);
689         return;
690     }
691
692     const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
693     const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
694     if (qt_region_strictContains(dirty, translatedRect)) {
695         if (updateImmediately)
696             sendUpdateRequest(tlw, updateImmediately);
697         return; // Already dirty
698     }
699
700     if (invalidateBuffer) {
701         const bool eventAlreadyPosted = !dirty.isEmpty();
702         dirty += translatedRect;
703         if (!eventAlreadyPosted || updateImmediately)
704             sendUpdateRequest(tlw, updateImmediately);
705         return;
706     }
707
708     if (dirtyWidgets.isEmpty()) {
709         addDirtyWidget(widget, rect);
710         sendUpdateRequest(tlw, updateImmediately);
711         return;
712     }
713
714     if (widget->d_func()->inDirtyList) {
715         if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
716             widget->d_func()->dirty += widgetRect;
717     } else {
718         addDirtyWidget(widget, rect);
719     }
720
721     if (updateImmediately)
722         sendUpdateRequest(tlw, updateImmediately);
723 }
724
725 /*!
726     Marks the \a region of the \a widget as dirty on screen. The \a region will be copied from
727     the backing store to the \a widget's native parent next time flush() is called.
728
729     Paint on screen widgets are ignored.
730 */
731 void QWidgetBackingStore::markDirtyOnScreen(const QRegion &region, QWidget *widget, const QPoint &topLevelOffset)
732 {
733     if (!widget || widget->d_func()->paintOnScreen() || region.isEmpty())
734         return;
735
736 #if defined(Q_WS_QWS) || defined(Q_WS_MAC)
737     if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
738         dirtyOnScreen += region.translated(topLevelOffset);
739     return;
740 #endif
741
742     // Top-level.
743     if (widget == tlw) {
744         if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
745             dirtyOnScreen += region;
746         return;
747     }
748
749     // Alien widgets.
750     if (!widget->internalWinId() && !widget->isWindow()) {
751         QWidget *nativeParent = widget->nativeParentWidget();        // Alien widgets with the top-level as the native parent (common case).
752         if (nativeParent == tlw) {
753             if (!widget->testAttribute(Qt::WA_WState_InPaintEvent))
754                 dirtyOnScreen += region.translated(topLevelOffset);
755             return;
756         }
757
758         // Alien widgets with native parent != tlw.
759         QWidgetPrivate *nativeParentPrivate = nativeParent->d_func();
760         if (!nativeParentPrivate->needsFlush)
761             nativeParentPrivate->needsFlush = new QRegion;
762         const QPoint nativeParentOffset = widget->mapTo(nativeParent, QPoint());
763         *nativeParentPrivate->needsFlush += region.translated(nativeParentOffset);
764         appendDirtyOnScreenWidget(nativeParent);
765         return;
766     }
767
768     // Native child widgets.
769     QWidgetPrivate *widgetPrivate = widget->d_func();
770     if (!widgetPrivate->needsFlush)
771         widgetPrivate->needsFlush = new QRegion;
772     *widgetPrivate->needsFlush += region;
773     appendDirtyOnScreenWidget(widget);
774 }
775
776 void QWidgetBackingStore::removeDirtyWidget(QWidget *w)
777 {
778     if (!w)
779         return;
780
781     dirtyWidgetsRemoveAll(w);
782     dirtyOnScreenWidgetsRemoveAll(w);
783     resetWidget(w);
784
785     QWidgetPrivate *wd = w->d_func();
786     const int n = wd->children.count();
787     for (int i = 0; i < n; ++i) {
788         if (QWidget *child = qobject_cast<QWidget*>(wd->children.at(i)))
789             removeDirtyWidget(child);
790     }
791 }
792
793 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
794 bool QWidgetBackingStore::hasDirtyWindowDecoration() const
795 {
796     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
797     if (tlwExtra && tlwExtra->qwsManager)
798         return !tlwExtra->qwsManager->d_func()->dirtyRegions.isEmpty();
799     return false;
800 }
801
802 void QWidgetBackingStore::paintWindowDecoration()
803 {
804     if (!hasDirtyWindowDecoration())
805         return;
806
807     QDecoration &decoration = QApplication::qwsDecoration();
808     const QRect decorationRect = tlw->rect();
809     QRegion decorationRegion = decoration.region(tlw, decorationRect);
810
811     QWSManagerPrivate *managerPrivate = tlw->d_func()->topData()->qwsManager->d_func();
812     const bool doClipping = !managerPrivate->entireDecorationNeedsRepaint
813                             && !managerPrivate->dirtyClip.isEmpty();
814
815     if (doClipping) {
816         decorationRegion &= static_cast<QWSWindowSurface *>(windowSurface)->clipRegion();
817         decorationRegion &= managerPrivate->dirtyClip;
818     }
819
820     if (decorationRegion.isEmpty())
821         return;
822
823     //### The QWS decorations do not always paint the pixels they promise to paint.
824     // This causes painting problems with QWSMemorySurface. Since none of the other
825     // window surfaces actually use the region, passing an empty region is a safe
826     // workaround.
827
828     windowSurface->beginPaint(QRegion());
829
830     QPaintEngine *engine = windowSurface->paintDevice()->paintEngine();
831     Q_ASSERT(engine);
832     const QRegion oldSystemClip(engine->systemClip());
833     engine->setSystemClip(decorationRegion.translated(tlwOffset));
834
835     QPainter painter(windowSurface->paintDevice());
836     painter.setFont(QApplication::font());
837     painter.translate(tlwOffset);
838
839     const int numDirty = managerPrivate->dirtyRegions.size();
840     for (int i = 0; i < numDirty; ++i) {
841         const int area = managerPrivate->dirtyRegions.at(i);
842
843         QRegion clipRegion = decoration.region(tlw, decorationRect, area);
844         if (!clipRegion.isEmpty()) {
845             // Decoration styles changes the clip and assumes the old clip is non-empty,
846             // so we have to set it, but in theory it shouldn't be required.
847             painter.setClipRegion(clipRegion);
848             decoration.paint(&painter, tlw, area, managerPrivate->dirtyStates.at(i));
849         }
850     }
851     markDirtyOnScreen(decorationRegion, tlw, QPoint());
852
853     painter.end();
854     windowSurface->endPaint(decorationRegion);
855     managerPrivate->clearDirtyRegions();
856     engine->setSystemClip(oldSystemClip);
857 }
858 #endif
859
860 void QWidgetBackingStore::updateLists(QWidget *cur)
861 {
862     if (!cur)
863         return;
864
865     QList<QObject*> children = cur->children();
866     for (int i = 0; i < children.size(); ++i) {
867         QWidget *child = qobject_cast<QWidget*>(children.at(i));
868         if (!child)
869             continue;
870
871         updateLists(child);
872     }
873
874     if (cur->testAttribute(Qt::WA_StaticContents))
875         addStaticWidget(cur);
876
877 #ifdef Q_BACKINGSTORE_SUBSURFACES
878     QTLWExtra *extra = cur->d_func()->maybeTopData();
879     if (extra && extra->windowSurface && cur != tlw)
880         subSurfaces.append(extra->windowSurface);
881 #endif
882 }
883
884 QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
885     : tlw(topLevel), dirtyOnScreenWidgets(0), hasDirtyFromPreviousSync(false)
886     , fullUpdatePending(0)
887 {
888     windowSurface = tlw->windowSurface();
889     if (!windowSurface)
890         windowSurface = topLevel->d_func()->createDefaultWindowSurface();
891
892     // The QWindowSurface constructor will call QWidget::setWindowSurface(),
893     // but automatically created surfaces should not be added to the topdata.
894 #ifdef Q_BACKINGSTORE_SUBSURFACES
895     Q_ASSERT(topLevel->d_func()->topData()->windowSurface == windowSurface);
896 #endif
897     topLevel->d_func()->topData()->windowSurface = 0;
898
899     // Ensure all existing subsurfaces and static widgets are added to their respective lists.
900     updateLists(topLevel);
901 }
902
903 QWidgetBackingStore::~QWidgetBackingStore()
904 {
905     for (int c = 0; c < dirtyWidgets.size(); ++c) {
906         resetWidget(dirtyWidgets.at(c));
907     }
908
909     delete windowSurface;
910     windowSurface = 0;
911     delete dirtyOnScreenWidgets;
912     dirtyOnScreenWidgets = 0;
913 }
914
915 //parent's coordinates; move whole rect; update parent and widget
916 //assume the screen blt has already been done, so we don't need to refresh that part
917 void QWidgetPrivate::moveRect(const QRect &rect, int dx, int dy)
918 {
919     Q_Q(QWidget);
920     if (!q->isVisible() || (dx == 0 && dy == 0))
921         return;
922
923     QWidget *tlw = q->window();
924     QTLWExtra* x = tlw->d_func()->topData();
925     if (x->inTopLevelResize)
926         return;
927
928     static int accelEnv = -1;
929     if (accelEnv == -1) {
930         accelEnv = qgetenv("QT_NO_FAST_MOVE").toInt() == 0;
931     }
932
933     QWidget *pw = q->parentWidget();
934     QPoint toplevelOffset = pw->mapTo(tlw, QPoint());
935     QWidgetPrivate *pd = pw->d_func();
936     QRect clipR(pd->clipRect());
937 #ifdef Q_WS_QWS
938     QWidgetBackingStore *wbs = x->backingStore.data();
939     QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
940     clipR = clipR.intersected(surface->clipRegion().translated(-toplevelOffset).boundingRect());
941 #endif
942     const QRect newRect(rect.translated(dx, dy));
943     QRect destRect = rect.intersected(clipR);
944     if (destRect.isValid())
945         destRect = destRect.translated(dx, dy).intersected(clipR);
946     const QRect sourceRect(destRect.translated(-dx, -dy));
947     const QRect parentRect(rect & clipR);
948
949     bool accelerateMove = accelEnv && isOpaque
950 #ifndef QT_NO_GRAPHICSVIEW
951                           // No accelerate move for proxy widgets.
952                           && !tlw->d_func()->extra->proxyWidget
953 #endif
954                           && !isOverlapped(sourceRect) && !isOverlapped(destRect);
955
956     if (!accelerateMove) {
957         QRegion parentR(effectiveRectFor(parentRect));
958         if (!extra || !extra->hasMask) {
959             parentR -= newRect;
960         } else {
961             // invalidateBuffer() excludes anything outside the mask
962             parentR += newRect & clipR;
963         }
964         pd->invalidateBuffer(parentR);
965         invalidateBuffer((newRect & clipR).translated(-data.crect.topLeft()));
966     } else {
967
968         QWidgetBackingStore *wbs = x->backingStore.data();
969         QRegion childExpose(newRect & clipR);
970
971         if (sourceRect.isValid() && wbs->bltRect(sourceRect, dx, dy, pw))
972             childExpose -= destRect;
973
974         if (!pw->updatesEnabled())
975             return;
976
977         const bool childUpdatesEnabled = q->updatesEnabled();
978         if (childUpdatesEnabled && !childExpose.isEmpty()) {
979             childExpose.translate(-data.crect.topLeft());
980             wbs->markDirty(childExpose, q);
981             isMoved = true;
982         }
983
984         QRegion parentExpose(parentRect);
985         parentExpose -= newRect;
986         if (extra && extra->hasMask)
987             parentExpose += QRegion(newRect) - extra->mask.translated(data.crect.topLeft());
988
989         if (!parentExpose.isEmpty()) {
990             wbs->markDirty(parentExpose, pw);
991             pd->isMoved = true;
992         }
993
994         if (childUpdatesEnabled) {
995             QRegion needsFlush(sourceRect);
996             needsFlush += destRect;
997             wbs->markDirtyOnScreen(needsFlush, pw, toplevelOffset);
998         }
999     }
1000 }
1001
1002 //widget's coordinates; scroll within rect;  only update widget
1003 void QWidgetPrivate::scrollRect(const QRect &rect, int dx, int dy)
1004 {
1005     Q_Q(QWidget);
1006     QWidget *tlw = q->window();
1007     QTLWExtra* x = tlw->d_func()->topData();
1008     if (x->inTopLevelResize)
1009         return;
1010
1011     QWidgetBackingStore *wbs = x->backingStore.data();
1012     if (!wbs)
1013         return;
1014
1015     static int accelEnv = -1;
1016     if (accelEnv == -1) {
1017         accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
1018     }
1019
1020     QRect scrollRect = rect & clipRect();
1021     bool overlapped = false;
1022     bool accelerateScroll = accelEnv && isOpaque
1023                             && !(overlapped = isOverlapped(scrollRect.translated(data.crect.topLeft())));
1024
1025 #if defined(Q_WS_QWS)
1026     QWSWindowSurface *surface;
1027     surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
1028
1029     if (accelerateScroll && !surface->isBuffered()) {
1030         const QRegion surfaceClip = surface->clipRegion();
1031         const QRegion outsideClip = QRegion(rect) - surfaceClip;
1032         if (!outsideClip.isEmpty()) {
1033             const QVector<QRect> clipped = (surfaceClip & rect).rects();
1034             if (clipped.size() < 8) {
1035                 for (int i = 0; i < clipped.size(); ++i)
1036                     this->scrollRect(clipped.at(i), dx, dy);
1037                 return;
1038             } else {
1039                 accelerateScroll = false;
1040             }
1041         }
1042     }
1043 #endif // Q_WS_QWS
1044
1045     if (!accelerateScroll) {
1046         if (overlapped) {
1047             QRegion region(scrollRect);
1048             subtractOpaqueSiblings(region);
1049             invalidateBuffer(region);
1050         }else {
1051             invalidateBuffer(scrollRect);
1052         }
1053     } else {
1054         const QPoint toplevelOffset = q->mapTo(tlw, QPoint());
1055 #ifdef Q_WS_QWS
1056         QWSWindowSurface *surface = static_cast<QWSWindowSurface*>(wbs->windowSurface);
1057         const QRegion clip = surface->clipRegion().translated(-toplevelOffset) & scrollRect;
1058         const QRect clipBoundingRect = clip.boundingRect();
1059         scrollRect &= clipBoundingRect;
1060 #endif
1061         const QRect destRect = scrollRect.translated(dx, dy) & scrollRect;
1062         const QRect sourceRect = destRect.translated(-dx, -dy);
1063
1064         QRegion childExpose(scrollRect);
1065         if (sourceRect.isValid()) {
1066             if (wbs->bltRect(sourceRect, dx, dy, q))
1067                 childExpose -= destRect;
1068         }
1069
1070         if (inDirtyList) {
1071             if (rect == q->rect()) {
1072                 dirty.translate(dx, dy);
1073             } else {
1074                 QRegion dirtyScrollRegion = dirty.intersected(scrollRect);
1075                 if (!dirtyScrollRegion.isEmpty()) {
1076                     dirty -= dirtyScrollRegion;
1077                     dirtyScrollRegion.translate(dx, dy);
1078                     dirty += dirtyScrollRegion;
1079                 }
1080             }
1081         }
1082
1083         if (!q->updatesEnabled())
1084             return;
1085
1086         if (!childExpose.isEmpty()) {
1087             wbs->markDirty(childExpose, q);
1088             isScrolled = true;
1089         }
1090
1091         // Instead of using native scroll-on-screen, we copy from
1092         // backingstore, giving only one screen update for each
1093         // scroll, and a solid appearance
1094         wbs->markDirtyOnScreen(destRect, q, toplevelOffset);
1095     }
1096 }
1097
1098 static inline bool discardSyncRequest(QWidget *tlw, QTLWExtra *tlwExtra)
1099 {
1100     if (!tlw || !tlwExtra)
1101         return true;
1102
1103 #ifdef Q_WS_X11
1104     // Delay the sync until we get an Expose event from X11 (initial show).
1105     // Qt::WA_Mapped is set to true, but the actual mapping has not yet occurred.
1106     // However, we must repaint immediately regardless of the state if someone calls repaint().
1107     if (tlwExtra->waitingForMapNotify && !tlwExtra->inRepaint)
1108         return true;
1109 #endif
1110
1111     if (!tlw->testAttribute(Qt::WA_Mapped))
1112         return true;
1113
1114     if (!tlw->isVisible()
1115 #ifndef Q_WS_X11
1116         // If we're minimized on X11, WA_Mapped will be false and we
1117         // will return in the case above. Some window managers on X11
1118         // sends us the PropertyNotify to change the minimized state
1119         // *AFTER* we've received the expose event, which is baaad.
1120         || tlw->isMinimized()
1121 #endif
1122         )
1123         return true;
1124
1125     return false;
1126 }
1127
1128 /*!
1129     Synchronizes the \a exposedRegion of the \a exposedWidget with the backing store.
1130
1131     If there's nothing to repaint, the area is flushed and painting does not occur;
1132     otherwise the area is marked as dirty on screen and will be flushed right after
1133     we are done with all painting.
1134 */
1135 void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedRegion)
1136 {
1137     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
1138     if (discardSyncRequest(tlw, tlwExtra) || tlwExtra->inTopLevelResize)
1139         return;
1140
1141     if (!exposedWidget || !exposedWidget->internalWinId() || !exposedWidget->isVisible()
1142         || !exposedWidget->updatesEnabled() || exposedRegion.isEmpty()) {
1143         return;
1144     }
1145
1146     // If there's no preserved contents support we always need
1147     // to do a full repaint before flushing
1148     if (!windowSurface->hasFeature(QWindowSurface::PreservedContents))
1149         fullUpdatePending = true;
1150
1151     // Nothing to repaint.
1152     if (!isDirty()) {
1153         qt_flush(exposedWidget, exposedRegion, windowSurface, tlw, tlwOffset);
1154         return;
1155     }
1156
1157     if (exposedWidget != tlw)
1158         markDirtyOnScreen(exposedRegion, exposedWidget, exposedWidget->mapTo(tlw, QPoint()));
1159     else
1160         markDirtyOnScreen(exposedRegion, exposedWidget, QPoint());
1161     sync();
1162 }
1163
1164 /*!
1165     Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
1166 */
1167 void QWidgetBackingStore::sync()
1168 {
1169     QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
1170     if (discardSyncRequest(tlw, tlwExtra)) {
1171         // If the top-level is minimized, it's not visible on the screen so we can delay the
1172         // update until it's shown again. In order to do that we must keep the dirty states.
1173         // These will be cleared when we receive the first expose after showNormal().
1174         // However, if the widget is not visible (isVisible() returns false), everything will
1175         // be invalidated once the widget is shown again, so clear all dirty states.
1176         if (!tlw->isVisible()) {
1177             dirty = QRegion();
1178             for (int i = 0; i < dirtyWidgets.size(); ++i)
1179                 resetWidget(dirtyWidgets.at(i));
1180             dirtyWidgets.clear();
1181             fullUpdatePending = false;
1182         }
1183         return;
1184     }
1185
1186     const bool updatesDisabled = !tlw->updatesEnabled();
1187     bool repaintAllWidgets = false;
1188
1189     const bool inTopLevelResize = tlwExtra->inTopLevelResize;
1190     const QRect tlwRect(topLevelRect());
1191 #ifdef  Q_WS_QPA
1192     const QRect surfaceGeometry(tlwRect.topLeft(), windowSurface->size());
1193 #else
1194     const QRect surfaceGeometry(windowSurface->geometry());
1195 #endif
1196     if ((fullUpdatePending || inTopLevelResize || surfaceGeometry.size() != tlwRect.size()) && !updatesDisabled) {
1197         if (hasStaticContents()) {
1198             // Repaint existing dirty area and newly visible area.
1199             const QRect clipRect(0, 0, surfaceGeometry.width(), surfaceGeometry.height());
1200             const QRegion staticRegion(staticContents(0, clipRect));
1201             QRegion newVisible(0, 0, tlwRect.width(), tlwRect.height());
1202             newVisible -= staticRegion;
1203             dirty += newVisible;
1204             windowSurface->setStaticContents(staticRegion);
1205         } else {
1206             // Repaint everything.
1207             dirty = QRegion(0, 0, tlwRect.width(), tlwRect.height());
1208             for (int i = 0; i < dirtyWidgets.size(); ++i)
1209                 resetWidget(dirtyWidgets.at(i));
1210             dirtyWidgets.clear();
1211             repaintAllWidgets = true;
1212         }
1213     }
1214
1215 #ifdef Q_WS_QPA
1216     if (inTopLevelResize || surfaceGeometry.size() != tlwRect.size())
1217         windowSurface->resize(tlwRect.size());
1218 #else
1219     if (inTopLevelResize || surfaceGeometry != tlwRect)
1220         windowSurface->setGeometry(tlwRect);
1221 #endif
1222
1223     if (updatesDisabled)
1224         return;
1225
1226     if (hasDirtyFromPreviousSync)
1227         dirty += dirtyFromPreviousSync;
1228
1229     // Contains everything that needs repaint.
1230     QRegion toClean(dirty);
1231
1232     // Loop through all update() widgets and remove them from the list before they are
1233     // painted (in case someone calls update() in paintEvent). If the widget is opaque
1234     // and does not have transparent overlapping siblings, append it to the
1235     // opaqueNonOverlappedWidgets list and paint it directly without composition.
1236     QVarLengthArray<QWidget *, 32> opaqueNonOverlappedWidgets;
1237     for (int i = 0; i < dirtyWidgets.size(); ++i) {
1238         QWidget *w = dirtyWidgets.at(i);
1239         QWidgetPrivate *wd = w->d_func();
1240         if (wd->data.in_destructor)
1241             continue;
1242
1243         // Clip with mask() and clipRect().
1244         wd->dirty &= wd->clipRect();
1245         wd->clipToEffectiveMask(wd->dirty);
1246
1247         // Subtract opaque siblings and children.
1248         bool hasDirtySiblingsAbove = false;
1249         // We know for sure that the widget isn't overlapped if 'isMoved' is true.
1250         if (!wd->isMoved)
1251             wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove);
1252         // Scrolled and moved widgets must draw all children.
1253         if (!wd->isScrolled && !wd->isMoved)
1254             wd->subtractOpaqueChildren(wd->dirty, w->rect());
1255
1256         if (wd->dirty.isEmpty()) {
1257             resetWidget(w);
1258             continue;
1259         }
1260
1261         const QRegion widgetDirty(w != tlw ? wd->dirty.translated(w->mapTo(tlw, QPoint()))
1262                                            : wd->dirty);
1263         toClean += widgetDirty;
1264
1265 #ifndef QT_NO_GRAPHICSVIEW
1266         if (tlw->d_func()->extra->proxyWidget) {
1267             resetWidget(w);
1268             continue;
1269         }
1270 #endif
1271
1272         if (!hasDirtySiblingsAbove && wd->isOpaque && !dirty.intersects(widgetDirty.boundingRect())) {
1273             opaqueNonOverlappedWidgets.append(w);
1274         } else {
1275             resetWidget(w);
1276             dirty += widgetDirty;
1277         }
1278     }
1279     dirtyWidgets.clear();
1280
1281     fullUpdatePending = false;
1282
1283     if (toClean.isEmpty()) {
1284         // Nothing to repaint. However, we might have newly exposed areas on the
1285         // screen if this function was called from sync(QWidget *, QRegion)), so
1286         // we have to make sure those are flushed.
1287         flush();
1288         return;
1289     }
1290
1291 #ifndef QT_NO_GRAPHICSVIEW
1292     if (tlw->d_func()->extra->proxyWidget) {
1293         updateStaticContentsSize();
1294         dirty = QRegion();
1295         const QVector<QRect> rects(toClean.rects());
1296         for (int i = 0; i < rects.size(); ++i)
1297             tlw->d_func()->extra->proxyWidget->update(rects.at(i));
1298         return;
1299     }
1300 #endif
1301
1302 #ifndef Q_BACKINGSTORE_SUBSURFACES
1303     BeginPaintInfo beginPaintInfo;
1304     beginPaint(toClean, tlw, windowSurface, &beginPaintInfo);
1305     if (beginPaintInfo.nothingToPaint) {
1306         for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
1307             resetWidget(opaqueNonOverlappedWidgets[i]);
1308         dirty = QRegion();
1309         return;
1310     }
1311 #endif
1312
1313     // Must do this before sending any paint events because
1314     // the size may change in the paint event.
1315     updateStaticContentsSize();
1316     const QRegion dirtyCopy(dirty);
1317     dirty = QRegion();
1318
1319     // Paint opaque non overlapped widgets.
1320     for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
1321         QWidget *w = opaqueNonOverlappedWidgets[i];
1322         QWidgetPrivate *wd = w->d_func();
1323
1324         int flags = QWidgetPrivate::DrawRecursive;
1325         // Scrolled and moved widgets must draw all children.
1326         if (!wd->isScrolled && !wd->isMoved)
1327             flags |= QWidgetPrivate::DontDrawOpaqueChildren;
1328         if (w == tlw)
1329             flags |= QWidgetPrivate::DrawAsRoot;
1330
1331         QRegion toBePainted(wd->dirty);
1332         resetWidget(w);
1333
1334 #ifdef Q_BACKINGSTORE_SUBSURFACES
1335         QWindowSurface *subSurface = w->windowSurface();
1336         BeginPaintInfo beginPaintInfo;
1337
1338         QPoint off = w->mapTo(tlw, QPoint());
1339         toBePainted.translate(off);
1340         beginPaint(toBePainted, w, subSurface, &beginPaintInfo, true);
1341         toBePainted.translate(-off);
1342
1343         if (beginPaintInfo.nothingToPaint)
1344             continue;
1345
1346         if (beginPaintInfo.windowSurfaceRecreated) {
1347             // Eep the window surface has changed. The old one may have been
1348             // deleted, in which case we will segfault on the call to
1349             // painterOffset() below. Use the new window surface instead.
1350             subSurface = w->windowSurface();
1351         }
1352
1353         QPoint offset(tlwOffset);
1354         if (subSurface == windowSurface)
1355             offset += w->mapTo(tlw, QPoint());
1356         else
1357             offset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
1358         wd->drawWidget(subSurface->paintDevice(), toBePainted, offset, flags, 0, this);
1359
1360         endPaint(toBePainted, subSurface, &beginPaintInfo);
1361 #else
1362         QPoint offset(tlwOffset);
1363         if (w != tlw)
1364             offset += w->mapTo(tlw, QPoint());
1365         wd->drawWidget(windowSurface->paintDevice(), toBePainted, offset, flags, 0, this);
1366 #endif
1367     }
1368
1369     // Paint the rest with composition.
1370 #ifndef Q_BACKINGSTORE_SUBSURFACES
1371     if (repaintAllWidgets || !dirtyCopy.isEmpty()) {
1372         const int flags = QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawRecursive;
1373         tlw->d_func()->drawWidget(windowSurface->paintDevice(), dirtyCopy, tlwOffset, flags, 0, this);
1374     }
1375
1376     endPaint(toClean, windowSurface, &beginPaintInfo);
1377 #else
1378     if (!repaintAllWidgets && dirtyCopy.isEmpty())
1379         return; // Nothing more to paint.
1380
1381     QList<QWindowSurface *> surfaceList(subSurfaces);
1382     surfaceList.prepend(windowSurface);
1383     const QRect dirtyBoundingRect(dirtyCopy.boundingRect());
1384
1385     // Loop through all window surfaces (incl. the top-level surface) and
1386     // repaint those intersecting with the bounding rect of the dirty region.
1387     for (int i = 0; i < surfaceList.size(); ++i) {
1388         QWindowSurface *subSurface = surfaceList.at(i);
1389         QWidget *w = subSurface->window();
1390         QWidgetPrivate *wd = w->d_func();
1391
1392         const QRect clipRect = wd->clipRect().translated(w->mapTo(tlw, QPoint()));
1393         if (!qRectIntersects(dirtyBoundingRect, clipRect))
1394             continue;
1395
1396         toClean = dirtyCopy;
1397         BeginPaintInfo beginPaintInfo;
1398         beginPaint(toClean, w, subSurface, &beginPaintInfo);
1399         if (beginPaintInfo.nothingToPaint)
1400             continue;
1401
1402         if (beginPaintInfo.windowSurfaceRecreated) {
1403             // Eep the window surface has changed. The old one may have been
1404             // deleted, in which case we will segfault on the call to
1405             // painterOffset() below. Use the new window surface instead.
1406             subSurface = w->windowSurface();
1407         }
1408
1409         int flags = QWidgetPrivate::DrawRecursive;
1410         if (w == tlw)
1411             flags |= QWidgetPrivate::DrawAsRoot;
1412         const QPoint painterOffset = static_cast<QWSWindowSurface*>(subSurface)->painterOffset();
1413         wd->drawWidget(subSurface->paintDevice(), toClean, painterOffset, flags, 0, this);
1414
1415         endPaint(toClean, subSurface, &beginPaintInfo);
1416     }
1417 #endif
1418 }
1419
1420 /*!
1421     Flushes the contents of the backing store into the top-level widget.
1422     If the \a widget is non-zero, the content is flushed to the \a widget.
1423     If the \a surface is non-zero, the content of the \a surface is flushed.
1424 */
1425 void QWidgetBackingStore::flush(QWidget *widget, QWindowSurface *surface)
1426 {
1427 #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_MANAGER)
1428     paintWindowDecoration();
1429 #endif
1430
1431     if (!dirtyOnScreen.isEmpty()) {
1432         QWidget *target = widget ? widget : tlw;
1433         QWindowSurface *source = surface ? surface : windowSurface;
1434         qt_flush(target, dirtyOnScreen, source, tlw, tlwOffset);
1435         dirtyOnScreen = QRegion();
1436     }
1437
1438     if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
1439         return;
1440
1441     for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
1442         QWidget *w = dirtyOnScreenWidgets->at(i);
1443         QWidgetPrivate *wd = w->d_func();
1444         Q_ASSERT(wd->needsFlush);
1445         qt_flush(w, *wd->needsFlush, windowSurface, tlw, tlwOffset);
1446         *wd->needsFlush = QRegion();
1447     }
1448     dirtyOnScreenWidgets->clear();
1449 }
1450
1451 static inline bool discardInvalidateBufferRequest(QWidget *widget, QTLWExtra *tlwExtra)
1452 {
1453     Q_ASSERT(widget);
1454     if (QApplication::closingDown())
1455         return true;
1456
1457     if (!tlwExtra || tlwExtra->inTopLevelResize || !tlwExtra->backingStore)
1458         return true;
1459
1460     if (!widget->isVisible() || !widget->updatesEnabled())
1461         return true;
1462
1463     return false;
1464 }
1465
1466 /*!
1467     Invalidates the buffer when the widget is resized.
1468     Static areas are never invalidated unless absolutely needed.
1469 */
1470 void QWidgetPrivate::invalidateBuffer_resizeHelper(const QPoint &oldPos, const QSize &oldSize)
1471 {
1472     Q_Q(QWidget);
1473     Q_ASSERT(!q->isWindow());
1474     Q_ASSERT(q->parentWidget());
1475
1476     const bool staticContents = q->testAttribute(Qt::WA_StaticContents);
1477     const bool sizeDecreased = (data.crect.width() < oldSize.width())
1478                                || (data.crect.height() < oldSize.height());
1479
1480     const QPoint offset(data.crect.x() - oldPos.x(), data.crect.y() - oldPos.y());
1481     const bool parentAreaExposed = !offset.isNull() || sizeDecreased;
1482     const QRect newWidgetRect(q->rect());
1483     const QRect oldWidgetRect(0, 0, oldSize.width(), oldSize.height());
1484
1485     if (!staticContents || graphicsEffect) {
1486         QRegion staticChildren;
1487         QWidgetBackingStore *bs = 0;
1488         if (offset.isNull() && (bs = maybeBackingStore()))
1489             staticChildren = bs->staticContents(q, oldWidgetRect);
1490         const bool hasStaticChildren = !staticChildren.isEmpty();
1491
1492         if (hasStaticChildren) {
1493             QRegion dirty(newWidgetRect);
1494             dirty -= staticChildren;
1495             invalidateBuffer(dirty);
1496         } else {
1497             // Entire widget needs repaint.
1498             invalidateBuffer(newWidgetRect);
1499         }
1500
1501         if (!parentAreaExposed)
1502             return;
1503
1504         // Invalidate newly exposed area of the parent.
1505         if (!graphicsEffect && extra && extra->hasMask) {
1506             QRegion parentExpose(extra->mask.translated(oldPos));
1507             parentExpose &= QRect(oldPos, oldSize);
1508             if (hasStaticChildren)
1509                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1510             q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1511         } else {
1512             if (hasStaticChildren && !graphicsEffect) {
1513                 QRegion parentExpose(QRect(oldPos, oldSize));
1514                 parentExpose -= data.crect; // Offset is unchanged, safe to do this.
1515                 q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1516             } else {
1517                 q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(QRect(oldPos, oldSize)));
1518             }
1519         }
1520         return;
1521     }
1522
1523     // Move static content to its new position.
1524     if (!offset.isNull()) {
1525         if (sizeDecreased) {
1526             const QSize minSize(qMin(oldSize.width(), data.crect.width()),
1527                                 qMin(oldSize.height(), data.crect.height()));
1528             moveRect(QRect(oldPos, minSize), offset.x(), offset.y());
1529         } else {
1530             moveRect(QRect(oldPos, oldSize), offset.x(), offset.y());
1531         }
1532     }
1533
1534     // Invalidate newly visible area of the widget.
1535     if (!sizeDecreased || !oldWidgetRect.contains(newWidgetRect)) {
1536         QRegion newVisible(newWidgetRect);
1537         newVisible -= oldWidgetRect;
1538         invalidateBuffer(newVisible);
1539     }
1540
1541     if (!parentAreaExposed)
1542         return;
1543
1544     // Invalidate newly exposed area of the parent.
1545     const QRect oldRect(oldPos, oldSize);
1546     if (extra && extra->hasMask) {
1547         QRegion parentExpose(oldRect);
1548         parentExpose &= extra->mask.translated(oldPos);
1549         parentExpose -= (extra->mask.translated(data.crect.topLeft()) & data.crect);
1550         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1551     } else {
1552         QRegion parentExpose(oldRect);
1553         parentExpose -= data.crect;
1554         q->parentWidget()->d_func()->invalidateBuffer(parentExpose);
1555     }
1556 }
1557
1558 /*!
1559     Invalidates the \a rgn (in widget's coordinates) of the backing store, i.e.
1560     all widgets intersecting with the region will be repainted when the backing store
1561     is synced.
1562
1563     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1564 */
1565 void QWidgetPrivate::invalidateBuffer(const QRegion &rgn)
1566 {
1567     Q_Q(QWidget);
1568
1569     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1570     if (discardInvalidateBufferRequest(q, tlwExtra) || rgn.isEmpty())
1571         return;
1572
1573     QRegion wrgn(rgn);
1574     wrgn &= clipRect();
1575     if (!graphicsEffect && extra && extra->hasMask)
1576         wrgn &= extra->mask;
1577     if (wrgn.isEmpty())
1578         return;
1579
1580     tlwExtra->backingStore->markDirty(wrgn, q, false, true);
1581 }
1582
1583 /*!
1584     This function is equivalent to calling invalidateBuffer(QRegion(rect), ...), but
1585     is more efficient as it eliminates QRegion operations/allocations and can
1586     use the rect more precisely for additional cut-offs.
1587
1588     ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore).
1589 */
1590 void QWidgetPrivate::invalidateBuffer(const QRect &rect)
1591 {
1592     Q_Q(QWidget);
1593
1594     QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData();
1595     if (discardInvalidateBufferRequest(q, tlwExtra) || rect.isEmpty())
1596         return;
1597
1598     QRect wRect(rect);
1599     wRect &= clipRect();
1600     if (wRect.isEmpty())
1601         return;
1602
1603     if (graphicsEffect || !extra || !extra->hasMask) {
1604         tlwExtra->backingStore->markDirty(wRect, q, false, true);
1605         return;
1606     }
1607
1608     QRegion wRgn(extra->mask);
1609     wRgn &= wRect;
1610     if (wRgn.isEmpty())
1611         return;
1612
1613     tlwExtra->backingStore->markDirty(wRgn, q, false, true);
1614 }
1615
1616 void QWidgetPrivate::repaint_sys(const QRegion &rgn)
1617 {
1618     if (data.in_destructor)
1619         return;
1620
1621     Q_Q(QWidget);
1622     if (q->testAttribute(Qt::WA_StaticContents)) {
1623         if (!extra)
1624             createExtra();
1625         extra->staticContentsSize = data.crect.size();
1626     }
1627
1628 #ifdef Q_WS_QPA //Dont even call q->p
1629     QPaintEngine *engine = 0;
1630 #else
1631     QPaintEngine *engine = q->paintEngine();
1632 #endif
1633     // QGLWidget does not support partial updates if:
1634     // 1) The context is double buffered
1635     // 2) The context is single buffered and auto-fill background is enabled.
1636     const bool noPartialUpdateSupport = (engine && (engine->type() == QPaintEngine::OpenGL
1637                                                 || engine->type() == QPaintEngine::OpenGL2))
1638                                         && (usesDoubleBufferedGLContext || q->autoFillBackground());
1639     QRegion toBePainted(noPartialUpdateSupport ? q->rect() : rgn);
1640
1641 #ifdef Q_WS_MAC
1642     // No difference between update() and repaint() on the Mac.
1643     update_sys(toBePainted);
1644     return;
1645 #endif
1646
1647     toBePainted &= clipRect();
1648     clipToEffectiveMask(toBePainted);
1649     if (toBePainted.isEmpty())
1650         return; // Nothing to repaint.
1651
1652 #ifndef QT_NO_PAINT_DEBUG
1653     bool flushed = QWidgetBackingStore::flushPaint(q, toBePainted);
1654 #endif
1655
1656     drawWidget(q, toBePainted, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen, 0);
1657
1658 #ifndef QT_NO_PAINT_DEBUG
1659     if (flushed)
1660         QWidgetBackingStore::unflushPaint(q, toBePainted);
1661 #endif
1662
1663     if (!q->testAttribute(Qt::WA_PaintOutsidePaintEvent) && q->paintingActive())
1664         qWarning("QWidget::repaint: It is dangerous to leave painters active on a widget outside of the PaintEvent");
1665 }
1666
1667
1668 QT_END_NAMESPACE