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