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())
130 stroker->blend(stroker
->current_span, stroker->spans, &stroker->state->penData);
144 const QRect &cl = stroker->clip;
145 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
148 int offset = x + stroker
->ppl*y;
149 uint c = BYTE_MUL(stroker->color, coverage);
150 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
155 const QRect &cl = stroker->clip;
156 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
159 int offset = x + stroker
->ppl*y;
160 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
176 switch (strokeSelection) {
178 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, NoDasher>;
184 stroke = &QT_PREPEND_NAMESPACE(drawLine)<
drawPixel, Dasher>;
190 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, NoDasher>;
196 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<
drawPixel, Dasher>;
210 blend = state->penData.blend;
211 if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
212 clip &= state->clip->clipRect;
213 blend = state->penData.unclipped_blend;
216 int strokeSelection = 0;
217 if (blend == state->penData.unclipped_blend
218 && state->penData.type == QSpanData::Solid
219 && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
220 || state->penData.rasterBuffer->format == QImage::Format_RGB32)
221 && state->compositionMode() == QPainter::CompositionMode_SourceOver)
224 if (state->renderHints & QPainter::Antialiasing)
227 const QList<qreal> &penPattern = state->lastPen.dashPattern();
228 if (penPattern.isEmpty() || penPattern.size() > 1024) {
235 pattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
236 reversePattern =
static_cast<
int *>(malloc(penPattern.size() *
sizeof(
int)));
241 patternLength += qBound(1,
int(penPattern.at(i) * 64), 65536);
249 strokeSelection |=
Dashed;
255 qreal width = state->lastPen.widthF();
258 else if (state->lastPen.isCosmetic())
259 opacity =
static_cast<
int>(256 * width);
261 opacity =
static_cast<
int>(256 * width * state->txscale);
264 drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
267 color = multiplyAlpha256(state->penData.solidColor.rgba64(), opacity).toArgb32();
268 QRasterBuffer *buffer = state->penData.rasterBuffer;
269 pixels =
reinterpret_cast<uint *>(buffer->buffer());
270 ppl = buffer->stride<quint32>();
277 xmin = deviceRect.left() - 1;
278 xmax = deviceRect.right() + 2;
279 ymin = deviceRect.top() - 1;
280 ymax = deviceRect.bottom() + 2;
282 lastPixel.x = INT_MIN;
283 lastPixel.y = INT_MIN;
289 if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2))
296 y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
298 }
else if (x1 > xmax) {
301 y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
305 lastPixel.x = INT_MIN;
306 y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
308 }
else if (x2 > xmax) {
309 lastPixel.x = INT_MIN;
310 y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
317 x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
319 }
else if (y1 > ymax) {
322 x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
326 lastPixel.x = INT_MIN;
327 x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
329 }
else if (y2 > ymax) {
330 lastPixel.x = INT_MIN;
331 x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
338 lastPixel.x = INT_MIN;
345 QPointF start = p1 * state->matrix;
346 QPointF end = p2 * state->matrix;
353 patternOffset = state->lastPen.dashOffset()*64;
354 lastPixel.x = INT_MIN;
355 lastPixel.y = INT_MIN;
359 blend(current_span, spans, &state->penData);
365 const QPoint *end = points + num;
366 while (points < end) {
367 QPointF p = QPointF(*points) * state->matrix;
368 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
372 blend(current_span, spans, &state->penData);
378 const QPointF *end = points + num;
379 while (points < end) {
380 QPointF p = (*points) * state->matrix;
381 drawPixel(
this, std::floor(p.x()), std::floor(p.y()), 255);
385 blend(current_span, spans, &state->penData);
389void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
398 lastPixel.x = INT_MIN;
399 lastPixel.y = INT_MIN;
401 if (clipLine(rx1, ry1, rx2, ry2))
409 int dx = qAbs(x2 - x1);
410 int dy = qAbs(y2 - y1);
414 bool swapped =
false;
423 int y = (y1 + 32) >> 6;
424 int ys = (y2 + 32) >> 6;
426 int round = (xinc > 0) ? 32 : 0;
428 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
446 bool swapped =
false;
455 int x = (x1 + 32) >> 6;
456 int xs = (x2 + 32) >> 6;
458 int round = (yinc > 0) ? 32 : 0;
460 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
478 const qreal *points,
bool *closed)
480 const QPainterPath::ElementType *start = t;
485 if (*t == QPainterPath::MoveToElement)
490 int offset = t - start - 1;
492 *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
504 const qreal *points = path.points();
505 const QPainterPath::ElementType *type = path.elements();
508 const QPainterPath::ElementType *end = type + path.elementCount();
511 Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
513 QPointF p = QPointF(points[0], points[1]) * state->matrix;
514 patternOffset = state->lastPen.dashOffset()*64;
515 lastPixel.x = INT_MIN;
516 lastPixel.y = INT_MIN;
519 const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
521 const qreal *p = points + 2*(e-type);
522 QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
523 QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
524 calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
533 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
535 case QPainterPath::MoveToElement:
536 Q_ASSERT(!
"Logic error");
539 case QPainterPath::LineToElement:
540 if (!closed &&
drawCaps && type == e - 1)
548 case QPainterPath::CurveToElement: {
549 if (!closed &&
drawCaps && type == e - 3)
551 QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
552 QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
553 renderCubic(p, p2, p3, p4, caps);
559 case QPainterPath::CurveToDataElement:
560 Q_ASSERT(!
"QPainterPath::toSubpathPolygons(), bad element type");
567 QPointF p = QPointF(points[0], points[1]) * state->matrix;
569 patternOffset = state->lastPen.dashOffset()*64;
570 lastPixel.x = INT_MIN;
571 lastPixel.y = INT_MIN;
573 const qreal *begin = points;
574 const qreal *end = points + 2*path.elementCount();
576 bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
580 if (points[0] == end[-2] && points[1] == end[-1] && path.elementCount() > 2)
581 p2 = QPointF(end[-4], end[-3]) * state->matrix;
583 p2 = QPointF(end[-2], end[-1]) * state->matrix;
584 calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
587 bool fastPenAliased = (state->flags.fast_pen && !state->flags.antialiased);
589 while (points < end) {
590 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
592 if (!closed &&
drawCaps && points == end - 2)
595 bool moveNextStart =
stroke(this, p.x()
, p.y()
, p2.x()
, p2.y()
, caps
);
598
599
600
601
602
603
604
605 if (!fastPenAliased || moveNextStart || points == begin + 2 || points == end - 2)
610 if (path.hasImplicitClose())
615 blend(current_span, spans, &state->penData);
619void QCosmeticStroker::renderCubic(
const QPointF &p1,
const QPointF &p2,
const QPointF &p3,
const QPointF &p4,
int caps)
622 const int maxSubDivisions = 6;
623 PointF points[3*maxSubDivisions + 4];
625 points[3].x = p1.x();
626 points[3].y = p1.y();
627 points[2].x = p2.x();
628 points[2].y = p2.y();
629 points[1].x = p3.x();
630 points[1].y = p3.y();
631 points[0].x = p4.x();
632 points[0].y = p4.y();
635 int level = maxSubDivisions;
637 renderCubicSubdivision(p, level, caps);
642 const qreal half = .5;
645 points[6].x = points[3].x;
648 points[1].x = a = ( points[0].x + c ) * half;
649 points[5].x = b = ( points[3].x + d ) * half;
650 c = ( c + d ) * half;
651 points[2].x = a = ( a + c ) * half;
652 points[4].x = b = ( b + c ) * half;
653 points[3].x = ( a + b ) * half;
655 points[6].y = points[3].y;
658 points[1].y = a = ( points[0].y + c ) * half;
659 points[5].y = b = ( points[3].y + d ) * half;
660 c = ( c + d ) * half;
661 points[2].y = a = ( a + c ) * half;
662 points[4].y = b = ( b + c ) * half;
663 points[3].y = ( a + b ) * half;
669 qreal dx = points[3].x - points[0].x;
670 qreal dy = points[3].y - points[0].y;
671 qreal len =
static_cast<qreal>(.25) * (qAbs(dx) + qAbs(dy));
673 if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
674 qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
678 renderCubicSubdivision(points + 3, level, caps &
CapBegin);
679 renderCubicSubdivision(points, level, caps &
CapEnd);
684 stroke(this, points[3].x
, points[3].y
, points[0].x
, points[0].y
, caps
);
706
707
708
709template<
DrawPixel drawPixel,
class Dasher>
712 bool didDraw = qAbs(rx2 - rx1) + qAbs(ry2 - ry1) >= 1.0;
714 if (stroker->clipLine(rx1, ry1, rx2, ry2))
722 int dx = qAbs(x2 - x1);
723 int dy = qAbs(y2 - y1);
733 bool swapped =
false;
749 int y = (y1 + 32) >> 6;
750 int ys = (y2 + 32) >> 6;
751 int round = (xinc > 0) ? 32 : 0;
759 x += ((y * (1<<6)) + round - y1) * xinc >> 6;
765 last
.x = (x + (ys - y - 1)*xinc) >> 16;
770 bool axisAligned = qAbs(xinc) < (1 << 14);
771 if (stroker->lastPixel.x > INT_MIN) {
800 last
.x = (x + (ys - y - 1)*xinc) >> 16;
806 Dasher dasher(stroker, swapped, y * (1<<6), ys * (1<<6));
810 drawPixel(stroker, x >> 16, y, 255);
823 bool swapped =
false;
839 int x = (x1 + 32) >> 6;
840 int xs = (x2 + 32) >> 6;
841 int round = (yinc > 0) ? 32 : 0;
849 y += ((x * (1<<6)) + round - x1) * yinc >> 6;
856 last
.y = (y + (xs - x - 1)*yinc) >> 16;
860 bool axisAligned = qAbs(yinc) < (1 << 14);
861 if (stroker->lastPixel.x > INT_MIN) {
889 last
.y = (y + (xs - x - 1)*yinc) >> 16;
895 Dasher dasher(stroker, swapped, x * (1<<6), xs * (1<<6));
899 drawPixel(stroker, x, y >> 16, 255);
911template<
DrawPixel drawPixel,
class Dasher>
914 if (stroker->clipLine(rx1, ry1, rx2, ry2))
925 if (qAbs(dx) < qAbs(dy)) {
930 bool swapped =
false;
939 x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
943 Dasher dasher(stroker, swapped, y1, y2);
948 int alphaStart, alphaEnd;
950 alphaStart = y2 - y1;
951 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
954 alphaStart = 64 - (y1 & 63);
955 alphaEnd = (y2 & 63);
962 uint alpha =
static_cast<quint8>(x >> 8);
963 drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
964 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
972 uint alpha =
static_cast<quint8>(x >> 8);
973 drawPixel(stroker, x>>16, y, (255-alpha));
974 drawPixel(stroker, (x>>16) + 1, y, alpha);
981 if (alphaEnd && dasher.on()) {
982 uint alpha =
static_cast<quint8>(x >> 8);
983 drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
984 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
993 bool swapped =
false;
1002 y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
1006 Dasher dasher(stroker, swapped, x1, x2);
1013 int alphaStart, alphaEnd;
1015 alphaStart = x2 - x1;
1016 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
1019 alphaStart = 64 - (x1 & 63);
1020 alphaEnd = (x2 & 63);
1025 uint alpha =
static_cast<quint8>(y >> 8);
1026 drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
1027 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
1036 uint alpha =
static_cast<quint8>(y >> 8);
1037 drawPixel(stroker, x, y>>16, (255-alpha));
1038 drawPixel(stroker, x, (y>>16) + 1, alpha);
1045 if (alphaEnd && dasher.on()) {
1046 uint alpha =
static_cast<quint8>(y >> 8);
1047 drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
1048 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)