1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qcosmeticstroker_p.h"
43 #include "private/qpainterpath_p.h"
50 inline QString capString(int caps)
53 if (caps & QCosmeticStroker::CapBegin) {
56 if (caps & QCosmeticStroker::CapEnd) {
63 #define toF26Dot6(x) ((int)((x)*64.))
65 static inline uint sourceOver(uint d, uint color)
67 return color + BYTE_MUL(d, qAlpha(~color));
70 inline static int F16Dot16FixedDiv(int x, int y)
73 return (((qlonglong)x) << 16) / y;
77 typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
82 QCosmeticStroker *stroker;
88 Dasher(QCosmeticStroker *s, bool reverse, int start, int stop)
91 int delta = stop - start;
93 pattern = stroker->reversePattern;
94 offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32);
97 pattern = stroker->pattern;
98 offset = stroker->patternOffset - ((start & 63) - 32);
101 offset %= stroker->patternLength;
103 offset += stroker->patternLength;
106 while (offset>= pattern[dashIndex])
109 // qDebug() << " dasher" << offset/64. << reverse << dashIndex;
110 stroker->patternOffset += delta;
111 stroker->patternOffset %= stroker->patternLength;
115 return (dashIndex + dashOn) & 1;
119 if (offset >= pattern[dashIndex]) {
121 dashIndex %= stroker->patternSize;
123 offset %= stroker->patternLength;
124 // qDebug() << "dasher.adjust" << offset/64. << dashIndex;
129 NoDasher(QCosmeticStroker *, bool, int, int) {}
130 bool on() const { return true; }
131 void adjust(int = 0) {}
136 template<DrawPixel drawPixel, class Dasher>
137 static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
138 template<DrawPixel drawPixel, class Dasher>
139 static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
141 inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
143 const QRect &cl = stroker->clip;
144 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
147 int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ;
148 int lasty = stroker->spans[stroker->current_span-1].y;
150 if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) {
151 stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData);
152 stroker->current_span = 0;
155 stroker->spans[stroker->current_span].x = ushort(x);
156 stroker->spans[stroker->current_span].len = 1;
157 stroker->spans[stroker->current_span].y = y;
158 stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
159 ++stroker->current_span;
162 inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage)
164 const QRect &cl = stroker->clip;
165 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
168 int offset = x + stroker->ppl*y;
169 uint c = BYTE_MUL(stroker->color, coverage);
170 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
173 inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int)
175 const QRect &cl = stroker->clip;
176 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
179 int offset = x + stroker->ppl*y;
180 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
183 enum StrokeSelection {
192 static StrokeLine strokeLine(int strokeSelection)
196 switch (strokeSelection) {
197 case Aliased|Solid|RegularDraw:
198 stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, NoDasher>;
200 case Aliased|Solid|FastDraw:
201 stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, NoDasher>;
203 case Aliased|Dashed|RegularDraw:
204 stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, Dasher>;
206 case Aliased|Dashed|FastDraw:
207 stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, Dasher>;
209 case AntiAliased|Solid|RegularDraw:
210 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, NoDasher>;
212 case AntiAliased|Solid|FastDraw:
213 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, NoDasher>;
215 case AntiAliased|Dashed|RegularDraw:
216 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, Dasher>;
218 case AntiAliased|Dashed|FastDraw:
219 stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, Dasher>;
228 void QCosmeticStroker::setup()
230 blend = state->penData.blend;
231 if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
232 clip &= state->clip->clipRect;
233 blend = state->penData.unclipped_blend;
236 int strokeSelection = 0;
237 if (blend == state->penData.unclipped_blend
238 && state->penData.type == QSpanData::Solid
239 && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
240 || state->penData.rasterBuffer->format == QImage::Format_RGB32)
241 && state->compositionMode() == QPainter::CompositionMode_SourceOver)
242 strokeSelection |= FastDraw;
244 if (state->renderHints & QPainter::Antialiasing)
245 strokeSelection |= AntiAliased;
247 const QVector<qreal> &penPattern = state->lastPen.dashPattern();
248 if (penPattern.isEmpty()) {
249 Q_ASSERT(!pattern && !reversePattern);
255 pattern = (int *)malloc(penPattern.size()*sizeof(int));
256 reversePattern = (int *)malloc(penPattern.size()*sizeof(int));
257 patternSize = penPattern.size();
260 for (int i = 0; i < patternSize; ++i) {
261 patternLength += (int) qMax(1. , penPattern.at(i)*64.);
262 pattern[i] = patternLength;
265 for (int i = 0; i < patternSize; ++i) {
266 patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
267 reversePattern[i] = patternLength;
269 strokeSelection |= Dashed;
270 // qDebug() << "setup: size=" << patternSize << "length=" << patternLength/64.;
273 stroke = strokeLine(strokeSelection);
275 qreal width = state->lastPen.widthF();
278 else if (state->lastPen.isCosmetic())
279 opacity = (int) 256*width;
281 opacity = (int) 256*width*state->txscale;
282 opacity = qBound(0, opacity, 256);
284 drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
286 if (strokeSelection & FastDraw) {
287 color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0);
288 QRasterBuffer *buffer = state->penData.rasterBuffer;
289 pixels = (uint *)buffer->buffer();
290 ppl = buffer->bytesPerLine()>>2;
293 // setup FP clip bounds
294 xmin = clip.left() - 1;
295 xmax = clip.right() + 2;
296 ymin = clip.top() - 1;
297 ymax = clip.bottom() + 2;
302 // returns true if the whole line gets clipped away
303 bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
305 // basic/rough clipping is done in floating point coordinates to avoid
306 // integer overflow problems.
310 y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
312 } else if (x1 > xmax) {
315 y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
320 y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
322 } else if (x2 > xmax) {
324 y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
331 x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
333 } else if (y1 > ymax) {
336 x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
341 x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
343 } else if (y2 > ymax) {
345 x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
357 void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
359 QPointF start = p1 * state->matrix;
360 QPointF end = p2 * state->matrix;
362 patternOffset = state->lastPen.dashOffset()*64;
365 stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
367 blend(current_span, spans, &state->penData);
371 void QCosmeticStroker::drawPoints(const QPoint *points, int num)
373 const QPoint *end = points + num;
374 while (points < end) {
375 QPointF p = QPointF(*points) * state->matrix;
376 drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
380 blend(current_span, spans, &state->penData);
384 void QCosmeticStroker::drawPoints(const QPointF *points, int num)
386 const QPointF *end = points + num;
387 while (points < end) {
388 QPointF p = (*points) * state->matrix;
389 drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
393 blend(current_span, spans, &state->penData);
397 void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
399 // this is basically the same code as used in the aliased stroke method,
400 // but it only determines the direction and last point of a line
402 // This is being used to have proper dropout control for closed contours
403 // by calculating the direction and last pixel of the last segment in the contour.
404 // the info is then used to perform dropout control when drawing the first line segment
409 if (clipLine(rx1, ry1, rx2, ry2))
413 int x1 = toF26Dot6(rx1) + half;
414 int y1 = toF26Dot6(ry1) + half;
415 int x2 = toF26Dot6(rx2) + half;
416 int y2 = toF26Dot6(ry2) + half;
418 int dx = qAbs(x2 - x1);
419 int dy = qAbs(y2 - y1);
423 bool swapped = false;
429 int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
436 x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
439 lastPixel.x = x >> 16;
441 lastDir = QCosmeticStroker::BottomToTop;
443 lastPixel.x = (x + (ys - y - 1)*xinc) >> 16;
444 lastPixel.y = ys - 1;
445 lastDir = QCosmeticStroker::TopToBottom;
447 lastAxisAligned = qAbs(xinc) < (1 << 14);
454 bool swapped = false;
460 int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
467 y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
471 lastPixel.y = y >> 16;
472 lastDir = QCosmeticStroker::RightToLeft;
474 lastPixel.x = xs - 1;
475 lastPixel.y = (y + (xs - x - 1)*yinc) >> 16;
476 lastDir = QCosmeticStroker::LeftToRight;
478 lastAxisAligned = qAbs(yinc) < (1 << 14);
481 // qDebug() << " moveTo: setting last pixel to x/y dir" << lastPixel.x << lastPixel.y << lastDir;
484 static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end,
485 const qreal *points, bool *closed)
487 const QPainterPath::ElementType *start = t;
490 // find out if the subpath is closed
492 if (*t == QPainterPath::MoveToElement)
497 int offset = t - start - 1;
498 // qDebug() << "subpath" << offset << points[0] << points[1] << points[2*offset] << points[2*offset+1];
499 *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
504 void QCosmeticStroker::drawPath(const QVectorPath &path)
506 // qDebug() << ">>>> drawpath" << path.convertToPainterPath()
507 // << "antialiasing:" << (bool)(state->renderHints & QPainter::Antialiasing) << " implicit close:" << path.hasImplicitClose();
511 const qreal *points = path.points();
512 const QPainterPath::ElementType *type = path.elements();
515 const QPainterPath::ElementType *end = type + path.elementCount();
518 Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
520 QPointF p = QPointF(points[0], points[1]) * state->matrix;
522 patternOffset = state->lastPen.dashOffset()*64;
526 const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
528 const qreal *p = points + 2*(e-type);
529 QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
530 QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
531 calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
533 int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
534 // qDebug() << "closed =" << closed << capString(caps);
540 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
542 case QPainterPath::MoveToElement:
543 Q_ASSERT(!"Logic error");
546 case QPainterPath::LineToElement:
547 if (!closed && drawCaps && type == e - 1)
549 stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
555 case QPainterPath::CurveToElement: {
556 if (!closed && drawCaps && type == e - 3)
558 QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
559 QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
560 renderCubic(p, p2, p3, p4, caps);
566 case QPainterPath::CurveToDataElement:
567 Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
573 } else { // !type, simple polygon
574 QPointF p = QPointF(points[0], points[1]) * state->matrix;
576 patternOffset = state->lastPen.dashOffset()*64;
579 const qreal *end = points + 2*path.elementCount();
580 // handle closed path case
581 bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
582 int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
584 QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix;
585 calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
589 while (points < end) {
590 QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
592 if (!closed && drawCaps && points == end - 2)
595 stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
601 if (path.hasImplicitClose())
602 stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
606 blend(current_span, spans, &state->penData);
610 void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps)
612 // qDebug() << ">>>> renderCubic" << p1 << p2 << p3 << p4 << capString(caps);
613 const int maxSubDivisions = 6;
614 PointF points[3*maxSubDivisions + 4];
616 points[3].x = p1.x();
617 points[3].y = p1.y();
618 points[2].x = p2.x();
619 points[2].y = p2.y();
620 points[1].x = p3.x();
621 points[1].y = p3.y();
622 points[0].x = p4.x();
623 points[0].y = p4.y();
626 int level = maxSubDivisions;
628 renderCubicSubdivision(p, level, caps);
631 static void splitCubic(QCosmeticStroker::PointF *points)
633 const qreal half = .5;
636 points[6].x = points[3].x;
639 points[1].x = a = ( points[0].x + c ) * half;
640 points[5].x = b = ( points[3].x + d ) * half;
641 c = ( c + d ) * half;
642 points[2].x = a = ( a + c ) * half;
643 points[4].x = b = ( b + c ) * half;
644 points[3].x = ( a + b ) * half;
646 points[6].y = points[3].y;
649 points[1].y = a = ( points[0].y + c ) * half;
650 points[5].y = b = ( points[3].y + d ) * half;
651 c = ( c + d ) * half;
652 points[2].y = a = ( a + c ) * half;
653 points[4].y = b = ( b + c ) * half;
654 points[3].y = ( a + b ) * half;
657 void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps)
660 qreal dx = points[3].x - points[0].x;
661 qreal dy = points[3].y - points[0].y;
662 qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy));
664 if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
665 qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
669 renderCubicSubdivision(points + 3, level, caps & CapBegin);
670 renderCubicSubdivision(points, level, caps & CapEnd);
675 stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps);
678 static inline int swapCaps(int caps)
680 return ((caps & QCosmeticStroker::CapBegin) << 1) |
681 ((caps & QCosmeticStroker::CapEnd) >> 1);
684 // adjust line by half a pixel
685 static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
687 if (caps & QCosmeticStroker::CapBegin) {
691 if (caps & QCosmeticStroker::CapEnd) {
697 The hard part about this is dropout control and avoiding douple drawing of points when
698 the drawing shifts from horizontal to vertical or back.
700 template<DrawPixel drawPixel, class Dasher>
701 static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
703 if (stroker->clipLine(rx1, ry1, rx2, ry2))
706 static const int half = 32;
707 int x1 = toF26Dot6(rx1) + half;
708 int y1 = toF26Dot6(ry1) + half;
709 int x2 = toF26Dot6(rx2) + half;
710 int y2 = toF26Dot6(ry2) + half;
712 int dx = qAbs(x2 - x1);
713 int dy = qAbs(y2 - y1);
715 QCosmeticStroker::Point last = stroker->lastPixel;
717 // qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64.;
721 QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
723 bool swapped = false;
728 caps = swapCaps(caps);
729 dir = QCosmeticStroker::BottomToTop;
731 int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
734 if ((stroker->lastDir ^ QCosmeticStroker::VerticalMask) == dir)
735 caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
737 capAdjust(caps, y1, y2, x, xinc);
743 x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
745 // calculate first and last pixel and perform dropout control
746 QCosmeticStroker::Point first;
749 last.x = (x + (ys - y - 1)*xinc) >> 16;
754 bool axisAligned = qAbs(xinc) < (1 << 14);
755 if (stroker->lastPixel.x >= 0) {
756 if (first.x == stroker->lastPixel.x &&
757 first.y == stroker->lastPixel.y) {
758 // remove duplicated pixel
765 } else if (stroker->lastDir != dir &&
766 (((axisAligned && stroker->lastAxisAligned) &&
767 stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
768 (qAbs(stroker->lastPixel.x - first.x) > 1 ||
769 qAbs(stroker->lastPixel.y - first.y) > 1))) {
770 // have a missing pixel, insert it
779 stroker->lastDir = dir;
780 stroker->lastAxisAligned = axisAligned;
782 Dasher dasher(stroker, swapped, y << 6, ys << 6);
786 drawPixel(stroker, x >> 16, y, 255);
796 QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
798 bool swapped = false;
803 caps = swapCaps(caps);
804 dir = QCosmeticStroker::RightToLeft;
806 int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
809 if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
810 caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
812 capAdjust(caps, x1, x2, y, yinc);
818 y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
820 // calculate first and last pixel to perform dropout control
821 QCosmeticStroker::Point first;
825 last.y = (y + (xs - x - 1)*yinc) >> 16;
829 bool axisAligned = qAbs(yinc) < (1 << 14);
830 if (stroker->lastPixel.x >= 0) {
831 if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
832 // remove duplicated pixel
839 } else if (stroker->lastDir != dir &&
840 (((axisAligned && stroker->lastAxisAligned) &&
841 stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
842 (qAbs(stroker->lastPixel.x - first.x) > 1 ||
843 qAbs(stroker->lastPixel.y - first.y) > 1))) {
844 // have a missing pixel, insert it
853 stroker->lastDir = dir;
854 stroker->lastAxisAligned = axisAligned;
856 Dasher dasher(stroker, swapped, x << 6, xs << 6);
860 drawPixel(stroker, x, y >> 16, 255);
866 stroker->lastPixel = last;
870 template<DrawPixel drawPixel, class Dasher>
871 static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
873 if (stroker->clipLine(rx1, ry1, rx2, ry2))
876 int x1 = toF26Dot6(rx1);
877 int y1 = toF26Dot6(ry1);
878 int x2 = toF26Dot6(rx2);
879 int y2 = toF26Dot6(ry2);
884 if (qAbs(dx) < qAbs(dy)) {
887 int xinc = F16Dot16FixedDiv(dx, dy);
889 bool swapped = false;
894 caps = swapCaps(caps);
897 int x = (x1 - 32) << 10;
898 x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
900 capAdjust(caps, y1, y2, x, xinc);
902 Dasher dasher(stroker, swapped, y1, y2);
907 int alphaStart, alphaEnd;
909 alphaStart = y2 - y1;
910 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
913 alphaStart = 64 - (y1 & 63);
914 alphaEnd = (y2 & 63);
916 // qDebug() << "vertical" << x1/64. << y1/64. << x2/64. << y2/64.;
917 // qDebug() << " x=" << x << "dx=" << dx << "xi=" << (x>>16) << "xsi=" << ((x+(ys-y)*dx)>>16) << "y=" << y << "ys=" << ys;
921 uint alpha = (quint8)(x >> 8);
922 drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
923 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
931 uint alpha = (quint8)(x >> 8);
932 drawPixel(stroker, x>>16, y, (255-alpha));
933 drawPixel(stroker, (x>>16) + 1, y, alpha);
940 if (alphaEnd && dasher.on()) {
941 uint alpha = (quint8)(x >> 8);
942 drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
943 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
950 int yinc = F16Dot16FixedDiv(dy, dx);
952 bool swapped = false;
957 caps = swapCaps(caps);
960 int y = (y1 - 32) << 10;
961 y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
963 capAdjust(caps, x1, x2, y, yinc);
965 Dasher dasher(stroker, swapped, x1, x2);
970 // qDebug() << "horizontal" << x1/64. << y1/64. << x2/64. << y2/64.;
971 // qDebug() << " y=" << y << "dy=" << dy << "x=" << x << "xs=" << xs << "yi=" << (y>>16) << "ysi=" << ((y+(xs-x)*dy)>>16);
972 int alphaStart, alphaEnd;
974 alphaStart = x2 - x1;
975 Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
978 alphaStart = 64 - (x1 & 63);
979 alphaEnd = (x2 & 63);
984 uint alpha = (quint8)(y >> 8);
985 drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
986 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
995 uint alpha = (quint8)(y >> 8);
996 drawPixel(stroker, x, y>>16, (255-alpha));
997 drawPixel(stroker, x, (y>>16) + 1, alpha);
1004 if (alphaEnd && dasher.on()) {
1005 uint alpha = (quint8)(y >> 8);
1006 drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
1007 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);