~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): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/****************************************************************************
2
2
**
3
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
 
4
** All rights reserved.
4
5
** Contact: Nokia Corporation (qt-info@nokia.com)
5
6
**
6
7
** This file is part of the QtGui module of the Qt Toolkit.
7
8
**
8
9
** $QT_BEGIN_LICENSE:LGPL$
9
 
** Commercial Usage
10
 
** Licensees holding valid Qt Commercial licenses may use this file in
11
 
** accordance with the Qt Commercial License Agreement provided with the
12
 
** Software or, alternatively, in accordance with the terms contained in
13
 
** a written agreement between you and Nokia.
 
10
** No Commercial Usage
 
11
** This file contains pre-release code and may not be distributed.
 
12
** You may use this file in accordance with the terms and conditions
 
13
** contained in the Technology Preview License Agreement accompanying
 
14
** this package.
14
15
**
15
16
** GNU Lesser General Public License Usage
16
17
** Alternatively, this file may be used under the terms of the GNU Lesser
20
21
** ensure the GNU Lesser General Public License version 2.1 requirements
21
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22
23
**
23
 
** In addition, as a special exception, Nokia gives you certain
24
 
** additional rights. These rights are described in the Nokia Qt LGPL
25
 
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26
 
** package.
27
 
**
28
 
** GNU General Public License Usage
29
 
** Alternatively, this file may be used under the terms of the GNU
30
 
** General Public License version 3.0 as published by the Free Software
31
 
** Foundation and appearing in the file LICENSE.GPL included in the
32
 
** packaging of this file.  Please review the following information to
33
 
** ensure the GNU General Public License version 3.0 requirements will be
34
 
** met: http://www.gnu.org/copyleft/gpl.html.
35
 
**
36
 
** If you are unsure which license is appropriate for your use, please
37
 
** contact the sales department at http://www.qtsoftware.com/contact.
 
24
** In addition, as a special exception, Nokia gives you certain additional
 
25
** rights.  These rights are described in the Nokia Qt LGPL Exception
 
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
27
**
 
28
** If you have questions regarding the use of this file, please contact
 
29
** Nokia at qt-info@nokia.com.
 
30
**
 
31
**
 
32
**
 
33
**
 
34
**
 
35
**
 
36
**
 
37
**
38
38
** $QT_END_LICENSE$
39
39
**
40
40
****************************************************************************/
91
91
#    include <private/qfontengine_qpf_p.h>
92
92
#  endif
93
93
#  include <private/qabstractfontengine_p.h>
 
94
#elif defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
 
95
#  include <private/qfontengine_s60_p.h>
94
96
#endif
95
97
 
96
98
#if defined(Q_WS_WIN64)
110
112
#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
111
113
#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
112
114
 
113
 
#ifdef Q_WS_WIN
114
 
static bool qt_enable_16bit_colors = false;
115
 
#endif
116
 
 
117
115
// #define QT_DEBUG_DRAW
118
116
#ifdef QT_DEBUG_DRAW
119
 
void dumpClip(int width, int height, QClipData *clip);
 
117
void dumpClip(int width, int height, const QClipData *clip);
120
118
#endif
121
119
 
122
120
#define QT_FAST_SPANS
139
137
 * Span functions
140
138
 */
141
139
static void qt_span_fill_clipRect(int count, const QSpan *spans, void *userData);
142
 
static void qt_span_fill_clipRegion(int count, const QSpan *spans, void *userData);
143
140
static void qt_span_fill_clipped(int count, const QSpan *spans, void *userData);
144
141
static void qt_span_clip(int count, const QSpan *spans, void *userData);
145
142
static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *result);
347
344
#else
348
345
        (unsigned char *) malloc(d->rasterPoolSize);
349
346
#endif
 
347
    Q_CHECK_PTR(d->rasterPoolBase);
350
348
 
351
349
    // The antialiasing raster.
352
 
    d->grayRaster = new QT_FT_Raster;
353
 
    qt_ft_grays_raster.raster_new(0, d->grayRaster);
354
 
    qt_ft_grays_raster.raster_reset(*d->grayRaster, d->rasterPoolBase, d->rasterPoolSize);
355
 
 
356
 
    d->rasterizer = new QRasterizer;
357
 
    d->rasterBuffer = new QRasterBuffer();
358
 
    d->outlineMapper = new QOutlineMapper;
 
350
    d->grayRaster.reset(new QT_FT_Raster);
 
351
    Q_CHECK_PTR(d->grayRaster.data());
 
352
    if (qt_ft_grays_raster.raster_new(0, d->grayRaster.data()))
 
353
        QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
 
354
 
 
355
 
 
356
    qt_ft_grays_raster.raster_reset(*d->grayRaster.data(), d->rasterPoolBase, d->rasterPoolSize);
 
357
 
 
358
    d->rasterizer.reset(new QRasterizer);
 
359
    d->rasterBuffer.reset(new QRasterBuffer());
 
360
    d->outlineMapper.reset(new QOutlineMapper);
359
361
    d->outlinemapper_xform_dirty = true;
360
362
 
361
363
    d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
362
364
    d->basicStroker.setLineToHook(qt_ft_outline_line_to);
363
365
    d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
364
 
    d->dashStroker = 0;
365
 
 
366
 
    d->baseClip = 0;
367
 
 
368
 
    d->image_filler.init(d->rasterBuffer, this);
 
366
 
 
367
    d->baseClip.reset(new QClipData(d->device->height()));
 
368
    d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
 
369
 
 
370
    d->image_filler.init(d->rasterBuffer.data(), this);
369
371
    d->image_filler.type = QSpanData::Texture;
370
372
 
371
 
    d->image_filler_xform.init(d->rasterBuffer, this);
 
373
    d->image_filler_xform.init(d->rasterBuffer.data(), this);
372
374
    d->image_filler_xform.type = QSpanData::Texture;
373
375
 
374
 
    d->solid_color_filler.init(d->rasterBuffer, this);
 
376
    d->solid_color_filler.init(d->rasterBuffer.data(), this);
375
377
    d->solid_color_filler.type = QSpanData::Solid;
376
378
 
377
379
    d->deviceDepth = d->device->depth();
440
442
    free(d->rasterPoolBase);
441
443
#endif
442
444
 
443
 
    qt_ft_grays_raster.raster_done(*d->grayRaster);
444
 
    delete d->grayRaster;
445
 
 
446
 
    delete d->rasterBuffer;
447
 
    delete d->outlineMapper;
448
 
    delete d->rasterizer;
449
 
    delete d->dashStroker;
 
445
    qt_ft_grays_raster.raster_done(*d->grayRaster.data());
450
446
}
451
447
 
452
448
/*!
482
478
 
483
479
    d->rasterizer->setClipRect(d->deviceRect);
484
480
 
485
 
    s->penData.init(d->rasterBuffer, this);
486
 
    s->penData.setup(s->pen.brush(), s->intOpacity);
 
481
    s->penData.init(d->rasterBuffer.data(), this);
 
482
    s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
487
483
    s->stroker = &d->basicStroker;
488
484
    d->basicStroker.setClipRect(d->deviceRect);
489
485
 
490
 
    s->brushData.init(d->rasterBuffer, this);
491
 
    s->brushData.setup(s->brush, s->intOpacity);
 
486
    s->brushData.init(d->rasterBuffer.data(), this);
 
487
    s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
492
488
 
493
489
    d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
494
490
 
499
495
             << ") devType:" << device->devType()
500
496
             << "devRect:" << d->deviceRect;
501
497
    if (d->baseClip) {
502
 
        dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), d->baseClip);
 
498
        dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
503
499
    }
504
500
#endif
505
501
 
509
505
 
510
506
    if (d->mono_surface)
511
507
        d->glyphCacheType = QFontEngineGlyphCache::Raster_Mono;
512
 
#ifdef Q_WS_WIN
513
 
    else if (qt_cleartype_enabled) {
 
508
#if defined(Q_WS_WIN)
 
509
    else if (qt_cleartype_enabled)
 
510
#elif defined (Q_WS_MAC)
 
511
    else if (true)
 
512
#else
 
513
    else if (false)
 
514
#endif
 
515
    {
514
516
        QImage::Format format = static_cast<QImage *>(d->device)->format();
515
517
        if (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)
516
518
            d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
517
519
        else
518
520
            d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
519
 
    }
520
 
#endif
521
 
    else
 
521
    } else
522
522
        d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
523
523
 
524
524
    setActive(true);
530
530
*/
531
531
bool QRasterPaintEngine::end()
532
532
{
 
533
#ifdef QT_DEBUG_DRAW
533
534
    Q_D(QRasterPaintEngine);
534
 
#ifdef QT_DEBUG_DRAW
535
535
    qDebug() << "QRasterPaintEngine::end devRect:" << d->deviceRect;
536
536
    if (d->baseClip) {
537
 
        dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), d->baseClip);
 
537
        dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->baseClip);
538
538
    }
539
539
#endif
540
540
 
541
 
    if (d->baseClip) {
542
 
        delete d->baseClip;
543
 
        d->baseClip = 0;
544
 
    }
545
 
 
546
541
    return true;
547
542
}
548
543
 
552
547
void QRasterPaintEngine::releaseBuffer()
553
548
{
554
549
    Q_D(QRasterPaintEngine);
555
 
    delete d->rasterBuffer;
556
 
    d->rasterBuffer = new QRasterBuffer;
 
550
    d->rasterBuffer.reset(new QRasterBuffer);
557
551
}
558
552
 
559
553
/*!
618
612
    d->isPlain45DegreeRotation = false;
619
613
    if (txop >= QTransform::TxRotate) {
620
614
        d->isPlain45DegreeRotation =
621
 
            (qFuzzyCompare(matrix.m11() + 1, qreal(1))
622
 
             && qFuzzyCompare(matrix.m12(), qreal(1))
623
 
             && qFuzzyCompare(matrix.m21(), qreal(-1))
624
 
             && qFuzzyCompare(matrix.m22() + 1, qreal(1))
625
 
                )
626
 
            ||
627
 
            (qFuzzyCompare(matrix.m11(), qreal(-1))
628
 
             && qFuzzyCompare(matrix.m12() + 1, qreal(1))
629
 
             && qFuzzyCompare(matrix.m21() + 1, qreal(1))
630
 
             && qFuzzyCompare(matrix.m22(), qreal(-1))
631
 
                )
632
 
            ||
633
 
            (qFuzzyCompare(matrix.m11() + 1, qreal(1))
634
 
             && qFuzzyCompare(matrix.m12(), qreal(-1))
635
 
             && qFuzzyCompare(matrix.m21(), qreal(1))
636
 
             && qFuzzyCompare(matrix.m22() + 1, qreal(1))
 
615
            (qFuzzyIsNull(matrix.m11())
 
616
             && qFuzzyIsNull(matrix.m12() - qreal(1))
 
617
             && qFuzzyIsNull(matrix.m21() + qreal(1))
 
618
             && qFuzzyIsNull(matrix.m22())
 
619
                )
 
620
            ||
 
621
            (qFuzzyIsNull(matrix.m11() + qreal(1))
 
622
             && qFuzzyIsNull(matrix.m12())
 
623
             && qFuzzyIsNull(matrix.m21())
 
624
             && qFuzzyIsNull(matrix.m22() + qreal(1))
 
625
                )
 
626
            ||
 
627
            (qFuzzyIsNull(matrix.m11())
 
628
             && qFuzzyIsNull(matrix.m12() + qreal(1))
 
629
             && qFuzzyIsNull(matrix.m21() - qreal(1))
 
630
             && qFuzzyIsNull(matrix.m22())
637
631
                )
638
632
            ;
639
633
    }
769
763
    s->strokeFlags = 0;
770
764
 
771
765
    s->penData.clip = d->clip();
772
 
    s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity);
 
766
    s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
773
767
 
774
768
    if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
775
769
        || pen.brush().transform().type() >= QTransform::TxNone) {
798
792
        s->stroker = &d->basicStroker;
799
793
    } else if (pen_style != Qt::NoPen) {
800
794
        if (!d->dashStroker)
801
 
            d->dashStroker = new QDashStroker(&d->basicStroker);
 
795
            d->dashStroker.reset(new QDashStroker(&d->basicStroker));
802
796
        if (pen.isCosmetic()) {
803
797
            d->dashStroker->setClipRect(d->deviceRect);
804
798
        } else {
808
802
        }
809
803
        d->dashStroker->setDashPattern(pen.dashPattern());
810
804
        d->dashStroker->setDashOffset(pen.dashOffset());
811
 
        s->stroker = d->dashStroker;
 
805
        s->stroker = d->dashStroker.data();
812
806
    } else {
813
807
        s->stroker = 0;
814
808
    }
869
863
    QRasterPaintEngineState *s = state();
870
864
    // must set clip prior to setup, as setup uses it...
871
865
    s->brushData.clip = d->clip();
872
 
    s->brushData.setup(brush, s->intOpacity);
 
866
    s->brushData.setup(brush, s->intOpacity, s->composition_mode);
873
867
    if (s->fillFlags & DirtyTransform
874
868
        || brush.transform().type() >= QTransform::TxNone)
875
869
        d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
1024
1018
{
1025
1019
    if (alpha == 0 || !clip.isValid())
1026
1020
        return;
 
1021
 
1027
1022
    Q_ASSERT(img.depth() >= 8);
1028
1023
 
1029
1024
    int srcBPL = img.bytesPerLine();
1092
1087
    if (!systemClip.isEmpty()) {
1093
1088
        QRegion clippedDeviceRgn = systemClip & clipRect;
1094
1089
        deviceRect = clippedDeviceRgn.boundingRect();
1095
 
        delete baseClip;
1096
 
        baseClip = new QClipData(device->height());
1097
1090
        baseClip->setClipRegion(clippedDeviceRgn);
1098
1091
    } else {
1099
1092
        deviceRect = clipRect;
 
1093
        baseClip->setClipRect(deviceRect);
1100
1094
    }
1101
1095
#ifdef QT_DEBUG_DRAW
1102
1096
    qDebug() << "systemStateChanged" << this << "deviceRect" << deviceRect << clipRect << systemClip;
1103
1097
#endif
 
1098
 
 
1099
    exDeviceRect = deviceRect;
 
1100
 
1104
1101
    Q_Q(QRasterPaintEngine);
1105
1102
    q->state()->strokeFlags |= QPaintEngine::DirtyClipRegion;
1106
1103
    q->state()->fillFlags |= QPaintEngine::DirtyClipRegion;
1168
1165
}
1169
1166
#endif
1170
1167
 
 
1168
static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
 
1169
{
 
1170
    if (s->flags.has_clip_ownership)
 
1171
        delete s->clip;
 
1172
    s->clip = 0;
 
1173
    s->flags.has_clip_ownership = false;
 
1174
}
 
1175
 
 
1176
static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
 
1177
{
 
1178
    s->fillFlags |= QPaintEngine::DirtyClipPath;
 
1179
    s->strokeFlags |= QPaintEngine::DirtyClipPath;
 
1180
    s->pixmapFlags |= QPaintEngine::DirtyClipPath;
 
1181
 
 
1182
    d->solid_color_filler.clip = d->clip();
 
1183
    d->solid_color_filler.adjustSpanMethods();
 
1184
 
 
1185
#ifdef QT_DEBUG_DRAW
 
1186
    dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
 
1187
#endif
 
1188
 
 
1189
}
 
1190
 
 
1191
 
1171
1192
/*!
1172
1193
    \internal
1173
1194
*/
1179
1200
    if (path.elements()) {
1180
1201
        for (int i=0; i<path.elementCount(); ++i) {
1181
1202
            qDebug() << " - " << path.elements()[i]
1182
 
                     << "(" << path.points()[i*2] << ", " << path.points()[i*2+1] << ")";
 
1203
                     << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1183
1204
        }
1184
1205
    } else {
1185
1206
        for (int i=0; i<path.elementCount(); ++i) {
1186
1207
            qDebug() << " ---- "
1187
 
                     << "(" << path.points()[i*2] << ", " << path.points()[i*2+1] << ")";
 
1208
                     << '(' << path.points()[i*2] << ", " << path.points()[i*2+1] << ')';
1188
1209
        }
1189
1210
    }
1190
1211
#endif
1216
1237
    }
1217
1238
 
1218
1239
    if (op == Qt::NoClip) {
1219
 
        if (s->flags.has_clip_ownership)
1220
 
            delete s->clip;
1221
 
        s->clip = 0;
1222
 
        s->flags.has_clip_ownership = false;
 
1240
        qrasterpaintengine_state_setNoClip(s);
1223
1241
 
1224
1242
    } else {
1225
 
        QClipData *base = d->baseClip;
 
1243
        QClipData *base = d->baseClip.data();
1226
1244
 
1227
1245
        // Intersect with current clip when available...
1228
1246
        if (op == Qt::IntersectClip && s->clip)
1261
1279
        s->clip = newClip;
1262
1280
        s->flags.has_clip_ownership = true;
1263
1281
    }
1264
 
 
1265
 
    s->fillFlags |= DirtyClipPath;
1266
 
    s->strokeFlags |= DirtyClipPath;
1267
 
    s->pixmapFlags |= DirtyClipPath;
1268
 
 
1269
 
    d->solid_color_filler.clip = d->clip();
1270
 
    d->solid_color_filler.adjustSpanMethods();
1271
 
 
1272
 
#ifdef QT_CLIPPING_RATIOS
1273
 
    checkClipRatios(d);
1274
 
#endif
 
1282
    qrasterpaintengine_dirty_clip(d, s);
1275
1283
}
1276
1284
 
1277
1285
 
1289
1297
    QRasterPaintEngineState *s = state();
1290
1298
 
1291
1299
    if (op == Qt::NoClip) {
1292
 
        if (s->flags.has_clip_ownership)
1293
 
            delete s->clip;
1294
 
        s->clip = d->baseClip;
1295
 
        s->flags.has_clip_ownership = false;
 
1300
        qrasterpaintengine_state_setNoClip(s);
1296
1301
 
1297
1302
    } else if (op == Qt::UniteClip || s->matrix.type() > QTransform::TxScale) {
1298
1303
        QPaintEngineEx::clip(rect, op);
1315
1320
            delete s->clip;
1316
1321
 
1317
1322
        s->clip = clip;
 
1323
        s->clip->enabled = true;
1318
1324
        s->flags.has_clip_ownership = true;
1319
1325
 
1320
1326
    } else { // intersect clip with current clip
1331
1337
                s->clip->setClipRect(base->clipRect & clipRect);
1332
1338
            else
1333
1339
                s->clip->setClipRegion(base->clipRegion & clipRect);
 
1340
            s->clip->enabled = true;
1334
1341
        } else {
1335
1342
            QPaintEngineEx::clip(rect, op);
1336
1343
            return;
1337
1344
        }
1338
1345
    }
1339
 
 
1340
 
    s->brushData.clip = d->clip();
1341
 
    s->penData.clip = d->clip();
1342
 
 
1343
 
    s->fillFlags |= DirtyClipPath;
1344
 
    s->strokeFlags |= DirtyClipPath;
1345
 
    s->pixmapFlags |= DirtyClipPath;
1346
 
 
1347
 
    d->solid_color_filler.clip = d->clip();
1348
 
    d->solid_color_filler.adjustSpanMethods();
1349
 
 
1350
 
 
1351
 
#ifdef QT_CLIPPING_RATIOS
1352
 
    checkClipRatios(d);
1353
 
#endif
 
1346
    qrasterpaintengine_dirty_clip(d, s);
1354
1347
}
1355
1348
 
 
1349
 
1356
1350
/*!
1357
1351
    \internal
1358
1352
*/
1359
1353
void QRasterPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
1360
1354
{
1361
 
    QPaintEngineEx::clip(region, op);
1362
 
}
1363
 
 
1364
 
/*!
1365
 
    \internal
1366
 
*/
1367
 
void QRasterPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
1368
 
{
1369
 
    QPaintEngineEx::clip(path, op);
 
1355
#ifdef QT_DEBUG_DRAW
 
1356
    qDebug() << "QRasterPaintEngine::clip(): " << region << op;
 
1357
#endif
 
1358
 
 
1359
    Q_D(QRasterPaintEngine);
 
1360
 
 
1361
    if (region.numRects() == 1) {
 
1362
        clip(region.boundingRect(), op);
 
1363
        return;
 
1364
    }
 
1365
 
 
1366
    QRasterPaintEngineState *s = state();
 
1367
    const QClipData *clip = d->clip();
 
1368
    const QClipData *baseClip = d->baseClip.data();
 
1369
 
 
1370
    if (op == Qt::NoClip) {
 
1371
        qrasterpaintengine_state_setNoClip(s);
 
1372
    } else if (s->matrix.type() > QTransform::TxScale
 
1373
               || op == Qt::UniteClip
 
1374
               || (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
 
1375
               || (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
 
1376
        QPaintEngineEx::clip(region, op);
 
1377
    } else {
 
1378
        const QClipData *curClip;
 
1379
        QClipData *newClip;
 
1380
 
 
1381
        if (op == Qt::IntersectClip)
 
1382
            curClip = clip;
 
1383
        else
 
1384
            curClip = baseClip;
 
1385
 
 
1386
        if (s->flags.has_clip_ownership) {
 
1387
            newClip = s->clip;
 
1388
            Q_ASSERT(newClip);
 
1389
        } else {
 
1390
            newClip = new QClipData(d->rasterBuffer->height());
 
1391
            s->clip = newClip;
 
1392
            s->flags.has_clip_ownership = true;
 
1393
        }
 
1394
 
 
1395
        QRegion r = s->matrix.map(region);
 
1396
        if (curClip->hasRectClip)
 
1397
            newClip->setClipRegion(r & curClip->clipRect);
 
1398
        else if (curClip->hasRegionClip)
 
1399
            newClip->setClipRegion(r & curClip->clipRegion);
 
1400
 
 
1401
        qrasterpaintengine_dirty_clip(d, s);
 
1402
    }
1370
1403
}
1371
1404
 
1372
1405
/*!
1400
1433
    }
1401
1434
 
1402
1435
    ensureOutlineMapper();
1403
 
    d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer);
 
1436
    d->rasterize(d->outlineMapper->convertPath(path), blend, fillData, d->rasterBuffer.data());
1404
1437
}
1405
1438
 
1406
1439
static void fillRect_normalized(const QRect &r, QSpanData *data,
1408
1441
{
1409
1442
    int x1, x2, y1, y2;
1410
1443
 
1411
 
    bool rectClipped = false;
 
1444
    bool rectClipped = true;
1412
1445
 
1413
1446
    if (data->clip) {
1414
1447
        x1 = qMax(r.x(), data->clip->xmin);
1638
1671
    QPaintEngineEx::drawRects(rects, rectCount);
1639
1672
}
1640
1673
 
1641
 
void QRasterPaintEnginePrivate::strokeProjective(const QPainterPath &path)
1642
 
{
1643
 
    Q_Q(QRasterPaintEngine);
1644
 
    QRasterPaintEngineState *s = q->state();
1645
 
 
1646
 
    const QPen &pen = s->lastPen;
1647
 
    QPainterPathStroker pathStroker;
1648
 
    pathStroker.setWidth(pen.width() == 0 ? qreal(1) : pen.width());
1649
 
    pathStroker.setCapStyle(pen.capStyle());
1650
 
    pathStroker.setJoinStyle(pen.joinStyle());
1651
 
    pathStroker.setMiterLimit(pen.miterLimit());
1652
 
    pathStroker.setDashOffset(pen.dashOffset());
1653
 
 
1654
 
    if (qpen_style(pen) == Qt::CustomDashLine)
1655
 
        pathStroker.setDashPattern(pen.dashPattern());
1656
 
    else
1657
 
        pathStroker.setDashPattern(qpen_style(pen));
1658
 
 
1659
 
    outlineMapper->setMatrix(QTransform());
1660
 
    const QPainterPath stroke = pen.isCosmetic()
1661
 
        ? pathStroker.createStroke(s->matrix.map(path))
1662
 
        : s->matrix.map(pathStroker.createStroke(path));
1663
 
 
1664
 
    rasterize(outlineMapper->convertPath(stroke), s->penData.blend, &s->penData, rasterBuffer);
1665
 
    outlinemapper_xform_dirty = true;
1666
 
}
1667
 
 
1668
 
 
1669
1674
 
1670
1675
/*!
1671
1676
    \internal
1677
1682
    if (!s->penData.blend)
1678
1683
        return;
1679
1684
 
1680
 
    if (s->flags.fast_pen && path.shape() <= QVectorPath::NonCurvedShapeHint && s->lastPen.brush().isOpaque()) {
1681
 
        strokePolygonCosmetic((QPointF *) path.points(), path.elementCount(),
1682
 
                              path.hasImplicitClose()
1683
 
                              ? WindingMode
1684
 
                              : PolylineMode);
 
1685
    if (s->flags.fast_pen && path.shape() <= QVectorPath::NonCurvedShapeHint
 
1686
        && s->lastPen.brush().isOpaque()) {
 
1687
        int count = path.elementCount();
 
1688
        QPointF *points = (QPointF *) path.points();
 
1689
        const QPainterPath::ElementType *types = path.elements();
 
1690
        if (types) {
 
1691
            int first = 0;
 
1692
            int last;
 
1693
            while (first < count) {
 
1694
                while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
 
1695
                last = first + 1;
 
1696
                while (last < count && types[last] == QPainterPath::LineToElement) ++last;
 
1697
                strokePolygonCosmetic(points + first, last - first,
 
1698
                                      path.hasImplicitClose() && last == count // only close last one..
 
1699
                                      ? WindingMode
 
1700
                                      : PolylineMode);
 
1701
                first = last;
 
1702
            }
 
1703
        } else {
 
1704
            strokePolygonCosmetic(points, count,
 
1705
                                  path.hasImplicitClose()
 
1706
                                  ? WindingMode
 
1707
                                  : PolylineMode);
 
1708
        }
1685
1709
 
1686
1710
    } else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1687
1711
        qreal width = s->lastPen.isCosmetic()
1711
1735
        const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
1712
1736
 
1713
1737
        for (int i = 0; i < lineCount; ++i) {
 
1738
            if (path.shape() == QVectorPath::LinesHint)
 
1739
                dashOffset = s->lastPen.dashOffset();
1714
1740
            if (lines[i].p1() == lines[i].p2()) {
1715
1741
                if (s->lastPen.capStyle() != Qt::FlatCap) {
1716
1742
                    QPointF p = lines[i].p1();
1738
1764
 
1739
1765
static inline QRect toNormalizedFillRect(const QRectF &rect)
1740
1766
{
1741
 
    const int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1742
 
    const int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1743
 
    const int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1744
 
    const int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1745
 
 
1746
 
    return QRect(x1, y1, x2 - x1, y2 - y1).normalized();
 
1767
    int x1 = qRound(rect.x() + aliasedCoordinateDelta);
 
1768
    int y1 = qRound(rect.y() + aliasedCoordinateDelta);
 
1769
    int x2 = qRound(rect.right() + aliasedCoordinateDelta);
 
1770
    int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
 
1771
 
 
1772
    if (x2 < x1)
 
1773
        qSwap(x1, x2);
 
1774
    if (y2 < y1)
 
1775
        qSwap(y1, y2);
 
1776
 
 
1777
    return QRect(x1, y1, x2 - x1, y2 - y1);
1747
1778
}
1748
1779
 
1749
1780
/*!
1754
1785
    if (path.isEmpty())
1755
1786
        return;
1756
1787
#ifdef QT_DEBUG_DRAW
1757
 
    QRealRect vectorPathBounds = path.controlPointRect();
1758
 
    QRectF rf(vectorPathBounds.x1, vectorPathBounds.y1,
1759
 
              vectorPathBounds.x2 - vectorPathBounds.x1, vectorPathBounds.y2 - vectorPathBounds.y1);
 
1788
    QRectF rf = path.controlPointRect();
1760
1789
    qDebug() << "QRasterPaintEngine::fill(): "
1761
1790
             << "size=" << path.elementCount()
1762
1791
             << ", hints=" << hex << path.hints()
1814
1843
    }
1815
1844
 
1816
1845
    // ### Optimize for non transformed ellipses and rectangles...
1817
 
    QRealRect r = path.controlPointRect();
1818
 
    QRectF cpRect(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1);
 
1846
    QRectF cpRect = path.controlPointRect();
1819
1847
    const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
1820
1848
    ProcessSpans blend = d->getBrushFunc(deviceRect, &s->brushData);
1821
1849
 
1833
1861
//         }
1834
1862
 
1835
1863
    ensureOutlineMapper();
1836
 
    d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer);
 
1864
    d->rasterize(d->outlineMapper->convertPath(path), blend, &s->brushData, d->rasterBuffer.data());
1837
1865
}
1838
1866
 
1839
1867
void QRasterPaintEngine::fillRect(const QRectF &r, QSpanData *data)
1903
1931
    QRasterPaintEngineState *s = state();
1904
1932
 
1905
1933
    d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
 
1934
    if ((d->solid_color_filler.solid.color & 0xff000000) == 0
 
1935
        && s->composition_mode == QPainter::CompositionMode_SourceOver) {
 
1936
        return;
 
1937
    }
1906
1938
    d->solid_color_filler.clip = d->clip();
1907
1939
    d->solid_color_filler.adjustSpanMethods();
1908
 
 
1909
1940
    fillRect(r, &d->solid_color_filler);
1910
1941
}
1911
1942
 
1912
 
/*!
1913
 
    \reimp
1914
 
*/
1915
 
void QRasterPaintEngine::drawPath(const QPainterPath &path)
1916
 
{
1917
 
#ifdef QT_DEBUG_DRAW
1918
 
    QRectF bounds = path.boundingRect();
1919
 
    qDebug(" - QRasterPaintEngine::drawPath(), [%.2f, %.2f, %.2f, %.2f]",
1920
 
           bounds.x(), bounds.y(), bounds.width(), bounds.height());
1921
 
#endif
1922
 
 
1923
 
    if (path.isEmpty())
1924
 
        return;
1925
 
 
1926
 
    // Filling..,
1927
 
    Q_D(QRasterPaintEngine);
1928
 
    QRasterPaintEngineState *s = state();
1929
 
 
1930
 
    ensureBrush();
1931
 
    if (s->brushData.blend) {
1932
 
        ensureOutlineMapper();
1933
 
        fillPath(path, &s->brushData);
1934
 
    }
1935
 
 
1936
 
    // Stroking...
1937
 
    ensurePen();
1938
 
    if (!s->penData.blend)
1939
 
        return;
1940
 
    {
1941
 
        if (s->matrix.type() >= QTransform::TxProject) {
1942
 
            d->strokeProjective(path);
1943
 
        } else {
1944
 
            Q_ASSERT(s->stroker);
1945
 
            d->outlineMapper->beginOutline(Qt::WindingFill);
1946
 
            qreal txscale = 1;
1947
 
            if (s->pen.isCosmetic() || (qt_scaleForTransform(s->matrix, &txscale) && txscale != 1)) {
1948
 
                const qreal strokeWidth = d->basicStroker.strokeWidth();
1949
 
                const QRectF clipRect = d->dashStroker ? d->dashStroker->clipRect() : QRectF();
1950
 
                if (d->dashStroker)
1951
 
                    d->dashStroker->setClipRect(d->deviceRect);
1952
 
                d->basicStroker.setStrokeWidth(strokeWidth * txscale);
1953
 
                d->outlineMapper->setMatrix(QTransform());
1954
 
                s->stroker->strokePath(path, d->outlineMapper, s->matrix);
1955
 
                d->outlinemapper_xform_dirty = true;
1956
 
                d->basicStroker.setStrokeWidth(strokeWidth);
1957
 
                if (d->dashStroker)
1958
 
                    d->dashStroker->setClipRect(clipRect);
1959
 
            } else {
1960
 
                ensureOutlineMapper();
1961
 
                s->stroker->strokePath(path, d->outlineMapper, QTransform());
1962
 
            }
1963
 
            d->outlineMapper->endOutline();
1964
 
 
1965
 
            ProcessSpans blend = d->getPenFunc(d->outlineMapper->controlPointRect,
1966
 
                    &s->penData);
1967
 
            d->rasterize(d->outlineMapper->outline(), blend, &s->penData, d->rasterBuffer);
1968
 
        }
1969
 
    }
1970
 
 
1971
 
}
1972
 
 
1973
1943
static inline bool isAbove(const QPointF *a, const QPointF *b)
1974
1944
{
1975
1945
    return a->y() < b->y();
2058
2028
    // scanconvert.
2059
2029
    ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2060
2030
                                              &s->brushData);
2061
 
    d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer);
 
2031
    d->rasterize(outline, brushBlend, &s->brushData, d->rasterBuffer.data());
2062
2032
}
2063
2033
 
2064
2034
/*!
2154
2124
            // scanconvert.
2155
2125
            ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
2156
2126
                                                      &s->brushData);
2157
 
            d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer);
 
2127
            d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
2158
2128
            d->outlineMapper->setCoordinateRounding(false);
2159
2129
        }
2160
2130
    }
2401
2371
#endif
2402
2372
 
2403
2373
    if (pixmap.data->classId() == QPixmapData::RasterClass) {
2404
 
        const QImage &image = ((QRasterPixmapData *) pixmap.data)->image;
 
2374
        const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2405
2375
        if (image.depth() == 1) {
2406
2376
            Q_D(QRasterPaintEngine);
2407
2377
            QRasterPaintEngineState *s = state();
2439
2409
#endif
2440
2410
 
2441
2411
    if (pixmap.data->classId() == QPixmapData::RasterClass) {
2442
 
        const QImage &image = ((QRasterPixmapData *) pixmap.data)->image;
 
2412
        const QImage &image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2443
2413
        if (image.depth() == 1) {
2444
2414
            Q_D(QRasterPaintEngine);
2445
2415
            QRasterPaintEngineState *s = state();
2525
2495
        const QClipData *clip = d->clip();
2526
2496
        QPointF pt(p.x() + s->matrix.dx(), p.y() + s->matrix.dy());
2527
2497
 
2528
 
        // ### TODO: remove this eventually...
2529
 
        static bool NO_BLEND_FUNC = !qgetenv("QT_NO_BLEND_FUNCTIONS").isNull();
2530
 
 
2531
 
        if (s->flags.fast_images && !NO_BLEND_FUNC) {
 
2498
        if (s->flags.fast_images) {
2532
2499
            SrcOverBlendFunc func = qBlendFunctions[d->rasterBuffer->format][img.format()];
2533
2500
            if (func) {
2534
2501
                if (!clip) {
2541
2508
            }
2542
2509
        }
2543
2510
 
 
2511
 
 
2512
 
2544
2513
        d->image_filler.clip = clip;
2545
2514
        d->image_filler.initTexture(&img, s->intOpacity, QTextureData::Plain, img.rect());
2546
2515
        if (!d->image_filler.blend)
2569
2538
    qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2570
2539
#endif
2571
2540
 
 
2541
    if (r.isEmpty())
 
2542
        return;
 
2543
 
2572
2544
    Q_D(QRasterPaintEngine);
2573
2545
    QRasterPaintEngineState *s = state();
2574
 
    const bool aa = s->flags.antialiased || s->flags.bilinear;
2575
 
    if (!aa && sr.size() == QSize(1, 1)) {
 
2546
    int sr_l = qFloor(sr.left());
 
2547
    int sr_r = qCeil(sr.right()) - 1;
 
2548
    int sr_t = qFloor(sr.top());
 
2549
    int sr_b = qCeil(sr.bottom()) - 1;
 
2550
 
 
2551
    if (!s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2576
2552
        // as fillRect will apply the aliased coordinate delta we need to
2577
2553
        // subtract it here as we don't use it for image drawing
2578
2554
        QTransform old = s->matrix;
2579
2555
        s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2580
 
        fillRect(r, QColor::fromRgba(img.pixel(sr.x(), sr.y())));
 
2556
 
 
2557
        // Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
 
2558
        QRgb color = img.pixel(sr_l, sr_t);
 
2559
        switch (img.format()) {
 
2560
        case QImage::Format_ARGB32_Premultiplied:
 
2561
        case QImage::Format_ARGB8565_Premultiplied:
 
2562
        case QImage::Format_ARGB6666_Premultiplied:
 
2563
        case QImage::Format_ARGB8555_Premultiplied:
 
2564
        case QImage::Format_ARGB4444_Premultiplied:
 
2565
            // Combine premultiplied color with the opacity set on the painter.
 
2566
            d->solid_color_filler.solid.color =
 
2567
                ((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
 
2568
                | ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
 
2569
            break;
 
2570
        default:
 
2571
            d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
 
2572
            break;
 
2573
        }
 
2574
 
 
2575
        if ((d->solid_color_filler.solid.color & 0xff000000) == 0
 
2576
            && s->composition_mode == QPainter::CompositionMode_SourceOver) {
 
2577
            return;
 
2578
        }
 
2579
 
 
2580
        d->solid_color_filler.clip = d->clip();
 
2581
        d->solid_color_filler.adjustSpanMethods();
 
2582
        fillRect(r, &d->solid_color_filler);
 
2583
 
2581
2584
        s->matrix = old;
2582
2585
        return;
2583
2586
    }
2589
2592
    if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2590
2593
 
2591
2594
        if (s->flags.fast_images) {
2592
 
            SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2593
 
            if (func && (!clip || clip->hasRectClip)) {
2594
 
                func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2595
 
                     img.bits(), img.bytesPerLine(),
2596
 
                     qt_mapRect_non_normalizing(r, s->matrix), sr,
2597
 
                     !clip ? d->deviceRect : clip->clipRect,
2598
 
                     s->intOpacity);
2599
 
                return;
 
2595
            if (s->matrix.type() > QTransform::TxScale) {
 
2596
                SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
 
2597
                if (func && (!clip || clip->hasRectClip)) {
 
2598
                    func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
 
2599
                         img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
 
2600
                         s->matrix, s->intOpacity);
 
2601
                    return;
 
2602
                }
 
2603
            } else {
 
2604
                SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
 
2605
                if (func && (!clip || clip->hasRectClip)) {
 
2606
                    func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
 
2607
                         img.bits(), img.bytesPerLine(),
 
2608
                         qt_mapRect_non_normalizing(r, s->matrix), sr,
 
2609
                         !clip ? d->deviceRect : clip->clipRect,
 
2610
                         s->intOpacity);
 
2611
                    return;
 
2612
                }
2600
2613
            }
2601
2614
        }
2602
2615
 
2612
2625
            return;
2613
2626
        d->image_filler_xform.setupMatrix(copy, s->flags.bilinear);
2614
2627
 
2615
 
        if (!aa && s->matrix.type() == QTransform::TxScale) {
 
2628
        if (!s->flags.antialiased && s->matrix.type() == QTransform::TxScale) {
2616
2629
            QRectF rr = s->matrix.mapRect(r);
2617
2630
 
2618
2631
            const int x1 = qRound(rr.x());
2628
2641
        ensureState();
2629
2642
        if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2630
2643
            d->initializeRasterizer(&d->image_filler_xform);
2631
 
            d->rasterizer->setAntialiased(aa);
 
2644
            d->rasterizer->setAntialiased(s->flags.antialiased);
2632
2645
 
2633
 
            const QPointF offs = aa ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
 
2646
            const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
2634
2647
 
2635
2648
            const QRectF &rect = r.normalized();
2636
2649
            const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
2643
2656
            return;
2644
2657
        }
2645
2658
#endif
2646
 
        bool wasAntialiased = s->flags.antialiased;
2647
 
        if (!s->flags.antialiased)
2648
 
            s->flags.antialiased = s->flags.bilinear;
2649
2659
        const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
2650
2660
        QPainterPath path;
2651
2661
        path.addRect(r);
2655
2665
                               m.m31() - offs, m.m32() - offs, m.m33());
2656
2666
        fillPath(path, &d->image_filler_xform);
2657
2667
        s->matrix = m;
2658
 
        s->flags.antialiased = wasAntialiased;
2659
2668
    } else {
2660
2669
 
2661
2670
        if (s->flags.fast_images) {
2705
2714
    QImage image;
2706
2715
 
2707
2716
    if (pixmap.data->classId() == QPixmapData::RasterClass) {
2708
 
        image = ((QRasterPixmapData *) pixmap.data)->image;
 
2717
        image = static_cast<QRasterPixmapData *>(pixmap.data.data())->image;
2709
2718
    } else {
2710
2719
        image = pixmap.toImage();
2711
2720
    }
2727
2736
        ensureState();
2728
2737
        if (s->flags.tx_noshear || s->matrix.type() == QTransform::TxScale) {
2729
2738
            d->initializeRasterizer(&d->image_filler_xform);
2730
 
            d->rasterizer->setAntialiased(s->flags.antialiased || s->flags.bilinear);
 
2739
            d->rasterizer->setAntialiased(s->flags.antialiased);
2731
2740
 
2732
2741
            const QRectF &rect = r.normalized();
2733
2742
            const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
2739
2748
            return;
2740
2749
        }
2741
2750
#endif
2742
 
        bool wasAntialiased = s->flags.antialiased;
2743
 
        if (!s->flags.antialiased)
2744
 
            s->flags.antialiased = s->flags.bilinear;
2745
2751
        QPainterPath path;
2746
2752
        path.addRect(r);
2747
2753
        fillPath(path, &d->image_filler_xform);
2748
 
        s->flags.antialiased = wasAntialiased;
2749
2754
    } else {
2750
2755
        d->image_filler.clip = d->clip();
2751
2756
 
2779
2784
    if (!s->penData.blend)
2780
2785
        return;
2781
2786
 
2782
 
    QRasterBuffer *rb = d->rasterBuffer;
 
2787
    QRasterBuffer *rb = d->rasterBuffer.data();
2783
2788
 
2784
2789
    const QRect rect(rx, ry, w, h);
2785
2790
    const QClipData *clip = d->clip();
3051
3056
    return;
3052
3057
}
3053
3058
 
3054
 
 
 
3059
#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
 
3060
void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
 
3061
{
 
3062
    Q_D(QRasterPaintEngine);
 
3063
    QRasterPaintEngineState *s = state();
 
3064
 
 
3065
    QFontEngine *fontEngine = ti.fontEngine;
 
3066
    if (fontEngine->type() != QFontEngine::S60FontEngine) {
 
3067
        QPaintEngineEx::drawTextItem(p, ti);
 
3068
        return;
 
3069
    }
 
3070
 
 
3071
    QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
 
3072
 
 
3073
    QVarLengthArray<QFixedPoint> positions;
 
3074
    QVarLengthArray<glyph_t> glyphs;
 
3075
    QTransform matrix = s->matrix;
 
3076
    matrix.translate(p.x(), p.y());
 
3077
    ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
 
3078
 
 
3079
    const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
 
3080
 
 
3081
    for (int i=0; i<glyphs.size(); ++i) {
 
3082
        TOpenFontCharMetrics tmetrics;
 
3083
        const TUint8 *glyphBitmapBytes;
 
3084
        TSize glyphBitmapSize;
 
3085
        fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
 
3086
        const glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]);
 
3087
        const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
 
3088
        const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
 
3089
 
 
3090
        alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
 
3091
    }
 
3092
 
 
3093
    return;
 
3094
}
 
3095
#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
3055
3096
 
3056
3097
/*!
3057
3098
 * Returns true if the rectangle is completly within the current clip
3068
3109
    }
3069
3110
 
3070
3111
 
3071
 
    // currently all painting functions clips to deviceRect internally
3072
 
    if (cl->clipRect == deviceRect)
3073
 
        return true;
 
3112
    if (cl->hasRectClip) {
 
3113
        // currently all painting functions clips to deviceRect internally
 
3114
        if (cl->clipRect == deviceRect)
 
3115
            return true;
3074
3116
 
3075
 
    if (cl->hasRegionClip) {
3076
3117
        // inline contains() for performance (we know the rects are normalized)
3077
3118
        const QRect &r1 = cl->clipRect;
3078
3119
        return (r.left() >= r1.left() && r.right() <= r1.right()
3098
3139
 
3099
3140
 
3100
3141
    // currently all painting functions that call this function clip to deviceRect internally
3101
 
    if (cl->clipRect == deviceRect)
 
3142
    if (cl->hasRectClip && cl->clipRect == deviceRect)
3102
3143
        return true;
3103
3144
 
3104
3145
    if (s->flags.antialiased)
3112
3153
        r.setHeight(r.height() + 2 * penWidth);
3113
3154
    }
3114
3155
 
3115
 
    if (!cl->clipRect.isEmpty()) {
 
3156
    if (cl->hasRectClip) {
3116
3157
        // inline contains() for performance (we know the rects are normalized)
3117
3158
        const QRect &r1 = cl->clipRect;
3118
3159
        return (r.left() >= r1.left() && r.right() <= r1.right()
3201
3242
    // ### cases we should delegate painting to the font engine
3202
3243
    // ### directly...
3203
3244
 
3204
 
#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
 
3245
#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
3205
3246
    QFontEngine::Type fontEngineType = ti.fontEngine->type();
3206
3247
    // qDebug() << "type" << fontEngineType << s->matrix.type();
3207
3248
    if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
3219
3260
        return;
3220
3261
    }
3221
3262
 
 
3263
#elif defined (Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // Q_WS_WIN || Q_WS_MAC
 
3264
    if (s->matrix.type() <= QTransform::TxTranslate) {
 
3265
        drawGlyphsS60(p, ti);
 
3266
        return;
 
3267
    }
3222
3268
#else // Q_WS_WIN || Q_WS_MAC
3223
3269
 
3224
3270
    QFontEngine *fontEngine = ti.fontEngine;
3239
3285
    }
3240
3286
#endif // Q_WS_QWS
3241
3287
 
3242
 
#if (defined(Q_WS_X11) || defined(Q_WS_QWS)) && !defined(QT_NO_FREETYPE)
 
3288
#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN)) && !defined(QT_NO_FREETYPE)
3243
3289
 
3244
3290
#if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2)
3245
3291
    if (fontEngine->type() == QFontEngine::QPF2) {
3311
3357
        break;
3312
3358
    default:
3313
3359
        Q_ASSERT(false);
 
3360
        depth = 0;
3314
3361
    };
3315
3362
 
3316
3363
    for(int i = 0; i < glyphs.size(); i++) {
3338
3385
            break;
3339
3386
        default:
3340
3387
            Q_ASSERT(false);
 
3388
            pitch = 0;
3341
3389
        };
3342
3390
 
3343
3391
        alphaPenBlt(glyph->data, pitch, depth,
3481
3529
        int m22 = int(s->matrix.m22());
3482
3530
        int dx = qFloor(s->matrix.dx() + aliasedCoordinateDelta);
3483
3531
        int dy = qFloor(s->matrix.dy() + aliasedCoordinateDelta);
3484
 
        int dashOffset = int(s->lastPen.dashOffset());
3485
3532
        for (int i=0; i<lineCount; ++i) {
 
3533
            int dashOffset = int(s->lastPen.dashOffset());
3486
3534
            if (s->flags.int_xform) {
3487
3535
                const QLine &l = lines[i];
3488
3536
                int x1 = l.x1() * m11 + dx;
3544
3592
 
3545
3593
        if (dash >= length) {
3546
3594
            dash = length;
3547
 
            *dashOffset += dash;
 
3595
            *dashOffset += dash / width;
3548
3596
            length = 0;
3549
3597
        } else {
3550
3598
            *dashOffset = 0;
3581
3629
                            ? LineDrawNormal
3582
3630
                            : LineDrawIncludeLastPixel;
3583
3631
 
3584
 
        int dashOffset = int(s->lastPen.dashOffset());
3585
3632
        for (int i=0; i<lineCount; ++i) {
 
3633
            int dashOffset = int(s->lastPen.dashOffset());
3586
3634
            QLineF line = (lines[i] * s->matrix).translated(aliasedCoordinateDelta, aliasedCoordinateDelta);
3587
3635
            const QRectF brect(QPointF(line.x1(), line.y1()),
3588
3636
                               QPointF(line.x2(), line.y2()));
3615
3663
    ensurePen();
3616
3664
    if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
3617
3665
         || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased))
 
3666
        && qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
3618
3667
#ifdef FLOATING_POINT_BUGGY_OR_NO_FPU
3619
3668
        && qMax(rect.width(), rect.height()) < 128 // integer math breakdown
3620
3669
#endif
3876
3925
{
3877
3926
    Q_ASSERT(c1->clipSpanHeight == c2->clipSpanHeight && c1->clipSpanHeight == result->clipSpanHeight);
3878
3927
 
3879
 
    // ### buffer overflow possible
3880
 
    const int BUFFER_SIZE = 4096;
3881
 
    int buffer[BUFFER_SIZE];
3882
 
    int *b = buffer;
3883
 
    int bsize = BUFFER_SIZE;
 
3928
    QVarLengthArray<short, 4096> buffer;
3884
3929
 
3885
3930
    QClipData::ClipLine *c1ClipLines = const_cast<QClipData *>(c1)->clipLines();
3886
3931
    QClipData::ClipLine *c2ClipLines = const_cast<QClipData *>(c2)->clipLines();
3906
3951
 
3907
3952
        // find required length
3908
3953
        int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len,
3909
 
                       c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
3910
 
        if (max > bsize) {
3911
 
            b = (int *)realloc(bsize == BUFFER_SIZE ? 0 : b, max*sizeof(int));
3912
 
            bsize = max;
3913
 
        }
3914
 
        memset(buffer, 0, BUFFER_SIZE * sizeof(int));
 
3954
                c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len);
 
3955
        buffer.resize(max);
 
3956
        memset(buffer.data(), 0, buffer.size() * sizeof(short));
3915
3957
 
3916
3958
        // Fill with old spans.
3917
3959
        for (int i = 0; i < c1_count; ++i) {
3947
3989
            result->appendSpan(sx, x - sx, y, coverage);
3948
3990
        }
3949
3991
    }
3950
 
    if (b != buffer)
3951
 
        free(b);
3952
3992
}
3953
3993
 
3954
3994
void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data)
3965
4005
    const QClipData *c = clip();
3966
4006
    if (c) {
3967
4007
        const QRect r(QPoint(c->xmin, c->ymin),
3968
 
                      QPoint(c->xmax, c->ymax));
 
4008
                      QSize(c->xmax - c->xmin, c->ymax - c->ymin));
3969
4009
        clipRect = clipRect.intersected(r);
3970
4010
        blend = data->blend;
3971
4011
    } else {
4048
4088
 
4049
4089
        rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
4050
4090
        rasterParams.gray_spans = callback;
4051
 
        error = qt_ft_grays_raster.raster_render(*grayRaster, &rasterParams);
 
4091
        error = qt_ft_grays_raster.raster_render(*grayRaster.data(), &rasterParams);
4052
4092
 
4053
4093
        // Out of memory, reallocate some more and try again...
4054
4094
        if (error == -6) { // -6 is Result_err_OutOfMemory
4073
4113
#else
4074
4114
                (unsigned char *) malloc(rasterPoolSize);
4075
4115
#endif
 
4116
            Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal.
4076
4117
 
4077
 
            qt_ft_grays_raster.raster_done(*grayRaster);
4078
 
            qt_ft_grays_raster.raster_new(0, grayRaster);
4079
 
            qt_ft_grays_raster.raster_reset(*grayRaster, rasterPoolBase, rasterPoolSize);
 
4118
            qt_ft_grays_raster.raster_done(*grayRaster.data());
 
4119
            qt_ft_grays_raster.raster_new(0, grayRaster.data());
 
4120
            qt_ft_grays_raster.raster_reset(*grayRaster.data(), rasterPoolBase, rasterPoolSize);
4080
4121
        } else {
4081
4122
            done = true;
4082
4123
        }
4090
4131
 
4091
4132
    s->flags.fast_images = !(s->renderHints & QPainter::SmoothPixmapTransform)
4092
4133
                           && rasterBuffer->compositionMode == QPainter::CompositionMode_SourceOver
4093
 
                           && s->matrix.type() <= QTransform::TxScale;
 
4134
                           && s->matrix.type() <= QTransform::TxShear;
4094
4135
}
4095
4136
 
4096
4137
 
4110
4151
    for (int y=0; y<height; ++y) {
4111
4152
        uchar *source = sourceImage.scanLine(y);
4112
4153
        QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
 
4154
        if (!source || !target)
 
4155
            QT_THROW(std::bad_alloc()); // we must have run out of memory
4113
4156
        for (int x=0; x < width; ++x)
4114
4157
            target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
4115
4158
    }
4195
4238
{
4196
4239
    return (width() * depth() + 7) / 8;
4197
4240
}
4198
 
#endif // Q_WS_QWS
4199
 
 
 
4241
 
 
4242
#elif defined(Q_OS_SYMBIAN)
 
4243
 
 
4244
void QRasterBuffer::prepareBuffer(int /* width */, int /* height */)
 
4245
{
 
4246
}
 
4247
 
 
4248
#endif // Q_OS_SYMBIAN
4200
4249
 
4201
4250
/*!
4202
4251
    \class QCustomRasterPaintDevice
4279
4328
    clipSpanHeight = height;
4280
4329
    m_clipLines = 0;
4281
4330
 
4282
 
    allocated = height;
 
4331
    allocated = 0;
4283
4332
    m_spans = 0;
4284
4333
    xmin = xmax = ymin = ymax = 0;
4285
4334
    count = 0;
4301
4350
    if (m_spans)
4302
4351
        return;
4303
4352
 
4304
 
    m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4305
 
    m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4306
 
 
4307
 
    if (hasRectClip) {
4308
 
        int y = 0;
4309
 
        while (y < ymin) {
4310
 
            m_clipLines[y].spans = 0;
4311
 
            m_clipLines[y].count = 0;
4312
 
            ++y;
4313
 
        }
4314
 
 
4315
 
        const int len = clipRect.width();
4316
 
        count = 0;
4317
 
        while (y < ymax) {
4318
 
            QSpan *span = m_spans + count;
4319
 
            span->x = xmin;
4320
 
            span->len = len;
4321
 
            span->y = y;
4322
 
            span->coverage = 255;
4323
 
            ++count;
4324
 
 
4325
 
            m_clipLines[y].spans = span;
4326
 
            m_clipLines[y].count = 1;
4327
 
            ++y;
4328
 
        }
4329
 
 
4330
 
        while (y < clipSpanHeight) {
4331
 
            m_clipLines[y].spans = 0;
4332
 
            m_clipLines[y].count = 0;
4333
 
            ++y;
4334
 
        }
4335
 
    } else if (hasRegionClip) {
4336
 
 
4337
 
        const QVector<QRect> rects = clipRegion.rects();
4338
 
        const int numRects = rects.size();
4339
 
 
4340
 
        { // resize
4341
 
            const int maxSpans = (ymax - ymin) * numRects;
4342
 
            if (maxSpans > allocated) {
4343
 
                m_spans = (QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan));
4344
 
                allocated = maxSpans;
4345
 
            }
4346
 
        }
4347
 
 
4348
 
        int y = 0;
4349
 
        int firstInBand = 0;
4350
 
        while (firstInBand < numRects) {
4351
 
            const int currMinY = rects.at(firstInBand).y();
4352
 
            const int currMaxY = currMinY + rects.at(firstInBand).height();
4353
 
 
4354
 
            while (y < currMinY) {
4355
 
                m_clipLines[y].spans = 0;
4356
 
                m_clipLines[y].count = 0;
4357
 
                ++y;
4358
 
            }
4359
 
 
4360
 
            int lastInBand = firstInBand;
4361
 
            while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4362
 
                ++lastInBand;
4363
 
 
4364
 
            while (y < currMaxY) {
4365
 
 
4366
 
                m_clipLines[y].spans = m_spans + count;
4367
 
                m_clipLines[y].count = lastInBand - firstInBand + 1;
4368
 
 
4369
 
                for (int r = firstInBand; r <= lastInBand; ++r) {
4370
 
                    const QRect &currRect = rects.at(r);
 
4353
    if (!m_clipLines)
 
4354
        m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
 
4355
 
 
4356
    Q_CHECK_PTR(m_clipLines);
 
4357
    QT_TRY {
 
4358
        m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
 
4359
        allocated = clipSpanHeight;
 
4360
        Q_CHECK_PTR(m_spans);
 
4361
 
 
4362
        QT_TRY {
 
4363
            if (hasRectClip) {
 
4364
                int y = 0;
 
4365
                while (y < ymin) {
 
4366
                    m_clipLines[y].spans = 0;
 
4367
                    m_clipLines[y].count = 0;
 
4368
                    ++y;
 
4369
                }
 
4370
 
 
4371
                const int len = clipRect.width();
 
4372
                count = 0;
 
4373
                while (y < ymax) {
4371
4374
                    QSpan *span = m_spans + count;
4372
 
                    span->x = currRect.x();
4373
 
                    span->len = currRect.width();
 
4375
                    span->x = xmin;
 
4376
                    span->len = len;
4374
4377
                    span->y = y;
4375
4378
                    span->coverage = 255;
4376
4379
                    ++count;
4377
 
                }
4378
 
                ++y;
 
4380
 
 
4381
                    m_clipLines[y].spans = span;
 
4382
                    m_clipLines[y].count = 1;
 
4383
                    ++y;
 
4384
                }
 
4385
 
 
4386
                while (y < clipSpanHeight) {
 
4387
                    m_clipLines[y].spans = 0;
 
4388
                    m_clipLines[y].count = 0;
 
4389
                    ++y;
 
4390
                }
 
4391
            } else if (hasRegionClip) {
 
4392
 
 
4393
                const QVector<QRect> rects = clipRegion.rects();
 
4394
                const int numRects = rects.size();
 
4395
 
 
4396
                { // resize
 
4397
                    const int maxSpans = (ymax - ymin) * numRects;
 
4398
                    if (maxSpans > allocated) {
 
4399
                        m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
 
4400
                        allocated = maxSpans;
 
4401
                    }
 
4402
                }
 
4403
 
 
4404
                int y = 0;
 
4405
                int firstInBand = 0;
 
4406
                count = 0;
 
4407
                while (firstInBand < numRects) {
 
4408
                    const int currMinY = rects.at(firstInBand).y();
 
4409
                    const int currMaxY = currMinY + rects.at(firstInBand).height();
 
4410
 
 
4411
                    while (y < currMinY) {
 
4412
                        m_clipLines[y].spans = 0;
 
4413
                        m_clipLines[y].count = 0;
 
4414
                        ++y;
 
4415
                    }
 
4416
 
 
4417
                    int lastInBand = firstInBand;
 
4418
                    while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
 
4419
                        ++lastInBand;
 
4420
 
 
4421
                    while (y < currMaxY) {
 
4422
 
 
4423
                        m_clipLines[y].spans = m_spans + count;
 
4424
                        m_clipLines[y].count = lastInBand - firstInBand + 1;
 
4425
 
 
4426
                        for (int r = firstInBand; r <= lastInBand; ++r) {
 
4427
                            const QRect &currRect = rects.at(r);
 
4428
                            QSpan *span = m_spans + count;
 
4429
                            span->x = currRect.x();
 
4430
                            span->len = currRect.width();
 
4431
                            span->y = y;
 
4432
                            span->coverage = 255;
 
4433
                            ++count;
 
4434
                        }
 
4435
                        ++y;
 
4436
                    }
 
4437
 
 
4438
                    firstInBand = lastInBand + 1;
 
4439
                }
 
4440
 
 
4441
                Q_ASSERT(count <= allocated);
 
4442
 
 
4443
                while (y < clipSpanHeight) {
 
4444
                    m_clipLines[y].spans = 0;
 
4445
                    m_clipLines[y].count = 0;
 
4446
                    ++y;
 
4447
                }
 
4448
 
4379
4449
            }
4380
 
 
4381
 
            firstInBand = lastInBand + 1;
4382
 
        }
4383
 
 
4384
 
        Q_ASSERT(count <= allocated);
4385
 
 
4386
 
        while (y < clipSpanHeight) {
4387
 
            m_clipLines[y].spans = 0;
4388
 
            m_clipLines[y].count = 0;
4389
 
            ++y;
4390
 
        }
4391
 
 
 
4450
        } QT_CATCH(...) {
 
4451
            free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
 
4452
            m_spans = 0;
 
4453
            QT_RETHROW;
 
4454
        }
 
4455
    } QT_CATCH(...) {
 
4456
        free(m_clipLines); // same for clipLines
 
4457
        m_clipLines = 0;
 
4458
        QT_RETHROW;
4392
4459
    }
4393
4460
}
4394
4461
 
4407
4474
    ymax = m_spans[count-1].y + 1;
4408
4475
    xmin = INT_MAX;
4409
4476
    xmax = 0;
 
4477
 
 
4478
    bool isRect = true;
 
4479
    int left = m_spans[0].x;
 
4480
    int right = m_spans[0].x + m_spans[0].len;
 
4481
 
4410
4482
    for (int i = 0; i < count; ++i) {
4411
 
//           qDebug() << "    " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4412
4483
        if (m_spans[i].y != y) {
 
4484
            if (m_spans[i].y != y + 1 && y != -1) {
 
4485
                isRect = false;
 
4486
            }
4413
4487
            y = m_spans[i].y;
4414
4488
            m_clipLines[y].spans = m_spans+i;
4415
4489
            m_clipLines[y].count = 0;
4416
4490
//              qDebug() << "        new line: y=" << y;
4417
4491
        }
4418
4492
        ++m_clipLines[y].count;
 
4493
        int sl = (int) m_spans[i].x;
 
4494
        int sr = sl + m_spans[i].len;
 
4495
 
4419
4496
        xmin = qMin(xmin, (int)m_spans[i].x);
4420
4497
        xmax = qMax(xmax, (int)m_spans[i].x + m_spans[i].len);
4421
 
    }
4422
 
    ++xmax;
4423
 
//     qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d", xmin, xmax, ymin, ymax);
 
4498
 
 
4499
        if (sl != left || sr != right)
 
4500
            isRect = false;
 
4501
    }
 
4502
//     qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d %s", xmin, xmax, ymin, ymax, isRect ? "rectangular" : "");
 
4503
 
 
4504
    if (isRect) {
 
4505
        hasRectClip = true;
 
4506
        clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
 
4507
    }
4424
4508
}
4425
4509
 
4426
4510
/*
4428
4512
 */
4429
4513
void QClipData::setClipRect(const QRect &rect)
4430
4514
{
4431
 
    if (rect == clipRect)
 
4515
    if (hasRectClip && rect == clipRect)
4432
4516
        return;
4433
4517
 
4434
4518
//    qDebug() << "setClipRect" << clipSpanHeight << count << allocated << rect;
4435
4519
    hasRectClip = true;
 
4520
    hasRegionClip = false;
4436
4521
    clipRect = rect;
4437
4522
 
4438
4523
    xmin = rect.x();
4441
4526
    ymax = qMin(rect.y() + rect.height(), clipSpanHeight);
4442
4527
 
4443
4528
    if (m_spans) {
4444
 
        delete m_spans;
 
4529
        free(m_spans);
4445
4530
        m_spans = 0;
4446
4531
    }
4447
4532
 
4459
4544
    }
4460
4545
 
4461
4546
    hasRegionClip = true;
 
4547
    hasRectClip = false;
4462
4548
    clipRegion = region;
4463
4549
 
4464
4550
    { // set bounding rect
4470
4556
    }
4471
4557
 
4472
4558
    if (m_spans) {
4473
 
        delete m_spans;
 
4559
        free(m_spans);
4474
4560
        m_spans = 0;
4475
4561
    }
4476
4562
 
4603
4689
    return n;
4604
4690
}
4605
4691
 
4606
 
/*
4607
 
    \internal
4608
 
    Clip spans to \a{clip}-region.
4609
 
    Returns number of unclipped spans
4610
 
*/
4611
 
static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4612
 
                              int *currSpan,
4613
 
                              QT_FT_Span *outSpans, int maxOut,
4614
 
                              const QRegion &clip)
4615
 
{
4616
 
    const QVector<QRect> rects = clip.rects();
4617
 
    const int numRects = rects.size();
4618
 
 
4619
 
    int r = 0;
4620
 
    short miny, minx, maxx, maxy;
4621
 
    {
4622
 
        const QRect &rect = rects[0];
4623
 
        miny = rect.top();
4624
 
        minx = rect.left();
4625
 
        maxx = rect.right();
4626
 
        maxy = rect.bottom();
4627
 
    }
4628
 
 
4629
 
    // TODO: better mapping of currY and startRect
4630
 
 
4631
 
    int n = 0;
4632
 
    int i = *currSpan;
4633
 
    int currY = spans[i].y;
4634
 
    while (i < numSpans) {
4635
 
 
4636
 
        if (spans[i].y != currY && r != 0) {
4637
 
            currY = spans[i].y;
4638
 
            r = 0;
4639
 
            const QRect &rect = rects[r];
4640
 
            miny = rect.top();
4641
 
            minx = rect.left();
4642
 
            maxx = rect.right();
4643
 
            maxy = rect.bottom();
4644
 
        }
4645
 
 
4646
 
        if (spans[i].y < miny) {
4647
 
            ++i;
4648
 
            continue;
4649
 
        }
4650
 
 
4651
 
        if (spans[i].y > maxy || spans[i].x > maxx) {
4652
 
            if (++r >= numRects) {
4653
 
                ++i;
4654
 
                continue;
4655
 
            }
4656
 
 
4657
 
            const QRect &rect = rects[r];
4658
 
            miny = rect.top();
4659
 
            minx = rect.left();
4660
 
            maxx = rect.right();
4661
 
            maxy = rect.bottom();
4662
 
            continue;
4663
 
        }
4664
 
 
4665
 
        if (spans[i].x + spans[i].len <= minx) {
4666
 
            ++i;
4667
 
            continue;
4668
 
        }
4669
 
 
4670
 
        outSpans[n].y = spans[i].y;
4671
 
        outSpans[n].coverage = spans[i].coverage;
4672
 
 
4673
 
        if (spans[i].x < minx) {
4674
 
            const ushort cutaway = minx - spans[i].x;
4675
 
            outSpans[n].len = qMin(spans[i].len - cutaway, maxx - minx + 1);
4676
 
            outSpans[n].x = minx;
4677
 
            if (outSpans[n].len == spans[i].len - cutaway) {
4678
 
                ++i;
4679
 
            } else {
4680
 
                // span wider than current rect
4681
 
                spans[i].len -= outSpans[n].len + cutaway;
4682
 
                spans[i].x = maxx + 1;
4683
 
            }
4684
 
        } else { // span starts inside current rect
4685
 
            outSpans[n].x = spans[i].x;
4686
 
            outSpans[n].len = qMin(spans[i].len,
4687
 
                                   ushort(maxx - spans[i].x + 1));
4688
 
            if (outSpans[n].len == spans[i].len) {
4689
 
                ++i;
4690
 
            } else {
4691
 
                // span wider than current rect
4692
 
                spans[i].len -= outSpans[n].len;
4693
 
                spans[i].x = maxx + 1;
4694
 
            }
4695
 
        }
4696
 
 
4697
 
        if (++n >= maxOut)
4698
 
            break;
4699
 
    }
4700
 
 
4701
 
    *currSpan = i;
4702
 
    return n;
4703
 
}
4704
4692
 
4705
4693
static void qt_span_fill_clipRect(int count, const QSpan *spans,
4706
4694
                                  void *userData)
4718
4706
        fillData->unclipped_blend(count, spans, fillData);
4719
4707
}
4720
4708
 
4721
 
static void qt_span_fill_clipRegion(int count, const QSpan *spans,
4722
 
                                    void *userData)
4723
 
{
4724
 
    QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4725
 
    Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4726
 
 
4727
 
    Q_ASSERT(fillData->clip);
4728
 
    Q_ASSERT(!fillData->clip->clipRegion.isEmpty());
4729
 
 
4730
 
    const int NSPANS = 256;
4731
 
    QSpan cspans[NSPANS];
4732
 
    int currentClip = 0;
4733
 
    while (currentClip < count) {
4734
 
        const int unclipped = qt_intersect_spans(const_cast<QSpan*>(spans),
4735
 
                                                 count, &currentClip,
4736
 
                                                 &cspans[0], NSPANS,
4737
 
                                                 fillData->clip->clipRegion);
4738
 
        if (unclipped > 0)
4739
 
            fillData->unclipped_blend(unclipped, cspans, fillData);
4740
 
    }
4741
 
 
4742
 
}
4743
 
 
4744
4709
static void qt_span_clip(int count, const QSpan *spans, void *userData)
4745
4710
{
4746
4711
    ClipData *clipData = reinterpret_cast<ClipData *>(userData);
4765
4730
                                           &newspans, newClip->allocated - newClip->count);
4766
4731
                newClip->count = newspans - newClip->m_spans;
4767
4732
                if (spans < end) {
 
4733
                    newClip->m_spans = q_check_ptr((QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)));
4768
4734
                    newClip->allocated *= 2;
4769
 
                    newClip->m_spans = (QSpan *)realloc(newClip->m_spans, newClip->allocated*sizeof(QSpan));
4770
4735
                }
4771
4736
            }
4772
4737
        }
5013
4978
 
5014
4979
extern QImage qt_imageForBrush(int brushStyle, bool invert);
5015
4980
 
5016
 
void QSpanData::setup(const QBrush &brush, int alpha)
 
4981
void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
5017
4982
{
5018
4983
    Qt::BrushStyle brushStyle = qbrush_style(brush);
5019
4984
    switch (brushStyle) {
5021
4986
        type = Solid;
5022
4987
        QColor c = qbrush_color(brush);
5023
4988
        solid.color = PREMUL(ARGB_COMBINE_ALPHA(c.rgba(), alpha));
 
4989
        if ((solid.color & 0xff000000) == 0
 
4990
            && compositionMode == QPainter::CompositionMode_SourceOver) {
 
4991
            type = None;
 
4992
        }
5024
4993
        break;
5025
4994
    }
5026
4995
 
5161
5130
        blend = unclipped_blend;
5162
5131
    } else if (clip->hasRectClip) {
5163
5132
        blend = clip->clipRect.isEmpty() ? 0 : qt_span_fill_clipRect;
5164
 
    } else if (clip->hasRegionClip) {
5165
 
        blend = clip->clipRegion.isEmpty() ? 0 : qt_span_fill_clipRegion;
5166
5133
    } else {
5167
5134
        blend = qt_span_fill_clipped;
5168
5135
    }
5319
5286
            dy = -dy;
5320
5287
        }
5321
5288
 
 
5289
        int x_lower_limit = - 128;
 
5290
        if (x1 < x_lower_limit) {
 
5291
            int cy = dy * (x_lower_limit - x1) / dx + y1;
 
5292
            drawLine_midpoint_i(x_lower_limit, cy, x2, y2, span_func, data, style, devRect);
 
5293
            return;
 
5294
        }
 
5295
 
5322
5296
        if (style == LineDrawNormal)
5323
5297
            --x2;
5324
5298
 
5456
5430
            dx = -dx;
5457
5431
        }
5458
5432
 
 
5433
        int y_lower_limit = - 128;
 
5434
        if (y1 < y_lower_limit) {
 
5435
            int cx = dx * (y_lower_limit - y1) / dy + x1;
 
5436
            drawLine_midpoint_i(cx, y_lower_limit, x2, y2, span_func, data, style, devRect);
 
5437
            return;
 
5438
        }
 
5439
 
5459
5440
        if (style == LineDrawNormal)
5460
5441
            --y2;
5461
5442
 
6132
6113
*/
6133
6114
 
6134
6115
#ifdef QT_DEBUG_DRAW
6135
 
void dumpClip(int width, int height, QClipData *clip)
 
6116
void dumpClip(int width, int height, const QClipData *clip)
6136
6117
{
6137
6118
    QImage clipImg(width, height, QImage::Format_ARGB32_Premultiplied);
6138
6119
    clipImg.fill(0xffff0000);
6142
6123
    int y0 = height;
6143
6124
    int y1 = 0;
6144
6125
 
 
6126
    ((QClipData *) clip)->spans(); // Force allocation of the spans structure...
 
6127
 
6145
6128
    for (int i = 0; i < clip->count; ++i) {
6146
 
        QSpan *span = clip->spans + i;
 
6129
        const QSpan *span = ((QClipData *) clip)->spans() + i;
6147
6130
        for (int j = 0; j < span->len; ++j)
6148
6131
            clipImg.setPixel(span->x + j, span->y, 0xffffff00);
6149
6132
        x0 = qMin(x0, int(span->x));
6161
6144
    Q_ASSERT(x1 >= 0);
6162
6145
 
6163
6146
    fprintf(stderr,"clip %d: %d %d - %d %d\n", counter, x0, y0, x1, y1);
6164
 
    clipImg.save(QString(QLatin1String("clip-%0.png")).arg(counter++));
 
6147
    clipImg.save(QString::fromLatin1("clip-%0.png").arg(counter++));
6165
6148
}
6166
6149
#endif
6167
6150