30#include <klocalizedstring.h>
57#define BEZIER_FLATNESS_THRESHOLD 0.5
68 : d(new
Private(this, device->colorSpace()))
76 : d(new
Private(this, device->colorSpace()))
89 d->patternTransform = QTransform();
99 delete d->maskPainter;
100 delete d->fillPainter;
104template <
bool useOldData>
108 const QRect &srcRect)
110 const QRect dstRect(dstPt, srcRect.size());
112 const QRect srcExtent = src->extent();
113 const QRect dstExtent = dst->
extent();
115 const QRect srcSampleRect = srcExtent & srcRect;
116 const QRect dstSampleRect = dstExtent & dstRect;
118 const bool srcEmpty = srcSampleRect.isEmpty();
119 const bool dstEmpty = dstSampleRect.isEmpty();
121 if (!srcEmpty || !dstEmpty) {
125 QRect srcCopyRect = srcRect;
126 QRect dstCopyRect = dstRect;
128 if (!srcExtent.contains(srcRect)) {
130 const QRect dstSampleInSrcCoords = dstSampleRect.translated(srcRect.topLeft() - dstPt);
132 if (dstSampleInSrcCoords.isEmpty() || srcSampleRect.contains(dstSampleInSrcCoords)) {
133 srcCopyRect = srcSampleRect;
135 srcCopyRect = srcSampleRect | dstSampleInSrcCoords;
137 dstCopyRect = QRect(dstPt + srcCopyRect.topLeft() - srcRect.topLeft(), srcCopyRect.size());
147 gc.
bitBlt(dstCopyRect.topLeft(), src, srcCopyRect);
156 const QRect &srcRect)
158 copyAreaOptimizedImpl<false>(dstPt, src, dst, srcRect);
164 const QRect &srcRect)
166 copyAreaOptimizedImpl<true>(dstPt, src, dst, srcRect);
172 const QRect &originalSrcRect,
181 const QRect srcRect = originalSrcRect & selectionRect;
182 const QPoint dstOffset = srcRect.topLeft() - originalSrcRect.topLeft();
183 const QRect dstRect = QRect(dstPt + dstOffset, srcRect.size());
185 const bool srcEmpty = (src->extent() & srcRect).isEmpty();
186 const bool dstEmpty = (dst->
extent() & dstRect).isEmpty();
188 if (!srcEmpty || !dstEmpty) {
197 gc.
bitBlt(dstRect.topLeft(), src, srcRect);
205 const QRect processRect = src->extent();
208 if (processRect.isEmpty())
return dst;
215 quint8 *alpha8Ptr = dstIt.
rawData();
217 const quint8 white = srcCS->
intensity8(srcPtr);
218 const quint8 alpha = srcCS->
opacityU8(srcPtr);
229 const QRect processRect = src->extent();
232 if (processRect.isEmpty())
return dst;
239 quint8 *alpha8Ptr = dstIt.
rawData();
250 const QRect processRect = src->extent();
253 if (processRect.isEmpty())
return dst;
260 quint8 *alpha8Ptr = dstIt.
rawData();
273 if (deviceBounds.isEmpty() ||
274 (deviceBounds & imageBounds) != imageBounds) {
307 d->cachedCompositeOp =
nullptr;
313 Q_ASSERT_X(!
d->transaction,
"KisPainter::end()",
314 "end() was called for the painter having a transaction. "
315 "Please use end/deleteTransaction() instead");
320 Q_ASSERT_X(!
d->transaction,
"KisPainter::beginTransaction()",
321 "You asked for a new transaction while still having "
322 "another one. Please finish the first one with "
323 "end/deleteTransaction() first");
326 Q_CHECK_PTR(
d->transaction);
327 d->transaction->undoCommand()->setTimedID(timedID);
332 Q_ASSERT_X(
d->transaction,
"KisPainter::revertTransaction()",
333 "No transaction is in progress");
335 d->transaction->revert();
336 delete d->transaction;
342 Q_ASSERT_X(
d->transaction,
"KisPainter::endTransaction()",
343 "No transaction is in progress");
345 d->transaction->commit(undoAdapter);
346 delete d->transaction;
352 Q_ASSERT_X(
d->transaction,
"KisPainter::endTransaction()",
353 "No transaction is in progress");
355 d->transaction->commit(undoAdapter);
356 delete d->transaction;
362 Q_ASSERT_X(
d->transaction,
"KisPainter::endTransaction()",
363 "No transaction is in progress");
366 delete d->transaction;
369 return transactionData;
374 if (!
d->transaction)
return;
376 delete d->transaction;
382 Q_ASSERT_X(!
d->transaction,
"KisPainter::putTransaction()",
383 "You asked for a new transaction while still having "
384 "another one. Please finish the first one with "
385 "end/deleteTransaction() first");
392 Q_ASSERT_X(
d->transaction,
"KisPainter::takeTransaction()",
393 "No transaction is in progress");
404 d->dirtyRects.clear();
411 QRect r = rc.normalized();
413 d->dirtyRects.append(rc);
419 d->dirtyRects.reserve(
d->dirtyRects.size() + rects.size());
421 Q_FOREACH (
const QRect &rc, rects) {
422 const QRect r = rc.normalized();
424 d->dirtyRects.append(rc);
431 if (!cachedCompositeOp || !cachedSourceColorSpace || !(*cachedSourceColorSpace == *srcCS)) {
432 cachedCompositeOp = colorSpace->compositeOp(compositeOpId, srcCS);
433 cachedSourceColorSpace = srcCS;
436 return cachedCompositeOp;
439inline bool KisPainter::Private::tryReduceSourceRect(
const KisPaintDevice *srcDev,
448 bool needsReadjustParams =
false;
468 *srcRect &= srcDev->
extent();
470 if (srcRect->isEmpty())
return true;
471 needsReadjustParams =
true;
479 *srcRect &= selection->selectedRect().translated(*srcX - *dstX,
482 if (srcRect->isEmpty())
return true;
483 needsReadjustParams =
true;
486 if (!paramInfo.channelFlags.isEmpty()) {
491 if ((paramInfo.channelFlags & onlyColor) == paramInfo.channelFlags) {
492 *srcRect &= device->extent().translated(*srcX - *dstX,
495 if (srcRect->isEmpty())
return true;
496 needsReadjustParams =
true;
500 if (needsReadjustParams) {
502 *dstX += srcRect->x() - *srcX;
503 *dstY += srcRect->y() - *srcY;
504 srcRect->getRect(srcX, srcY, srcWidth, srcHeight);
513 qint32 selX, qint32 selY,
514 qint32 srcX, qint32 srcY,
515 qint32 srcWidth, qint32 srcHeight)
521 if (srcWidth == 0 || srcHeight == 0)
return;
522 if (srcDev.
isNull())
return;
523 if (
d->device.isNull())
return;
530 QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
533 const int xSelectionOffset = selX - srcX;
534 const int ySelectionOffset = selY - srcY;
540 if (
d->tryReduceSourceRect(srcDev, &srcRect,
542 &srcWidth, &srcHeight,
543 &dstX, &dstY))
return;
545 const QRect selRect = QRect(srcX + xSelectionOffset,
546 srcY + ySelectionOffset,
547 srcWidth, srcHeight);
557 quint8* dstBytes = 0;
559 dstBytes =
new quint8[srcWidth * srcHeight *
d->device->pixelSize()];
560 }
catch (
const std::bad_alloc&) {
561 warnKrita <<
"KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth <<
" * " << srcHeight <<
" * " <<
d->device->pixelSize() <<
"dst bytes";
565 d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
568 quint8* srcBytes = 0;
570 srcBytes =
new quint8[srcWidth * srcHeight * srcDev->
pixelSize()];
571 }
catch (
const std::bad_alloc&) {
572 warnKrita <<
"KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth <<
" * " << srcHeight <<
" * " <<
d->device->pixelSize() <<
"src bytes";
576 srcDev->
readBytes(srcBytes, srcX, srcY, srcWidth, srcHeight);
578 const QRect selBounds =
selection->bounds();
579 const quint8 *selRowStart =
selection->data() +
580 (selBounds.width() * (selRect.y() - selBounds.top()) + (selRect.x() - selBounds.left())) *
selection->pixelSize();
588 d->paramInfo.dstRowStart = dstBytes;
589 d->paramInfo.dstRowStride = srcWidth *
d->device->pixelSize();
590 d->paramInfo.srcRowStart = srcBytes;
591 d->paramInfo.srcRowStride = srcWidth * srcDev->
pixelSize();
592 d->paramInfo.maskRowStart = selRowStart;
593 d->paramInfo.maskRowStride = selBounds.width() *
selection->pixelSize();
594 d->paramInfo.rows = srcHeight;
595 d->paramInfo.cols = srcWidth;
601 quint32 totalBytes = srcWidth * srcHeight *
selection->pixelSize();
602 quint8* mergedSelectionBytes = 0;
604 mergedSelectionBytes =
new quint8[ totalBytes ];
605 }
catch (
const std::bad_alloc&) {
606 warnKrita <<
"KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth <<
" * " << srcHeight <<
" * " <<
d->device->pixelSize() <<
"total bytes";
610 d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight);
613 multiplyParamInfo.
opacity = 1.0f;
614 multiplyParamInfo.
flow = 1.0f;
617 multiplyParamInfo.
dstRowStart = mergedSelectionBytes;
623 multiplyParamInfo.
rows = srcHeight;
624 multiplyParamInfo.
cols = srcWidth;
628 d->paramInfo.dstRowStart = dstBytes;
629 d->paramInfo.dstRowStride = srcWidth *
d->device->pixelSize();
630 d->paramInfo.srcRowStart = srcBytes;
631 d->paramInfo.srcRowStride = srcWidth * srcDev->
pixelSize();
632 d->paramInfo.maskRowStart = mergedSelectionBytes;
633 d->paramInfo.maskRowStride = srcWidth *
selection->pixelSize();
634 d->paramInfo.rows = srcHeight;
635 d->paramInfo.cols = srcWidth;
637 delete[] mergedSelectionBytes;
640 d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
652 qint32 srcWidth, qint32 srcHeight)
657template <
bool useOldSrcData>
660 qint32 srcX, qint32 srcY,
661 qint32 srcWidth, qint32 srcHeight)
665 if (srcWidth == 0 || srcHeight == 0)
return;
666 if (srcDev.
isNull())
return;
667 if (
d->device.isNull())
return;
669 QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
672 if(!
d->selection &&
d->isOpacityUnit &&
673 srcX == dstX && srcY == dstY &&
674 d->device->fastBitBltPossible(srcDev) &&
679 d->device->fastBitBltOldData(srcDev, srcRect);
681 d->device->fastBitBlt(srcDev, srcRect);
693 if (
d->tryReduceSourceRect(srcDev, &srcRect,
695 &srcWidth, &srcHeight,
696 &dstX, &dstY))
return;
701 qint32 rowsRemaining = srcHeight;
716 while (rowsRemaining > 0) {
720 qint32 columnsRemaining = srcWidth;
725 qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
726 rows = qMin(rows, numContiguousSelRows);
727 rows = qMin(rows, rowsRemaining);
729 while (columnsRemaining > 0) {
735 qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
736 columns = qMin(columns, numContiguousSelColumns);
737 columns = qMin(columns, columnsRemaining);
739 qint32 srcRowStride = srcIt->
rowStride(srcX_, srcY_);
740 srcIt->
moveTo(srcX_, srcY_);
742 qint32 dstRowStride = dstIt->
rowStride(dstX_, dstY_);
743 dstIt->
moveTo(dstX_, dstY_);
745 qint32 maskRowStride = maskIt->
rowStride(dstX_, dstY_);
746 maskIt->
moveTo(dstX_, dstY_);
748 d->paramInfo.dstRowStart = dstIt->
rawData();
749 d->paramInfo.dstRowStride = dstRowStride;
752 d->paramInfo.srcRowStride = srcRowStride;
754 d->paramInfo.maskRowStride = maskRowStride;
755 d->paramInfo.rows = rows;
756 d->paramInfo.cols = columns;
761 columnsRemaining -= columns;
766 rowsRemaining -= rows;
771 while (rowsRemaining > 0) {
775 qint32 columnsRemaining = srcWidth;
779 qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows);
780 rows = qMin(rows, rowsRemaining);
782 while (columnsRemaining > 0) {
787 qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns);
788 columns = qMin(columns, columnsRemaining);
790 qint32 srcRowStride = srcIt->
rowStride(srcX_, srcY_);
791 srcIt->
moveTo(srcX_, srcY_);
793 qint32 dstRowStride = dstIt->
rowStride(dstX_, dstY_);
794 dstIt->
moveTo(dstX_, dstY_);
796 d->paramInfo.dstRowStart = dstIt->
rawData();
797 d->paramInfo.dstRowStride = dstRowStride;
800 d->paramInfo.srcRowStride = srcRowStride;
801 d->paramInfo.maskRowStart = 0;
802 d->paramInfo.maskRowStride = 0;
803 d->paramInfo.rows = rows;
804 d->paramInfo.cols = columns;
809 columnsRemaining -= columns;
814 rowsRemaining -= rows;
824 qint32 srcX, qint32 srcY,
825 qint32 srcWidth, qint32 srcHeight)
827 bitBltImpl<false>(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight);
833 bitBlt(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
838 qint32 srcX, qint32 srcY,
839 qint32 srcWidth, qint32 srcHeight)
841 bitBltImpl<true>(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight);
847 bitBltOldData(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
855 if(width == 0 || height == 0 ||
d->device.isNull())
858 KoColor srcColor(color,
d->device->compositionSourceColorSpace());
862 qint32 rowsRemaining = height;
870 while(rowsRemaining > 0) {
873 qint32 columnsRemaining = width;
876 qint32 rows = qMin(numContiguousDstRows, numContiguousSelRows);
877 rows = qMin(rows, rowsRemaining);
879 while (columnsRemaining > 0) {
884 qint32 columns = qMin(numContiguousDstColumns, numContiguousSelColumns);
885 columns = qMin(columns, columnsRemaining);
887 qint32 dstRowStride = dstIt->
rowStride(dstX, dstY);
888 dstIt->
moveTo(dstX, dstY);
889 qint32 maskRowStride = maskIt->
rowStride(dstX, dstY);
891 maskIt->
moveTo(dstX, dstY);
893 d->paramInfo.dstRowStart = dstIt->
rawData();
894 d->paramInfo.dstRowStride = dstRowStride;
895 d->paramInfo.srcRowStart = srcColor.
data();
896 d->paramInfo.srcRowStride = 0;
898 d->paramInfo.maskRowStride = maskRowStride;
899 d->paramInfo.rows = rows;
900 d->paramInfo.cols = columns;
904 columnsRemaining -= columns;
908 rowsRemaining -= rows;
913 while(rowsRemaining > 0) {
916 qint32 columnsRemaining = width;
918 qint32 rows = qMin(numContiguousDstRows, rowsRemaining);
920 while(columnsRemaining > 0) {
923 qint32 columns = qMin(numContiguousDstColumns, columnsRemaining);
924 qint32 dstRowStride = dstIt->
rowStride(dstX, dstY);
925 dstIt->
moveTo(dstX, dstY);
927 d->paramInfo.dstRowStart = dstIt->
rawData();
928 d->paramInfo.dstRowStride = dstRowStride;
929 d->paramInfo.srcRowStart = srcColor.
data();
930 d->paramInfo.srcRowStride = 0;
931 d->paramInfo.maskRowStart = 0;
932 d->paramInfo.maskRowStride = 0;
933 d->paramInfo.rows = rows;
934 d->paramInfo.cols = columns;
938 columnsRemaining -= columns;
942 rowsRemaining -= rows;
952 qint32 srcX, qint32 srcY,
953 qint32 srcWidth, qint32 srcHeight)
957 if (srcWidth == 0 || srcHeight == 0)
return;
958 if (srcDev.
isNull())
return;
959 if (
d->device.isNull())
return;
961 QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
962 QRect srcBounds = srcDev->
bounds();
973 quint8* dstBytes = 0;
975 dstBytes =
new quint8[srcWidth * srcHeight *
d->device->pixelSize()];
976 }
catch (
const std::bad_alloc&) {
977 warnKrita <<
"KisPainter::bltFixed std::bad_alloc for " << srcWidth <<
" * " << srcHeight <<
" * " <<
d->device->pixelSize() <<
"total bytes";
980 d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
982 const quint8 *srcRowStart = srcDev->
data() +
983 (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->
pixelSize();
985 d->paramInfo.dstRowStart = dstBytes;
986 d->paramInfo.dstRowStride = srcWidth *
d->device->pixelSize();
987 d->paramInfo.srcRowStart = srcRowStart;
988 d->paramInfo.srcRowStride = srcBounds.width() * srcDev->
pixelSize();
989 d->paramInfo.maskRowStart = 0;
990 d->paramInfo.maskRowStride = 0;
991 d->paramInfo.rows = srcHeight;
992 d->paramInfo.cols = srcWidth;
998 quint8* selBytes = 0;
1000 selBytes =
new quint8[srcWidth * srcHeight * selectionProjection->
pixelSize()];
1002 catch (
const std::bad_alloc&) {
1007 selectionProjection->
readBytes(selBytes, dstX, dstY, srcWidth, srcHeight);
1008 d->paramInfo.maskRowStart = selBytes;
1009 d->paramInfo.maskRowStride = srcWidth * selectionProjection->
pixelSize();
1014 d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
1016 delete[]
d->paramInfo.maskRowStart;
1024 bltFixed(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
1030 qint32 selX, qint32 selY,
1031 qint32 srcX, qint32 srcY,
1032 quint32 srcWidth, quint32 srcHeight)
1038 if (srcWidth == 0 || srcHeight == 0)
return;
1039 if (srcDev.
isNull())
return;
1040 if (
d->device.isNull())
return;
1047 QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight);
1048 QRect selRect = QRect(selX, selY, srcWidth, srcHeight);
1050 QRect srcBounds = srcDev->
bounds();
1062 quint8* dstBytes = 0;
1064 dstBytes =
new quint8[srcWidth * srcHeight *
d->device->pixelSize()];
1065 }
catch (
const std::bad_alloc&) {
1066 warnKrita <<
"KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << srcWidth <<
" * " << srcHeight <<
" * " <<
d->device->pixelSize() <<
"total bytes";
1069 d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
1071 const quint8 *srcRowStart = srcDev->
data() +
1072 (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->
pixelSize();
1073 const quint8 *selRowStart =
selection->data() +
1074 (selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) *
selection->pixelSize();
1076 if (!
d->selection) {
1079 d->paramInfo.dstRowStart = dstBytes;
1080 d->paramInfo.dstRowStride = srcWidth *
d->device->pixelSize();
1081 d->paramInfo.srcRowStart = srcRowStart;
1082 d->paramInfo.srcRowStride = srcBounds.width() * srcDev->
pixelSize();
1083 d->paramInfo.maskRowStart = selRowStart;
1084 d->paramInfo.maskRowStride = selBounds.width() *
selection->pixelSize();
1085 d->paramInfo.rows = srcHeight;
1086 d->paramInfo.cols = srcWidth;
1092 quint32 totalBytes = srcWidth * srcHeight *
selection->pixelSize();
1093 quint8 * mergedSelectionBytes = 0;
1095 mergedSelectionBytes =
new quint8[ totalBytes ];
1096 }
catch (
const std::bad_alloc&) {
1097 warnKrita <<
"KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << totalBytes <<
"total bytes";
1101 d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight);
1104 multiplyParamInfo.
opacity = 1.0f;
1105 multiplyParamInfo.
flow = 1.0f;
1108 multiplyParamInfo.
dstRowStart = mergedSelectionBytes;
1114 multiplyParamInfo.
rows = srcHeight;
1115 multiplyParamInfo.
cols = srcWidth;
1119 d->paramInfo.dstRowStart = dstBytes;
1120 d->paramInfo.dstRowStride = srcWidth *
d->device->pixelSize();
1121 d->paramInfo.srcRowStart = srcRowStart;
1122 d->paramInfo.srcRowStride = srcBounds.width() * srcDev->
pixelSize();
1123 d->paramInfo.maskRowStart = mergedSelectionBytes;
1124 d->paramInfo.maskRowStride = srcWidth *
selection->pixelSize();
1125 d->paramInfo.rows = srcHeight;
1126 d->paramInfo.cols = srcWidth;
1129 delete[] mergedSelectionBytes;
1132 d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight);
1142 quint32 srcWidth, quint32 srcHeight)
1155 if (
d->device &&
d->paintOp &&
d->paintOp->canPaint()) {
1156 d->paintOp->paintLine(pi1, pi2, currentDistance);
1162 int index,
int numPoints)
1170 if (index >= points.count())
1174 numPoints = points.count();
1176 if (index + numPoints > points.count())
1177 numPoints = points.count() - index;
1179 if (numPoints > 1) {
1183 auto point = [rnd, strokeRnd] (
const QPointF &pt) {
1192 for (
int i = index; i < index + numPoints - 1; i++) {
1193 paintLine(point(points[i]), point(points[i + 1]), &saveDist);
1206 qreal d1 = line.absDistance(control1);
1207 qreal d2 = line.absDistance(control2);
1227 const QPointF &control1,
1228 const QPointF &control2,
1229 const QPointF &pos2,
1236 const QPointF &control1,
1237 const QPointF &control2,
1241 if (
d->paintOp &&
d->paintOp->canPaint()) {
1242 d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, currentDistance);
1249 QRectF normalizedRect =
rect.normalized();
1253 points.push_back(normalizedRect.topLeft());
1254 points.push_back(normalizedRect.bottomLeft());
1255 points.push_back(normalizedRect.bottomRight());
1256 points.push_back(normalizedRect.topRight());
1271 QRectF r =
rect.normalized();
1272 if (r.isEmpty())
return;
1276 const qreal kappa = 0.5522847498;
1277 const qreal lx = (r.width() / 2) * kappa;
1278 const qreal ly = (r.height() / 2) * kappa;
1280 QPointF center = r.center();
1282 QPointF
p0(r.left(), center.y());
1283 QPointF
p1(r.left(), center.y() - ly);
1284 QPointF
p2(center.x() - lx, r.top());
1285 QPointF
p3(center.x(), r.top());
1291 QPointF p4(center.x() + lx, r.top());
1292 QPointF p5(r.right(), center.y() - ly);
1293 QPointF p6(r.right(), center.y());
1297 QPointF p7(r.right(), center.y() + ly);
1298 QPointF p8(center.x() + lx, r.bottom());
1299 QPointF p9(center.x(), r.bottom());
1303 QPointF p10(center.x() - lx, r.bottom());
1304 QPointF p11(r.left(), center.y() + ly);
1322 if (
d->paintOp &&
d->paintOp->canPaint()) {
1323 d->paintOp->paintAt(pi, savedDist);
1329 if (points.count() < 3) {
1337 QPainterPath polygonPath;
1339 polygonPath.moveTo(points.at(0));
1341 for (
int pointIndex = 1; pointIndex < points.count(); pointIndex++) {
1342 polygonPath.lineTo(points.at(pointIndex));
1345 polygonPath.closeSubpath();
1358 if (points.count() > 1) {
1365 auto point = [rnd, strokeRnd] (
const QPointF &pt) {
1372 for (
int i = 0; i < points.count() - 1; i++) {
1388 QPointF lastPoint, nextPoint;
1389 int elementCount = path.elementCount();
1395 auto point = [rnd, strokeRnd] (
const QPointF &pt) {
1402 for (
int i = 0; i < elementCount; i++) {
1403 QPainterPath::Element element = path.elementAt(i);
1404 switch (element.type) {
1405 case QPainterPath::MoveToElement:
1406 lastPoint = QPointF(element.x, element.y);
1408 case QPainterPath::LineToElement:
1409 nextPoint = QPointF(element.x, element.y);
1410 paintLine(point(lastPoint), point(nextPoint), &saveDist);
1411 lastPoint = nextPoint;
1413 case QPainterPath::CurveToElement:
1414 nextPoint = QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y);
1416 QPointF(path.elementAt(i).x, path.elementAt(i).y),
1417 QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y),
1418 point(nextPoint), &saveDist);
1419 lastPoint = nextPoint;
1434 if (
d->mirrorHorizontally ||
d->mirrorVertically) {
1436 QPointF effectiveAxesCenter = lod.
map(
d->axesCenter);
1438 QTransform C1 = QTransform::fromTranslate(-effectiveAxesCenter.x(), -effectiveAxesCenter.y());
1439 QTransform C2 = QTransform::fromTranslate(effectiveAxesCenter.x(), effectiveAxesCenter.y());
1442 QPainterPath newPath;
1445 if (
d->mirrorHorizontally) {
1446 t = C1 * QTransform::fromScale(-1,1) * C2;
1447 newPath = t.map(path);
1448 newRect = t.mapRect(requestedRect);
1449 d->fillPainterPathImpl(newPath, newRect);
1452 if (
d->mirrorVertically) {
1453 t = C1 * QTransform::fromScale(1,-1) * C2;
1454 newPath = t.map(path);
1455 newRect = t.mapRect(requestedRect);
1456 d->fillPainterPathImpl(newPath, newRect);
1459 if (
d->mirrorHorizontally &&
d->mirrorVertically) {
1460 t = C1 * QTransform::fromScale(-1,-1) * C2;
1461 newPath = t.map(path);
1462 newRect = t.mapRect(requestedRect);
1463 d->fillPainterPathImpl(newPath, newRect);
1467 d->fillPainterPathImpl(path, requestedRect);
1470void KisPainter::Private::fillPainterPathImpl(
const QPainterPath& path,
const QRect &requestedRect)
1472 if (fillStyle == FillStyleNone) {
1480 polygon = device->createCompositionSourceDevice();
1486 Q_CHECK_PTR(polygon);
1488 QRectF boundingRect = path.boundingRect();
1489 QRect fillRect = boundingRect.toAlignedRect();
1492 fillRect.adjust(-1, -1, 1, 1);
1494 if (requestedRect.isValid()) {
1495 fillRect &= requestedRect;
1498 switch (fillStyle) {
1509 fillPainter->fillRectNoCompose(fillRect, pattern, patternTransform);
1512 case FillStyleGenerator:
1514 fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), q->generator());
1519 if (polygonMaskImage.isNull() || (maskPainter == 0)) {
1520 polygonMaskImage = QImage(maskImageWidth, maskImageHeight, QImage::Format_ARGB32_Premultiplied);
1521 maskPainter =
new QPainter(&polygonMaskImage);
1522 maskPainter->setRenderHint(QPainter::Antialiasing, q->antiAliasPolygonFill());
1526 const QColor black(Qt::black);
1527 const QBrush brush(Qt::white);
1528 for (qint32 x = fillRect.x();
x < fillRect.x() + fillRect.width();
x += maskImageWidth) {
1529 for (qint32 y = fillRect.y();
y < fillRect.y() + fillRect.height();
y += maskImageHeight) {
1531 polygonMaskImage.fill(black.rgb());
1532 maskPainter->translate(-x, -y);
1533 maskPainter->fillPath(path, brush);
1534 maskPainter->translate(x, y);
1536 qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, maskImageWidth);
1537 qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, maskImageHeight);
1542 for (
int row = y; row <
y + rectHeight; row++) {
1543 QRgb* line =
reinterpret_cast<QRgb*
>(polygonMaskImage.scanLine(row - y));
1545 tmp = qRed(line[lineIt->x() - x]);
1546 polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &
tmp, 1);
1547 }
while (lineIt->nextPixel());
1554 QRect bltRect = !requestedRect.isEmpty() ? requestedRect : fillRect;
1555 q->bitBlt(bltRect.x(), bltRect.y(), polygon, bltRect.x(), bltRect.y(), bltRect.width(), bltRect.height());
1566 pen.setColor(Qt::white);
1568 if (!
d->fillPainter) {
1569 d->polygon =
d->device->createCompositionSourceDevice();
1572 d->polygon->clear();
1575 Q_CHECK_PTR(
d->polygon);
1577 QRectF boundingRect = path.boundingRect();
1578 QRect fillRect = boundingRect.toAlignedRect();
1581 int penWidth = qRound(pen.widthF());
1582 fillRect.adjust(-penWidth, -penWidth, penWidth, penWidth);
1585 fillRect.adjust(-1, -1, 1, 1);
1587 if (!requestedRect.isNull()) {
1588 fillRect &= requestedRect;
1593 if (
d->polygonMaskImage.isNull() || (
d->maskPainter == 0)) {
1594 d->polygonMaskImage = QImage(
d->maskImageWidth,
d->maskImageHeight, QImage::Format_ARGB32_Premultiplied);
1595 d->maskPainter =
new QPainter(&
d->polygonMaskImage);
1600 const QColor black(Qt::black);
1601 QPen oldPen =
d->maskPainter->pen();
1602 d->maskPainter->setPen(pen);
1604 for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x +=
d->maskImageWidth) {
1605 for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y +=
d->maskImageHeight) {
1607 d->polygonMaskImage.fill(black.rgb());
1608 d->maskPainter->translate(-x, -y);
1609 d->maskPainter->drawPath(path);
1610 d->maskPainter->translate(x, y);
1612 qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x,
d->maskImageWidth);
1613 qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y,
d->maskImageHeight);
1618 for (
int row = y; row < y + rectHeight; row++) {
1619 QRgb* line =
reinterpret_cast<QRgb*
>(
d->polygonMaskImage.scanLine(row - y));
1621 tmp = qRed(line[lineIt->x() - x]);
1622 d->polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &
tmp, 1);
1623 }
while (lineIt->nextPixel());
1630 d->maskPainter->setPen(oldPen);
1631 QRect r =
d->polygon->extent();
1633 bitBlt(r.x(), r.y(),
d->polygon, r.x(), r.y(), r.width(), r.height());
1638 d->paramInfo.dstRowStart = dst;
1639 d->paramInfo.dstRowStride = 0;
1640 d->paramInfo.srcRowStart = color.
data();
1641 d->paramInfo.srcRowStride = 0;
1642 d->paramInfo.maskRowStart = 0;
1643 d->paramInfo.maskRowStride = 0;
1644 d->paramInfo.rows = 1;
1645 d->paramInfo.cols = 1;
1649 d->conversionFlags);
1654 int x1 = qFloor(start.x());
1655 int y1 = qFloor(start.y());
1656 int x2 = qFloor(end.x());
1657 int y2 = qFloor(end.y());
1659 if ((x2 == x1 ) && (y2 == y1))
return;
1664 qreal uniC = dstX*y1 - dstY*x1;
1665 qreal projectionDenominator = 1.0 / (pow((
double)dstX, 2) + pow((
double)dstY, 2));
1668 if (qAbs(dstX) > qAbs(dstY)){
1669 subPixel = start.x() - x1;
1671 subPixel = start.y() - y1;
1674 qreal halfWidth = width * 0.5 + subPixel;
1675 int W_ = qRound(halfWidth) + 1;
1683 if (x2<x1) std::swap(x1,x2);
1684 if (y2<y1) std::swap(y1,y2);
1686 qreal denominator = sqrt(pow((
double)dstY,2) + pow((
double)dstX,2));
1687 if (denominator == 0.0) {
1690 denominator = 1.0/denominator;
1692 qreal projection,scanX,scanY,AA_;
1696 selectionAccessor =
d->selection->projection()->createRandomConstAccessorNG();
1699 for (
int y = y1-W_; y < y2+W_ ; y++){
1700 for (
int x = x1-W_; x < x2+W_; x++){
1702 projection = ( (x-X1_)* dstX + (y-Y1_)*dstY ) * projectionDenominator;
1703 scanX = X1_ + projection * dstX;
1704 scanY = Y1_ + projection * dstY;
1706 if (((scanX < x1) || (scanX > x2)) || ((scanY < y1) || (scanY > y2))) {
1707 AA_ = qMin( sqrt( pow((
double)x - X1_, 2) + pow((
double)y - Y1_, 2) ),
1708 sqrt( pow((
double)x - X2_, 2) + pow((
double)y - Y2_, 2) ));
1710 AA_ = qAbs(dstY*x - dstX*y + uniC) * denominator;
1713 if (AA_>halfWidth) {
1718 if (selectionAccessor) selectionAccessor->
moveTo(x,y);
1723 if (antialias && AA_ > halfWidth - 1.0) {
1742 int x = qFloor(start.x());
1743 int y = qFloor(start.y());
1745 int x2 = qFloor(end.x());
1746 int y2 = qFloor(end.y());
1752 bool lockAxis =
true;
1756 }
else if ( yd != 0) {
1758 m = (float)yd / (
float)xd;
1768 selectionAccessor =
d->selection->projection()->createRandomConstAccessorNG();
1773 if (selectionAccessor) selectionAccessor->
moveTo(x,y);
1779 if (fabs(m) > 1.0f) {
1780 inc = (yd > 0) ? 1 : -1;
1781 m = (lockAxis)? 0 : 1.0f / m;
1789 if (selectionAccessor) selectionAccessor->
moveTo(x, y);
1796 inc = (xd > 0) ? 1 : -1;
1804 if (selectionAccessor) selectionAccessor->
moveTo(x, y);
1817 int x1 = qFloor(start.x());
1818 int y1 = qFloor(start.y());
1819 int x2 = qFloor(end.x());
1820 int y2 = qFloor(end.y());
1825 selectionAccessor =
d->selection->projection()->createRandomConstAccessorNG();
1834 float fx = (x = x1);
1835 float fy = (y = y1);
1836 float m = (float)yd / (
float)xd;
1840 inc = (yd > 0) ? 1 : -1;
1848 float br1 = qFloor(fx + 1) - fx;
1849 float br2 = fx - qFloor(fx);
1852 if (selectionAccessor) selectionAccessor->
moveTo(x, y);
1859 accessor->
moveTo(x + 1, y);
1860 if (selectionAccessor) selectionAccessor->
moveTo(x + 1, y);
1868 inc = (xd > 0) ? 1 : -1;
1875 float br1 = qFloor(fy + 1) - fy;
1876 float br2 = fy - qFloor(fy);
1879 if (selectionAccessor) selectionAccessor->
moveTo(x, y);
1886 accessor->
moveTo(x, y + 1);
1887 if (selectionAccessor) selectionAccessor->
moveTo(x, y + 1);
1902 int x1 = qFloor(start.x());
1903 int y1 = qFloor(start.y());
1904 int x2 = qFloor(end.x());
1905 int y2 = qFloor(end.y());
1910 selectionAccessor =
d->selection->projection()->createRandomConstAccessorNG();
1914 float xgap, ygap, xend, yend, yf, xf;
1915 float brightness1, brightness2;
1917 int ix1, ix2, iy1, iy2;
1926 int incr = (x1 < x2) ? 1 : -1;
1930 while (ix1 != ix2) {
1933 accessor->
moveTo(ix1, iy1);
1934 if (selectionAccessor) selectionAccessor->
moveTo(ix1, iy1);
1945 int incr = (y1 < y2) ? 1 : -1;
1949 while (iy1 != iy2) {
1952 accessor->
moveTo(ix1, iy1);
1953 if (selectionAccessor) selectionAccessor->
moveTo(ix1, iy1);
1962 if (fabs(xd) > fabs(yd)) {
1974 yend = y1 + grad * (xend - x1);
1983 brightness2 =
frac(yend) * xgap;
1988 accessor->
moveTo(ix1, iy1);
1989 if (selectionAccessor) selectionAccessor->
moveTo(ix1, iy1);
1996 accessor->
moveTo(ix1, iy1 + 1);
1997 if (selectionAccessor) selectionAccessor->
moveTo(ix1, iy1 + 1);
2008 yend = y2 + grad * (xend - x2);
2016 brightness2 =
frac(yend) * xgap;
2021 accessor->
moveTo(ix2, iy2);
2022 if (selectionAccessor) selectionAccessor->
moveTo(ix2, iy2);
2029 accessor->
moveTo(ix2, iy2 + 1);
2030 if (selectionAccessor) selectionAccessor->
moveTo(ix2, iy2 + 1);
2038 for (
int x = ix1 + 1; x <= ix2 - 1; x++) {
2040 brightness2 =
frac(yf);
2044 accessor->
moveTo(x, qFloor(yf));
2045 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yf));
2052 accessor->
moveTo(x, qFloor(yf) + 1);
2053 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yf) + 1);
2076 xend = x1 + grad * (yend - y1);
2085 brightness2 =
frac(xend) * ygap;
2090 accessor->
moveTo(ix1, iy1);
2091 if (selectionAccessor) selectionAccessor->
moveTo(ix1, iy1);
2098 accessor->
moveTo(x1 + 1, y1);
2099 if (selectionAccessor) selectionAccessor->
moveTo(x1 + 1, y1);
2110 xend = x2 + grad * (yend - y2);
2118 brightness2 =
frac(xend) * ygap;
2123 accessor->
moveTo(ix2, iy2);
2124 if (selectionAccessor) selectionAccessor->
moveTo(ix2, iy2);
2131 accessor->
moveTo(ix2 + 1, iy2);
2132 if (selectionAccessor) selectionAccessor->
moveTo(ix2 + 1, iy2);
2140 for (
int y = iy1 + 1; y <= iy2 - 1; y++) {
2142 brightness2 =
frac(xf);
2146 accessor->
moveTo(qFloor(xf), y);
2147 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xf), y);
2154 accessor->
moveTo(qFloor(xf) + 1, y);
2155 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xf) + 1, y);
2174 selectionAccessor =
d->selection->projection()->createRandomConstAccessorNG();
2185 float grada, gradb, dxa, dxb, dya, dyb, fraca, fracb,
2186 xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dstX, dstY;
2187 int x, y, ix1, ix2, iy1, iy2;
2189 int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b;
2190 int tp0, tn0, tp1, tn1;
2193 float opacity = 1.0;
2195 tp0 = startWidth / 2;
2196 tn0 = startWidth / 2;
2197 if (startWidth % 2 == 0)
2202 if (endWidth % 2 == 0)
2205 int x0 = qRound(start.x());
2206 int y0 = qRound(start.y());
2207 int x1 = qRound(end.x());
2208 int y1 = qRound(end.y());
2213 if (dstY < 0) dstY = -dstY;
2214 if (dstX < 0) dstX = -dstX;
2218 x0a = x0; y0a = y0 - tn0;
2219 x0b = x0; y0b = y0 + tp0;
2220 x1a = x1; y1a = y1 - tn1;
2221 x1b = x1; y1b = y1 + tp1;
2223 x0a = x0 - tn0; y0a = y0;
2224 x0b = x0 + tp0; y0b = y0;
2225 x1a = x1 - tn1; y1a = y1;
2226 x1b = x1 + tp1; y1b = y1;
2230 for (
int i = y0a; i <= y0b; i++) {
2233 if (selectionAccessor) selectionAccessor->
moveTo(x0, i);
2239 for (
int i = y1a; i <= y1b; i++) {
2242 if (selectionAccessor) selectionAccessor->
moveTo(x1, i);
2250 for (
int i = x0a; i <= x0b; i++) {
2253 if (selectionAccessor) selectionAccessor->
moveTo(i, y0);
2259 for (
int i = x1a; i <= x1b; i++) {
2268 if (x1 != x0 && y1 != y0) {
2271 accessor->
moveTo(x0a, y0a - 1);
2272 if (selectionAccessor) selectionAccessor->
moveTo(x0a, y0a - 1);
2276 opacity = .25 * c1.
opacityF() + (1 - .25) * alpha;
2281 accessor->
moveTo(x1b, y1b + 1);
2282 if (selectionAccessor) selectionAccessor->
moveTo(x1b, y1b + 1);
2286 opacity = .25 * c2.
opacityF() + (1 - .25) * alpha;
2293 accessor->
moveTo(x0a - 1, y0a);
2294 if (selectionAccessor) selectionAccessor->
moveTo(x0a - 1, y0a);
2298 opacity = .25 * c1.
opacityF() + (1 - .25) * alpha;
2303 accessor->
moveTo(x1b + 1, y1b);
2304 if (selectionAccessor) selectionAccessor->
moveTo(x1b + 1, y1b);
2308 opacity = .25 * c2.
opacityF() + (1 - .25) * alpha;
2324 xt = x1a; x1a = x0a; x0a = xt;
2325 yt = y1a; y1a = y0a; y0a = yt;
2326 xt = x1b; x1b = x0b; x0b = xt;
2327 yt = y1b; y1b = y0b; y0b = yt;
2328 xt = x1; x1 = x0; x0 = xt;
2329 yt = y1; y1 = y0; y0 = yt;
2331 tmp = c1; c1 = c2; c2 =
tmp;
2332 wt = startWidth; startWidth = endWidth; endWidth = wt;
2344 for (x = ix1 + 1; x <= ix2 - 1; x++) {
2345 fraca = yfa - qFloor(yfa);
2349 fracb = yfb - qFloor(yfb);
2354 opacity = ((x - ix1) / dstX) * c2.
opacityF() + (1 - (x - ix1) / dstX) * c1.
opacityF();
2357 accessor->
moveTo(x, qFloor(yfa));
2358 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yfa));
2362 opacity = b1a * c3.
opacityF() + (1 - b1a) * alpha;
2368 if (!(startWidth == 1 && endWidth == 1)) {
2369 accessor->
moveTo(x, qFloor(yfb));
2370 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yfb));
2374 opacity = b1b * c3.
opacityF() + (1 - b1b) * alpha;
2381 if (grada != 0 && grada != 1) {
2383 accessor->
moveTo(x, qFloor(yfa) + 1);
2384 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yfa) + 1);
2388 opacity = b2a * c3.
opacityF() + (1 - b2a) * alpha;
2396 if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
2398 accessor->
moveTo(x, qFloor(yfb) + 1);
2399 if (selectionAccessor) selectionAccessor->
moveTo(x, qFloor(yfb) + 1);
2403 opacity = b2b * c3.
opacityF() + (1 - b2b) * alpha;
2411 if (!(startWidth == 1 && endWidth == 1)) {
2413 for (
int i = qFloor(yfa) + 1; i <= qFloor(yfb); i++) {
2416 if (selectionAccessor) selectionAccessor->
moveTo(x, i);
2423 for (
int i = qFloor(yfa) + 1; i >= qFloor(yfb); i--) {
2426 if (selectionAccessor) selectionAccessor->
moveTo(x, i);
2441 xt = x1a; x1a = x0a; x0a = xt;
2442 yt = y1a; y1a = y0a; y0a = yt;
2443 xt = x1b; x1b = x0b; x0b = xt;
2444 yt = y1b; y1b = y0b; y0b = yt;
2445 xt = x1; x1 = x0; x0 = xt;
2446 yt = y1; y1 = y0; y0 = yt;
2449 tmp = c1; c1 = c2; c2 =
tmp;
2450 wt = startWidth; startWidth = endWidth; endWidth = wt;
2462 for (y = iy1 + 1; y <= iy2 - 1; y++) {
2463 fraca = xfa - qFloor(xfa);
2467 fracb = xfb - qFloor(xfb);
2472 opacity = ((y - iy1) / dstY) * c2.
opacityF() + (1 - (y - iy1) / dstY) * c1.
opacityF();
2475 accessor->
moveTo(qFloor(xfa), y);
2476 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xfa), y);
2480 opacity = b1a * c3.
opacityF() + (1 - b1a) * alpha;
2486 if (!(startWidth == 1 && endWidth == 1)) {
2488 accessor->
moveTo(qFloor(xfb), y);
2489 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xfb), y);
2493 opacity = b1b * c3.
opacityF() + (1 - b1b) * alpha;
2500 if (grada != 0 && grada != 1) {
2502 accessor->
moveTo(qFloor(xfa) + 1, y);
2503 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xfa) + 1, y);
2507 opacity = b2a * c3.
opacityF() + (1 - b2a) * alpha;
2515 if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) {
2517 accessor->
moveTo(qFloor(xfb) + 1, y);
2518 if (selectionAccessor) selectionAccessor->
moveTo(qFloor(xfb) + 1, y);
2522 opacity = b2b * c3.
opacityF() + (1 - b2b) * alpha;
2529 if (!(startWidth == 1 && endWidth == 1)) {
2531 for (
int i = qFloor(xfa) + 1; i <= qFloor(xfb); i++) {
2534 if (selectionAccessor) selectionAccessor->
moveTo(i, y);
2541 for (
int i = qFloor(xfb); i <= qFloor(xfa) + 1; i++) {
2544 if (selectionAccessor) selectionAccessor->
moveTo(i, y);
2583 d->paramInfo.channelFlags = QBitArray();
2589 return d->paramInfo.channelFlags;
2604 d->paintColor = color;
2606 d->paintColor.convertTo(
d->device->compositionSourceColorSpace());
2612 return d->paintColor;
2617 d->backgroundColor = color;
2619 d->backgroundColor.convertTo(
d->device->compositionSourceColorSpace());
2625 return d->backgroundColor;
2635 return d->generator;
2645 return d->fillStyle;
2650 d->patternTransform = transform;
2655 return d->patternTransform;
2665 return d->antiAliasPolygonFill;
2674 return d->strokeStyle;
2679 d->paramInfo.flow =
flow;
2684 return d->paramInfo.flow;
2690 d->paramInfo.updateOpacityAndAverage(opacity);
2695 d->paramInfo.setOpacityAndAverage(
d->paramInfo.opacity, averageOpacity);
2700 const float exponent = 0.1;
2702 return averageOpacity < opacity ?
2704 exponent * opacity + (1.0 - exponent) * (averageOpacity);
2710 d->paramInfo.opacity = float(opacity) / 255.0f;
2716 d->paramInfo.opacity = opacity;
2721 return d->paramInfo.opacity;
2726 return d->isOpacityUnit;
2731 d->isOpacityUnit =
true;
2742 return d->compositeOpId;
2747 if (op !=
d->compositeOpId) {
2748 d->compositeOpId = op;
2749 d->cachedCompositeOp =
nullptr;
2760 return d->selection;
2765 return d->progressUpdater;
2785 d->paintOp = paintop;
2788 warnKrita <<
"Could not create paintop for preset " <<
preset->name();
2794 return d->paintOpPreset;
2811 d->axesCenter = other->
d->axesCenter;
2812 d->mirrorHorizontally = other->
d->mirrorHorizontally;
2813 d->mirrorVertically = other->
d->mirrorVertically;
2818 return d->mirrorHorizontally ||
d->mirrorVertically;
2823 return d->mirrorHorizontally;
2828 return d->mirrorVertically;
2834 d->maskImageWidth = qBound(1, width, 256);
2835 d->maskImageHeight = qBound(1, height, 256);
2837 d->polygonMaskImage = QImage();
2867 d->renderingIntent = intent;
2877 d->runnableStrokeJobsInterface = interface;
2882 if (!
d->runnableStrokeJobsInterface) {
2883 if (!
d->fakeRunnableStrokeJobsInterface) {
2886 return d->fakeRunnableStrokeJobsInterface.data();
2889 return d->runnableStrokeJobsInterface;
2894 if (!
d->mirrorHorizontally && !
d->mirrorVertically)
return;
2905 if (!
d->mirrorHorizontally && !
d->mirrorVertically)
return;
2916 if (!
d->mirrorHorizontally && !
d->mirrorVertically)
return;
2927 int x = rc.topLeft().x();
2928 int y = rc.topLeft().y();
2931 QPoint effectiveAxesCenter = t.
map(
d->axesCenter).toPoint();
2933 int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
2934 int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
2936 if (
d->mirrorHorizontally &&
d->mirrorVertically){
2937 dab->
mirror(
true,
false);
2938 bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height());
2940 bltFixed(mirrorX, mirrorY, dab, 0,0,rc.width(),rc.height());
2941 dab->
mirror(
true,
false);
2942 bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height());
2945 else if (
d->mirrorHorizontally){
2946 dab->
mirror(
true,
false);
2947 bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height());
2949 else if (
d->mirrorVertically){
2950 dab->
mirror(
false,
true);
2951 bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height());
2958 int x = rc.topLeft().x();
2959 int y = rc.topLeft().y();
2962 QPoint effectiveAxesCenter = t.
map(
d->axesCenter).toPoint();
2964 int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
2965 int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
2967 if (
d->mirrorHorizontally &&
d->mirrorVertically){
2968 dab->
mirror(
true,
false);
2969 mask->
mirror(
true,
false);
2973 mask->
mirror(
false,
true);
2976 dab->
mirror(
true,
false);
2977 mask->
mirror(
true,
false);
2980 }
else if (
d->mirrorHorizontally){
2981 dab->
mirror(
true,
false);
2982 mask->
mirror(
true,
false);
2985 }
else if (
d->mirrorVertically){
2986 dab->
mirror(
false,
true);
2987 mask->
mirror(
false,
true);
2995 if (
d->mirrorHorizontally ||
d->mirrorVertically){
2997 QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) );
2999 mirrorDab->lazyGrowBufferWithoutInitialization();
3009 if (
d->mirrorHorizontally ||
d->mirrorVertically){
3011 QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) );
3013 mirrorDab->lazyGrowBufferWithoutInitialization();
3023 int x = rc.topLeft().x();
3024 int y = rc.topLeft().y();
3027 QPoint effectiveAxesCenter = t.
map(
d->axesCenter).toPoint();
3029 int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x();
3030 int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y();
3034 if (
d->mirrorHorizontally &&
d->mirrorVertically){
3035 rects << QRect(mirrorX, y, rc.width(), rc.height());
3036 rects << QRect(mirrorX, mirrorY, rc.width(), rc.height());
3037 rects << QRect(x, mirrorY, rc.width(), rc.height());
3038 }
else if (
d->mirrorHorizontally) {
3039 rects << QRect(mirrorX, y, rc.width(), rc.height());
3040 }
else if (
d->mirrorVertically) {
3041 rects << QRect(x, mirrorY, rc.width(), rc.height());
3044 Q_FOREACH (
const QRect &rc, rects) {
3045 d->device->clear(rc);
3048 QRect resultRect = dab->
extent() | rc;
3049 bool intersects =
false;
3051 for (
int i = 1; i < rects.size(); i++) {
3052 if (rects[i].intersects(resultRect)) {
3066 Q_FOREACH (
const QRect &rc, rects) {
3067 bitBlt(rc.topLeft(), dab, rc);
3070 Q_FOREACH (
const QRect &rc, rects) {
3077 return !
d->dirtyRects.isEmpty();
3083 QPoint effectiveAxesCenter = t.
map(
d->axesCenter).toPoint();
3091 QPointF effectiveAxesCenter = t.
map(
d->axesCenter);
3098inline void mirrorOneObject(Qt::Orientation dir,
const QPointF ¢er, QRect *rc) {
3102inline void mirrorOneObject(Qt::Orientation dir,
const QPointF ¢er, QPointF *pt) {
3106inline void mirrorOneObject(Qt::Orientation dir,
const QPointF ¢er, QPair<QPointF, QPointF> *pair) {
3112template<
class T>
QVector<T> KisPainter::Private::calculateMirroredObjects(
const T &
object)
3117 const QPointF effectiveAxesCenter = t.map(this->axesCenter);
3119 T baseObject = object;
3120 result << baseObject;
3122 if (this->mirrorHorizontally && this->mirrorVertically){
3123 mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
3124 result << baseObject;
3125 mirrorOneObject(Qt::Vertical, effectiveAxesCenter, &baseObject);
3126 result << baseObject;
3127 mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
3128 result << baseObject;
3129 }
else if (this->mirrorHorizontally) {
3130 mirrorOneObject(Qt::Horizontal, effectiveAxesCenter, &baseObject);
3131 result << baseObject;
3132 }
else if (this->mirrorVertically) {
3133 mirrorOneObject(Qt::Vertical, effectiveAxesCenter, &baseObject);
3134 result << baseObject;
3142 return d->calculateMirroredObjects(rc);
3147 return d->calculateMirroredObjects(pos);
3152 return d->calculateMirroredObjects(pair);
const qreal OPACITY_OPAQUE_F
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
const QString COMPOSITE_MULT
const QString COMPOSITE_DESTINATION_ATOP
const QString COMPOSITE_DESTINATION_IN
qreal distance(const QPointF &p1, const QPointF &p2)
virtual quint8 * rawData()=0
virtual const quint8 * oldRawData() const =0
virtual bool wrapAroundMode() const =0
virtual QRect imageBorderRect() const
virtual QRect bounds() const =0
quint32 pixelSize() const
void mirror(bool horizontal, bool vertical)
const KoColorSpace * colorSpace() const
quint32 pixelSize() const
KisRandomConstAccessorSP createRandomConstAccessorNG() const
QRect exactBounds() const
const KoColorSpace * colorSpace() const
KoColor defaultPixel() const
KisDefaultBoundsBaseSP defaultBounds() const
void readBytes(quint8 *data, qint32 x, qint32 y, qint32 w, qint32 h) const
static KisPaintOpRegistry * instance()
KisPaintOp * paintOp(const KisPaintOpPresetSP preset, KisPainter *painter, KisNodeSP node, KisImageSP image) const
void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight)
KisTransaction * transaction
void init()
Initialize, set everything to '0' or defaults.
bool antiAliasPolygonFill
void drawWobblyLine(const QPointF &start, const QPointF &end)
void setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image)
void drawPainterPath(const QPainterPath &path, const QPen &pen, const QRect &requestedRect)
FillStyle
This enum contains the styles with which we can fill things like polygons and ellipses.
void setRenderingIntent(KoColorConversionTransformation::Intent intent)
void paintPainterPath(const QPainterPath &path)
const QVector< QRect > calculateAllMirroredRects(const QRect &rc)
void setPatternTransform(QTransform transform)
Set the transform on the pattern.
bool hasMirroring() const
void bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void putTransaction(KisTransaction *transaction)
continue a transaction started somewhere else
bool hasVerticalMirroring() const
void copyMirrorInformationFrom(const KisPainter *other)
void setStrokeStyle(StrokeStyle strokeStyle)
Set the current brush stroke style.
void addDirtyRects(const QVector< QRect > &rects)
qreal opacityF() const
Returns the opacity that is used in painting.
void paintPolygon(const vQPointF &points)
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
void revertTransaction()
Cancel all the changes made by the painter.
void setMaskImageSize(qint32 width, qint32 height)
void getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF &points) const
KUndo2Command * endAndTakeTransaction()
void setOpacityUpdateAverage(qreal opacity)
void setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags)
static KisPaintDeviceSP convertToAlphaAsAlpha(KisPaintDeviceSP src)
void compositeOnePixel(quint8 *dst, const KoColor &color)
void paintPolyline(const QVector< QPointF > &points, int index=0, int numPoints=-1)
void paintEllipse(const QRectF &rect)
void fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor &color)
static KisPaintDeviceSP convertToAlphaAsPureAlpha(KisPaintDeviceSP src)
float invertFrac(float value)
void bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void mirrorRect(Qt::Orientation direction, QRect *rc) const
KisFilterConfigurationSP generator
KisPaintOpPresetSP preset() const
Return the paintop preset.
void setSelection(KisSelectionSP selection)
void renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab)
KoUpdater * progressUpdater
void endTransaction(KisUndoAdapter *undoAdapter)
Finish the undoable paint operation.
void drawDDALine(const QPointF &start, const QPointF &end)
void paintAt(const KisPaintInformation &pos, KisDistanceInformation *savedDist)
KisTransaction * takeTransaction()
take transaction out of the reach of KisPainter
void mirrorDab(Qt::Orientation direction, KisRenderedDab *dab, bool skipMirrorPixels=false) const
KoColorConversionTransformation::ConversionFlags conversionFlags
void setMirrorInformation(const QPointF &axesCenter, bool mirrorHorizontally, bool mirrorVertically)
StrokeStyle
The style of the brush stroke around polygons and so.
void drawThickLine(const QPointF &start, const QPointF &end, int startWidth, int endWidth)
void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab)
void drawWuLine(const QPointF &start, const QPointF &end)
void setAverageOpacity(qreal averageOpacity)
void setBackgroundColor(const KoColor &color)
void beginTransaction(const KUndo2MagicString &transactionName=KUndo2MagicString(), int timedID=-1)
Begin an undoable paint operation.
QTransform patternTransform
void setOpacityF(qreal opacity)
void setGenerator(KisFilterConfigurationSP generator)
Set the current generator (a generator can be used to fill an area.
bool hasDirtyRegion() const
static qreal blendAverageOpacity(qreal opacity, qreal averageOpacity)
static KisPaintDeviceSP convertToAlphaAsGray(KisPaintDeviceSP src)
void setGradient(const KoAbstractGradientSP gradient)
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
const QVector< QPointF > calculateAllMirroredPoints(const QPointF &pos)
void setFillStyle(FillStyle fillStyle)
Set the current style with which to fill.
void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
void begin(KisPaintDeviceSP device)
const KoCompositeOp * compositeOp(const KoColorSpace *srcCS)
void setOpacityU8(quint8 opacity)
Set the opacity which is used in painting (like filling polygons)
static void copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
void fillPainterPath(const QPainterPath &path)
void setPattern(const KoPatternSP pattern)
Set the current pattern.
void setProgress(KoUpdater *progressUpdater)
KisPainter()
Construct painter without a device.
void fillPolygon(const vQPointF &points, FillStyle fillStyle)
Fill the polygon defined by points with the fillStyle.
void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab)
void paintRect(const QRectF &rect)
void drawLine(const QPointF &start, const QPointF &end)
KisRunnableStrokeJobsInterface * runnableStrokeJobsInterface
void addDirtyRect(const QRect &r)
static bool checkDeviceHasTransparency(KisPaintDeviceSP dev)
void setPaintColor(const KoColor &color)
void setAntiAliasPolygonFill(bool antiAliasPolygonFill)
Set whether a polygon's filled area should be anti-aliased or not. The default is true.
KoAbstractGradientSP gradient
void bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
bool hasHorizontalMirroring() const
void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setRunnableStrokeJobsInterface(KisRunnableStrokeJobsInterface *interface)
QVector< QRect > takeDirtyRegion()
void setChannelFlags(QBitArray channelFlags)
void setCompositeOpId(const KoCompositeOp *op)
void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance)
virtual qint32 rowStride(qint32 x, qint32 y) const =0
virtual qint32 numContiguousRows(qint32 y) const =0
virtual void moveTo(qint32 x, qint32 y)=0
virtual qint32 numContiguousColumns(qint32 x) const =0
ALWAYS_INLINE quint8 * rawData()
ALWAYS_INLINE const quint8 * rawDataConst() const
static _Tdst multiply(_T a, _Tdst b)
virtual quint8 intensity8(const quint8 *src) const =0
virtual void multiplyAlpha(quint8 *pixels, quint8 alpha, qint32 nPixels) const =0
virtual qreal opacityF(const quint8 *pixel) const =0
QBitArray channelFlags(bool color=true, bool alpha=false) const
virtual quint8 opacityU8(const quint8 *pixel) const =0
const KoCompositeOp * compositeOp(const QString &id, const KoColorSpace *srcSpace=nullptr) const
void setOpacity(quint8 alpha)
const KoColorSpace * colorSpace() const
return the current colorSpace
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
const quint8 SELECTION_THRESHOLD
static void getBezierCurvePoints(const KisVector2D &pos1, const KisVector2D &control1, const KisVector2D &control2, const KisVector2D &pos2, vQPointF &points)
#define BEZIER_FLATNESS_THRESHOLD
void copyAreaOptimizedImpl(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect)
Eigen::Hyperplane< qreal, 2 > LineEquation
KisVector2D toKisVector2D(const QPointF &p)
Eigen::Matrix< qreal, 2, 1 > KisVector2D
QPointF toQPointF(const ExpressionType &expr)
qreal directionBetweenPoints(const QPointF &p1, const QPointF &p2, qreal defaultAngle)
void mirrorDab(Qt::Orientation dir, const QPoint ¢er, KisRenderedDab *dab, bool skipMirrorPixels)
void mirrorPoint(Qt::Orientation dir, const QPoint ¢er, QPointF *pt)
void mirrorRect(Qt::Orientation dir, const QPoint ¢er, QRect *rc)
QRect selectedRect() const
static KoColorSpaceRegistry * instance()
const KoColorSpace * alpha8()
const quint8 * srcRowStart
const quint8 * maskRowStart
void composite(quint8 *dstRowStart, qint32 dstRowStride, const quint8 *srcRowStart, qint32 srcRowStride, const quint8 *maskRowStart, qint32 maskRowStride, qint32 rows, qint32 numColumns, float opacity, const QBitArray &channelFlags=QBitArray()) const