~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to .pc/kubuntu_01_arm_needs_qreal.diff/krita/image/kis_painter.cc

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
3
 
 *  Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
4
 
 *  Copyright (c) 2004 Clarence Dang <dang@kde.org>
5
 
 *  Copyright (c) 2004 Adrian Page <adrian@pagenet.plus.com>
6
 
 *  Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
7
 
 *  Copyright (c) 2008 Lukas Tvrdy <lukast.dev@gmail.com>
8
 
 *
9
 
 *  This program is free software; you can redistribute it and/or modify
10
 
 *  it under the terms of the GNU General Public License as published by
11
 
 *  the Free Software Foundation; either version 2 of the License, or
12
 
 *  (at your option) any later version.
13
 
 *
14
 
 *  This program is distributed in the hope that it will be useful,
15
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
 *  GNU General Public License for more details.
18
 
 *
19
 
 *  You should have received a copy of the GNU General Public License
20
 
 *  along with this program; if not, write to the Free Software
21
 
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 
 */
23
 
 
24
 
#include "kis_painter.h"
25
 
#include <stdlib.h>
26
 
#include <string.h>
27
 
#include <cfloat>
28
 
#include <cmath>
29
 
#include <climits>
30
 
#include <strings.h>
31
 
 
32
 
#include <qregion.h>
33
 
#include <QImage>
34
 
#include <QRect>
35
 
#include <QString>
36
 
#include <QStringList>
37
 
#include <QUndoCommand>
38
 
 
39
 
#include <kis_debug.h>
40
 
#include <klocale.h>
41
 
#include <kglobal.h>
42
 
#include <ksharedconfig.h>
43
 
#include <kconfiggroup.h>
44
 
 
45
 
#include <KoColorSpace.h>
46
 
#include <KoColor.h>
47
 
#include <KoCompositeOp.h>
48
 
 
49
 
#include "kis_image.h"
50
 
#include "filter/kis_filter.h"
51
 
#include "kis_layer.h"
52
 
#include "kis_paint_device.h"
53
 
#include "kis_fixed_paint_device.h"
54
 
#include "kis_transaction.h"
55
 
#include "kis_types.h"
56
 
#include "kis_vec.h"
57
 
#include "kis_iterators_pixel.h"
58
 
#include "kis_random_accessor.h"
59
 
#include "kis_paintop.h"
60
 
#include "kis_selection.h"
61
 
#include "kis_fill_painter.h"
62
 
#include "filter/kis_filter_configuration.h"
63
 
#include "kis_pixel_selection.h"
64
 
#include "kis_paint_information.h"
65
 
#include "kis_paintop_registry.h"
66
 
#include "kis_perspective_math.h"
67
 
 
68
 
// Maximum distance from a Bezier control point to the line through the start
69
 
// and end points for the curve to be considered flat.
70
 
#define BEZIER_FLATNESS_THRESHOLD 0.5
71
 
 
72
 
struct KisPainter::Private {
73
 
    KisPaintDeviceSP            device;
74
 
    KisSelectionSP              selection;
75
 
    KisTransaction*             transaction;
76
 
    KoUpdater*                  progressUpdater;
77
 
 
78
 
    QRegion                     dirtyRegion;
79
 
    QRect                       dirtyRect;
80
 
    KisPaintOp*                 paintOp;
81
 
    QRect                       bounds;
82
 
    KoColor                     paintColor;
83
 
    KoColor                     backgroundColor;
84
 
    KoColor                     fillColor;
85
 
    const KisFilterConfiguration* generator;
86
 
    KisPaintLayer*              sourceLayer;
87
 
    FillStyle                   fillStyle;
88
 
    StrokeStyle                 strokeStyle;
89
 
    bool                        antiAliasPolygonFill;
90
 
    const KisPattern*           pattern;
91
 
    QPointF                     duplicateOffset;
92
 
    quint8                      opacity;
93
 
    quint32                     pixelSize;
94
 
    const KoColorSpace*         colorSpace;
95
 
    KoColorProfile*             profile;
96
 
    const KoCompositeOp*        compositeOp;
97
 
    QBitArray                   channelFlags;
98
 
    bool                        useBoundingDirtyRect;
99
 
    const KoAbstractGradient*   gradient;
100
 
    KisPaintOpPresetSP          paintOpPreset;
101
 
    QImage                      polygonMaskImage;
102
 
    QPainter*                   maskPainter;
103
 
    KisFillPainter*             fillPainter;
104
 
    qint32                      maskImageWidth;
105
 
    qint32                      maskImageHeight;
106
 
    bool                        alphaLocked;
107
 
};
108
 
 
109
 
KisPainter::KisPainter()
110
 
        : d(new Private)
111
 
{
112
 
    init();
113
 
}
114
 
 
115
 
KisPainter::KisPainter(KisPaintDeviceSP device)
116
 
        : d(new Private)
117
 
{
118
 
    init();
119
 
    Q_ASSERT(device);
120
 
    begin(device);
121
 
}
122
 
 
123
 
KisPainter::KisPainter(KisPaintDeviceSP device, KisSelectionSP selection)
124
 
        : d(new Private)
125
 
{
126
 
    init();
127
 
    Q_ASSERT(device);
128
 
    begin(device);
129
 
    d->selection = selection;
130
 
}
131
 
 
132
 
void KisPainter::init()
133
 
{
134
 
    d->selection = 0 ;
135
 
    d->transaction = 0;
136
 
    d->paintOp = 0;
137
 
    d->pattern = 0;
138
 
    d->opacity = OPACITY_OPAQUE_U8;
139
 
    d->sourceLayer = 0;
140
 
    d->fillStyle = FillStyleNone;
141
 
    d->strokeStyle = StrokeStyleBrush;
142
 
    d->antiAliasPolygonFill = true;
143
 
    d->bounds = QRect();
144
 
    d->progressUpdater = 0;
145
 
    d->gradient = 0;
146
 
    d->maskPainter = 0;
147
 
    d->fillPainter = 0;
148
 
    d->maskImageWidth = 255;
149
 
    d->maskImageHeight = 255;
150
 
    d->alphaLocked = false;
151
 
 
152
 
    KConfigGroup cfg = KGlobal::config()->group("");
153
 
    d->useBoundingDirtyRect = cfg.readEntry("aggregate_dirty_regions", true);
154
 
}
155
 
 
156
 
KisPainter::~KisPainter()
157
 
{
158
 
    QUndoCommand* cmd = end();
159
 
    Q_ASSERT(cmd == 0);
160
 
    delete cmd;
161
 
    delete d->paintOp;
162
 
    delete d->maskPainter;
163
 
    delete d->fillPainter;
164
 
    delete d;
165
 
}
166
 
 
167
 
void KisPainter::begin(KisPaintDeviceSP device)
168
 
{
169
 
    begin(device, d->selection);
170
 
}
171
 
 
172
 
void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection)
173
 
{
174
 
    if (!device) return;
175
 
    d->selection = selection;
176
 
    Q_ASSERT(device->colorSpace());
177
 
 
178
 
    delete d->transaction;
179
 
    d->transaction = 0;
180
 
 
181
 
    d->device = device;
182
 
    d->colorSpace = device->colorSpace();
183
 
    d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER);
184
 
    d->pixelSize = device->pixelSize();
185
 
}
186
 
QUndoCommand *KisPainter::end()
187
 
{
188
 
    return endTransaction();
189
 
}
190
 
 
191
 
void KisPainter::beginTransaction(const QString& customName)
192
 
{
193
 
    delete d->transaction;
194
 
    d->transaction = new KisTransaction(customName, d->device);
195
 
    Q_CHECK_PTR(d->transaction);
196
 
}
197
 
 
198
 
void KisPainter::beginTransaction(KisTransaction* command)
199
 
{
200
 
    delete d->transaction;
201
 
    d->transaction = command;
202
 
}
203
 
 
204
 
 
205
 
QUndoCommand* KisPainter::endTransaction()
206
 
{
207
 
    if (!d->transaction) return 0;
208
 
 
209
 
    if (d->device)
210
 
        d->device->disconnect(d->transaction);
211
 
 
212
 
    QUndoCommand *command = d->transaction;
213
 
    d->transaction = 0;
214
 
    return command;
215
 
}
216
 
 
217
 
QRegion KisPainter::dirtyRegion()
218
 
{
219
 
    if (d->useBoundingDirtyRect) {
220
 
        QRegion r(d->dirtyRect);
221
 
        d->dirtyRegion = QRegion();
222
 
        d->dirtyRect = QRect();
223
 
        return r;
224
 
    } else {
225
 
        QRegion r = d->dirtyRegion;
226
 
        d->dirtyRegion = QRegion();
227
 
        return r;
228
 
    }
229
 
}
230
 
 
231
 
 
232
 
QRegion KisPainter::addDirtyRect(const QRect & rc)
233
 
{
234
 
    QRect r = rc.normalized();
235
 
 
236
 
    if (!r.isValid() || r.width() <= 0 || r.height() <= 0) {
237
 
        return d->dirtyRegion;
238
 
    }
239
 
 
240
 
    if (d->useBoundingDirtyRect) {
241
 
        d->dirtyRect = d->dirtyRect.united(r);
242
 
        return QRegion(d->dirtyRect);
243
 
    } else {
244
 
        d->dirtyRegion += QRegion(r);
245
 
        return d->dirtyRegion;
246
 
    }
247
 
}
248
 
 
249
 
void KisPainter::bitBlt(qint32 dx, qint32 dy, const KisPaintDeviceSP srcdev, const KisFixedPaintDeviceSP selection, qint32 sx, qint32 sy, qint32 sw, qint32 sh)
250
 
{
251
 
    if (sw == 0 || sh == 0) return;
252
 
    if (srcdev.isNull()) return;
253
 
    if (d->device.isNull()) return;
254
 
 
255
 
    Q_ASSERT(srcdev->pixelSize() == d->pixelSize);
256
 
    Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
257
 
 
258
 
    QRect srcRect = QRect(sx, sy, sw, sh);
259
 
 
260
 
    // In case of COMPOSITE_COPY restricting bitblt to extent can
261
 
    // have unexpected behavior since it would reduce the area that
262
 
    // is copied.
263
 
    if (d->compositeOp->id() != COMPOSITE_COPY) {
264
 
        srcRect &= srcdev->extent();
265
 
    }
266
 
 
267
 
    if (srcRect.isEmpty()) {
268
 
        return;
269
 
    }
270
 
 
271
 
    dx += srcRect.x() - sx;
272
 
    dy += srcRect.y() - sy;
273
 
 
274
 
    sx = srcRect.x();
275
 
    sy = srcRect.y();
276
 
    sw = srcRect.width();
277
 
    sh = srcRect.height();
278
 
 
279
 
    quint8 * srcBytes = new quint8[ sw * sh * srcdev->pixelSize()];
280
 
    srcdev->readBytes(srcBytes,sx,sy,sw,sh);
281
 
 
282
 
    quint8 * dstBytes = new quint8[ sw * sh * d->device->pixelSize()];
283
 
    d->device->readBytes(dstBytes, dx,dy, sw, sh);
284
 
 
285
 
    quint8 * selectionBytes = new quint8[ sw * sh * selection->pixelSize()];
286
 
    selection->readBytes(selectionBytes, 0, 0, sw, sh);
287
 
 
288
 
    d->colorSpace->bitBlt(dstBytes,
289
 
                        sw * d->device->pixelSize(),
290
 
                        srcdev->colorSpace(),
291
 
                        srcBytes,
292
 
                        sw * srcdev->colorSpace()->pixelSize(),
293
 
                        selectionBytes,
294
 
                        sw  * selection->pixelSize(),
295
 
                        d->opacity,
296
 
                        sh,
297
 
                        sw,
298
 
                        d->compositeOp,
299
 
                        d->channelFlags);
300
 
 
301
 
    d->device->writeBytes(dstBytes, dx, dy, sw, sh);
302
 
 
303
 
    delete [] srcBytes;
304
 
    delete [] dstBytes;
305
 
 
306
 
    addDirtyRect(QRect(dx, dy, sw, sh));
307
 
}
308
 
 
309
 
 
310
 
 
311
 
void KisPainter::bitBlt(qint32 dx, qint32 dy,
312
 
                        const KisPaintDeviceSP srcdev,
313
 
                        qint32 sx, qint32 sy,
314
 
                        qint32 sw, qint32 sh)
315
 
{
316
 
    if (sw == 0 || sh == 0) return;
317
 
    if (srcdev.isNull()) return;
318
 
    if (d->device.isNull()) return;
319
 
 
320
 
    QRect srcRect = QRect(sx, sy, sw, sh);
321
 
 
322
 
    // In case of COMPOSITE_COPY restricting bitblt to extent can
323
 
    // have unexpected behavior since it would reduce the area that
324
 
    // is copied.
325
 
    if (d->compositeOp->id() != COMPOSITE_COPY) {
326
 
        srcRect &= srcdev->extent();
327
 
    }
328
 
 
329
 
    if (srcRect.isEmpty()) {
330
 
        return;
331
 
    }
332
 
 
333
 
    dx += srcRect.x() - sx;
334
 
    dy += srcRect.y() - sy;
335
 
 
336
 
    sx = srcRect.x();
337
 
    sy = srcRect.y();
338
 
    sw = srcRect.width();
339
 
    sh = srcRect.height();
340
 
 
341
 
    const KoColorSpace * srcCs = srcdev->colorSpace();
342
 
 
343
 
    qint32 dstY = dy;
344
 
    qint32 srcY = sy;
345
 
    qint32 rowsRemaining = sh;
346
 
 
347
 
    KisRandomConstAccessorPixel srcIt = srcdev->createRandomConstAccessor(sx, sy);
348
 
    KisRandomAccessorPixel dstIt = d->device->createRandomAccessor(dx, dy);
349
 
 
350
 
    if (d->selection) {
351
 
 
352
 
        KisRandomConstAccessorPixel maskIt = d->selection->createRandomConstAccessor(dx, dy);
353
 
 
354
 
        while (rowsRemaining > 0) {
355
 
 
356
 
            qint32 dstX = dx;
357
 
            qint32 srcX = sx;
358
 
            qint32 columnsRemaining = sw;
359
 
            qint32 numContiguousDstRows = d->device->numContiguousRows(dstY, dstX, dstX + sw - 1);
360
 
            qint32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
361
 
            qint32 numContiguousSelRows = d->selection->numContiguousRows(srcY, srcX, srcX + sw - 1);
362
 
 
363
 
            qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
364
 
            rows = qMin(rows, numContiguousSelRows);
365
 
            rows = qMin(rows, rowsRemaining);
366
 
 
367
 
            while (columnsRemaining > 0) {
368
 
 
369
 
                qint32 numContiguousDstColumns = d->device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
370
 
                qint32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
371
 
                qint32 numContiguousSelColumns = d->selection->numContiguousColumns(srcX, srcY, srcY + rows - 1);
372
 
 
373
 
                qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
374
 
                columns = qMin(columns, numContiguousSelColumns);
375
 
                columns = qMin(columns, columnsRemaining);
376
 
 
377
 
                qint32 srcRowStride = srcdev->rowStride(srcX, srcY);
378
 
                srcIt.moveTo(srcX, srcY);
379
 
 
380
 
                qint32 dstRowStride = d->device->rowStride(dstX, dstY);
381
 
                dstIt.moveTo(dstX, dstY);
382
 
 
383
 
                qint32 maskRowStride = d->selection->rowStride(dstX, dstY);
384
 
                maskIt.moveTo(dstX, dstY);
385
 
 
386
 
                d->colorSpace->bitBlt(dstIt.rawData(),
387
 
                                      dstRowStride,
388
 
                                      srcCs,
389
 
                                      srcIt.rawData(),
390
 
                                      srcRowStride,
391
 
                                      maskIt.rawData(),
392
 
                                      maskRowStride,
393
 
                                      d->opacity,
394
 
                                      rows,
395
 
                                      columns,
396
 
                                      d->compositeOp,
397
 
                                      d->channelFlags);
398
 
                srcX += columns;
399
 
                dstX += columns;
400
 
                columnsRemaining -= columns;
401
 
            }
402
 
 
403
 
            srcY += rows;
404
 
            dstY += rows;
405
 
            rowsRemaining -= rows;
406
 
        }
407
 
    } else {
408
 
 
409
 
        while (rowsRemaining > 0) {
410
 
 
411
 
            qint32 dstX = dx;
412
 
            qint32 srcX = sx;
413
 
            qint32 columnsRemaining = sw;
414
 
            qint32 numContiguousDstRows = d->device->numContiguousRows(dstY, dstX, dstX + sw - 1);
415
 
            qint32 numContiguousSrcRows = srcdev->numContiguousRows(srcY, srcX, srcX + sw - 1);
416
 
 
417
 
            qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
418
 
            rows = qMin(rows, rowsRemaining);
419
 
 
420
 
            while (columnsRemaining > 0) {
421
 
 
422
 
                qint32 numContiguousDstColumns = d->device->numContiguousColumns(dstX, dstY, dstY + rows - 1);
423
 
                qint32 numContiguousSrcColumns = srcdev->numContiguousColumns(srcX, srcY, srcY + rows - 1);
424
 
 
425
 
                qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
426
 
                columns = qMin(columns, columnsRemaining);
427
 
 
428
 
                qint32 srcRowStride = srcdev->rowStride(srcX, srcY);
429
 
                srcIt.moveTo(srcX, srcY);
430
 
 
431
 
                qint32 dstRowStride = d->device->rowStride(dstX, dstY);
432
 
                dstIt.moveTo(dstX, dstY);
433
 
 
434
 
                d->colorSpace->bitBlt(dstIt.rawData(),
435
 
                                      dstRowStride,
436
 
                                      srcCs,
437
 
                                      srcIt.rawData(),
438
 
                                      srcRowStride,
439
 
                                      0,
440
 
                                      0,
441
 
                                      d->opacity,
442
 
                                      rows,
443
 
                                      columns,
444
 
                                      d->compositeOp,
445
 
                                      d->channelFlags);
446
 
 
447
 
                srcX += columns;
448
 
                dstX += columns;
449
 
                columnsRemaining -= columns;
450
 
            }
451
 
 
452
 
            srcY += rows;
453
 
            dstY += rows;
454
 
            rowsRemaining -= rows;
455
 
        }
456
 
    }
457
 
 
458
 
    addDirtyRect(QRect(dx, dy, sw, sh));
459
 
}
460
 
 
461
 
void KisPainter::bitBlt(const QPoint & pos, const KisPaintDeviceSP src, const QRect & srcRect)
462
 
{
463
 
    bitBlt(pos.x(), pos.y(), src, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
464
 
}
465
 
 
466
 
 
467
 
 
468
 
void KisPainter::bltFixed(qint32 dx, qint32 dy,
469
 
                          const KisFixedPaintDeviceSP srcDev,
470
 
                          qint32 sx, qint32 sy,
471
 
                          qint32 sw, qint32 sh)
472
 
{
473
 
    if (sw == 0 || sh == 0) return;
474
 
    if (srcDev.isNull()) return;
475
 
    if (d->device.isNull()) return;
476
 
    Q_ASSERT(srcDev->pixelSize() == d->pixelSize);
477
 
 
478
 
    QRect srcRect = QRect(sx, sy, sw, sh);
479
 
 
480
 
    if (srcRect.isEmpty()) {
481
 
        return;
482
 
    }
483
 
 
484
 
    if (!srcRect.contains(srcDev->bounds())) {
485
 
        srcRect = srcDev->bounds();
486
 
    }
487
 
 
488
 
    dx += srcRect.x() - sx;
489
 
    dy += srcRect.y() - sy;
490
 
 
491
 
    sx = srcRect.x();
492
 
    sy = srcRect.y();
493
 
    sw = srcRect.width();
494
 
    sh = srcRect.height();
495
 
 
496
 
    const KoColorSpace * srcCs = d->colorSpace;
497
 
    quint8* dstBytes = new quint8[sw * sh * d->device->pixelSize()];
498
 
    d->device->readBytes(dstBytes, dx, dy, sw, sh);
499
 
 
500
 
    if (d->selection) {
501
 
 
502
 
        quint8* selBytes = new quint8[sw * sh * d->selection->pixelSize()];
503
 
        d->selection->readBytes(selBytes, dx, dy, sw, sh);
504
 
 
505
 
        d->colorSpace->bitBlt(dstBytes,
506
 
                              sw * d->device->pixelSize(),
507
 
                              srcCs,
508
 
                              srcDev->data() + sx,
509
 
                              srcDev->bounds().width() * srcDev->pixelSize(),
510
 
                              selBytes,
511
 
                              sw  * d->selection->pixelSize(),
512
 
                              d->opacity,
513
 
                              sh,
514
 
                              sw,
515
 
                              d->compositeOp,
516
 
                              d->channelFlags);
517
 
 
518
 
        delete[] selBytes;
519
 
    } else {
520
 
        d->colorSpace->bitBlt(dstBytes,
521
 
                              sw * d->device->pixelSize(),
522
 
                              srcCs,
523
 
                              srcDev->data() + sx,
524
 
                              srcDev->bounds().width() * srcDev->pixelSize(),
525
 
                              0,
526
 
                              0,
527
 
                              d->opacity,
528
 
                              sh,
529
 
                              sw,
530
 
                              d->compositeOp,
531
 
                              d->channelFlags);
532
 
 
533
 
    }
534
 
 
535
 
    d->device->writeBytes(dstBytes, dx, dy, sw, sh);
536
 
 
537
 
    delete[] dstBytes;
538
 
 
539
 
    addDirtyRect(QRect(dx, dy, sw, sh));
540
 
}
541
 
 
542
 
 
543
 
void KisPainter::bltFixed(qint32 dx, qint32 dy,
544
 
                          const KisFixedPaintDeviceSP srcDev,
545
 
                          const KisFixedPaintDeviceSP selection,
546
 
                          qint32 sx, qint32 sy,
547
 
                          qint32 sw, qint32 sh)
548
 
{
549
 
    if (sw == 0 || sh == 0) return;
550
 
    if (srcDev.isNull()) return;
551
 
    if (d->device.isNull()) return;
552
 
    Q_ASSERT(srcDev->pixelSize() == d->pixelSize);
553
 
    Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8());
554
 
 
555
 
    QRect srcRect = QRect(sx, sy, sw, sh);
556
 
 
557
 
    if (srcRect.isEmpty()) {
558
 
        return;
559
 
    }
560
 
 
561
 
    if (!srcRect.contains(srcDev->bounds())) {
562
 
        srcRect = srcDev->bounds();
563
 
    }
564
 
 
565
 
    dx += srcRect.x() - sx;
566
 
    dy += srcRect.y() - sy;
567
 
 
568
 
    sx = srcRect.x();
569
 
    sy = srcRect.y();
570
 
    sw = srcRect.width();
571
 
    sh = srcRect.height();
572
 
 
573
 
    const KoColorSpace * srcCs = d->colorSpace;
574
 
    quint8* dstBytes = new quint8[sw * sh * d->device->pixelSize()];
575
 
    d->device->readBytes(dstBytes, dx, dy, sw, sh);
576
 
 
577
 
    quint8* selBytes = selection->data();
578
 
 
579
 
    d->colorSpace->bitBlt(dstBytes,
580
 
                            sw * d->device->pixelSize(),
581
 
                            srcCs,
582
 
                            srcDev->data() + sx,
583
 
                            srcDev->bounds().width() * srcDev->pixelSize(),
584
 
                            selBytes,
585
 
                            sw  * selection->pixelSize(),
586
 
                            d->opacity,
587
 
                            sh,
588
 
                            sw,
589
 
                            d->compositeOp,
590
 
                            d->channelFlags);
591
 
 
592
 
 
593
 
    d->device->writeBytes(dstBytes, dx, dy, sw, sh);
594
 
 
595
 
    delete[] dstBytes;
596
 
 
597
 
    addDirtyRect(QRect(dx, dy, sw, sh));
598
 
}
599
 
 
600
 
 
601
 
void KisPainter::bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP src, const QRect & srcRect)
602
 
{
603
 
    bltFixed(pos.x(), pos.y(), src, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
604
 
}
605
 
 
606
 
KisDistanceInformation KisPainter::paintLine(const KisPaintInformation &pi1,
607
 
                             const KisPaintInformation &pi2,
608
 
                             const KisDistanceInformation& savedDist)
609
 
{
610
 
    if (!d->device) return KisDistanceInformation();
611
 
    if (!d->paintOp || !d->paintOp->canPaint()) return KisDistanceInformation();
612
 
 
613
 
    return d->paintOp->paintLine(pi1, pi2, savedDist);
614
 
}
615
 
 
616
 
void KisPainter::paintPolyline(const vQPointF &points,
617
 
                               int index, int numPoints)
618
 
{
619
 
    if (index >= (int) points.count())
620
 
        return;
621
 
 
622
 
    if (numPoints < 0)
623
 
        numPoints = points.count();
624
 
 
625
 
    if (index + numPoints > (int) points.count())
626
 
        numPoints = points.count() - index;
627
 
 
628
 
 
629
 
    KisDistanceInformation saveDist;
630
 
    for (int i = index; i < index + numPoints - 1; i++) {
631
 
        saveDist = paintLine(points [index], points [index + 1], saveDist);
632
 
    }
633
 
}
634
 
 
635
 
static void getBezierCurvePoints(const KisVector2D &pos1,
636
 
                                 const KisVector2D &control1,
637
 
                                 const KisVector2D &control2,
638
 
                                 const KisVector2D &pos2,
639
 
                                 vQPointF& points)
640
 
{
641
 
    LineEquation line = LineEquation::Through(pos1, pos2);
642
 
    qreal d1 = line.absDistance(control1);
643
 
    qreal d2 = line.absDistance(control2);
644
 
 
645
 
    if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) {
646
 
        points.push_back(toQPointF(pos1));
647
 
    } else {
648
 
        // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508
649
 
 
650
 
        KisVector2D l2 = (pos1 + control1) / 2;
651
 
        KisVector2D h = (control1 + control2) / 2;
652
 
        KisVector2D l3 = (l2 + h) / 2;
653
 
        KisVector2D r3 = (control2 + pos2) / 2;
654
 
        KisVector2D r2 = (h + r3) / 2;
655
 
        KisVector2D l4 = (l3 + r2) / 2;
656
 
 
657
 
        getBezierCurvePoints(pos1, l2, l3, l4, points);
658
 
        getBezierCurvePoints(l4, r2, r3, pos2, points);
659
 
    }
660
 
}
661
 
 
662
 
void KisPainter::getBezierCurvePoints(const QPointF &pos1,
663
 
                                      const QPointF &control1,
664
 
                                      const QPointF &control2,
665
 
                                      const QPointF &pos2,
666
 
                                      vQPointF& points) const
667
 
{
668
 
    ::getBezierCurvePoints(toKisVector2D(pos1), toKisVector2D(control1), toKisVector2D(control2), toKisVector2D(pos2), points);
669
 
}
670
 
 
671
 
KisDistanceInformation KisPainter::paintBezierCurve(const KisPaintInformation &pi1,
672
 
                                    const QPointF &control1,
673
 
                                    const QPointF &control2,
674
 
                                    const KisPaintInformation &pi2,
675
 
                                    const KisDistanceInformation& savedDist)
676
 
{
677
 
    if (d->paintOp && d->paintOp->canPaint()) {
678
 
        return d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, savedDist);
679
 
    }
680
 
    return KisDistanceInformation();
681
 
}
682
 
 
683
 
void KisPainter::paintRect(const QRectF &rect)
684
 
{
685
 
    QRectF normalizedRect = rect.normalized();
686
 
 
687
 
    vQPointF points;
688
 
 
689
 
    points.push_back(normalizedRect.topLeft());
690
 
    points.push_back(normalizedRect.bottomLeft());
691
 
    points.push_back(normalizedRect.bottomRight());
692
 
    points.push_back(normalizedRect.topRight());
693
 
 
694
 
    paintPolygon(points);
695
 
}
696
 
 
697
 
void KisPainter::paintRect(const double x,
698
 
                           const double y,
699
 
                           const double w,
700
 
                           const double h)
701
 
{
702
 
    paintRect(QRectF(x, y, w, h));
703
 
}
704
 
 
705
 
void KisPainter::paintEllipse(const QRectF &rect)
706
 
{
707
 
    QRectF r = rect.normalized(); // normalize before checking as negative width and height are empty too
708
 
    if (r.isEmpty()) return;
709
 
 
710
 
    // See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation.
711
 
    // kappa = (4/3*(sqrt(2)-1))
712
 
    const double kappa = 0.5522847498;
713
 
    const double lx = (r.width() / 2) * kappa;
714
 
    const double ly = (r.height() / 2) * kappa;
715
 
 
716
 
    QPointF center = r.center();
717
 
 
718
 
    QPointF p0(r.left(), center.y());
719
 
    QPointF p1(r.left(), center.y() - ly);
720
 
    QPointF p2(center.x() - lx, r.top());
721
 
    QPointF p3(center.x(), r.top());
722
 
 
723
 
    vQPointF points;
724
 
 
725
 
    getBezierCurvePoints(p0, p1, p2, p3, points);
726
 
 
727
 
    QPointF p4(center.x() + lx, r.top());
728
 
    QPointF p5(r.right(), center.y() - ly);
729
 
    QPointF p6(r.right(), center.y());
730
 
 
731
 
    getBezierCurvePoints(p3, p4, p5, p6, points);
732
 
 
733
 
    QPointF p7(r.right(), center.y() + ly);
734
 
    QPointF p8(center.x() + lx, r.bottom());
735
 
    QPointF p9(center.x(), r.bottom());
736
 
 
737
 
    getBezierCurvePoints(p6, p7, p8, p9, points);
738
 
 
739
 
    QPointF p10(center.x() - lx, r.bottom());
740
 
    QPointF p11(r.left(), center.y() + ly);
741
 
 
742
 
    getBezierCurvePoints(p9, p10, p11, p0, points);
743
 
 
744
 
    paintPolygon(points);
745
 
}
746
 
 
747
 
void KisPainter::paintEllipse(const double x,
748
 
                              const double y,
749
 
                              const double w,
750
 
                              const double h)
751
 
{
752
 
    paintEllipse(QRectF(x, y, w, h));
753
 
}
754
 
 
755
 
double KisPainter::paintAt(const KisPaintInformation& pi)
756
 
{
757
 
    if (!d->paintOp || !d->paintOp->canPaint()) return 0.0;
758
 
    return d->paintOp->paintAt(pi);
759
 
}
760
 
 
761
 
void KisPainter::fillPolygon(const vQPointF& points, FillStyle fillStyle)
762
 
{
763
 
    if (points.count() < 3) {
764
 
        return;
765
 
    }
766
 
 
767
 
    if (fillStyle == FillStyleNone) {
768
 
        return;
769
 
    }
770
 
 
771
 
    QPainterPath polygonPath;
772
 
 
773
 
    polygonPath.moveTo(points.at(0));
774
 
 
775
 
    for (int pointIndex = 1; pointIndex < points.count(); pointIndex++) {
776
 
        polygonPath.lineTo(points.at(pointIndex));
777
 
    }
778
 
 
779
 
    polygonPath.closeSubpath();
780
 
 
781
 
    d->fillStyle = fillStyle;
782
 
    fillPainterPath(polygonPath);
783
 
}
784
 
 
785
 
void KisPainter::paintPolygon(const vQPointF& points)
786
 
{
787
 
    if (d->fillStyle != FillStyleNone) {
788
 
        fillPolygon(points, d->fillStyle);
789
 
    }
790
 
 
791
 
    if (d->strokeStyle != StrokeStyleNone) {
792
 
        if (points.count() > 1) {
793
 
            KisDistanceInformation distance;
794
 
 
795
 
            for (int i = 0; i < points.count() - 1; i++) {
796
 
                distance = paintLine(KisPaintInformation(points[i]), KisPaintInformation(points[i + 1]), distance);
797
 
            }
798
 
            paintLine(points[points.count() - 1], points[0], distance);
799
 
        }
800
 
    }
801
 
}
802
 
 
803
 
void KisPainter::paintPainterPath(const QPainterPath& path)
804
 
{
805
 
    if (d->fillStyle != FillStyleNone) {
806
 
        fillPainterPath(path);
807
 
    }
808
 
 
809
 
    QPointF lastPoint, nextPoint;
810
 
    int elementCount = path.elementCount();
811
 
    KisDistanceInformation saveDist;
812
 
    for (int i = 0; i < elementCount; i++) {
813
 
        QPainterPath::Element element = path.elementAt(i);
814
 
        switch (element.type) {
815
 
        case QPainterPath::MoveToElement:
816
 
            lastPoint =  QPointF(element.x, element.y);
817
 
            break;
818
 
        case QPainterPath::LineToElement:
819
 
            nextPoint =  QPointF(element.x, element.y);
820
 
            saveDist = paintLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint), saveDist);
821
 
            lastPoint = nextPoint;
822
 
            break;
823
 
        case QPainterPath::CurveToElement:
824
 
            nextPoint =  QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y);
825
 
            saveDist = paintBezierCurve(KisPaintInformation(lastPoint),
826
 
                             QPointF(path.elementAt(i).x, path.elementAt(i).y),
827
 
                             QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y),
828
 
                             KisPaintInformation(nextPoint), saveDist);
829
 
            lastPoint = nextPoint;
830
 
            break;
831
 
        default:
832
 
            continue;
833
 
        }
834
 
    }
835
 
}
836
 
 
837
 
void KisPainter::fillPainterPath(const QPainterPath& path)
838
 
{
839
 
    FillStyle fillStyle = d->fillStyle;
840
 
 
841
 
    if (fillStyle == FillStyleNone) {
842
 
        return;
843
 
    }
844
 
 
845
 
    // Fill the polygon bounding rectangle with the required contents then we'll
846
 
    // create a mask for the actual polygon coverage.
847
 
 
848
 
    KisPaintDeviceSP polygon = new KisPaintDevice(d->device->colorSpace());
849
 
    Q_CHECK_PTR(polygon);
850
 
 
851
 
    if (!d->fillPainter) {
852
 
        d->fillPainter = new KisFillPainter(polygon);
853
 
    } else {
854
 
        d->fillPainter->begin(polygon);
855
 
    }
856
 
 
857
 
 
858
 
    QRectF boundingRect = path.boundingRect();
859
 
    QRect fillRect;
860
 
 
861
 
    fillRect.setLeft((qint32)floor(boundingRect.left()));
862
 
    fillRect.setRight((qint32)ceil(boundingRect.right()));
863
 
    fillRect.setTop((qint32)floor(boundingRect.top()));
864
 
    fillRect.setBottom((qint32)ceil(boundingRect.bottom()));
865
 
 
866
 
    // Expand the rectangle to allow for anti-aliasing.
867
 
    fillRect.adjust(-1, -1, 1, 1);
868
 
 
869
 
    // Clip to the image bounds.
870
 
    if (d->bounds.isValid()) {
871
 
        fillRect &= d->bounds;
872
 
    }
873
 
 
874
 
    switch (fillStyle) {
875
 
    default:
876
 
        // Fall through
877
 
    case FillStyleGradient:
878
 
        // Currently unsupported, fall through
879
 
    case FillStyleStrokes:
880
 
        // Currently unsupported, fall through
881
 
        warnImage << "Unknown or unsupported fill style in fillPolygon\n";
882
 
    case FillStyleForegroundColor:
883
 
        d->fillPainter->fillRect(fillRect, paintColor(), OPACITY_OPAQUE_U8);
884
 
        break;
885
 
    case FillStyleBackgroundColor:
886
 
        d->fillPainter->fillRect(fillRect, backgroundColor(), OPACITY_OPAQUE_U8);
887
 
        break;
888
 
    case FillStylePattern:
889
 
        Q_ASSERT(d->pattern != 0);
890
 
        d->fillPainter->fillRect(fillRect, d->pattern);
891
 
        break;
892
 
    case FillStyleGenerator:
893
 
        Q_ASSERT(d->generator != 0);
894
 
        d->fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), generator());
895
 
        break;
896
 
    }
897
 
 
898
 
    if (d->polygonMaskImage.isNull() || (d->maskPainter == 0)) {
899
 
        d->polygonMaskImage = QImage(d->maskImageWidth, d->maskImageHeight, QImage::Format_ARGB32);
900
 
        d->maskPainter = new QPainter(&d->polygonMaskImage);
901
 
        d->maskPainter->setRenderHint(QPainter::Antialiasing, antiAliasPolygonFill());
902
 
    }
903
 
 
904
 
    // Break the mask up into chunks so we don't have to allocate a potentially very large QImage.
905
 
    const QColor opaqueColor(OPACITY_OPAQUE_U8, OPACITY_OPAQUE_U8, OPACITY_OPAQUE_U8, 255);
906
 
    const QBrush brush(opaqueColor);
907
 
    for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += d->maskImageWidth) {
908
 
        for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += d->maskImageHeight) {
909
 
 
910
 
            d->polygonMaskImage.fill(qRgba(OPACITY_TRANSPARENT_U8, OPACITY_TRANSPARENT_U8, OPACITY_TRANSPARENT_U8, 255));
911
 
            d->maskPainter->translate(-x, -y);
912
 
            d->maskPainter->fillPath(path, brush);
913
 
            d->maskPainter->translate(x, y);
914
 
 
915
 
            qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, d->maskImageWidth);
916
 
            qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, d->maskImageHeight);
917
 
 
918
 
            KisHLineIterator lineIt = polygon->createHLineIterator(x, y, rectWidth);
919
 
 
920
 
            quint8 tmp;
921
 
            for (int row = y; row < y + rectHeight; row++) {
922
 
                QRgb* line = reinterpret_cast<QRgb*>(d->polygonMaskImage.scanLine(row - y));
923
 
                while (!lineIt.isDone()) {
924
 
                    tmp = qRed(line[lineIt.x() - x]);
925
 
                    polygon->colorSpace()->applyAlphaU8Mask(lineIt.rawData(),
926
 
                                                            &tmp, 1);
927
 
                    ++lineIt;
928
 
                }
929
 
                lineIt.nextRow();
930
 
            }
931
 
 
932
 
        }
933
 
    }
934
 
 
935
 
    QRect r = polygon->extent();
936
 
 
937
 
    // The strokes for the outline may have already added updated the dirtyrect, but it can't hurt,
938
 
    // and if we're painting without outlines, then there will be no dirty rect. Let's do it ourselves...
939
 
    bitBlt(r.x(), r.y(), polygon, r.x(), r.y(), r.width(), r.height());
940
 
}
941
 
 
942
 
void KisPainter::drawLine(const QPointF & start, const QPointF & end)
943
 
{
944
 
    drawThickLine(start, end, 1, 1);
945
 
}
946
 
 
947
 
void KisPainter::drawDDALine(const QPointF & start, const QPointF & end)
948
 
{
949
 
    KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
950
 
    int pixelSize = d->device->pixelSize();
951
 
 
952
 
    // Width and height of the line
953
 
    int xd = (int)(end.x() - start.x());
954
 
    int yd = (int)(end.y() - start.y());
955
 
 
956
 
    int x = start.x();
957
 
    int y = start.y();
958
 
    float fx = start.x();
959
 
    float fy = start.y();
960
 
    float m = (float)yd / (float)xd;
961
 
    int y2 = end.y();
962
 
    int x2 = end.x();
963
 
 
964
 
    if (fabs(m) > 1) {
965
 
        int incr;
966
 
        if (yd > 0) {
967
 
            m = 1.0f / m;
968
 
            incr = 1;
969
 
        } else {
970
 
            m = -1.0f / m;
971
 
            incr = -1;
972
 
        }
973
 
        while (y != y2) {
974
 
            fx = fx + m;
975
 
            y = y + incr;
976
 
            x = (int)(fx + 0.5f);
977
 
            accessor.moveTo(x, y);
978
 
            if (accessor.isSelected()) {
979
 
                memcpy(accessor.rawData(), d->paintColor.data(), pixelSize);
980
 
            }
981
 
        }
982
 
    } else {
983
 
        int incr;
984
 
        if (xd > 0) {
985
 
            incr = 1;
986
 
        } else {
987
 
            incr = -1;
988
 
            m = -m;
989
 
        }
990
 
        while (x != x2) {
991
 
            fy = fy + m;
992
 
            x = x + incr;
993
 
            y = (int)(fy + 0.5f);
994
 
            accessor.moveTo(x, y);
995
 
            if (accessor.isSelected()) {
996
 
                memcpy(accessor.rawData(), d->paintColor.data(), pixelSize);
997
 
            }
998
 
        }
999
 
    }
1000
 
 
1001
 
}
1002
 
 
1003
 
void KisPainter::drawWobblyLine(const QPointF & start, const QPointF & end)
1004
 
{
1005
 
    KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1006
 
    int pixelSize = d->device->pixelSize();
1007
 
    KoColor mycolor(d->paintColor);
1008
 
 
1009
 
    int x1 = start.x();
1010
 
    int y1 = start.y();
1011
 
    int x2 = end.x();
1012
 
    int y2 = end.y();
1013
 
 
1014
 
    // Width and height of the line
1015
 
    int xd = (x2 - x1);
1016
 
    int yd = (y2 - y1);
1017
 
 
1018
 
    int x;
1019
 
    int y;
1020
 
    float fx = (x = x1);
1021
 
    float fy = (y = y1);
1022
 
    float m = (float)yd / (float)xd;
1023
 
 
1024
 
    if (fabs(m) > 1) {
1025
 
        int incr;
1026
 
        if (yd > 0) {
1027
 
            m = 1.0f / m;
1028
 
            incr = 1;
1029
 
        } else {
1030
 
            m = -1.0f / m;
1031
 
            incr = -1;
1032
 
        }
1033
 
        while (y != y2) {
1034
 
            fx = fx + m;
1035
 
            y = y + incr;
1036
 
 
1037
 
            x = (int)(fx + 0.5f);
1038
 
            float br1 = int(fx + 1) - fx;
1039
 
            float br2 = fx - (int)fx;
1040
 
 
1041
 
            accessor.moveTo(x, y);
1042
 
            if (accessor.isSelected()) {
1043
 
                mycolor.setOpacity((quint8)(255*br1));
1044
 
                memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1045
 
            }
1046
 
 
1047
 
            accessor.moveTo(x + 1, y);
1048
 
            if (accessor.isSelected()) {
1049
 
                mycolor.setOpacity((quint8)(255*br2));
1050
 
                memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1051
 
            }
1052
 
        }
1053
 
    } else {
1054
 
        int incr;
1055
 
        if (xd > 0) {
1056
 
            incr = 1;
1057
 
        } else {
1058
 
            incr = -1;
1059
 
            m = -m;
1060
 
        }
1061
 
        while (x != x2) {
1062
 
            fy = fy + m;
1063
 
            x = x + incr;
1064
 
            y = (int)(fy + 0.5f);
1065
 
 
1066
 
            float br1 = int(fy + 1) - fy;
1067
 
            float br2 = fy - (int)fy;
1068
 
 
1069
 
            accessor.moveTo(x, y);
1070
 
            if (accessor.isSelected()) {
1071
 
                mycolor.setOpacity((quint8)(255*br1));
1072
 
                memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1073
 
            }
1074
 
 
1075
 
            accessor.moveTo(x, y + 1);
1076
 
            if (accessor.isSelected()) {
1077
 
                mycolor.setOpacity((quint8)(255*br2));
1078
 
                memcpy(accessor.rawData(), mycolor.data(), pixelSize);
1079
 
            }
1080
 
        }
1081
 
    }
1082
 
 
1083
 
}
1084
 
 
1085
 
void KisPainter::drawWuLine(const QPointF & start, const QPointF & end)
1086
 
{
1087
 
    KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1088
 
    int pixelSize = d->device->pixelSize();
1089
 
    KoColor lineColor(d->paintColor);
1090
 
 
1091
 
    int x1 = start.x();
1092
 
    int y1 = start.y();
1093
 
    int x2 = end.x();
1094
 
    int y2 = end.y();
1095
 
 
1096
 
 
1097
 
    float grad, xd, yd;
1098
 
    float xgap, ygap, xend, yend, yf, xf;
1099
 
    float brightness1, brightness2;
1100
 
 
1101
 
    int ix1, ix2, iy1, iy2;
1102
 
    quint8 c1, c2;
1103
 
    const float MaxPixelValue = 255.0f;
1104
 
 
1105
 
    // gradient of line
1106
 
    xd = (x2 - x1);
1107
 
    yd = (y2 - y1);
1108
 
 
1109
 
    if (yd == 0) {
1110
 
        /* Horizontal line */
1111
 
        int incr = (x1 < x2) ? 1 : -1;
1112
 
        ix1 = (int)x1;
1113
 
        ix2 = (int)x2;
1114
 
        iy1 = (int)y1;
1115
 
        while (ix1 != ix2) {
1116
 
            ix1 = ix1 + incr;
1117
 
            accessor.moveTo(ix1, iy1);
1118
 
            if (accessor.isSelected()) {
1119
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1120
 
            }
1121
 
        }
1122
 
        return;
1123
 
    }
1124
 
 
1125
 
    if (xd == 0) {
1126
 
        /* Vertical line */
1127
 
        int incr = (y1 < y2) ? 1 : -1;
1128
 
        iy1 = (int)y1;
1129
 
        iy2 = (int)y2;
1130
 
        ix1 = (int)x1;
1131
 
        while (iy1 != iy2) {
1132
 
            iy1 = iy1 + incr;
1133
 
            accessor.moveTo(ix1, iy1);
1134
 
            if (accessor.isSelected()) {
1135
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1136
 
            }
1137
 
        }
1138
 
        return;
1139
 
    }
1140
 
 
1141
 
    if (fabs(xd) > fabs(yd)) {
1142
 
        // horizontal line
1143
 
        // line have to be paint from left to right
1144
 
        if (x1 > x2) {
1145
 
            float tmp;
1146
 
            tmp = x1; x1 = x2; x2 = tmp;
1147
 
            tmp = y1; y1 = y2; y2 = tmp;
1148
 
            xd = (x2 - x1);
1149
 
            yd = (y2 - y1);
1150
 
        }
1151
 
        grad = yd / xd;
1152
 
        // nearest X,Y interger coordinates
1153
 
        xend = static_cast<int>(x1 + 0.5f);
1154
 
        yend = y1 + grad * (xend - x1);
1155
 
 
1156
 
        xgap = invertFrac(x1 + 0.5f);
1157
 
 
1158
 
        ix1 = static_cast<int>(xend);
1159
 
        iy1 = static_cast<int>(yend);
1160
 
 
1161
 
        // calc the intensity of the other end point pixel pair.
1162
 
        brightness1 = invertFrac(yend) * xgap;
1163
 
        brightness2 =       frac(yend) * xgap;
1164
 
 
1165
 
        c1 = (int)(brightness1 * MaxPixelValue);
1166
 
        c2 = (int)(brightness2 * MaxPixelValue);
1167
 
 
1168
 
        accessor.moveTo(ix1, iy1);
1169
 
        if (accessor.isSelected()) {
1170
 
            lineColor.setOpacity(c1);
1171
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1172
 
        }
1173
 
 
1174
 
        accessor.moveTo(ix1, iy1 + 1);
1175
 
        if (accessor.isSelected()) {
1176
 
            lineColor.setOpacity(c2);
1177
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1178
 
        }
1179
 
 
1180
 
        // calc first Y-intersection for main loop
1181
 
        yf = yend + grad;
1182
 
 
1183
 
        xend = trunc(x2 + 0.5f);
1184
 
        yend = y2 + grad * (xend - x2);
1185
 
 
1186
 
        xgap = invertFrac(x2 - 0.5f);
1187
 
 
1188
 
        ix2 = static_cast<int>(xend);
1189
 
        iy2 = static_cast<int>(yend);
1190
 
 
1191
 
        brightness1 = invertFrac(yend) * xgap;
1192
 
        brightness2 =    frac(yend) * xgap;
1193
 
 
1194
 
        c1 = (int)(brightness1 * MaxPixelValue);
1195
 
        c2 = (int)(brightness2 * MaxPixelValue);
1196
 
 
1197
 
        accessor.moveTo(ix2, iy2);
1198
 
        if (accessor.isSelected()) {
1199
 
            lineColor.setOpacity(c1);
1200
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1201
 
        }
1202
 
 
1203
 
        accessor.moveTo(ix2, iy2 + 1);
1204
 
        if (accessor.isSelected()) {
1205
 
            lineColor.setOpacity(c2);
1206
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1207
 
        }
1208
 
 
1209
 
        // main loop
1210
 
        for (int x = ix1 + 1; x <= ix2 - 1; x++) {
1211
 
            brightness1 = invertFrac(yf);
1212
 
            brightness2 =    frac(yf);
1213
 
            c1 = (int)(brightness1 * MaxPixelValue);
1214
 
            c2 = (int)(brightness2 * MaxPixelValue);
1215
 
 
1216
 
            accessor.moveTo(x, int (yf));
1217
 
            if (accessor.isSelected()) {
1218
 
                lineColor.setOpacity(c1);
1219
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1220
 
            }
1221
 
 
1222
 
            accessor.moveTo(x, int (yf) + 1);
1223
 
            if (accessor.isSelected()) {
1224
 
                lineColor.setOpacity(c2);
1225
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1226
 
            }
1227
 
 
1228
 
            yf = yf + grad;
1229
 
        }
1230
 
    } else {
1231
 
        //vertical
1232
 
        // line have to be painted from left to right
1233
 
        if (y1 > y2) {
1234
 
            float tmp;
1235
 
            tmp = x1; x1 = x2; x2 = tmp;
1236
 
            tmp = y1; y1 = y2; y2 = tmp;
1237
 
            xd = (x2 - x1);
1238
 
            yd = (y2 - y1);
1239
 
        }
1240
 
 
1241
 
        grad = xd / yd;
1242
 
 
1243
 
        // nearest X,Y interger coordinates
1244
 
        yend = static_cast<int>(y1 + 0.5f);
1245
 
        xend = x1 + grad * (yend - y1);
1246
 
 
1247
 
        ygap = invertFrac(y1 + 0.5f);
1248
 
 
1249
 
        ix1 = static_cast<int>(xend);
1250
 
        iy1 = static_cast<int>(yend);
1251
 
 
1252
 
        // calc the intensity of the other end point pixel pair.
1253
 
        brightness1 = invertFrac(xend) * ygap;
1254
 
        brightness2 =       frac(xend) * ygap;
1255
 
 
1256
 
        c1 = (int)(brightness1 * MaxPixelValue);
1257
 
        c2 = (int)(brightness2 * MaxPixelValue);
1258
 
 
1259
 
        accessor.moveTo(ix1, iy1);
1260
 
        if (accessor.isSelected()) {
1261
 
            lineColor.setOpacity(c1);
1262
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1263
 
        }
1264
 
 
1265
 
        accessor.moveTo(x1 + 1, y1);
1266
 
        if (accessor.isSelected()) {
1267
 
            lineColor.setOpacity(c2);
1268
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1269
 
        }
1270
 
 
1271
 
        // calc first Y-intersection for main loop
1272
 
        xf = xend + grad;
1273
 
 
1274
 
        yend = trunc(y2 + 0.5f);
1275
 
        xend = x2 + grad * (yend - y2);
1276
 
 
1277
 
        ygap = invertFrac(y2 - 0.5f);
1278
 
 
1279
 
        ix2 = static_cast<int>(xend);
1280
 
        iy2 = static_cast<int>(yend);
1281
 
 
1282
 
        brightness1 = invertFrac(xend) * ygap;
1283
 
        brightness2 =    frac(xend) * ygap;
1284
 
 
1285
 
        c1 = (int)(brightness1 * MaxPixelValue);
1286
 
        c2 = (int)(brightness2 * MaxPixelValue);
1287
 
 
1288
 
        accessor.moveTo(ix2, iy2);
1289
 
        if (accessor.isSelected()) {
1290
 
            lineColor.setOpacity(c1);
1291
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1292
 
        }
1293
 
 
1294
 
        accessor.moveTo(ix2 + 1, iy2);
1295
 
        if (accessor.isSelected()) {
1296
 
            lineColor.setOpacity(c2);
1297
 
            memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1298
 
        }
1299
 
 
1300
 
        // main loop
1301
 
        for (int y = iy1 + 1; y <= iy2 - 1; y++) {
1302
 
            brightness1 = invertFrac(xf);
1303
 
            brightness2 =    frac(xf);
1304
 
            c1 = (int)(brightness1 * MaxPixelValue);
1305
 
            c2 = (int)(brightness2 * MaxPixelValue);
1306
 
 
1307
 
            accessor.moveTo(int (xf), y);
1308
 
            if (accessor.isSelected()) {
1309
 
                lineColor.setOpacity(c1);
1310
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1311
 
            }
1312
 
 
1313
 
            accessor.moveTo(int (xf) + 1, y);
1314
 
            if (accessor.isSelected()) {
1315
 
                lineColor.setOpacity(c2);
1316
 
                memcpy(accessor.rawData(), lineColor.data(), pixelSize);
1317
 
            }
1318
 
 
1319
 
            xf = xf + grad;
1320
 
        }
1321
 
    }//end-of-else
1322
 
 
1323
 
}
1324
 
 
1325
 
void KisPainter::drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth)
1326
 
{
1327
 
    KisRandomAccessorPixel accessor = d->device->createRandomAccessor(start.x(), start.y(), d->selection);
1328
 
    int pixelSize = d->device->pixelSize();
1329
 
    KoColorSpace * cs = d->device->colorSpace();
1330
 
 
1331
 
    KoColor c1(d->paintColor);
1332
 
    KoColor c2(d->paintColor);
1333
 
    KoColor c3(d->paintColor);
1334
 
    KoColor col1(c1);
1335
 
    KoColor col2(c1);
1336
 
 
1337
 
    float grada, gradb, dxa, dxb, dya, dyb, adya, adyb, fraca, fracb,
1338
 
    xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dx, dy;
1339
 
    int x, y, ix1, ix2, iy1, iy2;
1340
 
 
1341
 
    KoColor pix;
1342
 
 
1343
 
    int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b;
1344
 
    int tp0, tn0, tp1, tn1;
1345
 
 
1346
 
    int horizontal = 0;
1347
 
    float opacity = 1.0;
1348
 
 
1349
 
    tp0 = startWidth / 2;
1350
 
    tn0 = startWidth / 2;
1351
 
    if (startWidth % 2 == 0) // even width startWidth
1352
 
        tn0--;
1353
 
 
1354
 
    tp1 = endWidth / 2;
1355
 
    tn1 = endWidth / 2;
1356
 
    if (endWidth % 2 == 0) // even width endWidth
1357
 
        tn1--;
1358
 
 
1359
 
    int x0 = start.x();
1360
 
    int y0 = start.y();
1361
 
    int x1 = end.x();
1362
 
    int y1 = end.y();
1363
 
 
1364
 
    dx = x1 - x0; // run of general line
1365
 
    dy = y1 - y0; // rise of general line
1366
 
 
1367
 
    if (dy < 0) dy = -dy;
1368
 
    if (dx < 0) dx = -dx;
1369
 
 
1370
 
    if (dx > dy) { // horizontalish
1371
 
        horizontal = 1;
1372
 
        x0a = x0;   y0a = y0 - tn0;
1373
 
        x0b = x0;   y0b = y0 + tp0;
1374
 
        x1a = x1;   y1a = y1 - tn1;
1375
 
        x1b = x1;   y1b = y1 + tp1;
1376
 
    } else {
1377
 
        x0a = x0 - tn0;   y0a = y0;
1378
 
        x0b = x0 + tp0;   y0b = y0;
1379
 
        x1a = x1 - tn1;   y1a = y1;
1380
 
        x1b = x1 + tp1;   y1b = y1;
1381
 
    }
1382
 
 
1383
 
    if (horizontal) { // draw endpoints
1384
 
        for (int i = y0a; i <= y0b; i++) {
1385
 
            accessor.moveTo(x0, i);
1386
 
            if (accessor.isSelected()) {
1387
 
                memcpy(accessor.rawData(), c1.data(), pixelSize);
1388
 
            }
1389
 
        }
1390
 
        for (int i = y1a; i <= y1b; i++) {
1391
 
            accessor.moveTo(x1, i);
1392
 
            if (accessor.isSelected()) {
1393
 
                memcpy(accessor.rawData(), c1.data(), pixelSize);
1394
 
            }
1395
 
        }
1396
 
 
1397
 
    } else {
1398
 
        for (int i = x0a; i <= x0b; i++) {
1399
 
            accessor.moveTo(i, y0);
1400
 
            if (accessor.isSelected()) {
1401
 
                memcpy(accessor.rawData(), c1.data(), pixelSize);
1402
 
            }
1403
 
        }
1404
 
        for (int i = x1a; i <= x1b; i++) {
1405
 
            accessor.moveTo(i, y1);
1406
 
            if (accessor.isSelected()) {
1407
 
                memcpy(accessor.rawData(), c1.data(), pixelSize);
1408
 
            }
1409
 
        }
1410
 
    }
1411
 
 
1412
 
    //antialias endpoints
1413
 
    if (x1 != x0 && y1 != y0) {
1414
 
        if (horizontal) {
1415
 
            accessor.moveTo(x0a, y0a - 1);
1416
 
            if (accessor.isSelected()) {
1417
 
                qreal alpha = cs->opacityF(accessor.rawData());
1418
 
                opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
1419
 
                col1.setOpacity(opacity);
1420
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1421
 
            }
1422
 
 
1423
 
            accessor.moveTo(x1b, y1b + 1);
1424
 
            if (accessor.isSelected()) {
1425
 
                qreal alpha = cs->opacityF(accessor.rawData());
1426
 
                opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
1427
 
                col1.setOpacity(opacity);
1428
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1429
 
            }
1430
 
 
1431
 
        } else {
1432
 
            accessor.moveTo(x0a - 1, y0a);
1433
 
            if (accessor.isSelected()) {
1434
 
                qreal alpha = cs->opacityF(accessor.rawData());
1435
 
                opacity = .25 * c1.opacityF() + (1 - .25) * alpha;
1436
 
                col1.setOpacity(opacity);
1437
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1438
 
            }
1439
 
 
1440
 
            accessor.moveTo(x1b + 1, y1b);
1441
 
            if (accessor.isSelected()) {
1442
 
                qreal alpha = cs->opacityF(accessor.rawData());
1443
 
                opacity = .25 * c2.opacityF() + (1 - .25) * alpha;
1444
 
                col1.setOpacity(opacity);
1445
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1446
 
            }
1447
 
        }
1448
 
    }
1449
 
 
1450
 
    dxa = x1a - x0a; // run of a
1451
 
    dya = y1a - y0a; // rise of a
1452
 
    dxb = x1b - x0b; // run of b
1453
 
    dyb = y1b - y0b; // rise of b
1454
 
 
1455
 
    if (dya < 0) adya = -dya;
1456
 
    else adya = dya;
1457
 
    if (dyb < 0) adyb = -dyb;
1458
 
    else adyb = dyb;
1459
 
 
1460
 
 
1461
 
    if (horizontal) { // horizontal-ish lines
1462
 
        if (x1 < x0) {
1463
 
            int xt, yt, wt;
1464
 
            KoColor tmp;
1465
 
            xt = x1a;     x1a = x0a;    x0a = xt;
1466
 
            yt = y1a;     y1a = y0a;    y0a = yt;
1467
 
            xt = x1b;     x1b = x0b;    x0b = xt;
1468
 
            yt = y1b;     y1b = y0b;    y0b = yt;
1469
 
            xt = x1;      x1 = x0;      x0 = xt;
1470
 
            yt = y1;      y1 = y0;      y0 = yt;
1471
 
 
1472
 
            tmp = c1; c1 = c2; c2 = tmp;
1473
 
            wt = startWidth;      startWidth = endWidth;      endWidth = wt;
1474
 
        }
1475
 
 
1476
 
        grada = dya / dxa;
1477
 
        gradb = dyb / dxb;
1478
 
 
1479
 
        ix1 = x0;   iy1 = y0;
1480
 
        ix2 = x1;   iy2 = y1;
1481
 
 
1482
 
        yfa = y0a + grada;
1483
 
        yfb = y0b + gradb;
1484
 
 
1485
 
        for (x = ix1 + 1; x <= ix2 - 1; x++) {
1486
 
            fraca = yfa - int (yfa);
1487
 
            b1a = 1 - fraca;
1488
 
            b2a = fraca;
1489
 
 
1490
 
            fracb = yfb - int (yfb);
1491
 
            b1b = 1 - fracb;
1492
 
            b2b = fracb;
1493
 
 
1494
 
            // color first pixel of bottom line
1495
 
            opacity = ((x - ix1) / dx) * c2.opacityF() + (1 - (x - ix1) / dx) * c1.opacityF();
1496
 
            c3.setOpacity(opacity);
1497
 
 
1498
 
            accessor.moveTo(x, (int)yfa);
1499
 
            if (accessor.isSelected()) {
1500
 
                qreal alpha = cs->opacityF(accessor.rawData());
1501
 
                opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
1502
 
                col1.setOpacity(opacity);
1503
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1504
 
            }
1505
 
 
1506
 
            // color first pixel of top line
1507
 
            if (!(startWidth == 1 && endWidth == 1)) {
1508
 
                accessor.moveTo(x, (int)yfb);
1509
 
                if (accessor.isSelected()) {
1510
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1511
 
                    opacity = b1b * c3.opacityF() + (1 - b1b) * alpha;
1512
 
                    col1.setOpacity(opacity);
1513
 
                    memcpy(accessor.rawData(), col1.data(), pixelSize);
1514
 
                }
1515
 
            }
1516
 
 
1517
 
            // color second pixel of bottom line
1518
 
            if (grada != 0 && grada != 1) { // if not flat or exact diagonal
1519
 
                accessor.moveTo(x, int (yfa) + 1);
1520
 
                if (accessor.isSelected()) {
1521
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1522
 
                    opacity = b2a * c3.opacityF() + (1 - b2a)  * alpha;
1523
 
                    col2.setOpacity(opacity);
1524
 
                    memcpy(accessor.rawData(), col2.data(), pixelSize);
1525
 
                }
1526
 
 
1527
 
            }
1528
 
 
1529
 
            // color second pixel of top line
1530
 
            if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
1531
 
                accessor.moveTo(x, int (yfb) + 1);
1532
 
                if (accessor.isSelected()) {
1533
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1534
 
                    opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
1535
 
                    col2.setOpacity(opacity);
1536
 
                    memcpy(accessor.rawData(), col2.data(), pixelSize);
1537
 
                }
1538
 
 
1539
 
            }
1540
 
 
1541
 
            // fill remaining pixels
1542
 
            if (!(startWidth == 1 && endWidth == 1)) {
1543
 
                if (yfa < yfb)
1544
 
                    for (int i = yfa + 1; i <= yfb; i++) {
1545
 
                        accessor.moveTo(x, i);
1546
 
                        if (accessor.isSelected()) {
1547
 
                            memcpy(accessor.rawData(), c3.data(), pixelSize);
1548
 
                        }
1549
 
                    }
1550
 
                else
1551
 
                    for (int i = yfa + 1; i >= yfb; i--) {
1552
 
                        accessor.moveTo(x, i);
1553
 
                        if (accessor.isSelected()) {
1554
 
                            memcpy(accessor.rawData(), c3.data(), pixelSize);
1555
 
                        }
1556
 
                    }
1557
 
 
1558
 
            }
1559
 
 
1560
 
            yfa += grada;
1561
 
            yfb += gradb;
1562
 
        }
1563
 
    } else { // vertical-ish lines
1564
 
        if (y1 < y0) {
1565
 
            int xt, yt, wt;
1566
 
            xt = x1a;     x1a = x0a;    x0a = xt;
1567
 
            yt = y1a;     y1a = y0a;    y0a = yt;
1568
 
            xt = x1b;     x1b = x0b;    x0b = xt;
1569
 
            yt = y1b;     y1b = y0b;    y0b = yt;
1570
 
            xt = x1;      x1 = x0;      x0 = xt;
1571
 
            yt = y1;      y1 = y0;      y0 = yt;
1572
 
 
1573
 
            KoColor tmp;
1574
 
            tmp = c1; c1 = c2; c2 = tmp;
1575
 
            wt = startWidth;      startWidth = endWidth;      endWidth = wt;
1576
 
        }
1577
 
 
1578
 
        grada = dxa / dya;
1579
 
        gradb = dxb / dyb;
1580
 
 
1581
 
        ix1 = x0;   iy1 = y0;
1582
 
        ix2 = x1;   iy2 = y1;
1583
 
 
1584
 
        xfa = x0a + grada;
1585
 
        xfb = x0b + gradb;
1586
 
 
1587
 
        for (y = iy1 + 1; y <= iy2 - 1; y++) {
1588
 
            fraca = xfa - int (xfa);
1589
 
            b1a = 1 - fraca;
1590
 
            b2a = fraca;
1591
 
 
1592
 
            fracb = xfb - int (xfb);
1593
 
            b1b = 1 - fracb;
1594
 
            b2b = fracb;
1595
 
 
1596
 
            // color first pixel of left line
1597
 
            opacity = ((y - iy1) / dy) * c2.opacityF() + (1 - (y - iy1) / dy) * c1.opacityF();
1598
 
            c3.setOpacity(opacity);
1599
 
 
1600
 
            accessor.moveTo(int (xfa), y);
1601
 
            if (accessor.isSelected()) {
1602
 
                qreal alpha = cs->opacityF(accessor.rawData());
1603
 
                opacity = b1a * c3.opacityF() + (1 - b1a) * alpha;
1604
 
                col1.setOpacity(opacity);
1605
 
                memcpy(accessor.rawData(), col1.data(), pixelSize);
1606
 
            }
1607
 
 
1608
 
            // color first pixel of right line
1609
 
            if (!(startWidth == 1 && endWidth == 1)) {
1610
 
                accessor.moveTo(int(xfb), y);
1611
 
                if (accessor.isSelected()) {
1612
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1613
 
                    opacity = b1b * c3.opacityF() + (1 - b1b)  * alpha;
1614
 
                    col1.setOpacity(opacity);
1615
 
                    memcpy(accessor.rawData(), col1.data(), pixelSize);
1616
 
                }
1617
 
            }
1618
 
 
1619
 
            // color second pixel of left line
1620
 
            if (grada != 0 && grada != 1) { // if not flat or exact diagonal
1621
 
                accessor.moveTo(int(xfa) + 1, y);
1622
 
                if (accessor.isSelected()) {
1623
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1624
 
                    opacity = b2a * c3.opacityF() + (1 - b2a) * alpha;
1625
 
                    col2.setOpacity(opacity);
1626
 
                    memcpy(accessor.rawData(), col2.data(), pixelSize);
1627
 
                }
1628
 
 
1629
 
            }
1630
 
 
1631
 
            // color second pixel of right line
1632
 
            if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
1633
 
                accessor.moveTo(int(xfb) + 1, y);
1634
 
                if (accessor.isSelected()) {
1635
 
                    qreal alpha = cs->opacityF(accessor.rawData());
1636
 
                    opacity = b2b * c3.opacityF() + (1 - b2b) * alpha;
1637
 
                    col2.setOpacity(opacity);
1638
 
                    memcpy(accessor.rawData(), col2.data(), pixelSize);
1639
 
                }
1640
 
            }
1641
 
 
1642
 
            // fill remaining pixels between current xfa,xfb
1643
 
            if (!(startWidth == 1 && endWidth == 1)) {
1644
 
                if (xfa < xfb)
1645
 
                    for (int i = (int) xfa + 1; i <= (int) xfb; i++) {
1646
 
                        accessor.moveTo(i, y);
1647
 
                        if (accessor.isSelected()) {
1648
 
                            memcpy(accessor.rawData(), c3.data(), pixelSize);
1649
 
                        }
1650
 
                    }
1651
 
                else
1652
 
                    for (int i = (int) xfb; i <= (int) xfa + 1; i++) {
1653
 
                        accessor.moveTo(i, y);
1654
 
                        if (accessor.isSelected()) {
1655
 
                            memcpy(accessor.rawData(), c3.data(), pixelSize);
1656
 
                        }
1657
 
                    }
1658
 
            }
1659
 
 
1660
 
            xfa += grada;
1661
 
            xfb += gradb;
1662
 
        }
1663
 
    }
1664
 
 
1665
 
}
1666
 
 
1667
 
 
1668
 
 
1669
 
void KisPainter::setProgress(KoUpdater * progressUpdater)
1670
 
{
1671
 
    d->progressUpdater = progressUpdater;
1672
 
}
1673
 
 
1674
 
const KisPaintDeviceSP KisPainter::device() const
1675
 
{
1676
 
    return d->device;
1677
 
}
1678
 
KisPaintDeviceSP KisPainter::device()
1679
 
{
1680
 
    return d->device;
1681
 
}
1682
 
 
1683
 
void KisPainter::setChannelFlags(QBitArray channelFlags)
1684
 
{
1685
 
    Q_ASSERT(d->channelFlags.isEmpty() || (uint)d->channelFlags.size() == d->colorSpace->channelCount());
1686
 
    d->channelFlags = channelFlags;
1687
 
    setLockAlpha(d->alphaLocked);
1688
 
}
1689
 
 
1690
 
QBitArray KisPainter::channelFlags()
1691
 
{
1692
 
    return d->channelFlags;
1693
 
}
1694
 
 
1695
 
void KisPainter::setPattern(const KisPattern * pattern)
1696
 
{
1697
 
    d->pattern = pattern;
1698
 
}
1699
 
 
1700
 
const KisPattern * KisPainter::pattern() const
1701
 
{
1702
 
    return d->pattern;
1703
 
}
1704
 
 
1705
 
void KisPainter::setPaintColor(const KoColor& color)
1706
 
{
1707
 
    d->paintColor = color;
1708
 
    if (d->device) {
1709
 
        d->paintColor.convertTo(d->device->colorSpace());
1710
 
    }
1711
 
}
1712
 
 
1713
 
const KoColor &KisPainter::paintColor() const
1714
 
{
1715
 
    return d->paintColor;
1716
 
}
1717
 
 
1718
 
void KisPainter::setBackgroundColor(const KoColor& color)
1719
 
{
1720
 
    d->backgroundColor = color;
1721
 
    if (d->device) {
1722
 
        d->backgroundColor.convertTo(d->device->colorSpace());
1723
 
    }
1724
 
}
1725
 
 
1726
 
const KoColor &KisPainter::backgroundColor() const
1727
 
{
1728
 
    return d->backgroundColor;
1729
 
}
1730
 
 
1731
 
void KisPainter::setFillColor(const KoColor& color)
1732
 
{
1733
 
    d->fillColor = color;
1734
 
}
1735
 
 
1736
 
const KoColor &KisPainter::fillColor() const
1737
 
{
1738
 
    return d->fillColor;
1739
 
}
1740
 
 
1741
 
void KisPainter::setGenerator(const KisFilterConfiguration * generator)
1742
 
{
1743
 
    d->generator = generator;
1744
 
}
1745
 
 
1746
 
const KisFilterConfiguration * KisPainter::generator() const
1747
 
{
1748
 
    return d->generator;
1749
 
}
1750
 
 
1751
 
void KisPainter::setFillStyle(FillStyle fillStyle)
1752
 
{
1753
 
    d->fillStyle = fillStyle;
1754
 
}
1755
 
 
1756
 
KisPainter::FillStyle KisPainter::fillStyle() const
1757
 
{
1758
 
    return d->fillStyle;
1759
 
}
1760
 
 
1761
 
void KisPainter::setAntiAliasPolygonFill(bool antiAliasPolygonFill)
1762
 
{
1763
 
    d->antiAliasPolygonFill = antiAliasPolygonFill;
1764
 
}
1765
 
 
1766
 
bool KisPainter::antiAliasPolygonFill()
1767
 
{
1768
 
    return d->antiAliasPolygonFill;
1769
 
}
1770
 
 
1771
 
void KisPainter::setStrokeStyle(KisPainter::StrokeStyle strokeStyle)
1772
 
{
1773
 
    d->strokeStyle = strokeStyle;
1774
 
}
1775
 
KisPainter::StrokeStyle KisPainter::strokeStyle() const
1776
 
{
1777
 
    return d->strokeStyle;
1778
 
}
1779
 
 
1780
 
void KisPainter::setOpacity(quint8 opacity)
1781
 
{
1782
 
    d->opacity = opacity;
1783
 
}
1784
 
 
1785
 
quint8 KisPainter::opacity() const
1786
 
{
1787
 
    return d->opacity;
1788
 
}
1789
 
 
1790
 
void KisPainter::setBounds(const QRect & bounds)
1791
 
{
1792
 
    d->bounds = bounds;
1793
 
}
1794
 
 
1795
 
QRect KisPainter::bounds()
1796
 
{
1797
 
    return d->bounds;
1798
 
}
1799
 
 
1800
 
void KisPainter::setCompositeOp(const KoCompositeOp * op)
1801
 
{
1802
 
    d->compositeOp = op;
1803
 
}
1804
 
 
1805
 
const KoCompositeOp * KisPainter::compositeOp()
1806
 
{
1807
 
    return d->compositeOp;
1808
 
}
1809
 
 
1810
 
void KisPainter::setCompositeOp(const QString& op)
1811
 
{
1812
 
    d->compositeOp = d->colorSpace->compositeOp(op);
1813
 
}
1814
 
 
1815
 
void KisPainter::setSelection(KisSelectionSP selection)
1816
 
{
1817
 
    d->selection = selection;
1818
 
}
1819
 
 
1820
 
KisSelectionSP KisPainter::selection()
1821
 
{
1822
 
    return d->selection;
1823
 
}
1824
 
 
1825
 
KoUpdater * KisPainter::progressUpdater()
1826
 
{
1827
 
    return d->progressUpdater;
1828
 
}
1829
 
 
1830
 
void KisPainter::setGradient(const KoAbstractGradient* gradient)
1831
 
{
1832
 
    d->gradient = gradient;
1833
 
}
1834
 
 
1835
 
const KoAbstractGradient* KisPainter::gradient()
1836
 
{
1837
 
    return d->gradient;
1838
 
}
1839
 
 
1840
 
void KisPainter::setPaintOpPreset(KisPaintOpPresetSP preset, KisImageWSP image)
1841
 
{
1842
 
    d->paintOpPreset = preset;
1843
 
    delete d->paintOp;
1844
 
    d->paintOp = KisPaintOpRegistry::instance()->paintOp(preset, this, image);
1845
 
}
1846
 
 
1847
 
KisPaintOpPresetSP KisPainter::preset() const
1848
 
{
1849
 
    return d->paintOpPreset;
1850
 
}
1851
 
 
1852
 
KisPaintOp* KisPainter::paintOp() const
1853
 
{
1854
 
    return d->paintOp;
1855
 
}
1856
 
 
1857
 
 
1858
 
void KisPainter::setMaskImageSize(qint32 width, qint32 height)
1859
 
{
1860
 
 
1861
 
    d->maskImageWidth = qBound(1, width, 256);
1862
 
    d->maskImageHeight = qBound(1, height, 256);
1863
 
    d->fillPainter = 0;
1864
 
    d->polygonMaskImage = QImage();
1865
 
}
1866
 
 
1867
 
void KisPainter::setLockAlpha(bool protect)
1868
 
{
1869
 
    d->alphaLocked = protect;
1870
 
    if (d->channelFlags.isEmpty()) {
1871
 
        d->channelFlags = d->colorSpace->channelFlags(true, !d->alphaLocked, true, true);
1872
 
    }
1873
 
    else {
1874
 
        Q_ASSERT((uint)d->channelFlags.size() == d->colorSpace->channelCount());
1875
 
        QList<KoChannelInfo*> channels = d->colorSpace->channels();
1876
 
        foreach (KoChannelInfo* channel, channels) {
1877
 
            if (channel->channelType() == KoChannelInfo::ALPHA) {
1878
 
                d->channelFlags.setBit(channel->index(), !d->alphaLocked);
1879
 
            }
1880
 
        }
1881
 
    }
1882
 
}
1883
 
 
1884
 
bool KisPainter::alphaLocked() const
1885
 
{
1886
 
    return d->alphaLocked;
1887
 
}
1888