Changeset 74


Ignore:
Timestamp:
Mar 26, 2006, 4:09:02 PM (19 years ago)
Author:
dmik
Message:

More QCanvas fixes: forced the transformation mode to be Areas in some sensitive places (for example, when drawing the background); reimplemented the "garbage on the edges" removal fix.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/canvas/qcanvas.cpp

    r73 r74  
    4949#include <stdlib.h>
    5050
    51 //#define QT_NO_CANVAS_ROUNDING_FIX
     51// QT_NO_CANVAS_ROUNDING_FIX macro encloses some hacks to QCanvas intended
     52// to get rid of artefacts and distortions caused by rounding errors. These
     53// hacks give much better results when the canvas is scaled, sheared or
     54// rotated in the canvas view; however they are just quick patches and not
     55// perfect -- there are still some artefacts possible in rare cases. As far
     56// as I understand, there is a general problem in the QCanvas design: it
     57// operates on integers (instead of doubles) when doing series of direct and
     58// inverse transformations in a row, that results in a big inaccuracy (more
     59// than one pixel in some cases).
     60//
     61// So far, this fix is tested on OS/2 only, so it is disabled for other
     62// platforms.
     63
     64#if !defined(Q_WS_PM)
     65#define QT_NO_CANVAS_ROUNDING_FIX
     66#endif
    5267
    5368#if !defined(QT_NO_TRANSFORMATIONS) && !defined(QT_NO_CANVAS_ROUNDING_FIX)
     
    193208}
    194209
    195 /*!
    196  * \internal
    197  *
    198  * Similar to mapRectMax, but with the opposite meaning. Tries to return
    199  * a region that is completely inside the given rectangle after transformation.
    200  * \a br is the target bounding rectangle (to minimize calculations).
    201  *
    202  * Using this function to clip out areas of the canvas view not covered by the
    203  * canvas eliminates garbage at canvas edges that can be well seen when the
    204  * canvas is rotated in the view.
    205  */
    206 static
    207 QRegion mapRectMin( const QWMatrix &m, const QRect &r, const QRect &br )
    208 {
    209     QRegion rgn;
    210    
    211     if ( m.isIdentity() ) {
    212         rgn = QRegion( r );
    213         return rgn;
    214     }
    215 
    216     if ( m.m12() == 0.0 && m.m21() == 0.0 ) {
    217         QRect rect = r;   
    218         // make bottom right exclusive
    219         ++ rect.rBottom();
    220         ++ rect.rRight();
    221         double x1, y1, x2, y2;
    222         // no shear or rotation, map two coords
    223         m.map( rect.left(), rect.top(), &x1, &y1 );
    224         m.map( rect.right(), rect.bottom(), &x2, &y2 );
    225         // get integers (partially covered points are excluded)
    226         x1 = ceil( x1 );
    227         y1 = ceil( y1 );
    228         x2 = floor( x2 );
    229         y2 = floor( y2 );
    230         // compose the result
    231         rect.setCoords( int( x1 ), int( y1 ), int( x2 ), int( y2 ) );
    232         // make bottom right inclusive again
    233         -- rect.rBottom();
    234         -- rect.rRight();
    235         rgn = QRegion( rect );
    236     } else {
    237         // make the rectangle smaller to compensate for differences in
    238         // line drawing routines of the underlying OS (when defining regions
    239         // from polygons) and by Qt tansformations (when transforming images
    240         // or when determining invalid chunks)
    241         QPointArray pa( r );
    242         pa = m.map( pa );
    243         rgn = QRegion( pa );
    244         // limit to the bounding rect (expanded to compensate shifts)
    245         QRect rect = br;
    246         rect.addCoords( -1, 0, 1, 0 );
    247         rgn &= QRegion( rect );
    248         // create a copy of the region and shift each towards other by 1 pixel
    249         // to compensate for (clip out) differences in line drawing routines of
    250         // the underlying OS (when defining regions from polygons) and in Qt
    251         // tansformation routines (when transforming images or when determining
    252         // invalid chunks)
    253         QRegion rgn2 = rgn;
    254         rgn.translate( 1, 0 );
    255         rgn2.translate( -1, 0 );
    256         // take an intersection
    257         rgn &= rgn2;
    258     }
    259    
    260     return rgn;
    261 }
    262 
    263210#endif
    264211
     
    12261173    QRect ivr = vr;
    12271174    if ( wm.m12() != 0.0 || wm.m21() != 0.0 ) {
    1228         // compensate for rounding errors happening on the path
     1175        // Compensate for rounding errors happening somewhere on the path
    12291176        // update() -> drawViewArea() after many transformations (can be seen
    1230         // when moving items in a canvas view that makes the canvas smaller
     1177        // when moving items in a canvas view that scales the canvas down
    12311178        // and rotates it to ~270 degress clockwise)
    12321179        ivr.addCoords( -1, -1, 1, 1 );
     
    12481195
    12491196#ifndef QT_NO_TRANSFORMATIONS
    1250 #if !defined(QT_NO_CANVAS_ROUNDING_FIX)
    1251         QRect cvr = vr; cvr.moveBy(tl.x(),tl.y());
    1252         QRegion ra = mapRectMin( wm * twm, all, cvr );
    1253 #else       
    12541197#if !defined(Q_WS_PM)
    12551198        // For translation-only transformation, it is safe to include the right
     
    12671210        QPointArray a( all );
    12681211#endif
     1212#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1213        QWMatrix::TransformationMode oldMode = QWMatrix::transformationMode();
     1214        QWMatrix::setTransformationMode( QWMatrix::Areas );
     1215#endif       
    12691216        a = (wm*twm).map(a);
     1217#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1218        QWMatrix::setTransformationMode( oldMode );
    12701219#endif       
    1271 #else
     1220#else // QT_NO_TRANSFORMATIONS
    12721221#if !defined(Q_WS_PM)
    12731222        QPointArray a( QRect(all.x(),all.y(),all.width()+1,all.height()+1) );
     
    12771226#endif
    12781227        if ( view->viewport()->backgroundMode() == NoBackground ) {
    1279 #if !defined(QT_NO_CANVAS_ROUNDING_FIX)
    1280             p->setClipRegion( QRegion( cvr ) - ra );
    1281 #else
    12821228            QRect cvr = vr; cvr.moveBy(tl.x(),tl.y());
    12831229            p->setClipRegion(QRegion(cvr)-QRegion(a));
    1284 #endif
    12851230            p->fillRect(vr,view->viewport()->palette()
    12861231                .brush(QPalette::Active,QColorGroup::Background));
    12871232        }
    1288 #if !defined(QT_NO_CANVAS_ROUNDING_FIX)
    1289         p->setClipRegion( ra );
    1290 #else
    12911233        p->setClipRegion(a);
    1292 #endif           
    12931234    }
    12941235
     
    13641305                    p.translate(tl.x(),tl.y());
    13651306#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
    1366                     drawViewArea( view, &p, mapRectMax( wm, r ), dblbuf );
     1307                    QRect vr = mapRectMax( wm, r );
     1308                    if ( wm.m12() != 0.0 || wm.m21() != 0.0 ) {
     1309                        // Compensate for rounding errors happening sometimes
     1310                        // after two direct and inverse transformations
     1311                        vr.addCoords( 0, 0, 1, 1 );
     1312                    }
     1313                    drawViewArea( view, &p, vr, dblbuf );
    13671314#else
    13681315                    drawViewArea( view, &p, wm.map(r), dblbuf );
     
    16141561    allvisible.sort();
    16151562
     1563#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1564    QRect safeArea = area;
     1565    if (p && !p->worldMatrix().isIdentity()) {
     1566        // Increase bounds that lay on the edges to get rid of drawing artefacts
     1567        // caused by differeces in regions defined using 4 points and rectangles
     1568        // drawn under the non-identity matrix
     1569        if ( area.x() == 0 ) safeArea.rLeft() -= 2;
     1570        if ( area.y() == 0 ) safeArea.rTop() -= 2;
     1571        if ( area.right() == width() - 1 ) safeArea.rRight() += 2;
     1572        if ( area.bottom() == height() - 1 ) safeArea.rBottom() += 2;
     1573    }
     1574
     1575    // Force the transformation mode to Areas. W/o this, drawBackground() and
     1576    // drawForeground() will not fill the canvas correctly when scaling up
     1577    // takes place.
     1578    QWMatrix::TransformationMode oldMode = QWMatrix::transformationMode();
     1579    QWMatrix::setTransformationMode( QWMatrix::Areas );
     1580#endif
     1581   
    16161582    if ( double_buffer )
    16171583        ensureOffScrSize( area.width(), area.height() );
     
    16221588        painter.translate(-area.x(),-area.y());
    16231589        if ( p ) {
     1590#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1591            QRect r = safeArea;
     1592            r.moveBy (-area.x(), -area.y());
     1593            painter.setClipRect(r);
     1594#else
    16241595            painter.setClipRect(QRect(0,0,area.width(),area.height()));
     1596#endif
    16251597        } else {
    16261598            painter.setClipRegion(rgn);
    16271599        }
     1600#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1601        drawBackground(painter,safeArea);
     1602#else
    16281603        drawBackground(painter,area);
     1604#endif
    16291605        allvisible.drawUnique(painter);
     1606#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1607        drawForeground(painter,safeArea);
     1608#else
    16301609        drawForeground(painter,area);
     1610#endif
    16311611        painter.end();
    16321612        if ( p ) {
    16331613            p->drawPixmap( area.x(), area.y(), offscr,
    16341614                0, 0, area.width(), area.height() );
    1635             return;
    16361615        }
    16371616    } else if ( p ) {
     1617#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1618        drawBackground(*p,safeArea);
     1619#else
    16381620        drawBackground(*p,area);
     1621#endif
    16391622        allvisible.drawUnique(*p);
     1623#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1624        drawForeground(*p,safeArea);
     1625#else
    16401626        drawForeground(*p,area);
    1641         return;
    1642     }
    1643 
     1627#endif
     1628    }
     1629
     1630    if ( p )
     1631        return;
     1632   
     1633#if !defined(QT_NO_CANVAS_ROUNDING_FIX)
     1634    QWMatrix::setTransformationMode( oldMode );
     1635#endif
     1636   
    16441637    QPoint trtr; // keeps track of total translation of rgn
    16451638
Note: See TracChangeset for help on using the changeset viewer.