5#include "private/qpainterpath_p.h"
6#include "private/qrgba64_p.h"
12inline QString capString(
int caps)
15 if (caps & QCosmeticStroker::CapBegin) {
18 if (caps & QCosmeticStroker::CapEnd) {
25#if Q_PROCESSOR_WORDSIZE == 8
31#define toF26Dot6(x) static_cast<int>((x) * 64.
)
35 return color + BYTE_MUL(d, qAlpha(~color));
40#if Q_PROCESSOR_WORDSIZE == 8
41 return FDot16(x) * (1<<16) / y;
44 return static_cast<qlonglong>(x) * (1<<16) / y;
45 return x * (1<<16) / y;
63 int delta = stop - start;
78 while (dashIndex < stroker
->patternSize - 1 && offset>= pattern[dashIndex])
87 return (dashIndex + dashOn) & 1;
91 if (offset >= pattern[dashIndex]) {
102 bool on()
const {
return true; }
103 void adjust(
int = 0) {}
109
110
111
112
113template<
DrawPixel drawPixel,
class Dasher>
115template<
DrawPixel drawPixel,
class Dasher>
120 const QRect &cl = stroker->clip;
121 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
129 stroker->blend(stroker
->current_span, stroker->spans, &stroker->state->penData);
143 const QRect &cl = stroker->clip;
144 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
147 int offset = x + stroker
->ppl*y;
148 uint c = BYTE_MUL(stroker->color, coverage);
149 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
154 const QRect &cl = stroker->clip;
155 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
158 int offset = x + stroker
->ppl*y;
159 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
175 switch (strokeSelection) {
177 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, NoDasher>;
183 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, Dasher>;
189 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, NoDasher>;
195 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, Dasher>;
209 blend = state->penData.blend;
210 if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
211 clip &= state->clip->clipRect;
212 blend = state->penData.unclipped_blend;
215 int strokeSelection = 0;
216 if (blend == state->penData.unclipped_blend
217 && state->penData.type == QSpanData::Solid
218 && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
219 || state->penData.rasterBuffer->format == QImage::Format_RGB32)
220 && state->compositionMode() == QPainter::CompositionMode_SourceOver)
223 if (state->renderHints & QPainter::Antialiasing)
226 const QList<qreal> &penPattern = state->lastPen.dashPattern();
227 if (penPattern.isEmpty() || penPattern.size() > 1024) {
234 pattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
235 reversePattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
240 patternLength += qBound(1,
int(penPattern.at(i) * 64), 65536);
248 strokeSelection |=
Dashed;
254 qreal width = state->lastPen.widthF();
257 else if (state->lastPen.isCosmetic())
258 opacity =
static_cast<
int>(256 * width);
260 opacity =
static_cast<
int>(256 * width * state->txscale);
263 drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
266 color = multiplyAlpha256(state->penData.solidColor.rgba64(), opacity).toArgb32();
267 QRasterBuffer *buffer = state->penData.rasterBuffer;
268 pixels =
reinterpret_cast<uint *>(buffer->buffer());
269 ppl = buffer->stride<quint32>();
276 xmin = deviceRect.left() - 1;
277 xmax = deviceRect.right() + 2;
278 ymin = deviceRect.top() - 1;
279 ymax = deviceRect.bottom() + 2;
281 lastPixel.x = INT_MIN;
282 lastPixel.y = INT_MIN;
288 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
295 y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
297 }
else if (x1 > xmax) {
300 y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
304 lastPixel.x = INT_MIN;
305 y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
307 }
else if (x2 > xmax) {
308 lastPixel.x = INT_MIN;
309 y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
316 x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
318 }
else if (y1 > ymax) {
321 x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
325 lastPixel.x = INT_MIN;
326 x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
328 }
else if (y2 > ymax) {
329 lastPixel.x = INT_MIN;
330 x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
337 lastPixel.x = INT_MIN;
344 QPointF start = p1 * state->matrix;
345 QPointF end = p2 * state->matrix;
352 patternOffset = state->lastPen.dashOffset()*64;
353 lastPixel.x = INT_MIN;
354 lastPixel.y = INT_MIN;
358 blend(current_span, spans, &state->penData);
364 const QPoint *end = points + num;
365 while (points < end) {
366 QPointF p = QPointF(*points) * state->matrix;
367 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
371 blend(current_span, spans, &state->penData);
377 const QPointF *end = points + num;
378 while (points < end) {
379 QPointF p = (*points) * state->matrix;
380 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
384 blend(current_span, spans, &state->penData);
388void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
397 lastPixel.x = INT_MIN;
398 lastPixel.y = INT_MIN;
400 if (clipLine(rx1, ry1, rx2, ry2))
408 int dx = qAbs(x2 - x1);
409 int dy = qAbs(y2 - y1);
413 bool swapped =
false;
422 int y = (y1 + 32) >> 6;
423 int ys = (y2 + 32) >> 6;
425 int round = (xinc > 0) ? 32 : 0;
427 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
445 bool swapped =
false;
454 int x = (x1 + 32) >> 6;
455 int xs = (x2 + 32) >> 6;
457 int round = (yinc > 0) ? 32 : 0;
459 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
477 const qreal *points,
bool *closed)
479 const QPainterPath::ElementType *start = t;
484 if (*t == QPainterPath::MoveToElement)
489 int offset = t - start - 1;
491 *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
503 const qreal *points = path.points();
504 const QPainterPath::ElementType *type = path.elements();
507 const QPainterPath::ElementType *end = type + path.elementCount();
510 Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
512 QPointF p = QPointF(points[0], points[1]) * state->matrix;
513 patternOffset = state->lastPen.dashOffset()*64;
514 lastPixel.x = INT_MIN;
515 lastPixel.y = INT_MIN;
518 const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
520 const qreal *p = points + 2*(e-type);
521 QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
522 QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
523 calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
532 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
534 case QPainterPath::MoveToElement:
535 Q_ASSERT(!
"Logic error");
538 case QPainterPath::LineToElement:
539 if (!closed &&
drawCaps && type == e - 1)
547 case QPainterPath::CurveToElement: {
548 if (!closed &&
drawCaps && type == e - 3)
550 QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
551 QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
552 renderCubic(p, p2, p3, p4, caps);
558 case QPainterPath::CurveToDataElement:
559 Q_ASSERT(!
"QPainterPath::toSubpathPolygons(), bad element type");
566 QPointF p = QPointF(points[0], points[1]) * state->matrix;
568 patternOffset = state->lastPen.dashOffset()*64;
569 lastPixel.x = INT_MIN;
570 lastPixel.y = INT_MIN;
572 const qreal *begin = points;
573 const qreal *end = points + 2*path.elementCount();
575 bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
579 if (points[0] == end[-2] && points[1] == end[-1] && path.elementCount() > 2)
580 p2 = QPointF(end[-4], end[-3]) * state->matrix;
582 p2 = QPointF(end[-2], end[-1]) * state->matrix;
583 calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
586 bool fastPenAliased = (state->flags.fast_pen && !state->flags.antialiased);
588 while (points < end) {
589 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
591 if (!closed &&
drawCaps && points == end - 2)
594 bool moveNextStart =
stroke(this, p.x()
, p.y()
, p2.x()
, p2.y()
, caps
);
597
598
599
600
601
602
603
604 if (!fastPenAliased || moveNextStart || points == begin + 2 || points == end - 2)
609 if (path.hasImplicitClose())
614 blend(current_span, spans, &state->penData);
618void QCosmeticStroker::renderCubic(
const QPointF &p1,
const QPointF &p2,
const QPointF &p3,
const QPointF &p4,
int caps)
621 const int maxSubDivisions = 6;
622 PointF points[3*maxSubDivisions + 4];
624 points[3].x = p1.x();
625 points[3].y = p1.y();
626 points[2].x = p2.x();
627 points[2].y = p2.y();
628 points[1].x = p3.x();
629 points[1].y = p3.y();
630 points[0].x = p4.x();
631 points[0].y = p4.y();
634 int level = maxSubDivisions;
636 renderCubicSubdivision(p, level, caps);
641 const qreal half = .5;
644 points[6].x = points[3].x;
647 points[1].x = a = ( points[0].x + c ) * half;
648 points[5].x = b = ( points[3].x + d ) * half;
649 c = ( c + d ) * half;
650 points[2].x = a = ( a + c ) * half;
651 points[4].x = b = ( b + c ) * half;
652 points[3].x = ( a + b ) * half;
654 points[6].y = points[3].y;
657 points[1].y = a = ( points[0].y + c ) * half;
658 points[5].y = b = ( points[3].y + d ) * half;
659 c = ( c + d ) * half;
660 points[2].y = a = ( a + c ) * half;
661 points[4].y = b = ( b + c ) * half;
662 points[3].y = ( a + b ) * half;
668 qreal dx = points[3].x - points[0].x;
669 qreal dy = points[3].y - points[0].y;
670 qreal len =
static_cast<qreal>(.25) * (qAbs(dx) + qAbs(dy));
672 if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
673 qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
677 renderCubicSubdivision(points + 3, level, caps &
CapBegin);
678 renderCubicSubdivision(points, level, caps &
CapEnd);
683 stroke(this, points[3].x
, points[3].y
, points[0].x
, points[0].y
, caps
);
705
706
707
708template<
DrawPixel drawPixel,
class Dasher>
711 bool didDraw = qAbs(rx2 - rx1) + qAbs(ry2 - ry1) >= 1.0;
713 if (stroker->clipLine(rx1, ry1, rx2, ry2))
721 int dx = qAbs(x2 - x1);
722 int dy = qAbs(y2 - y1);
732 bool swapped =
false;
748 int y = (y1 + 32) >> 6;
749 int ys = (y2 + 32) >> 6;
750 int round = (xinc > 0) ? 32 : 0;
758 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
764 last
.x = (x + (ys - y - 1)*xinc) >> 16;
769 bool axisAligned = qAbs(xinc) < (1 << 14);
770 if (stroker->lastPixel.x > INT_MIN) {
799 last
.x = (x + (ys - y - 1)*xinc) >> 16;
805 Dasher dasher(stroker, swapped, y * (1<<6), ys * (1<<6));
809 drawPixel(stroker, x >> 16, y, 255);
822 bool swapped =
false;
838 int x = (x1 + 32) >> 6;
839 int xs = (x2 + 32) >> 6;
840 int round = (yinc > 0) ? 32 : 0;
848 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
855 last
.y = (y + (xs - x - 1)*yinc) >> 16;
859 bool axisAligned = qAbs(yinc) < (1 << 14);
860 if (stroker->lastPixel.x > INT_MIN) {
888 last
.y = (y + (xs - x - 1)*yinc) >> 16;
894 Dasher dasher(stroker, swapped, x * (1<<6), xs * (1<<6));
898 drawPixel(stroker, x, y >> 16, 255);
910template<
DrawPixel drawPixel,
class Dasher>
913 if (stroker->clipLine(rx1, ry1, rx2, ry2))
924 if (qAbs(dx) < qAbs(dy)) {
929 bool swapped =
false;
938 x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
942 Dasher dasher(stroker, swapped, y1, y2);
947 int alphaStart, alphaEnd;
949 alphaStart = y2 - y1;
950 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
953 alphaStart = 64 - (y1 & 63);
954 alphaEnd = (y2 & 63);
961 uint alpha =
static_cast<quint8>(x >> 8);
962 drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
963 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
971 uint alpha =
static_cast<quint8>(x >> 8);
972 drawPixel(stroker, x>>16, y, (255-alpha));
973 drawPixel(stroker, (x>>16) + 1, y, alpha);
980 if (alphaEnd && dasher.on()) {
981 uint alpha =
static_cast<quint8>(x >> 8);
982 drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
983 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
992 bool swapped =
false;
1001 y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
1005 Dasher dasher(stroker, swapped, x1, x2);
1012 int alphaStart, alphaEnd;
1014 alphaStart = x2 - x1;
1015 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
1018 alphaStart = 64 - (x1 & 63);
1019 alphaEnd = (x2 & 63);
1024 uint alpha =
static_cast<quint8>(y >> 8);
1025 drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
1026 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
1035 uint alpha =
static_cast<quint8>(y >> 8);
1036 drawPixel(stroker, x, y>>16, (255-alpha));
1037 drawPixel(stroker, x, (y>>16) + 1, alpha);
1044 if (alphaEnd && dasher.on()) {
1045 uint alpha =
static_cast<quint8>(y >> 8);
1046 drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
1047 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);
void drawPath(const QVectorPath &path)
bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
void drawPoints(const QPoint *points, int num)
void drawLine(const QPointF &p1, const QPointF &p2)
static const QPainterPath::ElementType * subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, const qreal *points, bool *closed)
static bool drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps)
static StrokeLine strokeLine(int strokeSelection)
QT_BEGIN_NAMESPACE typedef int FDot16
void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int)
static void capAdjust(int caps, int &x1, int &x2, FDot16 &y, FDot16 yinc)
static uint sourceOver(uint d, uint color)
void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
static int swapCaps(int caps)
void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage)
void(* DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage)
static bool drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps)
static FDot16 FDot16FixedDiv(int x, int y)
static void splitCubic(QCosmeticStroker::PointF *points)
bool(* StrokeLine)(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps)