From 26e9f4e077c49d1191835def595e4fb70ee50be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20S=C3=B8rvig?= Date: Thu, 30 Jul 2009 14:19:50 +0200 Subject: Mac/Carbon: Fix issue causing update(QRegion) to fail on large widgets. HIViewSetNeedsDisplayInRegion fails on large regions with large coordinates, fall back on updating the entire region in this case. The task mentions coordinates outside the range of signed short, but the provided example demonstrates failures in the 10-20K range as well. --- src/gui/kernel/qwidget_mac.mm | 7 ++++++- src/gui/painting/qregion.h | 1 + src/gui/painting/qregion_mac.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 70eea3a..3bbf5d4 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3100,7 +3100,12 @@ void QWidgetPrivate::update_sys(const QRegion &rgn) return; dirtyOnWidget += rgn; #ifndef QT_MAC_USE_COCOA - HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgn.toQDRgn()), true); + RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys(); + if (rgnHandle) + HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true); + else { + HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow. + } #else // Cocoa doesn't do regions, it seems more efficient to just update the bounding rect instead of a potential number of message passes for each rect. const QRect &boundingRect = rgn.boundingRect(); diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index bfedcb1..6dfdc83 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -148,6 +148,7 @@ public: #elif defined(Q_WS_MAC) #if defined Q_WS_MAC32 RgnHandle toQDRgn() const; + RgnHandle toQDRgnForUpdate_sys() const; static QRegion fromQDRgn(RgnHandle shape); #endif #ifdef QT_MAC_USE_COCOA diff --git a/src/gui/painting/qregion_mac.cpp b/src/gui/painting/qregion_mac.cpp index b57f234..9b0e99f 100644 --- a/src/gui/painting/qregion_mac.cpp +++ b/src/gui/painting/qregion_mac.cpp @@ -155,6 +155,44 @@ RgnHandle QRegion::toQDRgn() const } return rgnHandle; } + +/*! + \internal + Create's a RegionHandle, it's the caller's responsibility to release. + Returns 0 if the QRegion overflows. +*/ +RgnHandle QRegion::toQDRgnForUpdate_sys() const +{ + RgnHandle rgnHandle = qt_mac_get_rgn(); + if(d->qt_rgn && d->qt_rgn->numRects) { + RgnHandle tmp_rgn = qt_mac_get_rgn(); + int n = d->qt_rgn->numRects; + const QRect *qt_r = (n == 1) ? &d->qt_rgn->extents : d->qt_rgn->rects.constData(); + while (n--) { + + // detect overflow. Tested for use with HIViewSetNeedsDisplayInRegion + // in QWidgetPrivate::update_sys(). + enum { HIViewSetNeedsDisplayInRegionOverflow = 10000 }; // empirically determined conservative value + qDebug() << qt_r->x() << qt_r->y() << qt_r->right() << qt_r->bottom(); + if (qt_r->right() > HIViewSetNeedsDisplayInRegionOverflow || qt_r->bottom() > HIViewSetNeedsDisplayInRegionOverflow) { + qt_mac_dispose_rgn(tmp_rgn); + qt_mac_dispose_rgn(rgnHandle); + return 0; + } + + SetRectRgn(tmp_rgn, + qMax(SHRT_MIN, qt_r->x()), + qMax(SHRT_MIN, qt_r->y()), + qMin(SHRT_MAX, qt_r->right() + 1), + qMin(SHRT_MAX, qt_r->bottom() + 1)); + UnionRgn(rgnHandle, tmp_rgn, rgnHandle); + ++qt_r; + } + qt_mac_dispose_rgn(tmp_rgn); + } + return rgnHandle; +} + #endif #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) -- cgit v0.12