src/gui/painting/qblendfunctions.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    38 ** $QT_END_LICENSE$
    38 ** $QT_END_LICENSE$
    39 **
    39 **
    40 ****************************************************************************/
    40 ****************************************************************************/
    41 
    41 
    42 #include <qmath.h>
    42 #include <qmath.h>
    43 #include "qdrawhelper_p.h"
    43 #include "qblendfunctions_p.h"
    44 
    44 
    45 QT_BEGIN_NAMESPACE
    45 QT_BEGIN_NAMESPACE
    46 
    46 
    47 struct SourceOnlyAlpha
    47 struct SourceOnlyAlpha
    48 {
    48 {
    86     return b;
    86     return b;
    87 }
    87 }
    88 
    88 
    89 struct Blend_RGB16_on_RGB16_NoAlpha {
    89 struct Blend_RGB16_on_RGB16_NoAlpha {
    90     inline void write(quint16 *dst, quint16 src) { *dst = src; }
    90     inline void write(quint16 *dst, quint16 src) { *dst = src; }
       
    91 
       
    92     inline void flush(void *) {}
    91 };
    93 };
    92 
    94 
    93 struct Blend_RGB16_on_RGB16_ConstAlpha {
    95 struct Blend_RGB16_on_RGB16_ConstAlpha {
    94     inline Blend_RGB16_on_RGB16_ConstAlpha(quint32 alpha) {
    96     inline Blend_RGB16_on_RGB16_ConstAlpha(quint32 alpha) {
    95         m_alpha = (alpha * 255) >> 8;
    97         m_alpha = (alpha * 255) >> 8;
    97     }
    99     }
    98 
   100 
    99     inline void write(quint16 *dst, quint16 src) {
   101     inline void write(quint16 *dst, quint16 src) {
   100         *dst = BYTE_MUL_RGB16(src, m_alpha) + BYTE_MUL_RGB16(*dst, m_ialpha);
   102         *dst = BYTE_MUL_RGB16(src, m_alpha) + BYTE_MUL_RGB16(*dst, m_ialpha);
   101     }
   103     }
       
   104 
       
   105     inline void flush(void *) {}
   102 
   106 
   103     quint32 m_alpha;
   107     quint32 m_alpha;
   104     quint32 m_ialpha;
   108     quint32 m_ialpha;
   105 };
   109 };
   106 
   110 
   112             if (alpha < 255)
   116             if (alpha < 255)
   113                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   117                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   114             *dst = s;
   118             *dst = s;
   115         }
   119         }
   116     }
   120     }
       
   121 
       
   122     inline void flush(void *) {}
   117 };
   123 };
   118 
   124 
   119 struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha {
   125 struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha {
   120     inline Blend_ARGB24_on_RGB16_SourceAndConstAlpha(quint32 alpha) {
   126     inline Blend_ARGB24_on_RGB16_SourceAndConstAlpha(quint32 alpha) {
   121         m_alpha = (alpha * 255) >> 8;
   127         m_alpha = (alpha * 255) >> 8;
   130                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   136                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   131             *dst = s;
   137             *dst = s;
   132         }
   138         }
   133     }
   139     }
   134 
   140 
       
   141     inline void flush(void *) {}
       
   142 
   135     quint32 m_alpha;
   143     quint32 m_alpha;
   136 };
   144 };
   137 
   145 
   138 struct Blend_ARGB32_on_RGB16_SourceAlpha {
   146 struct Blend_ARGB32_on_RGB16_SourceAlpha {
   139     inline void write(quint16 *dst, quint32 src) {
   147     inline void write(quint16 *dst, quint32 src) {
   143             if(alpha < 255)
   151             if(alpha < 255)
   144                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   152                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   145             *dst = s;
   153             *dst = s;
   146         }
   154         }
   147     }
   155     }
       
   156 
       
   157     inline void flush(void *) {}
   148 };
   158 };
   149 
   159 
   150 struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha {
   160 struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha {
   151     inline Blend_ARGB32_on_RGB16_SourceAndConstAlpha(quint32 alpha) {
   161     inline Blend_ARGB32_on_RGB16_SourceAndConstAlpha(quint32 alpha) {
   152         m_alpha = (alpha * 255) >> 8;
   162         m_alpha = (alpha * 255) >> 8;
   161                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   171                 s += BYTE_MUL_RGB16(*dst, 255 - alpha);
   162             *dst = s;
   172             *dst = s;
   163         }
   173         }
   164     }
   174     }
   165 
   175 
       
   176     inline void flush(void *) {}
       
   177 
   166     quint32 m_alpha;
   178     quint32 m_alpha;
   167 };
   179 };
   168 
       
   169 template <typename SRC, typename T>
       
   170 void qt_scale_image_16bit(uchar *destPixels, int dbpl,
       
   171                           const uchar *srcPixels, int sbpl,
       
   172                           const QRectF &targetRect,
       
   173                           const QRectF &srcRect,
       
   174                           const QRect &clip,
       
   175                           T blender)
       
   176 {
       
   177     qreal sx = targetRect.width() / (qreal) srcRect.width();
       
   178     qreal sy = targetRect.height() / (qreal) srcRect.height();
       
   179 
       
   180     int ix = 0x00010000 / sx;
       
   181     int iy = 0x00010000 / sy;
       
   182 
       
   183 //     qDebug() << "scale:" << endl
       
   184 //              << " - target" << targetRect << endl
       
   185 //              << " - source" << srcRect << endl
       
   186 //              << " - clip" << clip << endl
       
   187 //              << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
       
   188 
       
   189     int cx1 = clip.x();
       
   190     int cx2 = clip.x() + clip.width();
       
   191     int cy1 = clip.top();
       
   192     int cy2 = clip.y() + clip.height();
       
   193 
       
   194     int tx1 = qRound(targetRect.left());
       
   195     int tx2 = qRound(targetRect.right());
       
   196     int ty1 = qRound(targetRect.top());
       
   197     int ty2 = qRound(targetRect.bottom());
       
   198 
       
   199     if (tx2 < tx1)
       
   200         qSwap(tx2, tx1);
       
   201 
       
   202     if (ty2 < ty1)
       
   203         qSwap(ty2, ty1);
       
   204 
       
   205     if (tx1 < cx1)
       
   206         tx1 = cx1;
       
   207 
       
   208     if (tx2 >= cx2)
       
   209         tx2 = cx2;
       
   210 
       
   211     if (tx1 >= tx2)
       
   212         return;
       
   213 
       
   214     if (ty1 < cy1)
       
   215         ty1 = cy1;
       
   216 
       
   217     if (ty2 >= cy2)
       
   218        ty2 = cy2;
       
   219 
       
   220     if (ty1 >= ty2)
       
   221         return;
       
   222 
       
   223     int h = ty2 - ty1;
       
   224     int w = tx2 - tx1;
       
   225 
       
   226 
       
   227     quint32 basex;
       
   228     quint32 srcy;
       
   229 
       
   230     if (sx < 0) {
       
   231         int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
       
   232         basex = quint32(srcRect.right() * 65536) + dstx;
       
   233     } else {
       
   234         int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
       
   235         basex = quint32(srcRect.left() * 65536) + dstx;
       
   236     }
       
   237     if (sy < 0) {
       
   238         int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
       
   239         srcy = quint32(srcRect.bottom() * 65536) + dsty;
       
   240     } else {
       
   241         int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
       
   242         srcy = quint32(srcRect.top() * 65536) + dsty;
       
   243     }
       
   244 
       
   245     quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1;
       
   246 
       
   247     while (h--) {
       
   248         const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
       
   249         int srcx = basex;
       
   250         for (int x=0; x<w; ++x) {
       
   251             blender.write(&dst[x], src[srcx >> 16]);
       
   252             srcx += ix;
       
   253         }
       
   254         dst = (quint16 *)(((uchar *) dst) + dbpl);
       
   255         srcy += iy;
       
   256     }
       
   257 }
       
   258 
   180 
   259 void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
   181 void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
   260                                    const uchar *srcPixels, int sbpl,
   182                                    const uchar *srcPixels, int sbpl,
   261                                    const QRectF &targetRect,
   183                                    const QRectF &targetRect,
   262                                    const QRectF &sourceRect,
   184                                    const QRectF &sourceRect,
   445 }
   367 }
   446 
   368 
   447 
   369 
   448 
   370 
   449 
   371 
   450 static void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl,
   372 void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl,
   451                                                  const uchar *srcPixels, int sbpl,
   373                                           const uchar *srcPixels, int sbpl,
   452                                                  int w, int h,
   374                                           int w, int h,
   453                                                  int const_alpha)
   375                                           int const_alpha)
   454 {
   376 {
   455     quint16 *dst = (quint16 *) destPixels;
   377     quint16 *dst = (quint16 *) destPixels;
   456     const quint32 *src = (const quint32 *) srcPixels;
   378     const quint32 *src = (const quint32 *) srcPixels;
   457 
   379 
   458     const_alpha = (const_alpha * 255) >> 8;
   380     const_alpha = (const_alpha * 255) >> 8;
   641 
   563 
   642 
   564 
   643 
   565 
   644 struct Blend_RGB32_on_RGB32_NoAlpha {
   566 struct Blend_RGB32_on_RGB32_NoAlpha {
   645     inline void write(quint32 *dst, quint32 src) { *dst = src; }
   567     inline void write(quint32 *dst, quint32 src) { *dst = src; }
       
   568 
       
   569     inline void flush(void *) {}
   646 };
   570 };
   647 
   571 
   648 struct Blend_RGB32_on_RGB32_ConstAlpha {
   572 struct Blend_RGB32_on_RGB32_ConstAlpha {
   649     inline Blend_RGB32_on_RGB32_ConstAlpha(quint32 alpha) {
   573     inline Blend_RGB32_on_RGB32_ConstAlpha(quint32 alpha) {
   650         m_alpha = (alpha * 255) >> 8;
   574         m_alpha = (alpha * 255) >> 8;
   653 
   577 
   654     inline void write(quint32 *dst, quint32 src) {
   578     inline void write(quint32 *dst, quint32 src) {
   655         *dst = BYTE_MUL(src, m_alpha) + BYTE_MUL(*dst, m_ialpha);
   579         *dst = BYTE_MUL(src, m_alpha) + BYTE_MUL(*dst, m_ialpha);
   656     }
   580     }
   657 
   581 
       
   582     inline void flush(void *) {}
       
   583 
   658     quint32 m_alpha;
   584     quint32 m_alpha;
   659     quint32 m_ialpha;
   585     quint32 m_ialpha;
   660 };
   586 };
   661 
   587 
   662 struct Blend_ARGB32_on_ARGB32_SourceAlpha {
   588 struct Blend_ARGB32_on_ARGB32_SourceAlpha {
   663     inline void write(quint32 *dst, quint32 src) {
   589     inline void write(quint32 *dst, quint32 src) {
   664         *dst = src + BYTE_MUL(*dst, qAlpha(~src));
   590         *dst = src + BYTE_MUL(*dst, qAlpha(~src));
   665     }
   591     }
       
   592 
       
   593     inline void flush(void *) {}
   666 };
   594 };
   667 
   595 
   668 struct Blend_ARGB32_on_ARGB32_SourceAndConstAlpha {
   596 struct Blend_ARGB32_on_ARGB32_SourceAndConstAlpha {
   669     inline Blend_ARGB32_on_ARGB32_SourceAndConstAlpha(quint32 alpha) {
   597     inline Blend_ARGB32_on_ARGB32_SourceAndConstAlpha(quint32 alpha) {
   670         m_alpha = (alpha * 255) >> 8;
   598         m_alpha = (alpha * 255) >> 8;
   674     inline void write(quint32 *dst, quint32 src) {
   602     inline void write(quint32 *dst, quint32 src) {
   675         src = BYTE_MUL(src, m_alpha);
   603         src = BYTE_MUL(src, m_alpha);
   676         *dst = src + BYTE_MUL(*dst, qAlpha(~src));
   604         *dst = src + BYTE_MUL(*dst, qAlpha(~src));
   677     }
   605     }
   678 
   606 
       
   607     inline void flush(void *) {}
       
   608 
   679     quint32 m_alpha;
   609     quint32 m_alpha;
   680     quint32 m_ialpha;
   610     quint32 m_ialpha;
   681 };
   611 };
   682 
       
   683 template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
       
   684                                                 const uchar *srcPixels, int sbpl,
       
   685                                                 const QRectF &targetRect,
       
   686                                                 const QRectF &srcRect,
       
   687                                                 const QRect &clip,
       
   688                                                 T blender)
       
   689 {
       
   690     qreal sx = targetRect.width() / (qreal) srcRect.width();
       
   691     qreal sy = targetRect.height() / (qreal) srcRect.height();
       
   692 
       
   693     int ix = 0x00010000 / sx;
       
   694     int iy = 0x00010000 / sy;
       
   695 
       
   696 //     qDebug() << "scale:" << endl
       
   697 //              << " - target" << targetRect << endl
       
   698 //              << " - source" << srcRect << endl
       
   699 //              << " - clip" << clip << endl
       
   700 //              << " - sx=" << sx << " sy=" << sy << " ix=" << ix << " iy=" << iy;
       
   701 
       
   702     int cx1 = clip.x();
       
   703     int cx2 = clip.x() + clip.width();
       
   704     int cy1 = clip.top();
       
   705     int cy2 = clip.y() + clip.height();
       
   706 
       
   707     int tx1 = qRound(targetRect.left());
       
   708     int tx2 = qRound(targetRect.right());
       
   709     int ty1 = qRound(targetRect.top());
       
   710     int ty2 = qRound(targetRect.bottom());
       
   711 
       
   712     if (tx2 < tx1)
       
   713         qSwap(tx2, tx1);
       
   714 
       
   715     if (ty2 < ty1)
       
   716         qSwap(ty2, ty1);
       
   717 
       
   718     if (tx1 < cx1)
       
   719         tx1 = cx1;
       
   720 
       
   721     if (tx2 >= cx2)
       
   722         tx2 = cx2;
       
   723 
       
   724     if (tx1 >= tx2)
       
   725         return;
       
   726 
       
   727     if (ty1 < cy1)
       
   728         ty1 = cy1;
       
   729 
       
   730     if (ty2 >= cy2)
       
   731        ty2 = cy2;
       
   732 
       
   733     if (ty1 >= ty2)
       
   734         return;
       
   735 
       
   736     int h = ty2 - ty1;
       
   737     int w = tx2 - tx1;
       
   738 
       
   739     quint32 basex;
       
   740     quint32 srcy;
       
   741 
       
   742     if (sx < 0) {
       
   743         int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1;
       
   744         basex = quint32(srcRect.right() * 65536) + dstx;
       
   745     } else {
       
   746         int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1;
       
   747         basex = quint32(srcRect.left() * 65536) + dstx;
       
   748     }
       
   749     if (sy < 0) {
       
   750         int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1;
       
   751         srcy = quint32(srcRect.bottom() * 65536) + dsty;
       
   752     } else {
       
   753         int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1;
       
   754         srcy = quint32(srcRect.top() * 65536) + dsty;
       
   755     }
       
   756 
       
   757     quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1;
       
   758 
       
   759     while (h--) {
       
   760         const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
       
   761         int srcx = basex;
       
   762         for (int x=0; x<w; ++x) {
       
   763             blender.write(&dst[x], src[srcx >> 16]);
       
   764             srcx += ix;
       
   765         }
       
   766         dst = (quint32 *)(((uchar *) dst) + dbpl);
       
   767         srcy += iy;
       
   768     }
       
   769 }
       
   770 
   612 
   771 void qt_scale_image_rgb32_on_rgb32(uchar *destPixels, int dbpl,
   613 void qt_scale_image_rgb32_on_rgb32(uchar *destPixels, int dbpl,
   772                                    const uchar *srcPixels, int sbpl,
   614                                    const uchar *srcPixels, int sbpl,
   773                                    const QRectF &targetRect,
   615                                    const QRectF &targetRect,
   774                                    const QRectF &sourceRect,
   616                                    const QRectF &sourceRect,
   816         qt_scale_image_32bit(destPixels, dbpl, srcPixels, sbpl,
   658         qt_scale_image_32bit(destPixels, dbpl, srcPixels, sbpl,
   817                              targetRect, sourceRect, clip, constAlpha);
   659                              targetRect, sourceRect, clip, constAlpha);
   818     }
   660     }
   819 }
   661 }
   820 
   662 
   821 struct QTransformImageVertex
       
   822 {
       
   823     qreal x, y, u, v; // destination coordinates (x, y) and source coordinates (u, v)
       
   824 };
       
   825 
       
   826 template <class SrcT, class DestT, class Blender>
       
   827 void qt_transform_image_rasterize(DestT *destPixels, int dbpl,
       
   828                                   const SrcT *srcPixels, int sbpl,
       
   829                                   const QTransformImageVertex &topLeft, const QTransformImageVertex &bottomLeft,
       
   830                                   const QTransformImageVertex &topRight, const QTransformImageVertex &bottomRight,
       
   831                                   const QRect &sourceRect,
       
   832                                   const QRect &clip,
       
   833                                   qreal topY, qreal bottomY,
       
   834                                   int dudx, int dvdx, int dudy, int dvdy, int u0, int v0,
       
   835                                   Blender blender)
       
   836 {
       
   837     int fromY = qMax(qRound(topY), clip.top());
       
   838     int toY = qMin(qRound(bottomY), clip.top() + clip.height());
       
   839     if (fromY >= toY)
       
   840         return;
       
   841 
       
   842     qreal leftSlope = (bottomLeft.x - topLeft.x) / (bottomLeft.y - topLeft.y);
       
   843     qreal rightSlope = (bottomRight.x - topRight.x) / (bottomRight.y - topRight.y);
       
   844     int dx_l = int(leftSlope * 0x10000);
       
   845     int dx_r = int(rightSlope * 0x10000);
       
   846     int x_l = int((topLeft.x + (0.5 + fromY - topLeft.y) * leftSlope + 0.5) * 0x10000);
       
   847     int x_r = int((topRight.x + (0.5 + fromY - topRight.y) * rightSlope + 0.5) * 0x10000);
       
   848 
       
   849     int fromX, toX, x1, x2, u, v, i, ii;
       
   850     DestT *line;
       
   851     for (int y = fromY; y < toY; ++y) {
       
   852         line = reinterpret_cast<DestT *>(reinterpret_cast<uchar *>(destPixels) + y * dbpl);
       
   853 
       
   854         fromX = qMax(x_l >> 16, clip.left());
       
   855         toX = qMin(x_r >> 16, clip.left() + clip.width());
       
   856         if (fromX < toX) {
       
   857             // Because of rounding, we can get source coordinates outside the source image.
       
   858             // Clamp these coordinates to the source rect to avoid segmentation fault and
       
   859             // garbage on the screen.
       
   860 
       
   861             // Find the first pixel on the current scan line where the source coordinates are within the source rect.
       
   862             x1 = fromX;
       
   863             u = x1 * dudx + y * dudy + u0;
       
   864             v = x1 * dvdx + y * dvdy + v0;
       
   865             for (; x1 < toX; ++x1) {
       
   866                 int uu = u >> 16;
       
   867                 int vv = v >> 16;
       
   868                 if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
       
   869                     && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
       
   870                     break;
       
   871                 }
       
   872                 u += dudx;
       
   873                 v += dvdx;
       
   874             }
       
   875 
       
   876             // Find the last pixel on the current scan line where the source coordinates are within the source rect.
       
   877             x2 = toX;
       
   878             u = (x2 - 1) * dudx + y * dudy + u0;
       
   879             v = (x2 - 1) * dvdx + y * dvdy + v0;
       
   880             for (; x2 > x1; --x2) {
       
   881                 int uu = u >> 16;
       
   882                 int vv = v >> 16;
       
   883                 if (uu >= sourceRect.left() && uu < sourceRect.left() + sourceRect.width()
       
   884                     && vv >= sourceRect.top() && vv < sourceRect.top() + sourceRect.height()) {
       
   885                     break;
       
   886                 }
       
   887                 u -= dudx;
       
   888                 v -= dvdx;
       
   889             }
       
   890 
       
   891             // Set up values at the beginning of the scan line.
       
   892             u = fromX * dudx + y * dudy + u0;
       
   893             v = fromX * dvdx + y * dvdy + v0;
       
   894             line += fromX;
       
   895 
       
   896             // Beginning of the scan line, with per-pixel checks.
       
   897             i = x1 - fromX;
       
   898             while (i) {
       
   899                 int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
       
   900                 int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
       
   901                 blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
       
   902                 u += dudx;
       
   903                 v += dvdx;
       
   904                 ++line;
       
   905                 --i;
       
   906             }
       
   907 
       
   908             // Middle of the scan line, without checks.
       
   909             // Manual loop unrolling.
       
   910             i = x2 - x1;
       
   911             ii = i >> 3;
       
   912             while (ii) {
       
   913                 blender.write(&line[0], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   914                 blender.write(&line[1], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   915                 blender.write(&line[2], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   916                 blender.write(&line[3], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   917                 blender.write(&line[4], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   918                 blender.write(&line[5], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   919                 blender.write(&line[6], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   920                 blender.write(&line[7], reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx;
       
   921                 line += 8;
       
   922                 --ii;
       
   923             }
       
   924             switch (i & 7) {
       
   925                 case 7: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   926                 case 6: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   927                 case 5: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   928                 case 4: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   929                 case 3: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   930                 case 2: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   931                 case 1: blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + (v >> 16) * sbpl)[u >> 16]); u += dudx; v += dvdx; ++line;
       
   932             }
       
   933 
       
   934             // End of the scan line, with per-pixel checks.
       
   935             i = toX - x2;
       
   936             while (i) {
       
   937                 int uu = qBound(sourceRect.left(), u >> 16, sourceRect.left() + sourceRect.width() - 1);
       
   938                 int vv = qBound(sourceRect.top(), v >> 16, sourceRect.top() + sourceRect.height() - 1);
       
   939                 blender.write(line, reinterpret_cast<const SrcT *>(reinterpret_cast<const uchar *>(srcPixels) + vv * sbpl)[uu]);
       
   940                 u += dudx;
       
   941                 v += dvdx;
       
   942                 ++line;
       
   943                 --i;
       
   944             }
       
   945         }
       
   946         x_l += dx_l;
       
   947         x_r += dx_r;
       
   948     }
       
   949 }
       
   950 
       
   951 template <class SrcT, class DestT, class Blender>
       
   952 void qt_transform_image(DestT *destPixels, int dbpl,
       
   953                         const SrcT *srcPixels, int sbpl,
       
   954                         const QRectF &targetRect,
       
   955                         const QRectF &sourceRect,
       
   956                         const QRect &clip,
       
   957                         const QTransform &targetRectTransform,
       
   958                         Blender blender)
       
   959 {
       
   960     enum Corner
       
   961     {
       
   962         TopLeft,
       
   963         TopRight,
       
   964         BottomRight,
       
   965         BottomLeft
       
   966     };
       
   967 
       
   968     // map source rectangle to destination.
       
   969     QTransformImageVertex v[4];
       
   970     v[TopLeft].u = v[BottomLeft].u = sourceRect.left();
       
   971     v[TopLeft].v = v[TopRight].v = sourceRect.top();
       
   972     v[TopRight].u = v[BottomRight].u = sourceRect.right();
       
   973     v[BottomLeft].v = v[BottomRight].v = sourceRect.bottom();
       
   974     targetRectTransform.map(targetRect.left(), targetRect.top(), &v[TopLeft].x, &v[TopLeft].y);
       
   975     targetRectTransform.map(targetRect.right(), targetRect.top(), &v[TopRight].x, &v[TopRight].y);
       
   976     targetRectTransform.map(targetRect.left(), targetRect.bottom(), &v[BottomLeft].x, &v[BottomLeft].y);
       
   977     targetRectTransform.map(targetRect.right(), targetRect.bottom(), &v[BottomRight].x, &v[BottomRight].y);
       
   978 
       
   979     // find topmost vertex.
       
   980     int topmost = 0;
       
   981     for (int i = 1; i < 4; ++i) {
       
   982         if (v[i].y < v[topmost].y)
       
   983             topmost = i;
       
   984     }
       
   985     // rearrange array such that topmost vertex is at index 0.
       
   986     switch (topmost) {
       
   987     case 1:
       
   988         {
       
   989             QTransformImageVertex t = v[0];
       
   990             for (int i = 0; i < 3; ++i)
       
   991                 v[i] = v[i+1];
       
   992             v[3] = t;
       
   993         }
       
   994         break;
       
   995     case 2:
       
   996         qSwap(v[0], v[2]);
       
   997         qSwap(v[1], v[3]);
       
   998         break;
       
   999     case 3:
       
  1000         {
       
  1001             QTransformImageVertex t = v[3];
       
  1002             for (int i = 3; i > 0; --i)
       
  1003                 v[i] = v[i-1];
       
  1004             v[0] = t;
       
  1005         }
       
  1006         break;
       
  1007     }
       
  1008 
       
  1009     // if necessary, swap vertex 1 and 3 such that 1 is to the left of 3.
       
  1010     qreal dx1 = v[1].x - v[0].x;
       
  1011     qreal dy1 = v[1].y - v[0].y;
       
  1012     qreal dx2 = v[3].x - v[0].x;
       
  1013     qreal dy2 = v[3].y - v[0].y;
       
  1014     if (dx1 * dy2 - dx2 * dy1 > 0)
       
  1015         qSwap(v[1], v[3]);
       
  1016 
       
  1017     QTransformImageVertex u = {v[1].x - v[0].x, v[1].y - v[0].y, v[1].u - v[0].u, v[1].v - v[0].v};
       
  1018     QTransformImageVertex w = {v[2].x - v[0].x, v[2].y - v[0].y, v[2].u - v[0].u, v[2].v - v[0].v};
       
  1019 
       
  1020     qreal det = u.x * w.y - u.y * w.x;
       
  1021     if (det == 0)
       
  1022         return;
       
  1023 
       
  1024     qreal invDet = 1.0 / det;
       
  1025     qreal m11, m12, m21, m22, mdx, mdy;
       
  1026 
       
  1027     m11 = (u.u * w.y - u.y * w.u) * invDet;
       
  1028     m12 = (u.x * w.u - u.u * w.x) * invDet;
       
  1029     m21 = (u.v * w.y - u.y * w.v) * invDet;
       
  1030     m22 = (u.x * w.v - u.v * w.x) * invDet;
       
  1031     mdx = v[0].u - m11 * v[0].x - m12 * v[0].y;
       
  1032     mdy = v[0].v - m21 * v[0].x - m22 * v[0].y;
       
  1033 
       
  1034     int dudx = int(m11 * 0x10000);
       
  1035     int dvdx = int(m21 * 0x10000);
       
  1036     int dudy = int(m12 * 0x10000);
       
  1037     int dvdy = int(m22 * 0x10000);
       
  1038     int u0 = qCeil((0.5 * m11 + 0.5 * m12 + mdx) * 0x10000) - 1;
       
  1039     int v0 = qCeil((0.5 * m21 + 0.5 * m22 + mdy) * 0x10000) - 1;
       
  1040 
       
  1041     int x1 = qFloor(sourceRect.left());
       
  1042     int y1 = qFloor(sourceRect.top());
       
  1043     int x2 = qCeil(sourceRect.right());
       
  1044     int y2 = qCeil(sourceRect.bottom());
       
  1045     QRect sourceRectI(x1, y1, x2 - x1, y2 - y1);
       
  1046 
       
  1047     // rasterize trapezoids.
       
  1048     if (v[1].y < v[3].y) {
       
  1049         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1050         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[0], v[3], sourceRectI, clip, v[1].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1051         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[3].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1052     } else {
       
  1053         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[0], v[3], sourceRectI, clip, v[0].y, v[3].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1054         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[0], v[1], v[3], v[2], sourceRectI, clip, v[3].y, v[1].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1055         qt_transform_image_rasterize(destPixels, dbpl, srcPixels, sbpl, v[1], v[2], v[3], v[2], sourceRectI, clip, v[1].y, v[2].y, dudx, dvdx, dudy, dvdy, u0, v0, blender);
       
  1056     }
       
  1057 }
       
  1058 
       
  1059 void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
   663 void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
  1060                                        const uchar *srcPixels, int sbpl,
   664                                        const uchar *srcPixels, int sbpl,
  1061                                        const QRectF &targetRect,
   665                                        const QRectF &targetRect,
  1062                                        const QRectF &sourceRect,
   666                                        const QRectF &sourceRect,
  1063                                        const QRect &clip,
   667                                        const QRect &clip,