~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/painting/qpaintengine_raster.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define QT_FT_BEGIN_HEADER
 
2
#define QT_FT_END_HEADER
 
3
#include <private/qrasterdefs_p.h>
 
4
#include <private/qgrayraster_p.h>
 
5
#include <private/qblackraster_p.h>
 
6
 
 
7
#include <qpainterpath.h>
 
8
#include <qdebug.h>
 
9
#include <qhash.h>
 
10
#include <qlabel.h>
 
11
#include <qbitmap.h>
 
12
 
 
13
#include <private/qmath_p.h>
 
14
 
 
15
#include <private/qdatabuffer_p.h>
 
16
#include <private/qpainter_p.h>
 
17
#include <private/qtextengine_p.h>
 
18
#include <private/qpixmap_p.h>
 
19
#include <private/qfontengine_p.h>
 
20
 
 
21
#include "qpaintengine_raster_p.h"
 
22
 
 
23
#if defined(Q_WS_X11)
 
24
#  include <qwidget.h>
 
25
#  include <qx11info_x11.h>
 
26
#  include <X11/Xlib.h>
 
27
#  include <X11/Xutil.h>
 
28
#elif defined(Q_WS_WIN)
 
29
#  include <qt_windows.h>
 
30
#  include <qvarlengtharray.h>
 
31
#  include <private/qfontengine_p.h>
 
32
#elif defined(Q_WS_MAC)
 
33
#  include <private/qt_mac_p.h>
 
34
#endif
 
35
 
 
36
#if defined(Q_WS_WIN64)
 
37
#  include <malloc.h>
 
38
#endif
 
39
 
 
40
/* 
 
41
    Used to prevent division by zero in LinearGradientData::init. 
 
42
    This number does not have to be the smallest possible positive qreal.
 
43
    The size of the result of QPaintDevice::width() is more interesting, since the error
 
44
    is accumulated for each pixel in the interpolation. Thus, interpolating over a large number of pixels
 
45
    will make the error larger.
 
46
*/
 
47
#define GRADIENT_EPSILON  0.000000001  
 
48
 
 
49
#define qreal_to_fixed_26_6(f) (int(f * 64))
 
50
#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
 
51
#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
 
52
 
 
53
static QT_FT_Raster qt_gray_raster;
 
54
static QT_FT_Raster qt_black_raster;
 
55
 
 
56
static void qt_initialize_ft()
 
57
{
 
58
//    printf("qt_initialize_ft()\n");
 
59
    int error;
 
60
 
 
61
    // The antialiasing raster.
 
62
    error = qt_ft_grays_raster.raster_new(0, &qt_gray_raster);
 
63
    if (error) {
 
64
        qWarning("failed to initlize qt_ft_grays_raster");
 
65
        return;
 
66
    }
 
67
 
 
68
    unsigned long poolSize = 128 * 128;
 
69
 
 
70
#if defined(Q_WS_WIN64)
 
71
    unsigned char *poolBase = (unsigned char *) _aligned_malloc(poolSize, __alignof(void*));
 
72
#else
 
73
    unsigned char *poolBase = (unsigned char *) malloc(poolSize);
 
74
#endif
 
75
 
 
76
    qt_ft_grays_raster.raster_reset(qt_gray_raster, poolBase, poolSize);
 
77
 
 
78
    // Initialize the standard raster.
 
79
    error = qt_ft_standard_raster.raster_new(0, &qt_black_raster);
 
80
    if (error) {
 
81
        qWarning("Failed to initialize standard raster: code=%d\n", error);
 
82
        return;
 
83
    }
 
84
    qt_ft_standard_raster.raster_reset(qt_black_raster, poolBase, poolSize);
 
85
}
 
86
 
 
87
#ifdef Q_WS_WIN
 
88
void qt_draw_text_item(const QPointF &point, const QTextItemInt &ti, HDC hdc,
 
89
                       QRasterPaintEnginePrivate *d);
 
90
#endif
 
91
 
 
92
// #define QT_DEBUG_DRAW
 
93
// #define QT_DEBUG_CONVERT
 
94
 
 
95
/********************************************************************************
 
96
 * Span functions
 
97
 */
 
98
typedef void (*qt_span_func)(int y, int count, QT_FT_Span *spans, void *userData);
 
99
 
 
100
void qt_span_fill_clipped(int y, int count, QT_FT_Span *spans, void *userData);
 
101
void qt_span_solidfill(int y, int count, QT_FT_Span *spans, void *userData);
 
102
void qt_span_texturefill(int y, int count, QT_FT_Span *spans, void *userData);
 
103
void qt_span_texturefill_xform(int y, int count, QT_FT_Span *spans, void *userData);
 
104
void qt_span_linear_gradient(int y, int count, QT_FT_Span *spans, void *userData);
 
105
void qt_span_radial_gradient(int y, int count, QT_FT_Span *spans, void *userData);
 
106
void qt_span_conical_gradient(int y, int count, QT_FT_Span *spans, void *userData);
 
107
void qt_span_clip(int y, int count, QT_FT_Span *spans, void *userData);
 
108
 
 
109
struct SolidFillData
 
110
{
 
111
    QRasterBuffer *rasterBuffer;
 
112
    uint color;
 
113
    BlendColor blendColor;
 
114
    QPainter::CompositionMode compositionMode;
 
115
};
 
116
 
 
117
struct TextureFillData
 
118
{
 
119
    QRasterBuffer *rasterBuffer;
 
120
    const void *imageData;
 
121
    int width, height;
 
122
    bool hasAlpha;
 
123
    qreal m11, m12, m21, m22, dx, dy;   // inverse xform matrix
 
124
 
 
125
    Blend blend;
 
126
    BlendTransformed blendFunc;
 
127
 
 
128
    QPainter::CompositionMode compositionMode;
 
129
 
 
130
    void init(QRasterBuffer *rasterBuffer, const QImage *image, const QMatrix &matrix,
 
131
              Blend b, BlendTransformed func);
 
132
};
 
133
 
 
134
struct FillData
 
135
{
 
136
    QRasterBuffer *rasterBuffer;
 
137
    qt_span_func callback;
 
138
    void *data;
 
139
};
 
140
 
 
141
struct ClipData
 
142
{
 
143
    QRasterBuffer *rasterBuffer;
 
144
    Qt::ClipOperation operation;
 
145
    int lastIntersected;
 
146
};
 
147
 
 
148
void qt_scanconvert(QT_FT_Outline *outline, qt_span_func callback, void *userData, QT_FT_BBox *bounds, QRasterPaintEnginePrivate *d);
 
149
 
 
150
 
 
151
enum LineDrawMode {
 
152
    LineDrawClipped,
 
153
    LineDrawNormal,
 
154
    LineDrawIncludeLastPixel
 
155
};
 
156
 
 
157
static void drawLine_midpoint_f(const QLineF &line, qt_span_func span_func, void *data,
 
158
                         LineDrawMode style, const QRect &devRect);
 
159
// static void drawLine_midpoint_i(const QLine &line, qt_span_func span_func, void *data,
 
160
//                                 LineDrawMode style, const QRect &devRect);
 
161
 
 
162
 
 
163
/********************************************************************************
 
164
 * class QFTOutlineMapper
 
165
 *
 
166
 * Used to map between QPainterPath and the QT_FT_Outline structure used by the
 
167
 * freetype scanconvertor.
 
168
 *
 
169
 * The outline mapper uses a path iterator to get points from the path,
 
170
 * so that it is possible to transform the points as they are converted. The
 
171
 * callback can be a noop, translate or full-fledged xform. (Tests indicated
 
172
 * that using a C callback was low cost).
 
173
 */
 
174
class QFTOutlineMapper
 
175
{
 
176
public:
 
177
 
 
178
    /*!
 
179
      Sets up the matrix to be used for conversion. This also
 
180
      sets up the qt_path_iterator function that is used as a callback
 
181
      to get points.
 
182
    */
 
183
    void setMatrix(const QMatrix &m, uint /* txop */)
 
184
    {
 
185
        m_m11 = m.m11();
 
186
        m_m12 = m.m12();
 
187
        m_m21 = m.m21();
 
188
        m_m22 = m.m22();
 
189
        m_dx = m.dx();
 
190
        m_dy = m.dy();
 
191
    }
 
192
 
 
193
    inline qreal map_x(qreal x, qreal y) { return m_m11*x + m_m21*y + m_dx; }
 
194
 
 
195
    inline qreal map_y(qreal x, qreal y) { return m_m12*x + m_m22*y + m_dy; }
 
196
 
 
197
    void beginOutline(Qt::FillRule fillRule)
 
198
    {
 
199
#ifdef QT_DEBUG_CONVERT
 
200
        printf("QFTOutlineMapper::beginOutline rule=%d\n", fillRule);
 
201
#endif
 
202
 
 
203
        m_points.reset();
 
204
        m_tags.reset();
 
205
        m_contours.reset();
 
206
        m_outline.flags = fillRule == Qt::WindingFill
 
207
                          ? QT_FT_OUTLINE_NONE
 
208
                          : QT_FT_OUTLINE_EVEN_ODD_FILL;
 
209
        m_subpath_start.x = m_subpath_start.y = 0;
 
210
    }
 
211
 
 
212
    void endOutline()
 
213
    {
 
214
        closeSubpath();
 
215
 
 
216
        m_outline.n_contours = m_contours.size();
 
217
        m_outline.n_points = m_points.size();
 
218
 
 
219
        m_outline.points = m_points.data();
 
220
        m_outline.tags = m_tags.data();
 
221
        m_outline.contours = m_contours.data();
 
222
 
 
223
 
 
224
#ifdef QT_DEBUG_CONVERT
 
225
        printf("QFTOutlineMapper::endOutline\n");
 
226
 
 
227
        printf(" - contours: %d\n", m_outline.n_contours);
 
228
        for (int i=0; i<m_outline.n_contours; ++i) {
 
229
            printf("   - %d\n", m_outline.contours[i]);
 
230
        }
 
231
 
 
232
        printf(" - points: %d\n", m_outline.n_points);
 
233
        for (int i=0; i<m_outline.n_points; ++i) {
 
234
            printf("   - %d -- %.2f, %.2f, (%d, %d)\n", i,
 
235
                   m_outline.points[i].x / 64.0,
 
236
                   m_outline.points[i].y / 64.0,
 
237
                   m_outline.points[i], m_outline.points[i]);
 
238
        }
 
239
#endif
 
240
    }
 
241
 
 
242
    inline void closeSubpath()
 
243
    {
 
244
#ifdef QT_DEBUG_CONVERT
 
245
        printf("QFTOutlineMapper::closeSubpath()\n");
 
246
#endif
 
247
        int pointCount = m_points.size();
 
248
        if (pointCount>0) {
 
249
#ifdef QT_DEBUG_CONVERT
 
250
            printf(" - implicitly closed\n");
 
251
#endif
 
252
 
 
253
            QT_FT_Vector last = m_points.at(pointCount-1);
 
254
 
 
255
            // implicitly close last if not already closed.
 
256
            if (m_subpath_start.x != last.x || m_subpath_start.y != last.y) {
 
257
                m_points.add(m_subpath_start);
 
258
                m_tags.add(QT_FT_CURVE_TAG_ON);
 
259
            }
 
260
 
 
261
            // for close only (not first point)
 
262
            m_contours.add(m_points.size() - 1);
 
263
        }
 
264
    }
 
265
 
 
266
 
 
267
    void moveTo(const QPointF &pt)
 
268
    {
 
269
        QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(map_x(pt.x(), pt.y())),
 
270
                                  qreal_to_fixed_26_6(map_y(pt.x(), pt.y())) };
 
271
#ifdef QT_DEBUG_CONVERT
 
272
        printf("QFTOutlineMapper::moveTo(%.2f, %.2f): subpath started=(%.2f,%.2f)\n",
 
273
               pt_fixed.x / 64.0, pt_fixed.y / 64.0,
 
274
               m_subpath_start.x / 64.0, m_subpath_start.y / 64.0);
 
275
#endif
 
276
        closeSubpath();
 
277
        m_points.add(pt_fixed);
 
278
        m_tags.add(QT_FT_CURVE_TAG_ON);
 
279
        m_subpath_start = pt_fixed;
 
280
    }
 
281
 
 
282
 
 
283
    void lineTo(const QPointF &pt)
 
284
    {
 
285
        QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(map_x(pt.x(), pt.y())),
 
286
                                  qreal_to_fixed_26_6(map_y(pt.x(), pt.y())) };
 
287
#ifdef QT_DEBUG_CONVERT
 
288
        printf("QFTOutlineMapper::lineTo(%.2f, %.2f)\n",
 
289
               pt_fixed.x / 64.0, pt_fixed.y / 64.0);
 
290
#endif
 
291
        m_points.add(pt_fixed);
 
292
        m_tags.add(QT_FT_CURVE_TAG_ON);
 
293
    }
 
294
 
 
295
 
 
296
    void curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep)
 
297
    {
 
298
        QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(map_x(cp1.x(), cp1.y())),
 
299
                                   qreal_to_fixed_26_6(map_y(cp1.x(), cp1.y())) };
 
300
        QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6(map_x(cp2.x(), cp2.y())),
 
301
                                   qreal_to_fixed_26_6(map_y(cp2.x(), cp2.y())) };
 
302
        QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6(map_x(ep.x(), ep.y())),
 
303
                                  qreal_to_fixed_26_6(map_y(ep.x(), ep.y())) };
 
304
 
 
305
        m_points.add(cp1_fixed);
 
306
        m_points.add(cp2_fixed);
 
307
        m_points.add(ep_fixed);
 
308
 
 
309
#ifdef QT_DEBUG_CONVERT
 
310
        printf("QFTOutlineMapper::curveTo((%.2f,%.2f) ,(%.2f,%.2f), (%.2f,%.2f))\n",
 
311
               cp1_fixed.x / 64.0, cp1_fixed.y / 64.0,
 
312
               cp2_fixed.x / 64.0, cp2_fixed.y / 64.0,
 
313
               ep_fixed.x / 64.0, ep_fixed.y / 64.0);
 
314
#endif
 
315
 
 
316
        m_tags.add(QT_FT_CURVE_TAG_CUBIC);         // Control point 1
 
317
        m_tags.add(QT_FT_CURVE_TAG_CUBIC);         // Control point 2
 
318
        m_tags.add(QT_FT_CURVE_TAG_ON);            // End point
 
319
    }
 
320
 
 
321
 
 
322
 
 
323
    QT_FT_Outline *convertPath(const QPainterPath &path)
 
324
    {
 
325
        Q_ASSERT(!path.isEmpty());
 
326
 
 
327
        int elmCount = path.elementCount();
 
328
 
 
329
 
 
330
#ifdef QT_DEBUG_CONVERT
 
331
        printf("QFTOutlineMapper::convertPath(), size=%d\n", elmCount);
 
332
#endif
 
333
 
 
334
 
 
335
        beginOutline(path.fillRule());
 
336
 
 
337
        for (int index=0; index<elmCount; ++index) {
 
338
            const QPainterPath::Element &elm = path.elementAt(index);
 
339
 
 
340
            switch (elm.type) {
 
341
 
 
342
            case QPainterPath::MoveToElement:
 
343
                if (index == elmCount - 1)
 
344
                    continue;
 
345
                moveTo(elm);
 
346
                break;
 
347
 
 
348
            case QPainterPath::LineToElement:
 
349
                lineTo(elm);
 
350
                break;
 
351
 
 
352
            case QPainterPath::CurveToElement:
 
353
                curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
 
354
                index += 2;
 
355
                break;
 
356
 
 
357
            default:
 
358
                break; // This will never hit..
 
359
            }
 
360
        }
 
361
 
 
362
        endOutline();
 
363
 
 
364
        return &m_outline;
 
365
    }
 
366
public:
 
367
    QDataBuffer<QT_FT_Vector> m_points;
 
368
    QDataBuffer<char> m_tags;
 
369
    QDataBuffer<short> m_contours;
 
370
    QT_FT_Outline m_outline;
 
371
 
 
372
    QT_FT_Vector m_subpath_start;
 
373
 
 
374
    // Matrix
 
375
    qreal m_m11;
 
376
    qreal m_m12;
 
377
    qreal m_m21;
 
378
    qreal m_m22;
 
379
    qreal m_dx;
 
380
    qreal m_dy;
 
381
};
 
382
 
 
383
 
 
384
#if !defined(QT_NO_DEBUG) && 0
 
385
static void qt_debug_path(const QPainterPath &path)
 
386
{
 
387
    const char *names[] = {
 
388
        "MoveTo     ",
 
389
        "LineTo     ",
 
390
        "CurveTo    ",
 
391
        "CurveToData"
 
392
    };
 
393
 
 
394
    printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
 
395
    for (int i=0; i<path.elementCount(); ++i) {
 
396
        const QPainterPath::Element &e = path.elementAt(i);
 
397
        Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
 
398
        printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
 
399
    }
 
400
}
 
401
#endif
 
402
 
 
403
QHash<int, QImage> qt_raster_image_cache;
 
404
 
 
405
QRasterPaintEngine::QRasterPaintEngine()
 
406
    : QPaintEngine(*(new QRasterPaintEnginePrivate),
 
407
                   QPaintEngine::PaintEngineFeatures(AllFeatures)
 
408
        )
 
409
{
 
410
    Q_D(QRasterPaintEngine);
 
411
 
 
412
    d->rasterBuffer = new QRasterBuffer();
 
413
    d->fontRasterBuffer = new QRasterBuffer();
 
414
    d->outlineMapper = new QFTOutlineMapper;
 
415
    if (!qt_gray_raster || !qt_black_raster) {
 
416
        qt_initialize_ft();
 
417
    };
 
418
 
 
419
    d->fillData = new FillData;
 
420
    d->solidFillData = new SolidFillData;
 
421
    d->textureFillData = new TextureFillData;
 
422
    d->linearGradientData = new LinearGradientData;
 
423
    d->radialGradientData = new RadialGradientData;
 
424
    d->conicalGradientData = new ConicalGradientData;
 
425
 
 
426
    d->flushOnEnd = true;
 
427
}
 
428
 
 
429
QRasterPaintEngine::~QRasterPaintEngine()
 
430
{
 
431
    Q_D(QRasterPaintEngine);
 
432
 
 
433
    delete d->rasterBuffer;
 
434
    delete d->outlineMapper;
 
435
    delete d->fontRasterBuffer;
 
436
 
 
437
    delete d->fillData;
 
438
    delete d->solidFillData;
 
439
    delete d->textureFillData;
 
440
    delete d->linearGradientData;
 
441
    delete d->radialGradientData;
 
442
    delete d->conicalGradientData;
 
443
}
 
444
 
 
445
 
 
446
bool QRasterPaintEngine::begin(QPaintDevice *device)
 
447
{
 
448
    Q_D(QRasterPaintEngine);
 
449
 
 
450
    qInitDrawhelperAsm();
 
451
    d->deviceDepth = device->depth();
 
452
    d->clipEnabled = false;
 
453
    d->antialiased = false;
 
454
    d->bilinear = false;
 
455
    d->opaqueBackground = false;
 
456
    d->bgBrush = Qt::white;
 
457
    d->mono_surface = false;
 
458
    d->compositionMode = QPainter::CompositionMode_SourceOver;
 
459
 
 
460
    d->deviceRect = QRect(0, 0, device->width(), device->height());
 
461
 
 
462
    DrawHelper::Layout layout = DrawHelper::Layout_RGB32;
 
463
 
 
464
    gccaps &= ~PorterDuff;
 
465
 
 
466
    // reset paintevent clip
 
467
    d->baseClip = QPainterPath();
 
468
    if (device->devType() == QInternal::Widget) {
 
469
        QRegion sysClip = systemClip();
 
470
        if (!sysClip.isEmpty()) {
 
471
            d->baseClip.addRegion(sysClip);
 
472
            d->deviceRect = sysClip.boundingRect();
 
473
            // Shift the baseclip to absolute
 
474
            d->baseClip = d->baseClip * QMatrix(1, 0, 0, 1,
 
475
                                                -d->deviceRect.x(),
 
476
                                                -d->deviceRect.y());
 
477
        }
 
478
    }
 
479
#if defined(Q_WS_QWS)
 
480
    else if (device->devType() == QInternal::Pixmap) {
 
481
        // Only embedded uses system clipping on pixmaps
 
482
        QRegion sysClip = systemClip();
 
483
        if (!sysClip.isEmpty())
 
484
            d->baseClip.addRegion(sysClip);
 
485
    }
 
486
#endif
 
487
 
 
488
    bool isBitmap = false;
 
489
#if defined(Q_WS_WIN) || defined(Q_WS_QWS)
 
490
    if (device->devType() == QInternal::Pixmap) {
 
491
        QPixmap *pixmap = static_cast<QPixmap *>(device);
 
492
        if (pixmap->isNull()) {
 
493
            qWarning("Cannot paint on a null pixmap");
 
494
            return false;
 
495
        }
 
496
        QPixmapData *data = static_cast<QPixmap *>(device)->data;
 
497
        device = &data->image;
 
498
        isBitmap = pixmap->depth() == 1;
 
499
    }
 
500
#endif
 
501
 
 
502
    if (device->devType() == QInternal::Image) {
 
503
        QImage *image = static_cast<QImage *>(device);
 
504
        int format = image->format();
 
505
        d->flushOnEnd = (format != QImage::Format_ARGB32_Premultiplied
 
506
                         && format != QImage::Format_RGB32
 
507
                         && !isBitmap);
 
508
 
 
509
        d->rasterBuffer->prepare(image);
 
510
 
 
511
        if (format == QImage::Format_MonoLSB && isBitmap) {
 
512
            d->mono_surface = true;
 
513
            layout = DrawHelper::Layout_MonoLSB;
 
514
        } else if (format == QImage::Format_RGB32) {
 
515
            layout = DrawHelper::Layout_RGB32;
 
516
        } else if (format == QImage::Format_ARGB32_Premultiplied) {
 
517
            layout = DrawHelper::Layout_ARGB;
 
518
            gccaps |= PorterDuff;
 
519
        } else {
 
520
            qWarning("QRasterPaintEngine::begin(), unsupported image format (%d)\n"
 
521
                     "Supported image formats: Format_RGB32 and Format_ARGB32_Premultiplied",
 
522
                     format);
 
523
            return false;
 
524
        }
 
525
    } else {
 
526
        d->rasterBuffer->prepare(d->deviceRect.width(), d->deviceRect.height());
 
527
    }
 
528
 
 
529
    d->rasterBuffer->resetClip();
 
530
 
 
531
    d->drawHelper = qDrawHelper + layout;
 
532
 
 
533
    d->matrix = QMatrix();
 
534
    d->txop = QPainterPrivate::TxNone;
 
535
    d->outlineMapper->setMatrix(d->matrix, d->txop);
 
536
 
 
537
    if (device->depth() == 1) {
 
538
        d->pen = QPen(Qt::color1);
 
539
        d->brush = QBrush(Qt::color0);
 
540
    } else {
 
541
        d->pen = QPen(Qt::black);
 
542
        d->brush = QBrush(Qt::NoBrush);
 
543
    }
 
544
 
 
545
    updateClipPath(QPainterPath(), Qt::NoClip);
 
546
 
 
547
    setActive(true);
 
548
    return true;
 
549
}
 
550
 
 
551
 
 
552
bool QRasterPaintEngine::end()
 
553
{
 
554
    Q_D(QRasterPaintEngine);
 
555
 
 
556
    if (d->flushOnEnd)
 
557
        flush(d->pdev, QPoint());
 
558
 
 
559
    d->clipEnabled = false;
 
560
 
 
561
    setActive(false);
 
562
 
 
563
    return true;
 
564
}
 
565
 
 
566
 
 
567
void QRasterPaintEngine::setFlushOnEnd(bool flushOnEnd)
 
568
{
 
569
    Q_D(QRasterPaintEngine);
 
570
 
 
571
    d->flushOnEnd = flushOnEnd;
 
572
}
 
573
 
 
574
 
 
575
/*!
 
576
  Force the contents of the buffer out on the underlying device.
 
577
*/
 
578
void QRasterPaintEngine::flush(QPaintDevice *device, const QPoint &offset)
 
579
{
 
580
    Q_D(QRasterPaintEngine);
 
581
    Q_ASSERT(device);
 
582
 
 
583
#if defined(Q_WS_WIN)
 
584
    if (device->devType() == QInternal::Widget) {
 
585
        HDC hdc = device->getDC();
 
586
        Q_ASSERT(hdc);
 
587
 
 
588
        QRegion sysClip = systemClip();
 
589
        if (sysClip.isEmpty()) {
 
590
            BitBlt(hdc, d->deviceRect.x() + offset.x(), d->deviceRect.y() + offset.y(),
 
591
                   d->deviceRect.width(), d->deviceRect.height(),
 
592
                   d->rasterBuffer->hdc(), 0, 0, SRCCOPY);
 
593
        } else {
 
594
            QVector<QRect> rects = sysClip.rects();
 
595
            for (int i=0; i<rects.size(); ++i) {
 
596
                QRect r = rects.at(i);
 
597
                BitBlt(hdc,
 
598
                       r.x() + offset.x(), r.y() + offset.y(), r.width(), r.height(),
 
599
                       d->rasterBuffer->hdc(), r.x() - d->deviceRect.x(), r.y() - d->deviceRect.y(),
 
600
                       SRCCOPY);
 
601
            }
 
602
        }
 
603
        device->releaseDC(hdc);
 
604
        return;
 
605
    } else {
 
606
 
 
607
        QImage *target = 0;
 
608
 
 
609
        if (device->devType() == QInternal::Pixmap) {
 
610
            target = &static_cast<QPixmap *>(device)->data->image;
 
611
        } else if (device->devType() == QInternal::Image) {
 
612
            target = static_cast<QImage *>(device);
 
613
        }
 
614
 
 
615
        Q_ASSERT(target);
 
616
        Q_ASSERT(target->format() != QImage::Format_RGB32 &&
 
617
                 target->format() != QImage::Format_ARGB32_Premultiplied);
 
618
 
 
619
        switch (target->format()) {
 
620
 
 
621
        case QImage::Format_ARGB32:
 
622
            d->rasterBuffer->flushToARGBImage(target);
 
623
            break;
 
624
 
 
625
        default:
 
626
            qWarning("QRasterPaintEngine::flush(), unhandled case: %d", target->format());
 
627
            break;
 
628
        }
 
629
    }
 
630
 
 
631
#elif defined(Q_WS_MAC)
 
632
#  ifdef QMAC_NO_COREGRAPHICS
 
633
#    warning "unhandled"
 
634
#  else
 
635
    extern CGContextRef qt_macCreateCGHandle(const QPaintDevice *); //qpaintdevice_mac.cpp
 
636
    extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
 
637
 
 
638
    if(CGContextRef ctx = qt_mac_cg_context(device)) {
 
639
        CGRect rect = CGRectMake(d->deviceRect.x(), d->deviceRect.y(),
 
640
                                 d->deviceRect.width(), d->deviceRect.height());
 
641
        HIViewDrawCGImage(ctx, &rect, d->rasterBuffer->m_data); //top left
 
642
        CGContextRelease(ctx);
 
643
    }
 
644
#  endif
 
645
    Q_UNUSED(offset);
 
646
#else
 
647
    Q_UNUSED(d);
 
648
    Q_UNUSED(offset);
 
649
#endif
 
650
}
 
651
 
 
652
 
 
653
void QRasterPaintEngine::updateState(const QPaintEngineState &state)
 
654
{
 
655
    Q_D(QRasterPaintEngine);
 
656
 
 
657
    QPaintEngine::DirtyFlags flags = state.state();
 
658
 
 
659
    if (flags & DirtyTransform) {
 
660
        d->matrix = state.matrix();
 
661
        if (d->matrix.m12() != 0 || d->matrix.m21() != 0)
 
662
            d->txop = QPainterPrivate::TxRotShear;
 
663
        else if (d->matrix.m11() != 1 || d->matrix.m22() != 1)
 
664
            d->txop = QPainterPrivate::TxScale;
 
665
        else if (d->matrix.dx() != 0 || d->matrix.dy() != 0)
 
666
            d->txop = QPainterPrivate::TxTranslate;
 
667
        else
 
668
            d->txop = QPainterPrivate::TxNone;
 
669
        d->outlineMapper->setMatrix(d->matrix, d->txop);
 
670
    }
 
671
 
 
672
    if (flags & DirtyPen) {
 
673
        d->pen = state.pen();
 
674
    }
 
675
 
 
676
    if ((flags & DirtyBrush) || (flags & DirtyBrushOrigin)) {
 
677
        QBrush brush = state.brush();
 
678
        QPointF offset = state.brushOrigin();
 
679
        d->brush = brush;
 
680
        d->brushOffset = offset;
 
681
    }
 
682
 
 
683
    if (flags & DirtyBackgroundMode) {
 
684
        d->opaqueBackground = (state.backgroundMode() == Qt::OpaqueMode);
 
685
    }
 
686
 
 
687
    if (flags & DirtyBackground) {
 
688
        d->bgBrush = state.backgroundBrush();
 
689
    }
 
690
 
 
691
    if (flags & DirtyClipPath) {
 
692
        updateClipPath(state.clipPath(), state.clipOperation());
 
693
    }
 
694
 
 
695
    if (flags & DirtyClipRegion) {
 
696
        updateClipRegion(state.clipRegion(), state.clipOperation());
 
697
    }
 
698
 
 
699
    if (!d->mono_surface) {
 
700
        if (flags & DirtyHints) {
 
701
            d->antialiased = bool(state.renderHints() & QPainter::Antialiasing);
 
702
            d->bilinear = bool(state.renderHints() & QPainter::SmoothPixmapTransform);
 
703
        }
 
704
 
 
705
        if (flags & DirtyCompositionMode) {
 
706
            d->compositionMode = state.compositionMode();
 
707
        }
 
708
    }
 
709
}
 
710
 
 
711
 
 
712
void QRasterPaintEngine::updateClipRegion(const QRegion &r, Qt::ClipOperation op)
 
713
{
 
714
#ifdef QT_DEBUG_DRAW
 
715
    qDebug() << " - QRasterPaintEngine::updateClipRegion() op=" << op << r;
 
716
#endif
 
717
    QPainterPath p;
 
718
    p.addRegion(r);
 
719
    updateClipPath(p, op);
 
720
}
 
721
 
 
722
 
 
723
void QRasterPaintEngine::updateClipPath(const QPainterPath &path, Qt::ClipOperation op)
 
724
{
 
725
    Q_D(QRasterPaintEngine);
 
726
#ifdef QT_DEBUG_DRAW
 
727
    qDebug() << " - QRasterPaintEngine::updateClipPath(), op="
 
728
             << op
 
729
             << path.boundingRect();
 
730
#endif
 
731
    d->updateClip_helper(path, op);
 
732
 
 
733
    // Reset if baseClip if the operation it.
 
734
    if (!d->baseClip.isEmpty()) {
 
735
        switch (op) {
 
736
        case Qt::UniteClip:
 
737
        case Qt::ReplaceClip:
 
738
        case Qt::NoClip:
 
739
            d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
 
740
            d->updateClip_helper(d->baseClip, Qt::IntersectClip);
 
741
            d->outlineMapper->setMatrix(d->matrix, d->txop);
 
742
            break;
 
743
        default:
 
744
            break;
 
745
        }
 
746
    }
 
747
}
 
748
 
 
749
 
 
750
QImage qt_map_to_32bit(const QPixmap &pixmap)
 
751
{
 
752
    QImage image = pixmap.toImage();
 
753
    return image.convertToFormat(image.hasAlphaChannel()
 
754
                                 ? QImage::Format_ARGB32_Premultiplied
 
755
                                 : QImage::Format_RGB32);
 
756
}
 
757
 
 
758
void QRasterPaintEngine::fillPath(const QPainterPath &path, FillData *fillData)
 
759
{
 
760
#ifdef QT_DEBUG_DRAW
 
761
    qDebug() << " --- fillPath, bounds=" << path.boundingRect();
 
762
#endif
 
763
 
 
764
    if (!fillData->callback)
 
765
        return;
 
766
 
 
767
    Q_D(QRasterPaintEngine);
 
768
 
 
769
    QT_FT_BBox clipBox = { 0, 0, d->deviceRect.width(), d->deviceRect.height() };
 
770
 
 
771
    Q_ASSERT(d->deviceRect.width() <= d->rasterBuffer->width());
 
772
    Q_ASSERT(d->deviceRect.height() <= d->rasterBuffer->height());
 
773
 
 
774
    qt_scanconvert(d->outlineMapper->convertPath(path), fillData->callback, fillData->data, &clipBox, d);
 
775
}
 
776
 
 
777
 
 
778
void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
 
779
{
 
780
#ifdef QT_DEBUG_DRAW
 
781
    qDebug(" - QRasterPaintEngine::drawRect(), x=%.2f, y=%.2f, width=%.2f, height=%.2f",
 
782
           r.x(), r.y(), r.width(), r.height());
 
783
#endif
 
784
    Q_D(QRasterPaintEngine);
 
785
    if (!d->antialiased
 
786
        && d->txop <= QPainterPrivate::TxTranslate) {
 
787
 
 
788
        bool hasPen = d->pen.style() != Qt::NoPen;
 
789
        qreal offset_x = d->matrix.dx();
 
790
        qreal offset_y = d->matrix.dy();
 
791
 
 
792
        QBrush oldBrush = d->brush;
 
793
        d->brush = QBrush();
 
794
 
 
795
        for (int i=0; i<rectCount; ++i) {
 
796
            QRectF rect = rects[i].normalized();
 
797
            rect.translate(offset_x, offset_y);
 
798
 
 
799
            FillData fillData = d->fillForBrush(oldBrush);
 
800
            int x1 = qMax(qRound(rect.x()), 0);
 
801
            int x2 = qMin(qRound(rect.width() + rect.x()), d->rasterBuffer->width());
 
802
            int y1 = qMax(qRound(rect.y()), 0);
 
803
            int y2 = qMin(qRound(rect.height() + rect.y()), d->rasterBuffer->height());;
 
804
 
 
805
            int len = x2 - x1;
 
806
 
 
807
            if (fillData.callback && len > 0) {
 
808
                QT_FT_Span span;
 
809
                span.x = x1;
 
810
                span.len = x2 - x1;
 
811
                span.coverage = 255;
 
812
 
 
813
                // draw the fill
 
814
                for (int y=y1; y<y2; ++y) {
 
815
                    fillData.callback(y, 1, &span, fillData.data);
 
816
                }
 
817
            }
 
818
 
 
819
            if (hasPen)
 
820
                QPaintEngine::drawRects(&rects[i], 1);
 
821
        }
 
822
 
 
823
        d->brush = oldBrush;
 
824
    } else {
 
825
        QPaintEngine::drawRects(rects, rectCount);
 
826
    }
 
827
}
 
828
 
 
829
void QRasterPaintEngine::drawPath(const QPainterPath &path)
 
830
{
 
831
#ifdef QT_DEBUG_DRAW
 
832
    QRectF bounds = path.boundingRect();
 
833
    printf(" - QRasterPaintEngine::drawPath(), [%.2f, %.2f, %.2f, %.2f]\n",
 
834
           bounds.x(), bounds.y(), bounds.width(), bounds.height());
 
835
#endif
 
836
    if (path.isEmpty())
 
837
        return;
 
838
 
 
839
    Q_D(QRasterPaintEngine);
 
840
 
 
841
    if (d->brush.style() != Qt::NoBrush) {
 
842
        d->outlineMapper->setMatrix(d->matrix, d->txop);
 
843
        FillData fillData = d->fillForBrush(d->brush);
 
844
        fillPath(path, &fillData);
 
845
    }
 
846
 
 
847
    if (d->pen.style() != Qt::NoPen) {
 
848
        QPainterPathStroker stroker;
 
849
        stroker.setDashPattern(d->pen.style());
 
850
        stroker.setCapStyle(d->pen.capStyle());
 
851
        stroker.setJoinStyle(d->pen.joinStyle());
 
852
        QPainterPath stroke;
 
853
 
 
854
        qreal width = d->pen.widthF();
 
855
        if (width == 0) {
 
856
            stroker.setWidth(1);
 
857
            d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
 
858
            stroke = stroker.createStroke(path * d->matrix);
 
859
            if (stroke.isEmpty())
 
860
                return;
 
861
        } else {
 
862
            stroker.setWidth(width);
 
863
            stroker.setCurveThreshold(1 / (10 * d->matrix.m11() * d->matrix.m22()));
 
864
            stroke = stroker.createStroke(path);
 
865
            d->outlineMapper->setMatrix(d->matrix, d->txop);
 
866
            if (stroke.isEmpty())
 
867
                return;
 
868
        }
 
869
        FillData fillData = d->fillForBrush(QBrush(d->pen.brush()));
 
870
        fillPath(stroke, &fillData);
 
871
    }
 
872
 
 
873
    d->outlineMapper->setMatrix(d->matrix, d->txop);
 
874
}
 
875
 
 
876
 
 
877
void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
 
878
{
 
879
    Q_D(QRasterPaintEngine);
 
880
    QBrush oldBrush = d->brush;
 
881
    QPainterPath path(points[0]);
 
882
    for (int i=1; i<pointCount; ++i)
 
883
        path.lineTo(points[i]);
 
884
    if (mode == PolylineMode) {
 
885
        d->brush = QBrush();
 
886
    } else {
 
887
        path.setFillRule(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
 
888
        path.closeSubpath();
 
889
    }
 
890
    drawPath(path);
 
891
    d->brush = oldBrush;
 
892
}
 
893
 
 
894
 
 
895
void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
 
896
{
 
897
#ifdef QT_DEBUG_DRAW
 
898
    qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
 
899
#endif
 
900
 
 
901
    Q_D(QRasterPaintEngine);
 
902
 
 
903
    QImage image;
 
904
    if (pixmap.depth() == 1) {
 
905
        if (d->txop <= QPainterPrivate::TxTranslate
 
906
            && !d->opaqueBackground
 
907
            && r.size() == sr.size()
 
908
            && r.size() == pixmap.size()) {
 
909
            FillData fill = d->fillForBrush(QBrush(d->pen.color()));
 
910
            d->drawBitmap(r.topLeft() + QPointF(d->matrix.dx(), d->matrix.dy()), pixmap, &fill);
 
911
            return;
 
912
        } else {
 
913
            image = d->colorizeBitmap(pixmap.toImage(), d->pen.color());
 
914
        }
 
915
    } else {
 
916
        image = qt_map_to_32bit(pixmap);
 
917
    }
 
918
    drawImage(r, image, sr);
 
919
}
 
920
 
 
921
void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
 
922
                                   Qt::ImageConversionFlags)
 
923
{
 
924
#ifdef QT_DEBUG_DRAW
 
925
    qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
 
926
#endif
 
927
 
 
928
    const QImage image = img.format() == QImage::Format_RGB32
 
929
                         ? img
 
930
                         : img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
 
931
 
 
932
    Q_D(QRasterPaintEngine);
 
933
    TextureFillData textureData = {
 
934
        d->rasterBuffer,
 
935
        image.bits(), image.width(), image.height(), image.format() != QImage::Format_RGB32,
 
936
        0., 0., 0., 0., 0., 0.,
 
937
        d->drawHelper->blend,
 
938
        d->bilinear ? d->drawHelper->blendTransformedBilinear : d->drawHelper->blendTransformed,
 
939
        d->compositionMode
 
940
    };
 
941
    FillData fillData = { d->rasterBuffer, 0, &textureData };
 
942
 
 
943
    bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
 
944
 
 
945
    if (d->txop > QPainterPrivate::TxTranslate || stretch_sr) {
 
946
        fillData.callback = qt_span_texturefill_xform;
 
947
        QMatrix copy = d->matrix;
 
948
        copy.translate(r.x(), r.y());
 
949
        if (stretch_sr)
 
950
            copy.scale(r.width() / sr.width(), r.height() / sr.height());
 
951
        copy.translate(-sr.x(), -sr.y());
 
952
        QMatrix inv = copy.inverted();
 
953
        textureData.m11 = inv.m11();
 
954
        textureData.m12 = inv.m12();
 
955
        textureData.m21 = inv.m21();
 
956
        textureData.m22 = inv.m22();
 
957
        textureData.dx = inv.dx();
 
958
        textureData.dy = inv.dy();
 
959
    } else {
 
960
        fillData.callback = qt_span_texturefill;
 
961
        textureData.dx = -(r.x() + d->matrix.dx()) + sr.x();
 
962
        textureData.dy = -(r.y() + d->matrix.dy()) + sr.y();
 
963
    }
 
964
 
 
965
    QPainterPath path;
 
966
    path.addRect(r);
 
967
 
 
968
    FillData clippedFill = d->clipForFill(&fillData);
 
969
 
 
970
    bool wasAntialiased = d->antialiased;
 
971
    d->antialiased = d->bilinear;
 
972
 
 
973
    fillPath(path, &clippedFill);
 
974
 
 
975
    d->antialiased = wasAntialiased;
 
976
}
 
977
 
 
978
void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
 
979
{
 
980
#ifdef QT_DEBUG_DRAW
 
981
    qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
 
982
#endif
 
983
    Q_D(QRasterPaintEngine);
 
984
 
 
985
    QPainterPath path;
 
986
    path.addRect(r);
 
987
 
 
988
    QImage image;
 
989
    if (pixmap.depth() == 1)
 
990
        image = d->colorizeBitmap(pixmap.toImage(), d->pen.color());
 
991
    else
 
992
        image = qt_map_to_32bit(pixmap);
 
993
 
 
994
    TextureFillData textureData = {
 
995
        d->rasterBuffer,
 
996
        ((const QImage &)(image)).bits(), image.width(), image.height(), image.format() != QImage::Format_RGB32,
 
997
        0., 0., 0., 0., 0., 0.,
 
998
        d->drawHelper->blendTiled,
 
999
        d->bilinear ? d->drawHelper->blendTransformedBilinearTiled : d->drawHelper->blendTransformedTiled,
 
1000
        d->compositionMode
 
1001
    };
 
1002
    FillData fillData = { d->rasterBuffer, 0, &textureData };
 
1003
 
 
1004
    if (d->txop > QPainterPrivate::TxTranslate) {
 
1005
        fillData.callback = qt_span_texturefill_xform;
 
1006
        QMatrix copy = d->matrix;
 
1007
        copy.translate(r.x(), r.y());
 
1008
        copy.translate(-sr.x(), -sr.y());
 
1009
        QMatrix inv = copy.inverted();
 
1010
        textureData.m11 = inv.m11();
 
1011
        textureData.m12 = inv.m12();
 
1012
        textureData.m21 = inv.m21();
 
1013
        textureData.m22 = inv.m22();
 
1014
        textureData.dx = inv.dx();
 
1015
        textureData.dy = inv.dy();
 
1016
    } else {
 
1017
        fillData.callback = qt_span_texturefill;
 
1018
        textureData.dx = -( r.x() + d->matrix.dx()) + sr.x();
 
1019
        textureData.dy = -( r.y() + d->matrix.dy()) + sr.y();
 
1020
    }
 
1021
 
 
1022
    FillData clippedFill = d->clipForFill(&fillData);
 
1023
    fillPath(path, &clippedFill);
 
1024
}
 
1025
 
 
1026
 
 
1027
#ifdef Q_WS_QWS
 
1028
//QWS hack
 
1029
static inline uchar monoVal(const uchar* s, int x)
 
1030
{
 
1031
    return  (s[x>>3] << (x&7)) & 0x80;
 
1032
}
 
1033
void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, bool mono, int rx,int ry,int w,int h)
 
1034
{
 
1035
    Q_D(QRasterPaintEngine);
 
1036
 
 
1037
    // Decide on which span func to use
 
1038
    FillData fillData = d->fillForBrush(d->pen.brush());
 
1039
 
 
1040
    if (!fillData.callback)
 
1041
        return;
 
1042
 
 
1043
    int y0 = (ry < 0) ? -ry : 0;
 
1044
    int x0 = (rx < 0) ? -rx : 0;
 
1045
 
 
1046
    QRasterBuffer *rb = d->rasterBuffer;
 
1047
 
 
1048
    w = qMin(w, rb->width() - rx);
 
1049
    h = qMin(h, rb->height() - ry);
 
1050
 
 
1051
    static QDataBuffer<QT_FT_Span> spans;
 
1052
 
 
1053
    for (int y=y0; y < h; ++y) {
 
1054
        const uchar *scanline = static_cast<const uchar *>(src) + y*bpl;
 
1055
        // Generate spans for this y coord
 
1056
        spans.reset();
 
1057
 
 
1058
        if (mono) {
 
1059
            for (int x = x0; x < w; ) {
 
1060
 
 
1061
                // Skip those with 0 coverage
 
1062
                while (x < w && monoVal(scanline,x) == 0)
 
1063
                    ++x;
 
1064
                if (x >= w) break;
 
1065
 
 
1066
                int prev = monoVal(scanline,x);
 
1067
                QT_FT_Span span = { x + rx, 0, prev*255 };
 
1068
 
 
1069
                // extend span until we find a different one.
 
1070
                while (x < w && monoVal(scanline,x) == prev)
 
1071
                    ++x;
 
1072
                span.len = x +rx - span.x;
 
1073
 
 
1074
                spans.add(span);
 
1075
            }
 
1076
            // Call span func for current set of spans.
 
1077
            fillData.callback(y + ry, spans.size(), spans.data(), fillData.data);
 
1078
 
 
1079
        } else {
 
1080
            for (int x = x0; x < w; ) {
 
1081
                // Skip those with 0 coverage
 
1082
                while (x < w && scanline[x] == 0)
 
1083
                    ++x;
 
1084
                if (x >= w) break;
 
1085
 
 
1086
                int prev = scanline[x];
 
1087
                QT_FT_Span span = { x + rx, 0, scanline[x] };
 
1088
 
 
1089
                // extend span until we find a different one.
 
1090
                while (x < w && scanline[x] == prev)
 
1091
                    ++x;
 
1092
                span.len = x +rx - span.x;
 
1093
 
 
1094
                spans.add(span);
 
1095
            }
 
1096
        }
 
1097
        // Call span func for current set of spans.
 
1098
        fillData.callback(y + ry, spans.size(), spans.data(), fillData.data);
 
1099
    }
 
1100
}
 
1101
 
 
1102
void QRasterPaintEngine::qwsFillRect(int x, int y, int w, int h, const QBrush &brush)
 
1103
{
 
1104
    Q_D(QRasterPaintEngine);
 
1105
    FillData fillData = d->fillForBrush(brush);
 
1106
    int x1 = qMax(x,0);
 
1107
    int x2 = qMin(x+w, d->rasterBuffer->width());
 
1108
    int y1 = qMax(y, 0);
 
1109
    int y2 = qMin(y+h, d->rasterBuffer->height());;
 
1110
 
 
1111
    int len = x2 - x1;
 
1112
 
 
1113
    if (fillData.callback && len > 0) {
 
1114
        QT_FT_Span span;
 
1115
        span.x = x1;
 
1116
        span.len = x2 - x1;
 
1117
        span.coverage = 255;
 
1118
 
 
1119
        // draw the fill
 
1120
        for (int y=y1; y<y2; ++y) {
 
1121
            fillData.callback(y, 1, &span, fillData.data);
 
1122
        }
 
1123
    }
 
1124
}
 
1125
#endif
 
1126
 
 
1127
#ifdef Q_WS_X11
 
1128
void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
 
1129
{
 
1130
    QPaintEngine::drawTextItem(p, textItem);
 
1131
    return;
 
1132
 
 
1133
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
 
1134
 
 
1135
#ifdef QT_DEBUG_DRAW
 
1136
    printf(" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
 
1137
           p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
 
1138
#endif
 
1139
    Q_D(QRasterPaintEngine);
 
1140
 
 
1141
    switch(ti.fontEngine->type()) {
 
1142
    case QFontEngine::Multi:
 
1143
        d->drawMulti(p, ti);
 
1144
        break;
 
1145
    case QFontEngine::XLFD:
 
1146
        d->drawXLFD(p, ti);
 
1147
        break;
 
1148
    case QFontEngine::Box:
 
1149
        d->drawBox(p, ti);
 
1150
        break;
 
1151
#ifndef QT_NO_FONTCONFIG
 
1152
    case QFontEngine::Freetype: {
 
1153
            bool aa = d->antialiased;
 
1154
            d->antialiased = !d->mono_surface;
 
1155
            QPaintEngine::drawTextItem(p, ti);
 
1156
            d->antialiased = aa;
 
1157
        }
 
1158
        break;
 
1159
#endif
 
1160
    default:
 
1161
        Q_ASSERT(false);
 
1162
    }
 
1163
}
 
1164
 
 
1165
void QRasterPaintEnginePrivate::drawMulti(const QPointF &p, const QTextItem &textItem)
 
1166
{
 
1167
    Q_Q(QRasterPaintEngine);
 
1168
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
 
1169
    QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
 
1170
    QGlyphLayout *glyphs = ti.glyphs;
 
1171
    int which = glyphs[0].glyph >> 24;
 
1172
 
 
1173
    qreal x = p.x();
 
1174
    qreal y = p.y();
 
1175
 
 
1176
    int start = 0;
 
1177
    int end, i;
 
1178
    for (end = 0; end < ti.num_glyphs; ++end) {
 
1179
        const int e = glyphs[end].glyph >> 24;
 
1180
        if (e == which)
 
1181
            continue;
 
1182
 
 
1183
        // set the high byte to zero
 
1184
        for (i = start; i < end; ++i)
 
1185
            glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
 
1186
 
 
1187
        // draw the text
 
1188
        QTextItemInt ti2 = ti;
 
1189
        ti2.glyphs = ti.glyphs + start;
 
1190
        ti2.num_glyphs = end - start;
 
1191
        ti2.fontEngine = multi->engine(which);
 
1192
        ti2.f = ti.f;
 
1193
        q->drawTextItem(QPointF(x, y), ti2);
 
1194
 
 
1195
        // reset the high byte for all glyphs and advance to the next sub-string
 
1196
        const int hi = which << 24;
 
1197
        for (i = start; i < end; ++i) {
 
1198
            glyphs[i].glyph = hi | glyphs[i].glyph;
 
1199
            x += glyphs[i].advance.x();
 
1200
        }
 
1201
 
 
1202
        // change engine
 
1203
        start = end;
 
1204
        which = e;
 
1205
    }
 
1206
 
 
1207
    // set the high byte to zero
 
1208
    for (i = start; i < end; ++i)
 
1209
        glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
 
1210
 
 
1211
    // draw the text
 
1212
    QTextItemInt ti2 = ti;
 
1213
    ti2.glyphs = ti.glyphs + start;
 
1214
    ti2.num_glyphs = end - start;
 
1215
    ti2.fontEngine = multi->engine(which);
 
1216
    ti2.f = ti.f;
 
1217
    q->drawTextItem(QPointF(x,y), ti2);
 
1218
 
 
1219
    // reset the high byte for all glyphs
 
1220
    const int hi = which << 24;
 
1221
    for (i = start; i < end; ++i)
 
1222
        glyphs[i].glyph = hi | glyphs[i].glyph;
 
1223
}
 
1224
 
 
1225
void QRasterPaintEnginePrivate::drawXLFD(const QPointF &p, const QTextItem &textItem)
 
1226
{
 
1227
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
 
1228
 
 
1229
    // xlfd: draw into bitmap, convert to image and rasterize that
 
1230
 
 
1231
    // Decide on which span func to use
 
1232
    FillData fillData = fillForBrush(pen.brush());
 
1233
    if (!fillData.callback)
 
1234
        return;
 
1235
 
 
1236
    QRectF logRect(p.x(), p.y() - ti.ascent, ti.width, ti.ascent + ti.descent);
 
1237
    QRect devRect = matrix.mapRect(logRect).toRect();
 
1238
 
 
1239
    if(devRect.width() == 0 || devRect.height() == 0)
 
1240
        return;
 
1241
 
 
1242
    int w = qRound(ti.width);
 
1243
    int h = qRound(ti.ascent + ti.descent + 1);
 
1244
    QBitmap bm(w, h);
 
1245
    {
 
1246
        QPainter painter(&bm);
 
1247
        painter.fillRect(0, 0, w, h, Qt::color0);
 
1248
        painter.setPen(Qt::color1);
 
1249
 
 
1250
        QTextItemInt item;
 
1251
        item.flags = 0;
 
1252
        item.descent = ti.descent;
 
1253
        item.ascent = ti.ascent;
 
1254
        item.width = ti.width;
 
1255
        item.chars = 0;
 
1256
        item.num_chars = 0;
 
1257
        item.glyphs = ti.glyphs;
 
1258
        item.num_glyphs = ti.num_glyphs;
 
1259
        item.fontEngine = ti.fontEngine;
 
1260
        item.f = 0;
 
1261
 
 
1262
        painter.drawTextItem(QPointF(0, ti.ascent), item);
 
1263
    }
 
1264
 
 
1265
    drawBitmap(devRect.topLeft(), bm, &fillData);
 
1266
}
 
1267
 
 
1268
void QRasterPaintEnginePrivate::drawBox(const QPointF &, const QTextItem &)
 
1269
{
 
1270
    // nothing for now
 
1271
}
 
1272
 
 
1273
#else
 
1274
 
 
1275
void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
 
1276
{
 
1277
    const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
 
1278
 
 
1279
#ifdef QT_DEBUG_DRAW
 
1280
    printf(" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
 
1281
           p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
 
1282
#endif
 
1283
    Q_D(QRasterPaintEngine);
 
1284
#if defined(Q_WS_WIN)
 
1285
 
 
1286
 
 
1287
    if (d->txop >= QPainterPrivate::TxScale) {
 
1288
        bool antialiased = d->antialiased;
 
1289
        d->antialiased = true;
 
1290
        QPaintEngine::drawTextItem(p, textItem);
 
1291
        d->antialiased = antialiased;
 
1292
        return;
 
1293
    }
 
1294
 
 
1295
    int x_buffering = ti.ascent;
 
1296
    QRectF logRect(p.x(), p.y() - ti.ascent, ti.width + x_buffering, ti.ascent + ti.descent);
 
1297
    QRect devRect = d->matrix.mapRect(logRect).toRect();
 
1298
 
 
1299
    if(devRect.width() == 0 || devRect.height() == 0)
 
1300
        return;
 
1301
 
 
1302
    d->fontRasterBuffer->prepare(devRect.width(), devRect.height());
 
1303
    d->fontRasterBuffer->resetBuffer(255);
 
1304
 
 
1305
    // Fill buffer with stuff
 
1306
    qt_draw_text_item(QPoint(0, ti.ascent), ti, d->fontRasterBuffer->hdc(), d);
 
1307
 
 
1308
    // Decide on which span func to use
 
1309
    FillData fillData = d->fillForBrush(d->pen.brush());
 
1310
 
 
1311
    if (!fillData.callback)
 
1312
        return;
 
1313
 
 
1314
    // Boundaries
 
1315
    int ymax = qMin(devRect.y() + devRect.height(), d->rasterBuffer->height());
 
1316
    int ymin = qMax(devRect.y(), 0);
 
1317
    int xmax = qMin(devRect.x() + devRect.width(), d->rasterBuffer->width());
 
1318
    int xmin = qMax(devRect.x(), 0);
 
1319
 
 
1320
    static QDataBuffer<QT_FT_Span> spans;
 
1321
 
 
1322
    if (d->mono_surface) {
 
1323
        for (int y=ymin; y<ymax; ++y) {
 
1324
            QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
 
1325
            // Generate spans for this y coord
 
1326
            spans.reset();
 
1327
            for (int x = xmin; x<xmax; ) {
 
1328
                // Skip those with 0 coverage (black on white so inverted)
 
1329
                while (x < xmax && qGray(scanline[x]) > 0x80) ++x;
 
1330
                if (x >= xmax) break;
 
1331
 
 
1332
                QT_FT_Span span = { x, 0, 255 };
 
1333
 
 
1334
                // extend span until we find a different one.
 
1335
                while (x < xmax && qGray(scanline[x]) < 0x80) ++x;
 
1336
                span.len = x - span.x;
 
1337
 
 
1338
                spans.add(span);
 
1339
            }
 
1340
 
 
1341
            // Call span func for current set of spans.
 
1342
            fillData.callback(y, spans.size(), spans.data(), fillData.data);
 
1343
        }
 
1344
 
 
1345
    } else {
 
1346
        for (int y=ymin; y<ymax; ++y) {
 
1347
            QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
 
1348
            // Generate spans for this y coord
 
1349
            spans.reset();
 
1350
            for (int x = xmin; x<xmax; ) {
 
1351
                // Skip those with 0 coverage (black on white so inverted)
 
1352
                while (x < xmax && qGray(scanline[x]) == 255) ++x;
 
1353
                if (x >= xmax) break;
 
1354
 
 
1355
                int prev = qGray(scanline[x]);
 
1356
                QT_FT_Span span = { x, 0, 255 - prev };
 
1357
 
 
1358
                // extend span until we find a different one.
 
1359
                while (x < xmax && qGray(scanline[x]) == prev) ++x;
 
1360
                span.len = x - span.x;
 
1361
 
 
1362
                spans.add(span);
 
1363
            }
 
1364
 
 
1365
            // Call span func for current set of spans.
 
1366
            fillData.callback(y, spans.size(), spans.data(), fillData.data);
 
1367
        }
 
1368
    }
 
1369
 
 
1370
    return;
 
1371
 
 
1372
#elif defined Q_WS_QWS
 
1373
    bool useFontEngine = true;
 
1374
    QMatrix matrix = d->matrix;
 
1375
    bool simple = matrix.m11() == 1 && matrix.m12() == 0 && matrix.m21() == 0 && matrix.m22() == 1;
 
1376
    if (!simple) {
 
1377
        useFontEngine = false;
 
1378
        QFontEngine *fe = ti.fontEngine;
 
1379
        QFontEngine::FECaps fecaps = fe->capabilites();
 
1380
        useFontEngine = (fecaps == QFontEngine::FullTransformations);
 
1381
        if (!useFontEngine
 
1382
            && matrix.m11() == matrix.m22()
 
1383
            && matrix.m12() == -matrix.m21())
 
1384
            useFontEngine = (fecaps & QFontEngine::RotScale) == QFontEngine::RotScale;
 
1385
    }
 
1386
    if (useFontEngine) {
 
1387
        ti.fontEngine->draw(this, qRound(p.x()), qRound(p.y()), ti);
 
1388
        return;
 
1389
    }
 
1390
#endif // Q_WS_WIN
 
1391
 
 
1392
    // Fallthrough for embedded and default for mac.
 
1393
    bool aa = d->antialiased;
 
1394
    d->antialiased = true;
 
1395
    QPaintEngine::drawTextItem(p, ti);
 
1396
    d->antialiased = aa;
 
1397
    return;
 
1398
}
 
1399
#endif
 
1400
 
 
1401
 
 
1402
void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
 
1403
{
 
1404
    Q_D(QRasterPaintEngine);
 
1405
 
 
1406
    double pw = d->pen.widthF();
 
1407
 
 
1408
    if (d->txop > QPainterPrivate::TxTranslate || pw > 1) {
 
1409
        QBrush oldBrush = d->brush;
 
1410
        d->brush = Qt::NoBrush;
 
1411
 
 
1412
        const QPointF *end = points + pointCount;
 
1413
        while (points < end) {
 
1414
            QPainterPath path;
 
1415
            path.moveTo(*points);
 
1416
            path.lineTo(points->x() + 0.001, points->y());
 
1417
            drawPath(path);
 
1418
            ++points;
 
1419
        }
 
1420
 
 
1421
        d->brush = oldBrush;
 
1422
 
 
1423
    } else {
 
1424
        FillData fillData = d->fillForBrush(d->pen.brush());
 
1425
        if (!fillData.callback)
 
1426
            return;
 
1427
 
 
1428
        QT_FT_Span span = { 0, 1, 255 };
 
1429
        qreal dx = d->matrix.dx();
 
1430
        qreal dy = d->matrix.dy();
 
1431
        const QPointF *end = points + pointCount;
 
1432
        int x, y;
 
1433
        int left = 0;
 
1434
        int right = d->deviceRect.width();
 
1435
        int top = 0;
 
1436
        int bottom = d->deviceRect.height();
 
1437
        while (points < end) {
 
1438
            x = qRound(points->x() + dx);
 
1439
            y = qRound(points->y() + dy);
 
1440
            if (x >= left && x < right && y >= top && y < bottom) {
 
1441
                span.x = x;
 
1442
                fillData.callback(y, 1, &span, fillData.data);
 
1443
            }
 
1444
            ++points;
 
1445
        }
 
1446
    }
 
1447
}
 
1448
 
 
1449
void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
 
1450
{
 
1451
#ifdef QT_DEBUG_DRAW
 
1452
    qDebug() << " - QRasterPaintEngine::drawLine()";
 
1453
#endif
 
1454
 
 
1455
    Q_D(QRasterPaintEngine);
 
1456
    if (!d->antialiased
 
1457
        && d->pen.style() == Qt::SolidLine
 
1458
        && (d->pen.widthF() == 0
 
1459
            || (d->pen.widthF() <= 1 && d->txop <= QPainterPrivate::TxTranslate))) {
 
1460
 
 
1461
        QRect bounds(0, 0, d->deviceRect.width(), d->deviceRect.height());
 
1462
 
 
1463
        for (int i=0; i<lineCount; ++i) {
 
1464
            QLineF line = lines[i] * d->matrix;
 
1465
            LineDrawMode mode = LineDrawNormal;
 
1466
 
 
1467
            if (d->pen.capStyle() != Qt::FlatCap)
 
1468
                mode = LineDrawIncludeLastPixel;
 
1469
 
 
1470
            FillData fillData = d->fillForBrush(QBrush(d->pen.brush()));
 
1471
            drawLine_midpoint_f(line.toLine(), fillData.callback, fillData.data, mode, bounds);
 
1472
 
 
1473
        }
 
1474
        return;
 
1475
    }
 
1476
    QPaintEngine::drawLines(lines, lineCount);
 
1477
}
 
1478
 
 
1479
void QRasterPaintEngine::drawEllipse(const QRectF &rect)
 
1480
{
 
1481
    Q_D(QRasterPaintEngine);
 
1482
    if (!d->antialiased && d->pen.style() == Qt::NoPen && d->txop <= QPainterPrivate::TxTranslate) {
 
1483
        QPen oldPen = d->pen;
 
1484
        d->pen = QPen(d->brush, 0);
 
1485
        QPaintEngine::drawEllipse(rect.adjusted(0, 0, -1, -1));
 
1486
        d->pen = oldPen;
 
1487
    } else {
 
1488
        QPaintEngine::drawEllipse(rect);
 
1489
    }
 
1490
}
 
1491
 
 
1492
#ifdef Q_WS_WIN
 
1493
HDC QRasterPaintEngine::getDC() const
 
1494
{
 
1495
    Q_D(const QRasterPaintEngine);
 
1496
    return d->rasterBuffer->hdc();
 
1497
}
 
1498
 
 
1499
void QRasterPaintEngine::releaseDC(HDC) const
 
1500
{
 
1501
}
 
1502
#endif
 
1503
 
 
1504
 
 
1505
QPoint QRasterPaintEngine::coordinateOffset() const
 
1506
{
 
1507
    Q_D(const QRasterPaintEngine);
 
1508
    return QPoint(d->deviceRect.x(), d->deviceRect.y());
 
1509
}
 
1510
 
 
1511
void QRasterPaintEnginePrivate::drawBitmap(const QPointF &pos, const QPixmap &pm, FillData *fg)
 
1512
{
 
1513
    Q_ASSERT(fg);
 
1514
    Q_ASSERT(fg->callback);
 
1515
 
 
1516
    const QImage image = pm.toImage();
 
1517
    Q_ASSERT(image.depth() == 1);
 
1518
 
 
1519
    const int spanCount = 256;
 
1520
    QT_FT_Span spans[spanCount];
 
1521
    int n = 0;
 
1522
 
 
1523
    // Boundaries
 
1524
    int w = pm.width();
 
1525
    int h = pm.height();
 
1526
    int ymax = qMin(qRound(pos.y() + h), rasterBuffer->height());
 
1527
    int ymin = qMax(qRound(pos.y()), 0);
 
1528
    int xmax = qMin(qRound(pos.x() + w), rasterBuffer->width());
 
1529
    int xmin = qMax(qRound(pos.x()), 0);
 
1530
 
 
1531
    int x_offset = xmin - qRound(pos.x());
 
1532
 
 
1533
#if BITMAPS_ARE_MSB
 
1534
    QImage::Format format = image.format();
 
1535
#endif
 
1536
    for (int y = ymin; y < ymax; ++y) {
 
1537
        const uchar *src = image.scanLine(y - qRound(pos.y()));
 
1538
#if BITMAPS_ARE_MSB
 
1539
        if (format == QImage::Format_MonoLSB) {
 
1540
#endif
 
1541
            for (int x = 0; x < xmax - xmin; ++x) {
 
1542
                int src_x = x + x_offset;
 
1543
                uchar pixel = src[src_x >> 3];
 
1544
                if (!pixel) {
 
1545
                    x += 7;
 
1546
                    continue;
 
1547
                }
 
1548
                if (pixel & (0x1 << (src_x & 7))) {
 
1549
                    QT_FT_Span span = { xmin + x, 1, 255 };
 
1550
                    while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
 
1551
                        ++src_x;
 
1552
                        ++span.len;
 
1553
                    }
 
1554
                    x += span.len;
 
1555
                    spans[n] = span;
 
1556
                    ++n;
 
1557
                }
 
1558
                if (n == spanCount) {
 
1559
                    fg->callback(y, n, spans, fg->data);
 
1560
                    n = 0;
 
1561
                }
 
1562
            }
 
1563
#if BITMAPS_ARE_MSB
 
1564
        } else {
 
1565
            for (int x = 0; x < xmax - xmin; ++x) {
 
1566
                bool set = src[x >> 3] & (0x80 >> (x & 7));
 
1567
                if (set) {
 
1568
                    QT_FT_Span span = { xmin + x, 1, 255 };
 
1569
                    while (x < w-1 && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7))) {
 
1570
                        ++x;
 
1571
                        ++span.len;
 
1572
                    }
 
1573
 
 
1574
                    spans[n] = span;
 
1575
                    ++n;
 
1576
                }
 
1577
                if (n == spanCount) {
 
1578
                    fg->callback(y, n, spans, fg->data);
 
1579
                    n = 0;
 
1580
                }
 
1581
            }
 
1582
        }
 
1583
#endif
 
1584
        if (n) {
 
1585
            fg->callback(y, n, spans, fg->data);
 
1586
            n = 0;
 
1587
        }
 
1588
    }
 
1589
}
 
1590
 
 
1591
/* Sets up potential clipping for this FillData object.
 
1592
 * Note that the data object must be valid throughout the lifetime of
 
1593
 * the return value.
 
1594
 */
 
1595
FillData QRasterPaintEnginePrivate::clipForFill(FillData *data)
 
1596
{
 
1597
    if (clipEnabled && data->callback) {
 
1598
        FillData clipFillData = {
 
1599
            data->rasterBuffer,
 
1600
            qt_span_fill_clipped,
 
1601
            data
 
1602
        };
 
1603
        return clipFillData;
 
1604
    } else {
 
1605
        return *data;
 
1606
    }
 
1607
}
 
1608
 
 
1609
 
 
1610
FillData QRasterPaintEnginePrivate::fillForBrush(const QBrush &brush)
 
1611
{
 
1612
    Q_ASSERT(fillData);
 
1613
 
 
1614
    fillData->rasterBuffer = rasterBuffer;
 
1615
    fillData->callback = 0;
 
1616
    fillData->data = 0;
 
1617
 
 
1618
    switch (brush.style()) {
 
1619
 
 
1620
    case Qt::NoBrush:
 
1621
        break;
 
1622
 
 
1623
    case Qt::SolidPattern:
 
1624
        fillData->callback = qt_span_solidfill;
 
1625
        fillData->data = solidFillData;
 
1626
        solidFillData->color = PREMUL(brush.color().rgba());
 
1627
        solidFillData->rasterBuffer = fillData->rasterBuffer;
 
1628
        solidFillData->blendColor = drawHelper->blendColor;
 
1629
        solidFillData->compositionMode = compositionMode;
 
1630
        break;
 
1631
 
 
1632
    case Qt::TexturePattern:
 
1633
        {
 
1634
            QPixmap texture = brush.texture();
 
1635
            if (texture.depth() == 1) {
 
1636
                tempImage = colorizeBitmap(texture.toImage(), brush.color());
 
1637
            } else {
 
1638
                tempImage = qt_map_to_32bit(brush.texture());
 
1639
            }
 
1640
            fillData->data = textureFillData;
 
1641
            fillData->callback = txop > QPainterPrivate::TxTranslate
 
1642
                                 ? qt_span_texturefill_xform
 
1643
                                 : qt_span_texturefill;
 
1644
            textureFillData->compositionMode = compositionMode;
 
1645
            textureFillData->init(rasterBuffer, &tempImage, brushMatrix(),
 
1646
                                  drawHelper->blendTiled,
 
1647
                                  bilinear
 
1648
                                  ? drawHelper->blendTransformedBilinearTiled
 
1649
                                  : drawHelper->blendTransformedTiled);
 
1650
        }
 
1651
        break;
 
1652
 
 
1653
    case Qt::LinearGradientPattern:
 
1654
        {
 
1655
            linearGradientData->rasterBuffer = fillData->rasterBuffer;
 
1656
            linearGradientData->spread = brush.gradient()->spread();
 
1657
            linearGradientData->stopCount = brush.gradient()->stops().size();
 
1658
            linearGradientData->stopPoints = gradientStopPoints(brush.gradient());
 
1659
            linearGradientData->stopColors = gradientStopColors(brush.gradient());
 
1660
            const QLinearGradient *lg = static_cast<const QLinearGradient *>(brush.gradient());
 
1661
            linearGradientData->origin = lg->start();
 
1662
            linearGradientData->end = lg->finalStop();
 
1663
 
 
1664
            linearGradientData->brushMatrix = brushMatrix();
 
1665
            linearGradientData->alphaColor = !brush.isOpaque();
 
1666
            linearGradientData->init();
 
1667
            linearGradientData->initColorTable();
 
1668
            linearGradientData->blendFunc = drawHelper->blendLinearGradient;
 
1669
            linearGradientData->compositionMode = compositionMode;
 
1670
            fillData->callback = qt_span_linear_gradient;
 
1671
            fillData->data = linearGradientData;
 
1672
            break;
 
1673
        }
 
1674
 
 
1675
    case Qt::RadialGradientPattern:
 
1676
        {
 
1677
            radialGradientData->rasterBuffer = fillData->rasterBuffer;
 
1678
            radialGradientData->spread = brush.gradient()->spread();
 
1679
            radialGradientData->stopCount = brush.gradient()->stops().size();
 
1680
            radialGradientData->stopPoints = gradientStopPoints(brush.gradient());
 
1681
            radialGradientData->stopColors = gradientStopColors(brush.gradient());
 
1682
            radialGradientData->center =
 
1683
                static_cast<const QRadialGradient *>(brush.gradient())->center();
 
1684
            radialGradientData->radius =
 
1685
                static_cast<const QRadialGradient *>(brush.gradient())->radius();
 
1686
            radialGradientData->focal =
 
1687
                static_cast<const QRadialGradient *>(brush.gradient())->focalPoint();
 
1688
            radialGradientData->alphaColor = !brush.isOpaque();
 
1689
            radialGradientData->initColorTable();
 
1690
            radialGradientData->imatrix = brushMatrix().inverted();
 
1691
            radialGradientData->blendFunc = drawHelper->blendRadialGradient;
 
1692
            radialGradientData->compositionMode = compositionMode;
 
1693
 
 
1694
            fillData->data = radialGradientData;
 
1695
            fillData->callback = qt_span_radial_gradient;
 
1696
        }
 
1697
        break;
 
1698
 
 
1699
    case Qt::ConicalGradientPattern:
 
1700
        {
 
1701
            conicalGradientData->rasterBuffer = fillData->rasterBuffer;
 
1702
            conicalGradientData->spread = QGradient::RepeatSpread; // don't support any anyway
 
1703
            conicalGradientData->stopCount = brush.gradient()->stops().size();
 
1704
            conicalGradientData->stopPoints = gradientStopPoints(brush.gradient());
 
1705
            conicalGradientData->stopColors = gradientStopColors(brush.gradient());
 
1706
            conicalGradientData->alphaColor = !brush.isOpaque();
 
1707
            conicalGradientData->compositionMode = compositionMode;
 
1708
            conicalGradientData->blendFunc = drawHelper->blendConicalGradient;
 
1709
            const QConicalGradient *cg = static_cast<const QConicalGradient *>(brush.gradient());
 
1710
            conicalGradientData->init(cg->center(), cg->angle(), brushMatrix());
 
1711
            fillData->data = conicalGradientData;
 
1712
            fillData->callback = qt_span_conical_gradient;
 
1713
        }
 
1714
        break;
 
1715
 
 
1716
    case Qt::Dense1Pattern:
 
1717
    case Qt::Dense2Pattern:
 
1718
    case Qt::Dense3Pattern:
 
1719
    case Qt::Dense4Pattern:
 
1720
    case Qt::Dense5Pattern:
 
1721
    case Qt::Dense6Pattern:
 
1722
    case Qt::Dense7Pattern:
 
1723
    case Qt::HorPattern:
 
1724
    case Qt::VerPattern:
 
1725
    case Qt::CrossPattern:
 
1726
    case Qt::BDiagPattern:
 
1727
    case Qt::FDiagPattern:
 
1728
    case Qt::DiagCrossPattern:
 
1729
        {
 
1730
            extern QPixmap qt_pixmapForBrush(int brushStyle, bool invert);
 
1731
            QPixmap pixmap = qt_pixmapForBrush(brush.style(), true);
 
1732
 
 
1733
            Q_ASSERT(!pixmap.isNull());
 
1734
            Q_ASSERT(pixmap.depth() == 1);
 
1735
 
 
1736
            tempImage = colorizeBitmap(pixmap.toImage(), brush.color());
 
1737
            fillData->data = textureFillData;
 
1738
            fillData->callback = txop > QPainterPrivate::TxTranslate
 
1739
                                 ? qt_span_texturefill_xform
 
1740
                                 : qt_span_texturefill;
 
1741
            textureFillData->compositionMode = compositionMode;
 
1742
            textureFillData->init(rasterBuffer, &tempImage, brushMatrix(),
 
1743
                                  drawHelper->blendTiled,
 
1744
                                  bilinear
 
1745
                                  ? drawHelper->blendTransformedBilinearTiled
 
1746
                                  : drawHelper->blendTransformedTiled);
 
1747
        }
 
1748
        break;
 
1749
 
 
1750
 
 
1751
    default:
 
1752
        break;
 
1753
    }
 
1754
 
 
1755
    return clipForFill(fillData);
 
1756
}
 
1757
 
 
1758
 
 
1759
void QRasterPaintEnginePrivate::updateClip_helper(const QPainterPath &path, Qt::ClipOperation op)
 
1760
{
 
1761
#ifdef QT_DEBUG_DRAW
 
1762
    QRectF bounds = path.boundingRect();
 
1763
    qDebug() << " --- updateClip_helper(), op=" << op << ", bounds=" << bounds;
 
1764
#endif
 
1765
    if (op == Qt::IntersectClip && !clipEnabled)
 
1766
        op = Qt::ReplaceClip;
 
1767
 
 
1768
    clipEnabled = true;
 
1769
    ClipData clipData = { rasterBuffer, op, 0 };
 
1770
 
 
1771
    switch (op) {
 
1772
    case Qt::NoClip:
 
1773
        rasterBuffer->resetClip();
 
1774
        clipEnabled = false;
 
1775
        return;
 
1776
    case Qt::ReplaceClip:
 
1777
        rasterBuffer->resetClip();
 
1778
        break;
 
1779
    case Qt::UniteClip:
 
1780
        break;
 
1781
    case Qt::IntersectClip:
 
1782
        if (path.isEmpty())
 
1783
            rasterBuffer->resetClip();
 
1784
        clipData.lastIntersected = -1;
 
1785
        break;
 
1786
    }
 
1787
 
 
1788
    if (path.isEmpty())
 
1789
        return;
 
1790
 
 
1791
    QT_FT_BBox clipBox = { 0, 0, rasterBuffer->width(), rasterBuffer->height() };
 
1792
    qt_scanconvert(outlineMapper->convertPath(path), qt_span_clip, &clipData, &clipBox, this);
 
1793
 
 
1794
    // Need to reset the clipspans that where not touched during scan conversion.
 
1795
    if (op == Qt::IntersectClip) {
 
1796
        int start = clipData.lastIntersected + 1;
 
1797
        rasterBuffer->resetClipSpans(start, rasterBuffer->height() - start);
 
1798
    }
 
1799
}
 
1800
 
 
1801
qreal *QRasterPaintEnginePrivate::gradientStopPoints(const QGradient *gradient)
 
1802
{
 
1803
    stopPoints.reset();
 
1804
    QGradientStops stops = gradient->stops();
 
1805
    for (int i=0; i<stops.size(); ++i) {
 
1806
        Q_ASSERT(stops.at(i).first >= 0 && stops.at(i).first <= 1);
 
1807
        stopPoints.add(stops.at(i).first);
 
1808
    }
 
1809
    return stopPoints.data();
 
1810
}
 
1811
 
 
1812
uint *QRasterPaintEnginePrivate::gradientStopColors(const QGradient *gradient)
 
1813
{
 
1814
    stopColors.reset();
 
1815
    QGradientStops stops = gradient->stops();
 
1816
    for (int i=0; i<stops.size(); ++i)
 
1817
        stopColors.add(PREMUL(stops.at(i).second.rgba()));
 
1818
    return stopColors.data();
 
1819
}
 
1820
 
 
1821
 
 
1822
QImage QRasterPaintEnginePrivate::colorizeBitmap(const QImage &image, const QColor &color)
 
1823
{
 
1824
    Q_ASSERT(image.depth() == 1);
 
1825
 
 
1826
    QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
 
1827
    QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
 
1828
 
 
1829
    QRgb fg = PREMUL(color.rgba());
 
1830
    QRgb bg = opaqueBackground ? PREMUL(bgBrush.color().rgba()) : 0;
 
1831
 
 
1832
    for (int y=0; y<sourceImage.height(); ++y) {
 
1833
        uchar *source = sourceImage.scanLine(y);
 
1834
        QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
 
1835
        for (int x=0; x < sourceImage.width(); ++x)
 
1836
            target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
 
1837
    }
 
1838
    return dest;
 
1839
}
 
1840
 
 
1841
QRasterBuffer::~QRasterBuffer()
 
1842
{
 
1843
    if (m_clipSpanCount || m_clipSpanCapacity || m_clipSpans) {
 
1844
        Q_ASSERT(m_clipSpanCount);
 
1845
        qFree(m_clipSpanCount);
 
1846
 
 
1847
        Q_ASSERT(m_clipSpanCapacity);
 
1848
        qFree(m_clipSpanCapacity);
 
1849
 
 
1850
        Q_ASSERT(m_clipSpans);
 
1851
        for (int y=0; y<m_height; ++y)
 
1852
            qFree((QT_FT_Span *)m_clipSpans[y]);
 
1853
        qFree(m_clipSpans);
 
1854
    }
 
1855
 
 
1856
#if defined (Q_WS_WIN)
 
1857
    if (m_bitmap || m_hdc) {
 
1858
        Q_ASSERT(m_hdc);
 
1859
        Q_ASSERT(m_bitmap);
 
1860
        DeleteObject(m_hdc);
 
1861
        DeleteObject(m_bitmap);
 
1862
    }
 
1863
#endif
 
1864
}
 
1865
 
 
1866
void QRasterBuffer::init()
 
1867
{
 
1868
    m_clipSpanCount = 0;
 
1869
    m_clipSpanCapacity = 0;
 
1870
    m_clipSpans = 0;
 
1871
    m_clipSpanHeight = 0;
 
1872
}
 
1873
 
 
1874
 
 
1875
void QRasterBuffer::prepare(int w, int h)
 
1876
{
 
1877
    if (w<=m_width && h<=m_height)
 
1878
        return;
 
1879
 
 
1880
    prepareBuffer(w, h);
 
1881
    prepareClip(w, h);
 
1882
 
 
1883
    m_width = w;
 
1884
    m_height = h;
 
1885
    bytes_per_line = 4*m_width;
 
1886
}
 
1887
 
 
1888
 
 
1889
void QRasterBuffer::prepare(QImage *image)
 
1890
{
 
1891
 
 
1892
    int depth = image->depth();
 
1893
    if (depth == 32) {
 
1894
        prepareClip(image->width(), image->height());
 
1895
        m_buffer = (uchar *)image->bits();
 
1896
    } else if (depth == 1) {
 
1897
        prepareClip(image->width(), image->height());
 
1898
        m_buffer = (uchar *)image->bits();
 
1899
    } else {
 
1900
        qWarning("QRasterBuffer::prepare() cannot prepare from image of depth=%d", depth);
 
1901
    }
 
1902
    m_width = image->width();
 
1903
    m_height = image->height();
 
1904
    bytes_per_line = 4*(depth == 32 ? m_width : (m_width + 31)/32);
 
1905
}
 
1906
 
 
1907
void QRasterBuffer::prepareClip(int /*width*/, int height)
 
1908
{
 
1909
    if (height <= m_clipSpanHeight) {
 
1910
        resetClipSpans(0, height);
 
1911
    } else {
 
1912
 
 
1913
        m_clipSpanHeight = height;
 
1914
 
 
1915
        // clean up.. Should reuse old_height first elements for improved reallocs.
 
1916
        if (m_clipSpanCount || m_clipSpanCapacity || m_clipSpans) {
 
1917
            Q_ASSERT(m_clipSpanCount);
 
1918
            qFree(m_clipSpanCount);
 
1919
 
 
1920
            Q_ASSERT(m_clipSpanCapacity);
 
1921
            qFree(m_clipSpanCapacity);
 
1922
 
 
1923
            Q_ASSERT(m_clipSpans);
 
1924
            for (int y=0; y<m_height; ++y)
 
1925
                qFree((QT_FT_Span *)m_clipSpans[y]);
 
1926
            qFree(m_clipSpans);
 
1927
        }
 
1928
 
 
1929
        m_clipSpanCount = (int *) qMalloc(height * sizeof(int));
 
1930
        m_clipSpanCapacity = (int *) qMalloc(height * sizeof(int));
 
1931
        m_clipSpans = (QSpan **) qMalloc(height * sizeof(QT_FT_Span *));
 
1932
        for (int y=0; y<height; ++y) {
 
1933
            m_clipSpanCapacity[y] = 4;
 
1934
            m_clipSpanCount[y] = 0;
 
1935
            m_clipSpans[y] = (QSpan *) qMalloc(m_clipSpanCapacity[y] * sizeof(QSpan));
 
1936
        }
 
1937
    }
 
1938
}
 
1939
 
 
1940
 
 
1941
void QRasterBuffer::resetBuffer(int val)
 
1942
{
 
1943
    memset(m_buffer, val, m_width*m_height*sizeof(uint));
 
1944
}
 
1945
 
 
1946
#if defined(Q_WS_WIN)
 
1947
void QRasterBuffer::prepareBuffer(int width, int height)
 
1948
{
 
1949
    BITMAPINFO bmi;
 
1950
    memset(&bmi, 0, sizeof(bmi));
 
1951
    bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
 
1952
    bmi.bmiHeader.biWidth       = width;
 
1953
    bmi.bmiHeader.biHeight      = -height;
 
1954
    bmi.bmiHeader.biPlanes      = 1;
 
1955
    bmi.bmiHeader.biBitCount    = 32;
 
1956
    bmi.bmiHeader.biCompression = BI_RGB;
 
1957
    bmi.bmiHeader.biSizeImage   = 0;
 
1958
 
 
1959
    HDC displayDC = GetDC(0);
 
1960
 
 
1961
    // a little bit of cleanup...
 
1962
    if (m_bitmap || m_hdc) {
 
1963
        Q_ASSERT(m_hdc);
 
1964
        Q_ASSERT(m_bitmap);
 
1965
        DeleteObject(m_hdc);
 
1966
        DeleteObject(m_bitmap);
 
1967
    }
 
1968
 
 
1969
    m_hdc = CreateCompatibleDC(displayDC);
 
1970
    Q_ASSERT(m_hdc);
 
1971
 
 
1972
    m_buffer = 0;
 
1973
    m_bitmap = CreateDIBSection(m_hdc, &bmi, DIB_RGB_COLORS, (void**) &m_buffer, 0, 0);
 
1974
    Q_ASSERT(m_bitmap);
 
1975
    Q_ASSERT(m_buffer);
 
1976
    GdiFlush();
 
1977
 
 
1978
    SelectObject(m_hdc, m_bitmap);
 
1979
 
 
1980
    ReleaseDC(0, displayDC);
 
1981
}
 
1982
#elif defined(Q_WS_X11)
 
1983
void QRasterBuffer::prepareBuffer(int width, int height)
 
1984
{
 
1985
    delete[] m_buffer;
 
1986
    m_buffer = new uchar[width*height];
 
1987
    memset(m_buffer, 255, width*height*sizeof(uint));
 
1988
}
 
1989
#elif defined(Q_WS_MAC)
 
1990
static void qt_mac_raster_data_free(void *memory, const void *, size_t)
 
1991
{
 
1992
    free(memory);
 
1993
}
 
1994
 
 
1995
void QRasterBuffer::prepareBuffer(int width, int height)
 
1996
{
 
1997
    m_buffer = new uchar[width*height*sizeof(uint)];
 
1998
    memset(m_buffer, 255, width*height*sizeof(uint));
 
1999
 
 
2000
#ifdef QMAC_NO_COREGRAPHICS
 
2001
# warning "Unhandled!!"
 
2002
#else
 
2003
    if (m_data)
 
2004
        CGImageRelease(m_data);
 
2005
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
 
2006
    CGDataProviderRef provider = CGDataProviderCreateWithData(m_buffer, m_buffer, width*height,
 
2007
                                                              qt_mac_raster_data_free);
 
2008
    m_data = CGImageCreate(width, height, 8, 32, width, colorspace,
 
2009
                           kCGImageAlphaFirst, provider, 0, 0, kCGRenderingIntentDefault);
 
2010
    CGColorSpaceRelease(colorspace);
 
2011
    CGDataProviderRelease(provider);
 
2012
#endif
 
2013
 
 
2014
}
 
2015
#elif defined(Q_WS_QWS)
 
2016
void QRasterBuffer::prepareBuffer(int /*width*/, int /*height*/)
 
2017
{
 
2018
    qFatal("QRasterBuffer::prepareBuffer not implemented on embedded");
 
2019
    m_buffer = 0;
 
2020
}
 
2021
#endif
 
2022
 
 
2023
void QRasterBuffer::appendClipSpan(int x, int y, int len, int coverage)
 
2024
{
 
2025
//     printf("QRasterBuffer::apendClipSpan(x=%d, y=%d, len=%d, oldSize=%d\n", x, y, len,
 
2026
//            m_clipSpanCount[y]);
 
2027
 
 
2028
    QSpan *span = 0;
 
2029
 
 
2030
    int clipSpanCount = m_clipSpanCount[y];
 
2031
 
 
2032
    if (clipSpanCount == m_clipSpanCapacity[y])
 
2033
        resizeClipSpan(y, clipSpanCount << 1);
 
2034
 
 
2035
//     Uncomment for sanity checking
 
2036
//     for (int i=0; i<m_clipSpanCount[y]; ++i) {
 
2037
//         QSpan *s = m_clipSpans[y] + i;
 
2038
//         if (x < s->x + s->len) {
 
2039
//             printf("bad append clip for: x=%d, y=%d, len=%d, cov=%d\n", x, y, len, coverage);
 
2040
//             Q_ASSERT(0);
 
2041
//         }
 
2042
//     }
 
2043
 
 
2044
    span = m_clipSpans[y] + clipSpanCount;
 
2045
 
 
2046
    span->x = x;
 
2047
    span->len = len;
 
2048
    span->coverage = coverage;
 
2049
    m_clipSpanCount[y] += 1;
 
2050
}
 
2051
 
 
2052
void QRasterBuffer::replaceClipSpans(int y, QSpan *spans, int spanCount)
 
2053
{
 
2054
    if (m_clipSpanCapacity[y] < spanCount)
 
2055
        resizeClipSpan(y, spanCount);
 
2056
    memcpy(m_clipSpans[y], spans, spanCount * sizeof(QSpan));
 
2057
    m_clipSpanCount[y] = spanCount;
 
2058
}
 
2059
 
 
2060
void QRasterBuffer::resetClipSpans(int y, int count)
 
2061
{
 
2062
    memset(m_clipSpanCount + y, 0, count * sizeof(int));
 
2063
}
 
2064
 
 
2065
void QRasterBuffer::resetClip()
 
2066
{
 
2067
    memset(m_clipSpanCount, 0, m_height * sizeof(int));
 
2068
}
 
2069
 
 
2070
void QRasterBuffer::resizeClipSpan(int y, int size)
 
2071
{
 
2072
    Q_ASSERT(size > m_clipSpanCount[y]);
 
2073
    m_clipSpans[y] = (QSpan *) qRealloc(m_clipSpans[y], size * sizeof(QSpan));
 
2074
    m_clipSpanCapacity[y] = size;
 
2075
}
 
2076
 
 
2077
void qt_span_solidfill(int y, int count, QT_FT_Span *spans, void *userData)
 
2078
{
 
2079
    SolidFillData *data = reinterpret_cast<SolidFillData *>(userData);
 
2080
    QRasterBuffer *rb = data->rasterBuffer;
 
2081
    uchar *rasterBuffer = rb->scanLine(y);
 
2082
//     fprintf(stdout, "qt_span_solidfill, y=%d, count=%d rb->width=%d rb->bytes_per_line=%d\n", y, count, rb->width(), rb->bytesPerLine());
 
2083
//     fflush(stdout);
 
2084
 
 
2085
    Q_ASSERT(y >= 0);
 
2086
    Q_ASSERT(y < rb->height());
 
2087
 
 
2088
    BlendColorData bd;
 
2089
    bd.color = data->color;
 
2090
    bd.y = y;
 
2091
 
 
2092
    for (int span=0; span<count; ++span) {
 
2093
        Q_ASSERT(spans->x >= 0);
 
2094
        Q_ASSERT(spans->len > 0);
 
2095
        Q_ASSERT(spans->x + spans->len <= rb->width());
 
2096
        data->blendColor(rasterBuffer, (const QSpan *)spans, data->compositionMode, &bd);
 
2097
        ++spans;
 
2098
    }
 
2099
}
 
2100
 
 
2101
 
 
2102
void qt_span_texturefill(int y, int count, QT_FT_Span *spans, void *userData)
 
2103
{
 
2104
    TextureFillData *data = reinterpret_cast<TextureFillData *>(userData);
 
2105
    QRasterBuffer *rb = data->rasterBuffer;
 
2106
    int image_width = data->width;
 
2107
    int image_height = data->height;
 
2108
    int xoff = qRound(data->dx) % image_width;
 
2109
    int yoff = qRound(data->dy) % image_height;
 
2110
 
 
2111
    if (xoff < 0)
 
2112
        xoff += image_width;
 
2113
    if (yoff < 0)
 
2114
        yoff += image_height;
 
2115
 
 
2116
    uchar *baseTarget = rb->scanLine(y);
 
2117
    while (count--) {
 
2118
        QPainter::CompositionMode mode = data->compositionMode;
 
2119
        if (!data->hasAlpha && mode == QPainter::CompositionMode_SourceOver
 
2120
            && spans->coverage == 255)
 
2121
            mode = QPainter::CompositionMode_Source;
 
2122
        data->blend(baseTarget, (const QSpan *)spans, (xoff + spans->x)%image_width,
 
2123
                    ((y + yoff) % image_height), data->imageData, image_width, image_height,
 
2124
                    mode);
 
2125
        ++spans;
 
2126
    }
 
2127
}
 
2128
 
 
2129
void qt_span_texturefill_xform(int y, int count, QT_FT_Span *spans, void *userData)
 
2130
{
 
2131
    TextureFillData *data = reinterpret_cast<TextureFillData *>(userData);
 
2132
    QRasterBuffer *rb = data->rasterBuffer;
 
2133
    int image_width = data->width;
 
2134
    int image_height = data->height;
 
2135
    uchar *baseTarget = rb->scanLine(y);
 
2136
 
 
2137
    // Base point for the inversed transform
 
2138
    qreal ix = data->m21 * y + data->dx;
 
2139
    qreal iy = data->m22 * y + data->dy;
 
2140
 
 
2141
    // The increment pr x in the scanline
 
2142
    qreal dx = data->m11;
 
2143
    qreal dy = data->m12;
 
2144
 
 
2145
    while (count--) {
 
2146
        data->blendFunc(baseTarget, (const QSpan *)spans,
 
2147
                        ix, iy, dx, dy,
 
2148
                        data->imageData, image_width, image_height,
 
2149
                        data->compositionMode);
 
2150
        ++spans;
 
2151
    }
 
2152
}
 
2153
 
 
2154
 
 
2155
uint qt_gradient_pixel(const GradientData *data, double pos)
 
2156
{
 
2157
    int ipos = qRound(pos * GRADIENT_STOPTABLE_SIZE - 1);
 
2158
 
 
2159
  // calculate the actual offset.
 
2160
    if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
 
2161
        if (data->spread == QGradient::RepeatSpread) {
 
2162
            ipos = ipos % GRADIENT_STOPTABLE_SIZE;
 
2163
            ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
 
2164
 
 
2165
        } else if (data->spread == QGradient::ReflectSpread) {
 
2166
            const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
 
2167
            ipos = ipos % limit;
 
2168
            ipos = ipos < 0 ? limit + ipos : ipos;
 
2169
            ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
 
2170
 
 
2171
        } else {
 
2172
            if (ipos < 0) ipos = 0;
 
2173
            else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
 
2174
        }
 
2175
    }
 
2176
 
 
2177
    Q_ASSERT(ipos >= 0);
 
2178
    Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
 
2179
 
 
2180
    return data->colorTable[ipos];
 
2181
}
 
2182
 
 
2183
 
 
2184
void qt_span_linear_gradient(int y, int count, QT_FT_Span *spans, void *userData)
 
2185
{
 
2186
    LinearGradientData *data = reinterpret_cast<LinearGradientData *>(userData);
 
2187
    uchar *baseTarget = data->rasterBuffer->scanLine(y);
 
2188
 
 
2189
    qreal ybase = (y - data->origin.y()) * data->yincr;
 
2190
 
 
2191
    while (count--) {
 
2192
        data->blendFunc(baseTarget, (const QSpan *)spans, data, ybase, y, data->compositionMode);
 
2193
        ++spans;
 
2194
    }
 
2195
}
 
2196
 
 
2197
void qt_span_radial_gradient(int y, int count, QT_FT_Span *spans, void *userData)
 
2198
{
 
2199
    RadialGradientData *data = reinterpret_cast<RadialGradientData *>(userData);
 
2200
    uchar *baseTarget = data->rasterBuffer->scanLine(y);
 
2201
 
 
2202
    while (count--) {
 
2203
        data->blendFunc(baseTarget, (const QSpan *)spans, data, y, data->compositionMode);
 
2204
        ++spans;
 
2205
    }
 
2206
}
 
2207
 
 
2208
void qt_span_conical_gradient(int y, int count, QT_FT_Span *spans, void *userData)
 
2209
{
 
2210
    ConicalGradientData *data = reinterpret_cast<ConicalGradientData *>(userData);
 
2211
    uchar *baseTarget = data->rasterBuffer->scanLine(y);
 
2212
 
 
2213
    while (count--) {
 
2214
        data->blendFunc(baseTarget, (const QSpan *)spans, data, y, data->compositionMode);
 
2215
        ++spans;
 
2216
    }
 
2217
}
 
2218
 
 
2219
void qt_intersect_spans(QSpan *clipSpans, int clipSpanCount,
 
2220
                        QT_FT_Span *spans, int spanCount,
 
2221
                        QSpan **outSpans, int *outCount)
 
2222
{
 
2223
    static QDataBuffer<QSpan> newSpans;
 
2224
    newSpans.reset();
 
2225
 
 
2226
    int spanIndex = 0;
 
2227
    int clipSpanIndex = 0;
 
2228
 
 
2229
    int sx1, sx2, cx1, cx2;
 
2230
 
 
2231
    while (spanIndex < spanCount && clipSpanIndex < clipSpanCount) {
 
2232
        sx1 = spans[spanIndex].x;
 
2233
        sx2 = sx1 + spans[spanIndex].len;
 
2234
        cx1 = clipSpans[clipSpanIndex].x;
 
2235
        cx2 = cx1 + clipSpans[clipSpanIndex].len;
 
2236
 
 
2237
        if (cx1 < sx1 && cx2 < sx1) {
 
2238
            ++clipSpanIndex;
 
2239
        } else if (sx1 < cx1 && sx2 < cx1) {
 
2240
            ++spanIndex;
 
2241
        } else {
 
2242
            QSpan newClip;
 
2243
            newClip.x = qMax(sx1, cx1);
 
2244
            newClip.len = qMin(sx2, cx2) - newClip.x;
 
2245
            newClip.coverage = spans[spanIndex].coverage * clipSpans[clipSpanIndex].coverage / 255;
 
2246
            if (newClip.len>0)
 
2247
                newSpans.add(newClip);
 
2248
            if (sx2 < cx2) {
 
2249
                ++spanIndex;
 
2250
            } else {
 
2251
                ++clipSpanIndex;
 
2252
            }
 
2253
        }
 
2254
    }
 
2255
 
 
2256
    *outSpans = newSpans.data();
 
2257
    *outCount = newSpans.size();
 
2258
}
 
2259
 
 
2260
void qt_unite_spans(QSpan *clipSpans, int clipSpanCount,
 
2261
                    QT_FT_Span *spans, int spanCount,
 
2262
                    QSpan **outSpans, int *outCount)
 
2263
{
 
2264
 
 
2265
 
 
2266
    static QDataBuffer<QSpan> newSpans;
 
2267
    newSpans.reset();
 
2268
 
 
2269
 
 
2270
    // ### will leak for now... BTW, this is a horrible algorithm, but then again it works...
 
2271
    const int BUFFER_SIZE = 4096;
 
2272
    static int *buffer = (int*) malloc(BUFFER_SIZE * sizeof(int));
 
2273
    memset(buffer, 0, BUFFER_SIZE * sizeof(int));
 
2274
 
 
2275
    // Fill with old spans.
 
2276
    for (int i=0; i<clipSpanCount; ++i) {
 
2277
        QSpan *cs = clipSpans + i;
 
2278
        for (int j=cs->x; j<cs->x + cs->len; ++j)
 
2279
            buffer[j] += cs->coverage;
 
2280
    }
 
2281
 
 
2282
    // Fill with new spans
 
2283
    for (int i=0; i<spanCount; ++i) {
 
2284
        QT_FT_Span *s = spans + i;
 
2285
        for (int j=s->x; j<s->x + s->len; ++j) {
 
2286
            buffer[j] += s->coverage;
 
2287
            if (buffer[j] > 255) buffer[j] = 255;
 
2288
        }
 
2289
    }
 
2290
 
 
2291
 
 
2292
    int maxClip = clipSpanCount > 0
 
2293
                  ? clipSpans[clipSpanCount-1].x + clipSpans[clipSpanCount-1].len
 
2294
                  : -1;
 
2295
    int maxSpan = spanCount > 0
 
2296
                  ? spans[spanCount-1].x + spans[spanCount-1].len
 
2297
                  : -1;
 
2298
 
 
2299
    int max = qMax(maxClip, maxSpan);
 
2300
 
 
2301
    int x = 0;
 
2302
    while (x<max) {
 
2303
 
 
2304
        // Skip to next span
 
2305
        while (x < max && buffer[x] == 0) ++x;
 
2306
        if (x >= max) break;
 
2307
 
 
2308
        QSpan sp;
 
2309
        sp.x = x;
 
2310
        sp.coverage = buffer[x];
 
2311
 
 
2312
        // Find length of span
 
2313
        while (x < max && buffer[x] == sp.coverage) ++x;
 
2314
        sp.len = x - sp.x;
 
2315
 
 
2316
        newSpans.add(sp);
 
2317
    }
 
2318
 
 
2319
    *outSpans = newSpans.data();
 
2320
    *outCount = newSpans.size();
 
2321
}
 
2322
 
 
2323
 
 
2324
void qt_span_fill_clipped(int y, int spanCount, QT_FT_Span *spans, void *userData)
 
2325
{
 
2326
    FillData *fillData = reinterpret_cast<FillData *>(userData);
 
2327
 
 
2328
    Q_ASSERT(fillData->callback);
 
2329
 
 
2330
    QRasterBuffer *rb = fillData->rasterBuffer;
 
2331
 
 
2332
    QSpan *clippedSpans = 0;
 
2333
    int clippedSpanCount = 0;
 
2334
 
 
2335
    qt_intersect_spans(rb->clipSpans(y), rb->clipSpanCount(y),
 
2336
                       spans, spanCount,
 
2337
                       &clippedSpans, &clippedSpanCount);
 
2338
 
 
2339
    fillData->callback(y, clippedSpanCount, (QT_FT_Span *) clippedSpans, fillData->data);
 
2340
}
 
2341
 
 
2342
void qt_span_clip(int y, int count, QT_FT_Span *spans, void *userData)
 
2343
{
 
2344
    ClipData *clipData = reinterpret_cast<ClipData *>(userData);
 
2345
    QRasterBuffer *rb = clipData->rasterBuffer;
 
2346
 
 
2347
    switch (clipData->operation) {
 
2348
 
 
2349
    case Qt::IntersectClip:
 
2350
        {
 
2351
            QSpan *newSpans;
 
2352
            int newSpanCount = 0;
 
2353
            qt_intersect_spans(rb->clipSpans(y), rb->clipSpanCount(y),
 
2354
                               spans, count,
 
2355
                               &newSpans, &newSpanCount);
 
2356
 
 
2357
            // Clear the spans between last y spanned and this.
 
2358
            for (int i=clipData->lastIntersected+1; i<y; ++i)
 
2359
                rb->replaceClipSpans(i, 0, 0);
 
2360
            clipData->lastIntersected = y;
 
2361
 
 
2362
            // Replace this
 
2363
            rb->replaceClipSpans(y, newSpans, newSpanCount);
 
2364
        }
 
2365
        break;
 
2366
 
 
2367
    case Qt::UniteClip:
 
2368
        {
 
2369
            QSpan *newSpans;
 
2370
            int newSpanCount = 0;
 
2371
            qt_unite_spans(rb->clipSpans(y), rb->clipSpanCount(y),
 
2372
                           spans, count,
 
2373
                           &newSpans, &newSpanCount);
 
2374
 
 
2375
            rb->replaceClipSpans(y, newSpans, newSpanCount);
 
2376
        }
 
2377
        break;
 
2378
 
 
2379
    case Qt::ReplaceClip:
 
2380
        for (int i=0; i<count; ++i) {
 
2381
            rb->appendClipSpan(spans->x, y, spans->len, spans->coverage);
 
2382
            ++spans;
 
2383
        }
 
2384
        break;
 
2385
    case Qt::NoClip:
 
2386
        break;
 
2387
    }
 
2388
}
 
2389
 
 
2390
void qt_scanconvert(QT_FT_Outline *outline, qt_span_func callback, void *userData,
 
2391
                    QT_FT_BBox *boundingBox, QRasterPaintEnginePrivate *d)
 
2392
{
 
2393
    qt_span_func func = callback;
 
2394
    void *data = userData;
 
2395
 
 
2396
    QT_FT_Raster_Params rasterParams;
 
2397
    rasterParams.target = 0;
 
2398
    rasterParams.source = outline;
 
2399
    rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
 
2400
    rasterParams.gray_spans = 0;
 
2401
    rasterParams.black_spans = 0;
 
2402
    rasterParams.bit_test = 0;
 
2403
    rasterParams.bit_set = 0;
 
2404
    rasterParams.user = data;
 
2405
    rasterParams.clip_box = *boundingBox;
 
2406
 
 
2407
    if (d->antialiased) {
 
2408
        rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
 
2409
        rasterParams.gray_spans = func;
 
2410
        int error = qt_ft_grays_raster.raster_render(qt_gray_raster, &rasterParams);
 
2411
        if (error) {
 
2412
            printf("qt_scanconvert(), gray raster failed...: %d\n", error);
 
2413
        }
 
2414
    } else {
 
2415
        rasterParams.flags |= QT_FT_RASTER_FLAG_DIRECT;
 
2416
        rasterParams.black_spans = func;
 
2417
        int error = qt_ft_standard_raster.raster_render(qt_black_raster, &rasterParams);
 
2418
        if (error) {
 
2419
            qWarning("black raster failed to render, code=%d", error);
 
2420
        }
 
2421
    }
 
2422
 
 
2423
}
 
2424
 
 
2425
#ifndef QT_NO_DEBUG
 
2426
QImage QRasterBuffer::clipImage() const
 
2427
{
 
2428
    QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
 
2429
    image.fill(qRgb(0, 0, 0));
 
2430
 
 
2431
    for (int y = 0; y < m_height; ++y) {
 
2432
        QSpan *spans = clipSpans(y);
 
2433
        int count = clipSpanCount(y);
 
2434
 
 
2435
        while (count--) {
 
2436
            for (int x=spans->x; x<spans->x + spans->len; ++x) {
 
2437
                QRgb pixel = image.pixel(x, y);
 
2438
                image.setPixel(x, y, qRgb(spans->coverage, qGreen(pixel) + 10, 0));
 
2439
            }
 
2440
            ++spans;
 
2441
        }
 
2442
    }
 
2443
    return image;
 
2444
}
 
2445
 
 
2446
QImage QRasterBuffer::bufferImage() const
 
2447
{
 
2448
    QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
 
2449
 
 
2450
    for (int y = 0; y < m_height; ++y) {
 
2451
        uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
 
2452
 
 
2453
        for (int x=0; x<m_width; ++x) {
 
2454
            uint argb = span[x];
 
2455
            image.setPixel(x, y, argb);
 
2456
        }
 
2457
    }
 
2458
    return image;
 
2459
}
 
2460
#endif
 
2461
 
 
2462
 
 
2463
void QRasterBuffer::flushToARGBImage(QImage *target) const
 
2464
{
 
2465
    int w = qMin(m_width, target->width());
 
2466
    int h = qMin(m_height, target->height());
 
2467
 
 
2468
    for (int y=0; y<h; ++y) {
 
2469
        uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
 
2470
        QRgb *dest = (QRgb *) target->scanLine(y);
 
2471
        for (int x=0; x<w; ++x) {
 
2472
            QRgb pixel = sourceLine[x];
 
2473
            int alpha = qAlpha(pixel);
 
2474
            if (!alpha) {
 
2475
                dest[x] = 0;
 
2476
            } else {
 
2477
                dest[x] = (alpha << 24)
 
2478
                        | ((255*qRed(pixel)/alpha) << 16)
 
2479
                        | ((255*qGreen(pixel)/alpha) << 8)
 
2480
                        | ((255*qBlue(pixel)/alpha) << 0);
 
2481
            }
 
2482
        }
 
2483
    }
 
2484
}
 
2485
 
 
2486
void TextureFillData::init(QRasterBuffer *raster, const QImage *image, const QMatrix &matrix,
 
2487
                           Blend b, BlendTransformed func)
 
2488
{
 
2489
    rasterBuffer = raster;
 
2490
    imageData = (uint*) image->bits();
 
2491
    width = image->width();
 
2492
    height = image->height();
 
2493
    hasAlpha = image->format() != QImage::Format_RGB32;
 
2494
 
 
2495
    QMatrix inv = matrix.inverted();
 
2496
    m11 = inv.m11();
 
2497
    m12 = inv.m12();
 
2498
    m21 = inv.m21();
 
2499
    m22 = inv.m22();
 
2500
    dx = inv.dx();
 
2501
    dy = inv.dy();
 
2502
 
 
2503
    blend = b;
 
2504
    blendFunc = func;
 
2505
}
 
2506
 
 
2507
void GradientData::initColorTable()
 
2508
{
 
2509
    Q_ASSERT(stopCount > 0);
 
2510
 
 
2511
    // The position where the gradient begins and ends
 
2512
    int begin_pos = int(stopPoints[0] * GRADIENT_STOPTABLE_SIZE);
 
2513
    int end_pos = int(stopPoints[stopCount-1] * GRADIENT_STOPTABLE_SIZE);
 
2514
 
 
2515
    int pos = 0; // The position in the color table.
 
2516
 
 
2517
    // Up to first point
 
2518
    while (pos<=begin_pos) {
 
2519
        colorTable[pos] = stopColors[0];
 
2520
        ++pos;
 
2521
    }
 
2522
 
 
2523
    qreal incr = 1 / qreal(GRADIENT_STOPTABLE_SIZE); // the double increment.
 
2524
    qreal dpos = incr * pos; // The position in terms of 0-1.
 
2525
 
 
2526
    int current_stop = 0; // We always interpolate between current and current + 1.
 
2527
 
 
2528
    // Gradient area
 
2529
    while (pos < end_pos) {
 
2530
 
 
2531
        Q_ASSERT(current_stop < stopCount);
 
2532
 
 
2533
        uint current_color = stopColors[current_stop];
 
2534
        uint next_color = stopColors[current_stop+1];
 
2535
 
 
2536
        int dist = (int)(256*(dpos - stopPoints[current_stop])
 
2537
                         / (stopPoints[current_stop+1] - stopPoints[current_stop]));
 
2538
        int idist = 256 - dist;
 
2539
 
 
2540
        colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
 
2541
 
 
2542
        ++pos;
 
2543
        dpos += incr;
 
2544
 
 
2545
        if (dpos > stopPoints[current_stop+1]) {
 
2546
            ++current_stop;
 
2547
        }
 
2548
    }
 
2549
 
 
2550
    // After last point
 
2551
    while (pos < GRADIENT_STOPTABLE_SIZE) {
 
2552
        colorTable[pos] = stopColors[stopCount-1];
 
2553
        ++pos;
 
2554
    }
 
2555
}
 
2556
 
 
2557
/**
 
2558
 * Initialzes the xincr and yincr delta values that is used to interpolate the Linear Gradient
 
2559
 *
 
2560
 * The deltas are found by projecting the gradientline down to a horizontal (xincr) or vertical (yincr)
 
2561
 * line that covers the whole gradient (from 0 to 1.0).
 
2562
 * Given that the gradient line is d, the transformed normal vector is n, we use this formula to
 
2563
 * find the length of the side in the triangle is supposed to interpolate over the gradient:
 
2564
 * _     _                      _             _
 
2565
 * d + a*n = [l,0],       where d = [dx, dy], n = [ndx, ndy], l is the length of the line.
 
2566
 * since we have a zero in our equation, *a* can be found and is used to find *l*.
 
2567
 *
 
2568
 * rearranging, we get the length of line like this:
 
2569
 *
 
2570
 * l = dx - dy*ndx/ndy;  =>  xincr = 1.0/l
 
2571
 *
 
2572
 * We calculate yincr similarly:
 
2573
 * l = dy - dx*ndy/ndx;  =>  yincr = 1.0/l
 
2574
 *
 
2575
 *
 
2576
 * We then find the length of that line, and divides the length of the gradient (1.0) by the length
 
2577
 * of the line (in pixels)
 
2578
 *
 
2579
 *
 
2580
 */
 
2581
void LinearGradientData::init()
 
2582
{
 
2583
    qreal x1 = origin.x();
 
2584
    qreal y1 = origin.y();
 
2585
    qreal x2 = end.x();
 
2586
    qreal y2 = end.y();
 
2587
 
 
2588
#ifdef QT_DEBUG_DRAW
 
2589
    qDebug("LinearGradientData::init(), x1=%f, y1=%f, x2=%f, y2=%f, spread=%d",
 
2590
           x1, y1, x2, y2, spread);
 
2591
    for (int i=0; i<stopCount; ++i) {
 
2592
        qDebug(" - %d, pos=%f, color=%x", i, stopPoints[i], stopColors[i]);
 
2593
    }
 
2594
#endif
 
2595
 
 
2596
    // Calculate the normalvector and transform it.
 
2597
    QLineF n = brushMatrix.map(QLineF(x1, y1, x2, y2).normalVector() );
 
2598
 
 
2599
    origin = brushMatrix.map(origin);
 
2600
    end = brushMatrix.map(end);
 
2601
 
 
2602
    x1 = origin.x();
 
2603
    y1 = origin.y();
 
2604
    x2 = end.x();
 
2605
    y2 = end.y();
 
2606
 
 
2607
    qreal dx = x2 - x1;
 
2608
    qreal dy = y2 - y1;
 
2609
 
 
2610
    // qDebug() << "(" << x1 << "," << y1 << ")";
 
2611
    // qDebug() << "(" << x2 << "," << y2 << ")";
 
2612
 
 
2613
    qreal ndx = n.dx();
 
2614
    qreal ndy = n.dy();
 
2615
 
 
2616
    // qDebug() << "dx: " << dx << "dy: " << dy << "nx: " << nx << "nx: " << nx;;
 
2617
    // Find the length of the projection
 
2618
    
 
2619
    if (qAbs(ndy) > GRADIENT_EPSILON) {
 
2620
        qreal l = dx - dy*ndx/ndy;
 
2621
        xincr = 1.0/l;
 
2622
    } else {
 
2623
        xincr = 0;
 
2624
    }
 
2625
 
 
2626
    if (qAbs(ndx) > GRADIENT_EPSILON) {
 
2627
        qreal l = dy - dx*ndy/ndx;
 
2628
        yincr = 1.0/l;
 
2629
    } else {
 
2630
        yincr = 0;
 
2631
    }
 
2632
 
 
2633
    // qDebug() << "inc: " << xincr << "," << yincr;
 
2634
 
 
2635
}
 
2636
 
 
2637
void ConicalGradientData::init(const QPointF &pt, qreal a, const QMatrix &matrix)
 
2638
{
 
2639
    center = pt;
 
2640
    angle = a * 2 * Q_PI / 360.0;
 
2641
    imatrix = matrix.inverted();
 
2642
 
 
2643
    initColorTable();
 
2644
};
 
2645
 
 
2646
 
 
2647
#ifdef Q_WS_WIN
 
2648
static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
 
2649
                               QRasterPaintEnginePrivate *d)
 
2650
{
 
2651
    QPointF p = pos;
 
2652
 
 
2653
    if (d->txop > QPainterPrivate::TxTranslate) {
 
2654
        XFORM m;
 
2655
        m.eM11 = d->matrix.m11();
 
2656
        m.eM12 = d->matrix.m12();
 
2657
        m.eM21 = d->matrix.m21();
 
2658
        m.eM22 = d->matrix.m22();
 
2659
        // Don't include the translation since it is done when we write the HDC
 
2660
        // Back to the screen.
 
2661
        m.eDx  = 0;
 
2662
        m.eDy  = 0;
 
2663
        if (!SetGraphicsMode(hdc, GM_ADVANCED))
 
2664
            qErrnoWarning("QWin32PaintEngine::setNativeMatrix(), SetGraphicsMode failed");
 
2665
        if (!SetWorldTransform(hdc, &m))
 
2666
            qErrnoWarning("QWin32PaintEngine::setNativeMatrix(), SetWorldTransformation failed");
 
2667
    }
 
2668
 
 
2669
    QFontEngine *fe = ti.fontEngine;
 
2670
 
 
2671
    SetTextAlign(hdc, TA_BASELINE);
 
2672
    SetBkMode(hdc, TRANSPARENT);
 
2673
    SetTextColor(hdc, RGB(0, 0, 0));
 
2674
 
 
2675
    double scale = 1.;
 
2676
    int angle = 0;
 
2677
    bool transform = false;
 
2678
    bool has_kerning = ti.f->kerning();
 
2679
 
 
2680
    qreal x = p.x();
 
2681
    qreal y = p.y();
 
2682
 
 
2683
    if (d->txop >= QPainterPrivate::TxScale
 
2684
        && !(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
 
2685
        // Draw rotated and sheared text on Windows 95, 98
 
2686
 
 
2687
        // All versions can draw rotated text natively. Scaling can be done with window/viewport transformations.
 
2688
        // Shearing transformations are done by QPainter.
 
2689
 
 
2690
        // rotation + scale + translation
 
2691
        scale = sqrt(d->matrix.m11()*d->matrix.m22()
 
2692
                      - d->matrix.m12()*d->matrix.m21());
 
2693
        angle = qRound(1800*acos(d->matrix.m11()/scale)/Q_PI);
 
2694
        if (d->matrix.m12() < 0)
 
2695
            angle = 3600 - angle;
 
2696
 
 
2697
        transform = true;
 
2698
    }
 
2699
 
 
2700
    if (ti.flags & (QTextItem::Underline|QTextItem::StrikeOut) || scale != 1. || angle) {
 
2701
        LOGFONT lf = fe->logfont;
 
2702
        lf.lfUnderline = (ti.flags & QTextItem::Underline);
 
2703
        lf.lfStrikeOut = (ti.flags & QTextItem::StrikeOut);
 
2704
        if (angle) {
 
2705
            lf.lfOrientation = -angle;
 
2706
            lf.lfEscapement = -angle;
 
2707
        }
 
2708
        if (scale != 1.) {
 
2709
            lf.lfHeight = (int) (lf.lfHeight*scale);
 
2710
            lf.lfWidth = (int) (lf.lfWidth*scale);
 
2711
        }
 
2712
        HFONT hf = QT_WA_INLINE(CreateFontIndirectW(&lf), CreateFontIndirectA((LOGFONTA*)&lf));
 
2713
        SelectObject(hdc, hf);
 
2714
    } else {
 
2715
        SelectObject(hdc, fe->hfont);
 
2716
    }
 
2717
 
 
2718
    unsigned int options =  fe->ttf ? ETO_GLYPH_INDEX : 0;
 
2719
 
 
2720
    QGlyphLayout *glyphs = ti.glyphs;
 
2721
 
 
2722
    int xo = qRound(x);
 
2723
 
 
2724
    if (!(ti.flags & QTextItem::RightToLeft)) {
 
2725
        // hack to get symbol fonts working on Win95. See also QFontEngine constructor
 
2726
        if (fe->useTextOutA) {
 
2727
            // can only happen if !ttf
 
2728
            for(int i = 0; i < ti.num_glyphs; i++) {
 
2729
                QString str(QChar(glyphs->glyph));
 
2730
                QByteArray cstr = str.toLocal8Bit();
 
2731
                TextOutA(hdc, qRound(x + glyphs->offset.x()), qRound(y + glyphs->offset.y()),
 
2732
                         cstr.data(), cstr.length());
 
2733
                x += qRound(glyphs->advance.x());
 
2734
                glyphs++;
 
2735
            }
 
2736
        } else {
 
2737
            bool haveOffsets = false;
 
2738
            qreal w = 0;
 
2739
            for(int i = 0; i < ti.num_glyphs; i++) {
 
2740
                if (glyphs[i].offset.x() != 0 || glyphs[i].offset.y() != 0 || glyphs[i].space_18d6 != 0) {
 
2741
                    haveOffsets = true;
 
2742
                    break;
 
2743
                }
 
2744
                w += glyphs[i].advance.x();
 
2745
            }
 
2746
 
 
2747
            if (haveOffsets || transform || has_kerning) {
 
2748
                for(int i = 0; i < ti.num_glyphs; i++) {
 
2749
                    wchar_t chr = glyphs->glyph;
 
2750
                    qreal xp = x + glyphs->offset.x();
 
2751
                    qreal yp = y + glyphs->offset.y();
 
2752
                    if (transform)
 
2753
                        d->matrix.map(xp, yp, &xp, &yp);
 
2754
                    ExtTextOutW(hdc, qRound(xp), qRound(yp), options, 0, &chr, 1, 0);
 
2755
                    x += glyphs->advance.x() + ((qreal)glyphs->space_18d6) / 64.;
 
2756
                    y += glyphs->advance.y();
 
2757
                    glyphs++;
 
2758
                }
 
2759
            } else {
 
2760
                // fast path
 
2761
                QVarLengthArray<wchar_t> g(ti.num_glyphs);
 
2762
                for (int i = 0; i < ti.num_glyphs; ++i)
 
2763
                    g[i] = glyphs[i].glyph;
 
2764
                // fast path
 
2765
                ExtTextOutW(hdc,
 
2766
                            qRound(x + glyphs->offset.x()),
 
2767
                            qRound(y + glyphs->offset.y()),
 
2768
                            options, 0, g.data(), ti.num_glyphs, 0);
 
2769
                x += w;
 
2770
            }
 
2771
        }
 
2772
    } else {
 
2773
        int i = ti.num_glyphs;
 
2774
        while(i--) {
 
2775
            x += glyphs[i].advance.x() + ((qreal)glyphs[i].space_18d6) / 64.;
 
2776
            y += glyphs[i].advance.y();
 
2777
        }
 
2778
        i = 0;
 
2779
        while(i < ti.num_glyphs) {
 
2780
            x -= glyphs[i].advance.x();
 
2781
            y -= glyphs[i].advance.y();
 
2782
 
 
2783
            int xp = qRound(x+glyphs[i].offset.x());
 
2784
            int yp = qRound(y+glyphs[i].offset.y());
 
2785
            ExtTextOutW(hdc, xp, yp, options, 0, reinterpret_cast<wchar_t *>(&glyphs[i].glyph), 1, 0);
 
2786
 
 
2787
            if (glyphs[i].nKashidas) {
 
2788
                QChar ch(0x640); // Kashida character
 
2789
                QGlyphLayout g[8];
 
2790
                int nglyphs = 7;
 
2791
                ti.fontEngine->stringToCMap(&ch, 1, g, &nglyphs, 0);
 
2792
                for (uint k = 0; k < glyphs[i].nKashidas; ++k) {
 
2793
                    x -= g[0].advance.x();
 
2794
                    y -= g[0].advance.y();
 
2795
 
 
2796
                    int xp = qRound(x+g[0].offset.x());
 
2797
                    int yp = qRound(y+g[0].offset.y());
 
2798
                    ExtTextOutW(hdc, xp, yp, options, 0, reinterpret_cast<wchar_t *>(&g[0].glyph), 1, 0);
 
2799
                }
 
2800
            } else {
 
2801
                x -= ((qreal)glyphs[i].space_18d6) / 64;
 
2802
            }
 
2803
            ++i;
 
2804
        }
 
2805
    }
 
2806
 
 
2807
    if (ti.flags & (QTextItem::Underline|QTextItem::StrikeOut) || scale != 1. || angle)
 
2808
        DeleteObject(SelectObject(hdc, fe->hfont));
 
2809
 
 
2810
    if (ti.flags & (QTextItem::Overline)) {
 
2811
        int lw = qRound(fe->lineThickness());
 
2812
        int yp = qRound(y - fe->ascent() - 1);
 
2813
        Rectangle(hdc, xo, yp, qRound(x), yp + lw);
 
2814
 
 
2815
    }
 
2816
 
 
2817
    if (d->txop > QPainterPrivate::TxTranslate) {
 
2818
        XFORM m;
 
2819
        m.eM11 = m.eM22 = 1;
 
2820
        m.eDx = m.eDy = m.eM12 = m.eM21 = 0;
 
2821
        if (!SetWorldTransform(hdc, &m))
 
2822
            qErrnoWarning("SetWorldTransformation failed");
 
2823
        if (!SetGraphicsMode(hdc, GM_COMPATIBLE))
 
2824
            qErrnoWarning("SetGraphicsMode failed");
 
2825
    }
 
2826
}
 
2827
 
 
2828
static void draw_text_item_multi(const QPointF &p, const QTextItemInt &ti, HDC hdc,
 
2829
                       QRasterPaintEnginePrivate *d)
 
2830
{
 
2831
    QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
 
2832
    QGlyphLayout *glyphs = ti.glyphs;
 
2833
    int which = glyphs[0].glyph >> 24;
 
2834
 
 
2835
    qreal x = p.x();
 
2836
    qreal y = p.y();
 
2837
 
 
2838
    int start = 0;
 
2839
    int end, i;
 
2840
    for (end = 0; end < ti.num_glyphs; ++end) {
 
2841
        const int e = glyphs[end].glyph >> 24;
 
2842
        if (e == which)
 
2843
            continue;
 
2844
 
 
2845
        // set the high byte to zero
 
2846
        for (i = start; i < end; ++i)
 
2847
            glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
 
2848
 
 
2849
        // draw the text
 
2850
        QTextItemInt ti2 = ti;
 
2851
        ti2.glyphs = ti.glyphs + start;
 
2852
        ti2.num_glyphs = end - start;
 
2853
        ti2.fontEngine = multi->engine(which);
 
2854
        ti2.f = ti.f;
 
2855
        draw_text_item_win(QPointF(x, y), ti2, hdc, d);
 
2856
 
 
2857
        // reset the high byte for all glyphs and advance to the next sub-string
 
2858
        const int hi = which << 24;
 
2859
        for (i = start; i < end; ++i) {
 
2860
            glyphs[i].glyph = hi | glyphs[i].glyph;
 
2861
            x += glyphs[i].advance.x();
 
2862
        }
 
2863
 
 
2864
        // change engine
 
2865
        start = end;
 
2866
        which = e;
 
2867
    }
 
2868
 
 
2869
    // set the high byte to zero
 
2870
    for (i = start; i < end; ++i)
 
2871
        glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
 
2872
 
 
2873
    // draw the text
 
2874
    QTextItemInt ti2 = ti;
 
2875
    ti2.glyphs = ti.glyphs + start;
 
2876
    ti2.num_glyphs = end - start;
 
2877
    ti2.fontEngine = multi->engine(which);
 
2878
    ti2.f = ti.f;
 
2879
    draw_text_item_win(QPointF(x, y), ti2, hdc, d);
 
2880
 
 
2881
    // reset the high byte for all glyphs
 
2882
    const int hi = which << 24;
 
2883
    for (i = start; i < end; ++i)
 
2884
        glyphs[i].glyph = hi | glyphs[i].glyph;
 
2885
}
 
2886
 
 
2887
void qt_draw_text_item(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
 
2888
                       QRasterPaintEnginePrivate *d)
 
2889
{
 
2890
    if (!ti.num_glyphs)
 
2891
        return;
 
2892
 
 
2893
    switch(ti.fontEngine->type()) {
 
2894
    case QFontEngine::Multi:
 
2895
        draw_text_item_multi(pos, ti, hdc, d);
 
2896
        break;
 
2897
    case QFontEngine::Win:
 
2898
    default:
 
2899
        draw_text_item_win(pos, ti, hdc, d);
 
2900
        break;
 
2901
    }
 
2902
}
 
2903
 
 
2904
 
 
2905
 
 
2906
#endif
 
2907
 
 
2908
 
 
2909
static void drawLine_midpoint_f(const QLineF &line, qt_span_func span_func, void *data, LineDrawMode style, const QRect &devRect)
 
2910
{
 
2911
#if QT_DEBUG_DRAW
 
2912
    qDebug("   - drawLine_midpoint_f, x1=%.2f, y1=%.2f, x2=%.2f, y2=%.2f",
 
2913
           line.x1(), line.y1(), line.x2(), line.y2());
 
2914
#endif
 
2915
 
 
2916
    int x, y;
 
2917
    qreal dx, dy, d, incrE, incrNE;
 
2918
 
 
2919
    qreal x1 = line.x1();
 
2920
    qreal x2 = line.x2();
 
2921
    qreal y1 = line.y1();
 
2922
    qreal y2 = line.y2();
 
2923
 
 
2924
    QT_FT_Span span = { 0, 1, 255 };
 
2925
 
 
2926
    dx = x2 - x1;
 
2927
    dy = y2 - y1;
 
2928
 
 
2929
    // specialcase horizontal lines
 
2930
    if (dy == 0) {
 
2931
        if (y1 >= 0 && y1 < devRect.height()) {
 
2932
            int start = qMax(0, qRound(qMin(x1, x2)));
 
2933
            int stop = qRound(qMax(x1, x2)) + 1;
 
2934
            int stop_clipped = qMin(devRect.width(), stop);
 
2935
            int len = stop_clipped - start;
 
2936
            if (len > 0) {
 
2937
                if (style == LineDrawNormal && stop == stop_clipped)
 
2938
                    len--;
 
2939
                span.x = ushort(start);
 
2940
                span.len = ushort(len);
 
2941
                span_func(ushort(y1), 1, &span, data);
 
2942
            }
 
2943
        }
 
2944
        return;
 
2945
    } else if (dx == 0) {
 
2946
        if (x1 >= 0 && x1 < devRect.width()) {
 
2947
            int start = qMax(0, qRound(qMin(y1, y2)));
 
2948
            int stop = qRound(qMax(y1, y2)) + 1;
 
2949
            int stop_clipped = qMin(devRect.height(), stop);
 
2950
            if (style == LineDrawNormal && stop == stop_clipped)
 
2951
                --stop;
 
2952
            span.x = ushort(x1);
 
2953
            span.len = 1;
 
2954
            for (int i=start; i<stop_clipped; ++i)
 
2955
                span_func(i, 1, &span, data);
 
2956
        }
 
2957
        return;
 
2958
    }
 
2959
 
 
2960
 
 
2961
    if (qAbs(dx) >= qAbs(dy)) {       /* if x is the major axis: */
 
2962
 
 
2963
        if (x2 < x1) {  /* if coordinates are out of order */
 
2964
            qt_swap_qreal(x1, x2);
 
2965
            dx = -dx;
 
2966
 
 
2967
            qt_swap_qreal(y1, y2);
 
2968
            dy = -dy;
 
2969
        }
 
2970
 
 
2971
        if (style == LineDrawNormal)
 
2972
            --x2;
 
2973
 
 
2974
        // In the loops below we increment before call the span function so
 
2975
        // we need to stop one pixel before
 
2976
        x2 = qMin(x2, qreal(devRect.width() - 1));
 
2977
 
 
2978
        // completly clipped, so abort
 
2979
        if (x2 <= x1) {
 
2980
            return;
 
2981
        }
 
2982
 
 
2983
        x = qRound(x1);
 
2984
        y = qRound(y1);
 
2985
 
 
2986
        if (x>=0 && y>=0 && y < devRect.height()) {
 
2987
            Q_ASSERT(x >= 0 && y >= 0 && x < devRect.width() && y < devRect.height());
 
2988
            span.x = x;
 
2989
            span_func(y, 1, &span, data);
 
2990
        }
 
2991
 
 
2992
        if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
 
2993
            y2 = qMin(y2, qreal(devRect.height()) - 1);
 
2994
 
 
2995
            incrE = dy * 2;
 
2996
            d = incrE - dx;
 
2997
            incrNE = (dy - dx) * 2;
 
2998
 
 
2999
            if (y > y2)
 
3000
                return;
 
3001
 
 
3002
            while (x < x2) {
 
3003
                if (d > 0) {
 
3004
                    ++y;
 
3005
                    d += incrNE;
 
3006
                    if (y > y2)
 
3007
                        return;
 
3008
                } else {
 
3009
                    d += incrE;
 
3010
                }
 
3011
                ++x;
 
3012
 
 
3013
                if (x < 0 || y < 0)
 
3014
                    continue;
 
3015
 
 
3016
                Q_ASSERT(x<devRect.width());
 
3017
                Q_ASSERT(y<devRect.height());
 
3018
                span.x = x;
 
3019
                span_func(y, 1, &span, data);
 
3020
            }
 
3021
        } else {  // 0-45 and 180->225 (unit circle degrees)
 
3022
 
 
3023
            y1 = qMin(y1, qreal(devRect.height()) - 1);
 
3024
 
 
3025
            incrE = dy * 2;
 
3026
            d = incrE + dx;
 
3027
            incrNE = (dy + dx) * 2;
 
3028
 
 
3029
            if (y < 0)
 
3030
                return;
 
3031
 
 
3032
            while (x < x2) {
 
3033
                if (d < 0) {
 
3034
                    --y;
 
3035
                    d += incrNE;
 
3036
                    if (y < 0)
 
3037
                        return;
 
3038
                } else {
 
3039
                    d += incrE;
 
3040
                }
 
3041
                ++x;
 
3042
 
 
3043
                if (x < 0 || y > y1)
 
3044
                    continue;
 
3045
 
 
3046
                Q_ASSERT(x<devRect.width() && y<devRect.height());
 
3047
                span.x = x;
 
3048
                span_func(y, 1, &span, data);
 
3049
            }
 
3050
        }
 
3051
 
 
3052
    } else {
 
3053
 
 
3054
        // if y is the major axis:
 
3055
 
 
3056
        if (y2 < y1) {      /* if coordinates are out of order */
 
3057
            qt_swap_qreal(y1, y2);
 
3058
            dy = -dy;
 
3059
 
 
3060
            qt_swap_qreal(x1, x2);
 
3061
            dx = -dx;
 
3062
        }
 
3063
 
 
3064
        if (style == LineDrawNormal)
 
3065
            --y2;
 
3066
 
 
3067
        // In the loops below we increment before call the span function so
 
3068
        // we need to stop one pixel before
 
3069
        y2 = qMin(y2, qreal(devRect.height()) - 1);
 
3070
 
 
3071
        // completly clipped, so abort
 
3072
        if (y2 <= y1) {
 
3073
            return;
 
3074
        }
 
3075
 
 
3076
        x = qRound(x1);
 
3077
        y = qRound(y1);
 
3078
 
 
3079
        if (x>=0 && y>=0 && x < devRect.width()) {
 
3080
            Q_ASSERT(x >= 0 && y >= 0 && x < devRect.width() && y < devRect.height());
 
3081
            span.x = x;
 
3082
            span_func(y, 1, &span, data);
 
3083
        }
 
3084
 
 
3085
        if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
 
3086
            x2 = qMin(x2, qreal(devRect.width() - 1));
 
3087
            incrE = dx * 2;
 
3088
            d = incrE - dy;
 
3089
            incrNE = (dx - dy) * 2;
 
3090
 
 
3091
            if (x > x2)
 
3092
                return;
 
3093
 
 
3094
            while (y < y2) {
 
3095
                if (d > 0) {
 
3096
                    ++x;
 
3097
                    d += incrNE;
 
3098
                    if (x > x2)
 
3099
                        return;
 
3100
                } else {
 
3101
                    d += incrE;
 
3102
                }
 
3103
                ++y;
 
3104
                if (x < 0 || y < 0)
 
3105
                    continue;
 
3106
                Q_ASSERT(x<devRect.width() && y<devRect.height());
 
3107
                span.x = x;
 
3108
                span_func(y, 1, &span, data);
 
3109
            }
 
3110
        } else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
 
3111
            x1 = qMin(x1, qreal(devRect.width() - 1));
 
3112
            incrE = dx * 2;
 
3113
            d = incrE + dy;
 
3114
            incrNE = (dx + dy) * 2;
 
3115
 
 
3116
            if (x < 0)
 
3117
                return;
 
3118
 
 
3119
            while (y < y2) {
 
3120
                if (d < 0) {
 
3121
                    --x;
 
3122
                    d += incrNE;
 
3123
                    if (x < 0)
 
3124
                        return;;
 
3125
                } else {
 
3126
                    d += incrE;
 
3127
                }
 
3128
                ++y;
 
3129
                if (y < 0 || x > x1)
 
3130
                    continue;
 
3131
                Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
 
3132
                span.x = x;
 
3133
                span_func(y, 1, &span, data);
 
3134
            }
 
3135
        }
 
3136
    }
 
3137
}
 
3138
 
 
3139
#if 0
 
3140
static void drawLine_midpoint_i(const QLine &line, qt_span_func span_func, void *data,
 
3141
                                LineDrawMode style, const QRect &devRect)
 
3142
{
 
3143
#ifdef QT_DEBUG_DRAW
 
3144
    qDebug("   - drawLine_midpoint_i, x1=%d, y1=%d, x2=%d, y2=%d",
 
3145
           line.x1(), line.y1(), line.x2(), line.y2());
 
3146
#endif
 
3147
 
 
3148
    int x, y, dx, dy, d, incrE, incrNE;
 
3149
 
 
3150
    int x1 = line.x1();
 
3151
    int x2 = line.x2();
 
3152
    int y1 = line.y1();
 
3153
    int y2 = line.y2();
 
3154
 
 
3155
    // Decide if we need to clip and therefore call the float version...
 
3156
    {
 
3157
        enum { Left, Right, Top, Bottom };
 
3158
 
 
3159
        // clip the lines, after cohen-sutherland, see
 
3160
        // e.g. http://www.nondot.org/~sabre/graphpro/line6.html
 
3161
 
 
3162
        int p1 = ((x1 < devRect.left()) << Left)
 
3163
                 | ((x1 > devRect.right()) << Right)
 
3164
                 | ((y1 < devRect.top()) << Top)
 
3165
                 | ((y1 > devRect.bottom()) << Bottom);
 
3166
        int p2 = ((x2 < devRect.left()) << Left)
 
3167
                 | ((x2 > devRect.right()) << Right)
 
3168
                 | ((y2 < devRect.top()) << Top)
 
3169
                 | ((y2 > devRect.bottom()) << Bottom);
 
3170
 
 
3171
        if (p1 & p2) {
 
3172
            // completely outside
 
3173
            return;
 
3174
 
 
3175
        } else if (p1 | p2) {
 
3176
            // needs clipping
 
3177
            drawLine_midpoint_f(line, span_func, data, style, devRect);
 
3178
            return;
 
3179
        }
 
3180
    }
 
3181
 
 
3182
    static int use_int=0;
 
3183
    if (!use_int) {
 
3184
        printf("using int version\n");
 
3185
        use_int = 1;
 
3186
    }
 
3187
 
 
3188
    QT_FT_Span span = { 0, 1, 255 };
 
3189
 
 
3190
    dx = x2 - x1;
 
3191
    dy = y2 - y1;
 
3192
 
 
3193
    if (dy == 0) {
 
3194
        // Horizontal lines
 
3195
        if (y1 >= 0 && y1 < devRect.height()) {
 
3196
            int start = qMax(0, qMin(x1, x2));
 
3197
            int stop = qMin(devRect.width(), qMax(x1, x2) + 1);
 
3198
            int len = stop - start;
 
3199
            if (len > 0) {
 
3200
                if (style == LineDrawNormal)
 
3201
                    len--;
 
3202
                span.x = start;
 
3203
                span.len = len;
 
3204
                span_func(y1, 1, &span, data);
 
3205
            }
 
3206
        }
 
3207
        return;
 
3208
    } else if (dx == 0) {
 
3209
        // Vertical lines
 
3210
        if (x1 >= 0 && x1 < devRect.width()) {
 
3211
            int start = qMax(0, qMin(y1, y2));
 
3212
            int stop = qMin(devRect.height(), qMax(y1, y2) + 1);
 
3213
            if (style == LineDrawNormal)
 
3214
                --stop;
 
3215
            span.x = x1;
 
3216
            span.len = 1;
 
3217
            for (int i=start; i<stop; ++i)
 
3218
                span_func(i, 1, &span, data);
 
3219
        }
 
3220
        return;
 
3221
    }
 
3222
 
 
3223
 
 
3224
    if (qAbs(dx) >= qAbs(dy)) {       /* if x is the major axis: */
 
3225
 
 
3226
        if (x2 < x1) {  /* if coordinates are out of order */
 
3227
            qt_swap_int(x1, x2);
 
3228
            dx = -dx;
 
3229
 
 
3230
            qt_swap_int(y1, y2);
 
3231
            dy = -dy;
 
3232
        }
 
3233
 
 
3234
        if (style == LineDrawNormal)
 
3235
            --x2;
 
3236
 
 
3237
        x = x1;
 
3238
        y = y1;
 
3239
 
 
3240
        span.x = x;
 
3241
        span_func(y, 1, &span, data);
 
3242
 
 
3243
        if (y2 > y1) {  /* when it is decided to change y, y should be incremented */
 
3244
            incrE = dy << 1;
 
3245
            d = incrE - dx;
 
3246
            incrNE = (dy - dx) << 1;
 
3247
 
 
3248
            while (x < x2) {
 
3249
                if (d > 0) {
 
3250
                    ++y;
 
3251
                    d += incrNE;
 
3252
                } else {
 
3253
                    d += incrE;
 
3254
                }
 
3255
                ++x;
 
3256
                Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
 
3257
                span.x = x;
 
3258
                span_func(y, 1, &span, data);
 
3259
            }
 
3260
        }
 
3261
        else {       /* when it is decided to change y, y
 
3262
                        should be decremented */
 
3263
            incrE = dy << 1;
 
3264
            d = incrE + dx;
 
3265
            incrNE = (dy + dx) << 1;
 
3266
            while (x < x2) {
 
3267
                if (d < 0) {
 
3268
                    --y;
 
3269
                    d += incrNE;
 
3270
                } else {
 
3271
                    d += incrE;
 
3272
                }
 
3273
                ++x;
 
3274
                Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
 
3275
                span.x = x;
 
3276
                span_func(y, 1, &span, data);
 
3277
            }
 
3278
        }
 
3279
    }
 
3280
    else {   /* if y is the major axis: */
 
3281
 
 
3282
        if (y2 < y1) {      /* if coordinates are out of order */
 
3283
            qt_swap_int(y1, y2);
 
3284
            dy = -dy;
 
3285
 
 
3286
            qt_swap_int(x1, x2);
 
3287
            dx = -dx;
 
3288
        }
 
3289
 
 
3290
        if (style == LineDrawNormal)
 
3291
            --y2;
 
3292
 
 
3293
        x = x1;
 
3294
        y = y1;
 
3295
 
 
3296
        span.x = x;
 
3297
        span_func(y, 1, &span, data);
 
3298
 
 
3299
        if (x2 > x1) {      /* when it is decided to change x, x
 
3300
                               should be incremented */
 
3301
            incrE = dx << 1;
 
3302
            d = incrE - dy;
 
3303
            incrNE = (dx - dy) << 1;
 
3304
            while (y < y2) {
 
3305
                if (d > 0) {
 
3306
                    ++x;
 
3307
                    d += incrNE;
 
3308
                } else {
 
3309
                    d += incrE;
 
3310
                }
 
3311
                ++y;
 
3312
                Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
 
3313
                span.x = x;
 
3314
                span_func(y, 1, &span, data);
 
3315
            }
 
3316
        }
 
3317
        else {        /* when it is decided to change x, x
 
3318
                         should be decremented */
 
3319
            incrE = dx << 1;
 
3320
            d = incrE + dy;
 
3321
            incrNE = (dx + dy) << 1;
 
3322
 
 
3323
            while (y < y2) {
 
3324
                if (d < 0) {
 
3325
                    --x;
 
3326
                    d += incrNE;
 
3327
                } else {
 
3328
                    d += incrE;
 
3329
                }
 
3330
                ++y;
 
3331
                Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
 
3332
                span.x = x;
 
3333
                span_func(y, 1, &span, data);
 
3334
            }
 
3335
        }
 
3336
    }
 
3337
}
 
3338
#endif