6#include "private/qpainterpath_p.h"
7#include "private/qrgba64_p.h"
13inline QString capString(
int caps)
16 if (caps & QCosmeticStroker::CapBegin) {
19 if (caps & QCosmeticStroker::CapEnd) {
26#if Q_PROCESSOR_WORDSIZE == 8
32#define toF26Dot6(x) static_cast<int>((x) * 64.
)
36 return color + BYTE_MUL(d, qAlpha(~color));
41#if Q_PROCESSOR_WORDSIZE == 8
42 return FDot16(x) * (1<<16) / y;
45 return static_cast<qlonglong>(x) * (1<<16) / y;
46 return x * (1<<16) / y;
64 int delta = stop - start;
79 while (dashIndex < stroker
->patternSize - 1 && offset>= pattern[dashIndex])
88 return (dashIndex + dashOn) & 1;
92 if (offset >= pattern[dashIndex]) {
103 bool on()
const {
return true; }
104 void adjust(
int = 0) {}
110
111
112
113
114template<
DrawPixel drawPixel,
class Dasher>
116template<
DrawPixel drawPixel,
class Dasher>
121 const QRect &cl = stroker->clip;
122 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
125 const int cov = coverage * stroker
->opacity >> 8;
129 const int lastx = last.x + last.len;
132 if (y == last.y && x == lastx && cov == last.coverage) {
138 stroker->blend(stroker
->current_span, stroker->spans, &stroker->state->penData);
152 const QRect &cl = stroker->clip;
153 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
156 int offset = x + stroker
->ppl*y;
157 uint c = BYTE_MUL(stroker->color, coverage * stroker
->opacity >> 8);
158 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
163 const QRect &cl = stroker->clip;
164 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
167 int offset = x + stroker
->ppl*y;
168 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
184 switch (strokeSelection) {
186 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, NoDasher>;
192 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, Dasher>;
198 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, NoDasher>;
204 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, Dasher>;
218 blend = state->penData.blend;
219 const QClipData *effectiveClip = state->penData.clip;
220 if (effectiveClip && effectiveClip->hasRectClip && !effectiveClip->clipRect.isEmpty()) {
221 clip &= effectiveClip->clipRect;
222 blend = state->penData.unclipped_blend;
225 int strokeSelection = 0;
226 if (blend == state->penData.unclipped_blend
227 && state->penData.type == QSpanData::Solid
228 && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
229 || state->penData.rasterBuffer->format == QImage::Format_RGB32)
230 && state->compositionMode() == QPainter::CompositionMode_SourceOver)
233 if (state->renderHints & QPainter::Antialiasing)
236 const QList<qreal> &penPattern = state->lastPen.dashPattern();
237 if (penPattern.isEmpty() || penPattern.size() > 1024) {
244 pattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
245 reversePattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
250 patternLength += qBound(1,
int(penPattern.at(i) * 64), 65536);
258 strokeSelection |=
Dashed;
264 qreal width = state->lastPen.widthF();
267 else if (state->lastPen.isCosmetic())
268 opacity =
static_cast<
int>(256 * width);
270 opacity =
static_cast<
int>(256 * width * state->txscale);
273 drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
277 const uint solid = state->penData.solidColor.rgba();
278 color = (strokeSelection & AntiAliased) ? solid : BYTE_MUL(solid, 255 * opacity >> 8);
279 QRasterBuffer *buffer = state->penData.rasterBuffer;
280 pixels =
reinterpret_cast<uint *>(buffer->buffer());
281 ppl = buffer->stride<quint32>();
288 xmin = deviceRect.left() - 1;
289 xmax = deviceRect.right() + 2;
290 ymin = deviceRect.top() - 1;
291 ymax = deviceRect.bottom() + 2;
293 lastPixel.x = INT_MIN;
294 lastPixel.y = INT_MIN;
300 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
307 y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
309 }
else if (x1 > xmax) {
312 y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
316 lastPixel.x = INT_MIN;
317 y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
319 }
else if (x2 > xmax) {
320 lastPixel.x = INT_MIN;
321 y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
328 x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
330 }
else if (y1 > ymax) {
333 x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
337 lastPixel.x = INT_MIN;
338 x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
340 }
else if (y2 > ymax) {
341 lastPixel.x = INT_MIN;
342 x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
349 lastPixel.x = INT_MIN;
356 QPointF start = p1 * state->matrix;
357 QPointF end = p2 * state->matrix;
364 patternOffset = state->lastPen.dashOffset()*64;
365 lastPixel.x = INT_MIN;
366 lastPixel.y = INT_MIN;
370 blend(current_span, spans, &state->penData);
376 const QPoint *end = points + num;
377 while (points < end) {
378 QPointF p = QPointF(*points) * state->matrix;
379 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
383 blend(current_span, spans, &state->penData);
389 const QPointF *end = points + num;
390 while (points < end) {
391 QPointF p = (*points) * state->matrix;
392 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
396 blend(current_span, spans, &state->penData);
400void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
409 lastPixel.x = INT_MIN;
410 lastPixel.y = INT_MIN;
412 if (clipLine(rx1, ry1, rx2, ry2))
420 int dx = qAbs(x2 - x1);
421 int dy = qAbs(y2 - y1);
425 bool swapped =
false;
434 int y = (y1 + 32) >> 6;
435 int ys = (y2 + 32) >> 6;
437 int round = (xinc > 0) ? 32 : 0;
439 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
457 bool swapped =
false;
466 int x = (x1 + 32) >> 6;
467 int xs = (x2 + 32) >> 6;
469 int round = (yinc > 0) ? 32 : 0;
471 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
489 const qreal *points,
bool *closed)
491 const QPainterPath::ElementType *start = t;
496 if (*t == QPainterPath::MoveToElement)
501 int offset = t - start - 1;
503 *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
515 const qreal *points = path.points();
516 const QPainterPath::ElementType *type = path.elements();
519 const QPainterPath::ElementType *end = type + path.elementCount();
522 Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
524 QPointF p = QPointF(points[0], points[1]) * state->matrix;
525 patternOffset = state->lastPen.dashOffset()*64;
526 lastPixel.x = INT_MIN;
527 lastPixel.y = INT_MIN;
530 const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
532 const qreal *p = points + 2*(e-type);
533 QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
534 QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
535 calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
544 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
546 case QPainterPath::MoveToElement:
547 Q_ASSERT(!
"Logic error");
550 case QPainterPath::LineToElement:
551 if (!closed &&
drawCaps && type == e - 1)
559 case QPainterPath::CurveToElement: {
560 if (!closed &&
drawCaps && type == e - 3)
562 QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
563 QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
564 renderCubic(p, p2, p3, p4, caps);
570 case QPainterPath::CurveToDataElement:
571 Q_ASSERT(!
"QPainterPath::toSubpathPolygons(), bad element type");
578 QPointF p = QPointF(points[0], points[1]) * state->matrix;
580 patternOffset = state->lastPen.dashOffset()*64;
581 lastPixel.x = INT_MIN;
582 lastPixel.y = INT_MIN;
584 const qreal *begin = points;
585 const qreal *end = points + 2*path.elementCount();
587 bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
591 if (points[0] == end[-2] && points[1] == end[-1] && path.elementCount() > 2)
592 p2 = QPointF(end[-4], end[-3]) * state->matrix;
594 p2 = QPointF(end[-2], end[-1]) * state->matrix;
595 calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
598 bool fastPenAliased = (state->flags.fast_pen && !state->flags.antialiased);
600 while (points < end) {
601 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
603 if (!closed &&
drawCaps && points == end - 2)
606 bool moveNextStart =
stroke(this, p.x()
, p.y()
, p2.x()
, p2.y()
, caps
);
609
610
611
612
613
614
615
616 if (!fastPenAliased || moveNextStart || points == begin + 2 || points == end - 2)
621 if (path.hasImplicitClose())
626 blend(current_span, spans, &state->penData);
630void QCosmeticStroker::renderCubic(
const QPointF &p1,
const QPointF &p2,
const QPointF &p3,
const QPointF &p4,
int caps)
633 const int maxSubDivisions = 6;
634 PointF points[3*maxSubDivisions + 4];
636 points[3].x = p1.x();
637 points[3].y = p1.y();
638 points[2].x = p2.x();
639 points[2].y = p2.y();
640 points[1].x = p3.x();
641 points[1].y = p3.y();
642 points[0].x = p4.x();
643 points[0].y = p4.y();
646 int level = maxSubDivisions;
648 renderCubicSubdivision(p, level, caps);
653 const qreal half = .5;
656 points[6].x = points[3].x;
659 points[1].x = a = ( points[0].x + c ) * half;
660 points[5].x = b = ( points[3].x + d ) * half;
661 c = ( c + d ) * half;
662 points[2].x = a = ( a + c ) * half;
663 points[4].x = b = ( b + c ) * half;
664 points[3].x = ( a + b ) * half;
666 points[6].y = points[3].y;
669 points[1].y = a = ( points[0].y + c ) * half;
670 points[5].y = b = ( points[3].y + d ) * half;
671 c = ( c + d ) * half;
672 points[2].y = a = ( a + c ) * half;
673 points[4].y = b = ( b + c ) * half;
674 points[3].y = ( a + b ) * half;
680 qreal dx = points[3].x - points[0].x;
681 qreal dy = points[3].y - points[0].y;
682 qreal len =
static_cast<qreal>(.25) * (qAbs(dx) + qAbs(dy));
684 if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
685 qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
689 renderCubicSubdivision(points + 3, level, caps &
CapBegin);
690 renderCubicSubdivision(points, level, caps &
CapEnd);
695 stroke(this, points[3].x
, points[3].y
, points[0].x
, points[0].y
, caps
);
717
718
719
720template<
DrawPixel drawPixel,
class Dasher>
723 bool didDraw = qAbs(rx2 - rx1) + qAbs(ry2 - ry1) >= 1.0;
725 if (stroker->clipLine(rx1, ry1, rx2, ry2))
733 int dx = qAbs(x2 - x1);
734 int dy = qAbs(y2 - y1);
744 bool swapped =
false;
760 int y = (y1 + 32) >> 6;
761 int ys = (y2 + 32) >> 6;
762 int round = (xinc > 0) ? 32 : 0;
770 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
776 last
.x = (x + (ys - y - 1)*xinc) >> 16;
781 bool axisAligned = qAbs(xinc) < (1 << 14);
782 if (stroker->lastPixel.x > INT_MIN) {
811 last
.x = (x + (ys - y - 1)*xinc) >> 16;
817 Dasher dasher(stroker, swapped, y * (1<<6), ys * (1<<6));
821 drawPixel(stroker, x >> 16, y, 255);
834 bool swapped =
false;
850 int x = (x1 + 32) >> 6;
851 int xs = (x2 + 32) >> 6;
852 int round = (yinc > 0) ? 32 : 0;
860 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
867 last
.y = (y + (xs - x - 1)*yinc) >> 16;
871 bool axisAligned = qAbs(yinc) < (1 << 14);
872 if (stroker->lastPixel.x > INT_MIN) {
900 last
.y = (y + (xs - x - 1)*yinc) >> 16;
906 Dasher dasher(stroker, swapped, x * (1<<6), xs * (1<<6));
910 drawPixel(stroker, x, y >> 16, 255);
922template<
DrawPixel drawPixel,
class Dasher>
925 if (stroker->clipLine(rx1, ry1, rx2, ry2))
936 if (qAbs(dx) < qAbs(dy)) {
941 bool swapped =
false;
950 x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
954 Dasher dasher(stroker, swapped, y1, y2);
959 int alphaStart, alphaEnd;
961 alphaStart = y2 - y1;
962 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
965 alphaStart = 64 - (y1 & 63);
966 alphaEnd = (y2 & 63);
973 uint alpha =
static_cast<quint8>(x >> 8);
974 drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
975 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
983 uint alpha =
static_cast<quint8>(x >> 8);
984 drawPixel(stroker, x>>16, y, (255-alpha));
985 drawPixel(stroker, (x>>16) + 1, y, alpha);
992 if (alphaEnd && dasher.on()) {
993 uint alpha =
static_cast<quint8>(x >> 8);
994 drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
995 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
1004 bool swapped =
false;
1013 y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
1017 Dasher dasher(stroker, swapped, x1, x2);
1024 int alphaStart, alphaEnd;
1026 alphaStart = x2 - x1;
1027 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
1030 alphaStart = 64 - (x1 & 63);
1031 alphaEnd = (x2 & 63);
1036 uint alpha =
static_cast<quint8>(y >> 8);
1037 drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
1038 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
1047 uint alpha =
static_cast<quint8>(y >> 8);
1048 drawPixel(stroker, x, y>>16, (255-alpha));
1049 drawPixel(stroker, x, (y>>16) + 1, alpha);
1056 if (alphaEnd && dasher.on()) {
1057 uint alpha =
static_cast<quint8>(y >> 8);
1058 drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
1059 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)
Combined button and popup list for selecting options.
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)