File indexing completed on 2024-05-12 15:58:35

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_painter.h"
0008 #include "kis_painter_p.h"
0009 
0010 #include "kis_paint_device.h"
0011 #include "kis_fixed_paint_device.h"
0012 #include "kis_random_accessor_ng.h"
0013 #include "KisRenderedDab.h"
0014 
0015 void KisPainter::Private::applyDevice(const QRect &applyRect,
0016                                       const KisRenderedDab &dab,
0017                                       KisRandomAccessorSP dstIt,
0018                                       const KoColorSpace *srcColorSpace,
0019                                       KoCompositeOp::ParameterInfo &localParamInfo)
0020 {
0021     const QRect dabRect = dab.realBounds();
0022     const QRect rc = applyRect & dabRect;
0023 
0024     const int srcPixelSize = srcColorSpace->pixelSize();
0025     const int dabRowStride = srcPixelSize * dabRect.width();
0026 
0027 
0028     qint32 dstY = rc.y();
0029     qint32 rowsRemaining = rc.height();
0030 
0031     while (rowsRemaining > 0) {
0032         qint32 dstX = rc.x();
0033 
0034         qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY);
0035         qint32 rows = qMin(rowsRemaining, numContiguousDstRows);
0036 
0037         qint32 columnsRemaining = rc.width();
0038 
0039         while (columnsRemaining > 0) {
0040 
0041             qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX);
0042             qint32 columns = qMin(numContiguousDstColumns, columnsRemaining);
0043 
0044             qint32 dstRowStride = dstIt->rowStride(dstX, dstY);
0045             dstIt->moveTo(dstX, dstY);
0046 
0047             localParamInfo.dstRowStart   = dstIt->rawData();
0048             localParamInfo.dstRowStride  = dstRowStride;
0049             localParamInfo.maskRowStart  = 0;
0050             localParamInfo.maskRowStride = 0;
0051             localParamInfo.rows          = rows;
0052             localParamInfo.cols          = columns;
0053 
0054 
0055             const int dabX = dstX - dabRect.x();
0056             const int dabY = dstY - dabRect.y();
0057 
0058             localParamInfo.srcRowStart   = dab.device->constData() + dabX * srcPixelSize + dabY * dabRowStride;
0059             localParamInfo.srcRowStride  = dabRowStride;
0060             localParamInfo.setOpacityAndAverage(dab.opacity, dab.averageOpacity);
0061             localParamInfo.flow = dab.flow;
0062             colorSpace->bitBlt(srcColorSpace, localParamInfo, compositeOp(srcColorSpace), renderingIntent, conversionFlags);
0063 
0064             dstX += columns;
0065             columnsRemaining -= columns;
0066         }
0067 
0068         dstY += rows;
0069         rowsRemaining -= rows;
0070     }
0071 
0072 }
0073 
0074 void KisPainter::Private::applyDeviceWithSelection(const QRect &applyRect,
0075                                                    const KisRenderedDab &dab,
0076                                                    KisRandomAccessorSP dstIt,
0077                                                    KisRandomConstAccessorSP maskIt,
0078                                                    const KoColorSpace *srcColorSpace,
0079                                                    KoCompositeOp::ParameterInfo &localParamInfo)
0080 {
0081     const QRect dabRect = dab.realBounds();
0082     const QRect rc = applyRect & dabRect;
0083 
0084     const int srcPixelSize = srcColorSpace->pixelSize();
0085     const int dabRowStride = srcPixelSize * dabRect.width();
0086 
0087 
0088     qint32 dstY = rc.y();
0089     qint32 rowsRemaining = rc.height();
0090 
0091     while (rowsRemaining > 0) {
0092         qint32 dstX = rc.x();
0093 
0094         qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY);
0095         qint32 numContiguousMaskRows = maskIt->numContiguousRows(dstY);
0096         qint32 rows = qMin(rowsRemaining, qMin(numContiguousDstRows, numContiguousMaskRows));
0097 
0098         qint32 columnsRemaining = rc.width();
0099 
0100         while (columnsRemaining > 0) {
0101 
0102             qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX);
0103             qint32 numContiguousMaskColumns = maskIt->numContiguousColumns(dstX);
0104             qint32 columns = qMin(columnsRemaining, qMin(numContiguousDstColumns, numContiguousMaskColumns));
0105 
0106             qint32 dstRowStride = dstIt->rowStride(dstX, dstY);
0107             qint32 maskRowStride = maskIt->rowStride(dstX, dstY);
0108             dstIt->moveTo(dstX, dstY);
0109             maskIt->moveTo(dstX, dstY);
0110 
0111             localParamInfo.dstRowStart   = dstIt->rawData();
0112             localParamInfo.dstRowStride  = dstRowStride;
0113             localParamInfo.maskRowStart  = maskIt->rawDataConst();
0114             localParamInfo.maskRowStride = maskRowStride;
0115             localParamInfo.rows          = rows;
0116             localParamInfo.cols          = columns;
0117 
0118 
0119             const int dabX = dstX - dabRect.x();
0120             const int dabY = dstY - dabRect.y();
0121 
0122             localParamInfo.srcRowStart   = dab.device->constData() + dabX * srcPixelSize + dabY * dabRowStride;
0123             localParamInfo.srcRowStride  = dabRowStride;
0124             localParamInfo.setOpacityAndAverage(dab.opacity, dab.averageOpacity);
0125             localParamInfo.flow = dab.flow;
0126             colorSpace->bitBlt(srcColorSpace, localParamInfo, compositeOp(srcColorSpace), renderingIntent, conversionFlags);
0127 
0128             dstX += columns;
0129             columnsRemaining -= columns;
0130         }
0131 
0132         dstY += rows;
0133         rowsRemaining -= rows;
0134     }
0135 
0136 }
0137 
0138 void KisPainter::bltFixed(const QRect &applyRect, const QList<KisRenderedDab> allSrcDevices)
0139 {
0140     const KoColorSpace *srcColorSpace = 0;
0141     QList<KisRenderedDab> devices;
0142     QRect rc = applyRect;
0143 
0144     if (d->selection) {
0145         rc &= d->selection->selectedRect();
0146     }
0147 
0148     QRect totalDevicesRect;
0149 
0150     Q_FOREACH (const KisRenderedDab &dab, allSrcDevices) {
0151         if (rc.intersects(dab.realBounds())) {
0152             devices.append(dab);
0153             totalDevicesRect |= dab.realBounds();
0154         }
0155 
0156         if (!srcColorSpace) {
0157             srcColorSpace = dab.device->colorSpace();
0158         } else {
0159             KIS_SAFE_ASSERT_RECOVER_RETURN(*srcColorSpace == *dab.device->colorSpace());
0160         }
0161     }
0162 
0163     rc &= totalDevicesRect;
0164 
0165     if (devices.isEmpty() || rc.isEmpty()) return;
0166 
0167     KoCompositeOp::ParameterInfo localParamInfo = d->paramInfo;
0168     KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG();
0169     KisRandomConstAccessorSP maskIt = d->selection ? d->selection->projection()->createRandomConstAccessorNG() : 0;
0170 
0171     if (maskIt) {
0172         Q_FOREACH (const KisRenderedDab &dab, devices) {
0173             d->applyDeviceWithSelection(rc, dab, dstIt, maskIt, srcColorSpace, localParamInfo);
0174         }
0175     } else {
0176         Q_FOREACH (const KisRenderedDab &dab, devices) {
0177             d->applyDevice(rc, dab, dstIt, srcColorSpace, localParamInfo);
0178         }
0179     }
0180 
0181 
0182 #if 0
0183     // the code above does basically the same thing as this one,
0184     // but more efficiently :)
0185 
0186     Q_FOREACH (KisFixedPaintDeviceSP dev, devices) {
0187         const QRect copyRect = dev->bounds() & rc;
0188         if (copyRect.isEmpty()) continue;
0189 
0190         bltFixed(copyRect.topLeft(), dev, copyRect);
0191     }
0192 #endif
0193 }
0194