painting/qcosmeticstroker.cpp

Switch to Source codePreprocessed file
LineSource CodeCoverage
1 -
2 -
3 -
4static inline uint sourceOver(uint d, uint color) -
5{ -
6 return color + BYTE_MUL(d, qAlpha(~color));
-
7} -
8 -
9inline static int F16Dot16FixedDiv(int x, int y) -
10{ -
11 if (qAbs(x) > 0x7fff)
-
12 return (((qlonglong)x) << 16) / y;
-
13 return (x << 16) / y;
-
14} -
15 -
16typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage); -
17 -
18namespace { -
19 -
20struct Dasher { -
21 QCosmeticStroker *stroker; -
22 int *pattern; -
23 int offset; -
24 int dashIndex; -
25 int dashOn; -
26 -
27 Dasher(QCosmeticStroker *s, bool reverse, int start, int stop) -
28 : stroker(s) -
29 { -
30 int delta = stop - start; -
31 if (reverse) {
-
32 pattern = stroker->reversePattern; -
33 offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32); -
34 dashOn = 0; -
35 } else {
-
36 pattern = stroker->pattern; -
37 offset = stroker->patternOffset - ((start & 63) - 32); -
38 dashOn = 1; -
39 }
-
40 offset %= stroker->patternLength; -
41 if (offset < 0)
-
42 offset += stroker->patternLength;
-
43 -
44 dashIndex = 0; -
45 while (offset>= pattern[dashIndex])
-
46 ++dashIndex;
-
47 -
48 -
49 stroker->patternOffset += delta; -
50 stroker->patternOffset %= stroker->patternLength; -
51 }
-
52 -
53 bool on() const { -
54 return (dashIndex + dashOn) & 1;
-
55 } -
56 void adjust() { -
57 offset += 64; -
58 if (offset >= pattern[dashIndex]) {
-
59 ++dashIndex; -
60 dashIndex %= stroker->patternSize; -
61 }
-
62 offset %= stroker->patternLength; -
63 -
64 }
-
65}; -
66 -
67struct NoDasher { -
68 NoDasher(QCosmeticStroker *, bool, int, int) {} -
69 bool on() const { return true; }
-
70 void adjust(int = 0) {} -
71}; -
72 -
73}; -
74 -
75template<DrawPixel drawPixel, class Dasher> -
76static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps); -
77template<DrawPixel drawPixel, class Dasher> -
78static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps); -
79 -
80inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage) -
81{ -
82 const QRect &cl = stroker->clip; -
83 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
-
84 return;
-
85 -
86 int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ; -
87 int lasty = stroker->spans[stroker->current_span-1].y; -
88 -
89 if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) {
-
90 stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData); -
91 stroker->current_span = 0; -
92 }
-
93 -
94 stroker->spans[stroker->current_span].x = ushort(x); -
95 stroker->spans[stroker->current_span].len = 1; -
96 stroker->spans[stroker->current_span].y = y; -
97 stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8; -
98 ++stroker->current_span; -
99}
-
100 -
101inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage) -
102{ -
103 const QRect &cl = stroker->clip; -
104 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
-
105 return;
-
106 -
107 int offset = x + stroker->ppl*y; -
108 uint c = BYTE_MUL(stroker->color, coverage); -
109 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c); -
110}
-
111 -
112inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int) -
113{ -
114 const QRect &cl = stroker->clip; -
115 if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
-
116 return;
-
117 -
118 int offset = x + stroker->ppl*y; -
119 stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color); -
120}
-
121 -
122enum StrokeSelection { -
123 Aliased = 0, -
124 AntiAliased = 1, -
125 Solid = 0, -
126 Dashed = 2, -
127 RegularDraw = 0, -
128 FastDraw = 4 -
129}; -
130 -
131static StrokeLine strokeLine(int strokeSelection) -
132{ -
133 StrokeLine stroke; -
134 -
135 switch (strokeSelection) { -
136 case Aliased|Solid|RegularDraw: -
137 stroke = &::drawLine<drawPixel, NoDasher>; -
138 break;
-
139 case Aliased|Solid|FastDraw: -
140 stroke = &::drawLine<drawPixelARGB32Opaque, NoDasher>; -
141 break;
-
142 case Aliased|Dashed|RegularDraw: -
143 stroke = &::drawLine<drawPixel, Dasher>; -
144 break;
-
145 case Aliased|Dashed|FastDraw: -
146 stroke = &::drawLine<drawPixelARGB32Opaque, Dasher>; -
147 break;
-
148 case AntiAliased|Solid|RegularDraw: -
149 stroke = &::drawLineAA<drawPixel, NoDasher>; -
150 break;
-
151 case AntiAliased|Solid|FastDraw: -
152 stroke = &::drawLineAA<drawPixelARGB32, NoDasher>; -
153 break;
-
154 case AntiAliased|Dashed|RegularDraw: -
155 stroke = &::drawLineAA<drawPixel, Dasher>; -
156 break;
-
157 case AntiAliased|Dashed|FastDraw: -
158 stroke = &::drawLineAA<drawPixelARGB32, Dasher>; -
159 break;
-
160 default: -
161 qt_noop(); -
162 stroke = 0; -
163 }
-
164 return stroke;
-
165} -
166 -
167void QCosmeticStroker::setup() -
168{ -
169 blend = state->penData.blend; -
170 if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
evaluated: state->clip
TRUEFALSE
yes
Evaluation Count:9194
yes
Evaluation Count:62506
partially evaluated: state->clip->enabled
TRUEFALSE
yes
Evaluation Count:9194
no
Evaluation Count:0
evaluated: state->clip->hasRectClip
TRUEFALSE
yes
Evaluation Count:8526
yes
Evaluation Count:668
partially evaluated: !state->clip->clipRect.isEmpty()
TRUEFALSE
yes
Evaluation Count:8526
no
Evaluation Count:0
0-62506
171 clip &= state->clip->clipRect; -
172 blend = state->penData.unclipped_blend; -
173 }
executed: }
Execution Count:8526
8526
174 -
175 int strokeSelection = 0; -
176 if (blend == state->penData.unclipped_blend
evaluated: blend == state->penData.unclipped_blend
TRUEFALSE
yes
Evaluation Count:8526
yes
Evaluation Count:63174
8526-63174
177 && state->penData.type == QSpanData::Solid
evaluated: state->penData.type == QSpanData::Solid
TRUEFALSE
yes
Evaluation Count:8520
yes
Evaluation Count:6
6-8520
178 && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
evaluated: state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
TRUEFALSE
yes
Evaluation Count:442
yes
Evaluation Count:8078
442-8078
179 || state->penData.rasterBuffer->format == QImage::Format_RGB32)
evaluated: state->penData.rasterBuffer->format == QImage::Format_RGB32
TRUEFALSE
yes
Evaluation Count:29
yes
Evaluation Count:8049
29-8049
180 && state->compositionMode() == QPainter::CompositionMode_SourceOver)
partially evaluated: state->compositionMode() == QPainter::CompositionMode_SourceOver
TRUEFALSE
yes
Evaluation Count:471
no
Evaluation Count:0
0-471
181 strokeSelection |= FastDraw;
executed: strokeSelection |= FastDraw;
Execution Count:471
471
182 -
183 if (state->renderHints & QPainter::Antialiasing)
evaluated: state->renderHints & QPainter::Antialiasing
TRUEFALSE
yes
Evaluation Count:396
yes
Evaluation Count:71304
396-71304
184 strokeSelection |= AntiAliased;
executed: strokeSelection |= AntiAliased;
Execution Count:396
396
185 -
186 const QVector<qreal> &penPattern = state->lastPen.dashPattern(); -
187 if (penPattern.isEmpty()) {
evaluated: penPattern.isEmpty()
TRUEFALSE
yes
Evaluation Count:71677
yes
Evaluation Count:23
23-71677
188 qt_noop(); -
189 pattern = 0; -
190 reversePattern = 0; -
191 patternLength = 0; -
192 patternSize = 0; -
193 } else {
executed: }
Execution Count:71677
71677
194 pattern = (int *)malloc(penPattern.size()*sizeof(int)); -
195 reversePattern = (int *)malloc(penPattern.size()*sizeof(int)); -
196 patternSize = penPattern.size(); -
197 -
198 patternLength = 0; -
199 for (int i = 0; i < patternSize; ++i) {
evaluated: i < patternSize
TRUEFALSE
yes
Evaluation Count:46
yes
Evaluation Count:23
23-46
200 patternLength += (int) qMax(1. , penPattern.at(i)*64.); -
201 pattern[i] = patternLength; -
202 }
executed: }
Execution Count:46
46
203 patternLength = 0; -
204 for (int i = 0; i < patternSize; ++i) {
evaluated: i < patternSize
TRUEFALSE
yes
Evaluation Count:46
yes
Evaluation Count:23
23-46
205 patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.); -
206 reversePattern[i] = patternLength; -
207 }
executed: }
Execution Count:46
46
208 strokeSelection |= Dashed; -
209 -
210 }
executed: }
Execution Count:23
23
211 -
212 stroke = strokeLine(strokeSelection); -
213 -
214 qreal width = state->lastPen.widthF(); -
215 if (width == 0)
evaluated: width == 0
TRUEFALSE
yes
Evaluation Count:1879
yes
Evaluation Count:69821
1879-69821
216 opacity = 256;
executed: opacity = 256;
Execution Count:1879
1879
217 else if (qt_pen_is_cosmetic(state->lastPen, state->renderHints))
evaluated: qt_pen_is_cosmetic(state->lastPen, state->renderHints)
TRUEFALSE
yes
Evaluation Count:990
yes
Evaluation Count:68831
990-68831
218 opacity = (int) 256*width;
executed: opacity = (int) 256*width;
Execution Count:990
990
219 else -
220 opacity = (int) 256*width*state->txscale;
executed: opacity = (int) 256*width*state->txscale;
Execution Count:68831
68831
221 opacity = qBound(0, opacity, 256); -
222 -
223 drawCaps = state->lastPen.capStyle() != Qt::FlatCap; -
224 -
225 if (strokeSelection & FastDraw) {
evaluated: strokeSelection & FastDraw
TRUEFALSE
yes
Evaluation Count:471
yes
Evaluation Count:71229
471-71229
226 color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0); -
227 QRasterBuffer *buffer = state->penData.rasterBuffer; -
228 pixels = (uint *)buffer->buffer(); -
229 ppl = buffer->bytesPerLine()>>2; -
230 }
executed: }
Execution Count:471
471
231 -
232 -
233 -
234 -
235 -
236 xmin = clipdeviceRect.left() - 1; -
237 xmax = clipdeviceRect.right() + 2; -
238 ymin = clipdeviceRect.top() - 1; -
239 ymax = clipdeviceRect.bottom() + 2; -
240 -
241 lastPixel.x = -1; -
242}
executed: }
Execution Count:71700
71700
243 -
244 -
245bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2) -
246{ -
247 -
248 -
249 if (x1 < xmin) {
-
250 if (x2 <= xmin)
-
251 goto clipped;
-
252 y1 += (y2 - y1)/(x2 - x1) * (xmin - x1); -
253 x1 = xmin; -
254 } else if (x1 > xmax) {
-
255 if (x2 >= xmax)
-
256 goto clipped;
-
257 y1 += (y2 - y1)/(x2 - x1) * (xmax - x1); -
258 x1 = xmax; -
259 }
-
260 if (x2 < xmin) {
-
261 lastPixel.x = -1; -
262 y2 += (y2 - y1)/(x2 - x1) * (xmin - x2); -
263 x2 = xmin; -
264 } else if (x2 > xmax) {
-
265 lastPixel.x = -1; -
266 y2 += (y2 - y1)/(x2 - x1) * (xmax - x2); -
267 x2 = xmax; -
268 }
-
269 -
270 if (y1 < ymin) {
-
271 if (y2 <= ymin)
-
272 goto clipped;
-
273 x1 += (x2 - x1)/(y2 - y1) * (ymin - y1); -
274 y1 = ymin; -
275 } else if (y1 > ymax) {
-
276 if (y2 >= ymax)
-
277 goto clipped;
-
278 x1 += (x2 - x1)/(y2 - y1) * (ymax - y1); -
279 y1 = ymax; -
280 }
-
281 if (y2 < ymin) {
-
282 lastPixel.x = -1; -
283 x2 += (x2 - x1)/(y2 - y1) * (ymin - y2); -
284 y2 = ymin; -
285 } else if (y2 > ymax) {
-
286 lastPixel.x = -1; -
287 x2 += (x2 - x1)/(y2 - y1) * (ymax - y2); -
288 y2 = ymax; -
289 }
-
290 -
291 return false;
-
292 -
293 clipped: -
294 lastPixel.x = -1; -
295 return true;
-
296} -
297 -
298 -
299void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2) -
300{ -
301 if (p1 == p2) {
-
302 drawPoints(&p1, 1); -
303 return;
-
304 } -
305 -
306 QPointF start = p1 * state->matrix; -
307 QPointF end = p2 * state->matrix; -
308 -
309 patternOffset = state->lastPen.dashOffset()*64; -
310 lastPixel.x = -1; -
311 -
312 stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0); -
313 -
314 blend(current_span, spans, &state->penData); -
315 current_span = 0; -
316}
-
317 -
318void QCosmeticStroker::drawPoints(const QPoint *points, int num) -
319{ -
320 const QPoint *end = points + num; -
321 while (points < end) {
-
322 QPointF p = QPointF(*points) * state->matrix; -
323 drawPixel(this, qRound(p.x()), qRound(p.y()), 255); -
324 ++points; -
325 }
-
326 -
327 blend(current_span, spans, &state->penData); -
328 current_span = 0; -
329}
-
330 -
331void QCosmeticStroker::drawPoints(const QPointF *points, int num) -
332{ -
333 const QPointF *end = points + num; -
334 while (points < end) {
-
335 QPointF p = (*points) * state->matrix; -
336 drawPixel(this, qRound(p.x()), qRound(p.y()), 255); -
337 ++points; -
338 }
-
339 -
340 blend(current_span, spans, &state->penData); -
341 current_span = 0; -
342}
-
343 -
344void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2) -
345{ -
346 -
347 -
348 -
349 -
350 -
351 -
352 -
353 lastPixel.x = -1; -
354 lastPixel.y = -1; -
355 -
356 if (clipLine(rx1, ry1, rx2, ry2))
-
357 return;
-
358 -
359 const int half = legacyRounding ? 31 : 0;
-
360 int x1 = ((int)((rx1)*64.)) + half; -
361 int y1 = ((int)((ry1)*64.)) + half; -
362 int x2 = ((int)((rx2)*64.)) + half; -
363 int y2 = ((int)((ry2)*64.)) + half; -
364 -
365 int dx = qAbs(x2 - x1); -
366 int dy = qAbs(y2 - y1); -
367 -
368 if (dx < dy) {
-
369 -
370 bool swapped = false; -
371 if (y1 > y2) {
-
372 swapped = true; -
373 qSwap(y1, y2); -
374 qSwap(x1, x2); -
375 }
-
376 int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1); -
377 int x = x1 << 10; -
378 -
379 int y = (y1 + 32) >> 6; -
380 int ys = (y2 + 32) >> 6; -
381 -
382 if (y != ys) {
-
383 x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6; -
384 -
385 if (swapped) {
-
386 lastPixel.x = x >> 16; -
387 lastPixel.y = y; -
388 lastDir = QCosmeticStroker::BottomToTop; -
389 } else {
-
390 lastPixel.x = (x + (ys - y - 1)*xinc) >> 16; -
391 lastPixel.y = ys - 1; -
392 lastDir = QCosmeticStroker::TopToBottom; -
393 }
-
394 lastAxisAligned = qAbs(xinc) < (1 << 14); -
395 }
-
396 } else {
-
397 -
398 if (!dx)
-
399 return;
-
400 -
401 bool swapped = false; -
402 if (x1 > x2) {
-
403 swapped = true; -
404 qSwap(x1, x2); -
405 qSwap(y1, y2); -
406 }
-
407 int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1); -
408 int y = y1 << 10; -
409 -
410 int x = (x1 + 32) >> 6; -
411 int xs = (x2 + 32) >> 6; -
412 -
413 if (x != xs) {
-
414 y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6; -
415 -
416 if (swapped) {
-
417 lastPixel.x = x; -
418 lastPixel.y = y >> 16; -
419 lastDir = QCosmeticStroker::RightToLeft; -
420 } else {
-
421 lastPixel.x = xs - 1; -
422 lastPixel.y = (y + (xs - x - 1)*yinc) >> 16; -
423 lastDir = QCosmeticStroker::LeftToRight; -
424 }
-
425 lastAxisAligned = qAbs(yinc) < (1 << 14); -
426 }
-
427 }
-
428 -
429} -
430 -
431static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, -
432 const qreal *points, bool *closed) -
433{ -
434 const QPainterPath::ElementType *start = t; -
435 ++t; -
436 -
437 -
438 while (t < end) {
-
439 if (*t == QPainterPath::MoveToElement)
-
440 break;
-
441 ++t; -
442 }
-
443 -
444 int offset = t - start - 1; -
445 -
446 *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
-
447 -
448 return t;
-
449} -
450 -
451void QCosmeticStroker::drawPath(const QVectorPath &path) -
452{ -
453 -
454 -
455 if (path.isEmpty())
-
456 return;
-
457 -
458 const qreal *points = path.points(); -
459 const QPainterPath::ElementType *type = path.elements(); -
460 -
461 if (type) {
-
462 const QPainterPath::ElementType *end = type + path.elementCount(); -
463 -
464 while (type < end) {
-
465 qt_noop(); -
466 -
467 QPointF p = QPointF(points[0], points[1]) * state->matrix; -
468 patternOffset = state->lastPen.dashOffset()*64; -
469 lastPixel.x = -1; -
470 -
471 bool closed; -
472 const QPainterPath::ElementType *e = subPath(type, end, points, &closed); -
473 if (closed) {
-
474 const qreal *p = points + 2*(e-type); -
475 QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix; -
476 QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix; -
477 calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y()); -
478 }
-
479 int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
-
480 -
481 -
482 points += 2; -
483 ++type; -
484 -
485 while (type < e) {
-
486 QPointF p2 = QPointF(points[0], points[1]) * state->matrix; -
487 switch (*type) { -
488 case QPainterPath::MoveToElement: -
489 qt_noop(); -
490 break;
-
491 -
492 case QPainterPath::LineToElement: -
493 if (!closed && drawCaps && type == e - 1)
-
494 caps |= CapEnd;
-
495 stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps); -
496 p = p2; -
497 points += 2; -
498 ++type; -
499 break;
-
500 -
501 case QPainterPath::CurveToElement: { -
502 if (!closed && drawCaps && type == e - 3)
-
503 caps |= CapEnd;
-
504 QPointF p3 = QPointF(points[2], points[3]) * state->matrix; -
505 QPointF p4 = QPointF(points[4], points[5]) * state->matrix; -
506 renderCubic(p, p2, p3, p4, caps); -
507 p = p4; -
508 type += 3; -
509 points += 6; -
510 break;
-
511 } -
512 case QPainterPath::CurveToDataElement: -
513 qt_noop(); -
514 break;
-
515 } -
516 caps = NoCaps; -
517 }
-
518 }
-
519 } else {
-
520 QPointF p = QPointF(points[0], points[1]) * state->matrix; -
521 QPointF movedTo = p; -
522 patternOffset = state->lastPen.dashOffset()*64; -
523 lastPixel.x = -1; -
524 -
525 const qreal *end = points + 2*path.elementCount(); -
526 -
527 bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
-
528 int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
-
529 if (closed) {
-
530 QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix; -
531 calculateLastPoint(p2.x(), p2.y(), p.x(), p.y()); -
532 }
-
533 -
534 points += 2; -
535 while (points < end) {
-
536 QPointF p2 = QPointF(points[0], points[1]) * state->matrix; -
537 -
538 if (!closed && drawCaps && points == end - 2)
-
539 caps |= CapEnd;
-
540 -
541 stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps); -
542 -
543 p = p2; -
544 points += 2; -
545 caps = NoCaps; -
546 }
-
547 if (path.hasImplicitClose())
-
548 stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
-
549 }
-
550 -
551 -
552 blend(current_span, spans, &state->penData); -
553 current_span = 0; -
554}
-
555 -
556void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps) -
557{ -
558 -
559 const int maxSubDivisions = 6; -
560 PointF points[3*maxSubDivisions + 4]; -
561 -
562 points[3].x = p1.x(); -
563 points[3].y = p1.y(); -
564 points[2].x = p2.x(); -
565 points[2].y = p2.y(); -
566 points[1].x = p3.x(); -
567 points[1].y = p3.y(); -
568 points[0].x = p4.x(); -
569 points[0].y = p4.y(); -
570 -
571 PointF *p = points; -
572 int level = maxSubDivisions; -
573 -
574 renderCubicSubdivision(p, level, caps); -
575}
-
576 -
577static void splitCubic(QCosmeticStroker::PointF *points) -
578{ -
579 const qreal half = .5; -
580 qreal a, b, c, d; -
581 -
582 points[6].x = points[3].x; -
583 c = points[1].x; -
584 d = points[2].x; -
585 points[1].x = a = ( points[0].x + c ) * half; -
586 points[5].x = b = ( points[3].x + d ) * half; -
587 c = ( c + d ) * half; -
588 points[2].x = a = ( a + c ) * half; -
589 points[4].x = b = ( b + c ) * half; -
590 points[3].x = ( a + b ) * half; -
591 -
592 points[6].y = points[3].y; -
593 c = points[1].y; -
594 d = points[2].y; -
595 points[1].y = a = ( points[0].y + c ) * half; -
596 points[5].y = b = ( points[3].y + d ) * half; -
597 c = ( c + d ) * half; -
598 points[2].y = a = ( a + c ) * half; -
599 points[4].y = b = ( b + c ) * half; -
600 points[3].y = ( a + b ) * half; -
601}
-
602 -
603void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps) -
604{ -
605 if (level) {
-
606 qreal dx = points[3].x - points[0].x; -
607 qreal dy = points[3].y - points[0].y; -
608 qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy)); -
609 -
610 if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
-
611 qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
-
612 splitCubic(points); -
613 -
614 --level; -
615 renderCubicSubdivision(points + 3, level, caps & CapBegin); -
616 renderCubicSubdivision(points, level, caps & CapEnd); -
617 return;
-
618 } -
619 }
-
620 -
621 stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps); -
622}
-
623 -
624static inline int swapCaps(int caps) -
625{ -
626 return ((caps & QCosmeticStroker::CapBegin) << 1) | -
627 ((caps & QCosmeticStroker::CapEnd) >> 1);
-
628} -
629 -
630 -
631static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc) -
632{ -
633 if (caps & QCosmeticStroker::CapBegin) {
-
634 x1 -= 32; -
635 y -= yinc >> 1; -
636 }
-
637 if (caps & QCosmeticStroker::CapEnd) {
-
638 x2 += 32; -
639 }
-
640}
-
641 -
642 -
643 -
644 -
645 -
646template<DrawPixel drawPixel, class Dasher> -
647static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps) -
648{ -
649 if (stroker->clipLine(rx1, ry1, rx2, ry2))
-
650 return;
-
651 -
652 const int half = stroker->legacyRounding ? 31 : 0;
-
653 int x1 = ((int)((rx1)*64.)) + half; -
654 int y1 = ((int)((ry1)*64.)) + half; -
655 int x2 = ((int)((rx2)*64.)) + half; -
656 int y2 = ((int)((ry2)*64.)) + half; -
657 -
658 int dx = qAbs(x2 - x1); -
659 int dy = qAbs(y2 - y1); -
660 -
661 QCosmeticStroker::Point last = stroker->lastPixel; -
662 -
663 -
664 -
665 if (dx < dy) {
-
666 -
667 QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom; -
668 -
669 bool swapped = false; -
670 if (y1 > y2) {
-
671 swapped = true; -
672 qSwap(y1, y2); -
673 qSwap(x1, x2); -
674 caps = swapCaps(caps); -
675 dir = QCosmeticStroker::BottomToTop; -
676 }
-
677 int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1); -
678 int x = x1 << 10; -
679 -
680 if ((stroker->lastDir ^ QCosmeticStroker::VerticalMask) == dir)
-
681 caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
-
682 -
683 capAdjust(caps, y1, y2, x, xinc); -
684 -
685 int y = (y1 + 32) >> 6; -
686 int ys = (y2 + 32) >> 6; -
687 -
688 if (y != ys) {
-
689 x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6; -
690 -
691 -
692 QCosmeticStroker::Point first; -
693 first.x = x >> 16; -
694 first.y = y; -
695 last.x = (x + (ys - y - 1)*xinc) >> 16; -
696 last.y = ys - 1; -
697 if (swapped)
-
698 qSwap(first, last);
-
699 -
700 bool axisAligned = qAbs(xinc) < (1 << 14); -
701 if (stroker->lastPixel.x >= 0) {
-
702 if (first.x == stroker->lastPixel.x &&
-
703 first.y == stroker->lastPixel.y) {
-
704 -
705 if (swapped) {
-
706 --ys; -
707 } else {
-
708 ++y; -
709 x += xinc; -
710 }
-
711 } else if (stroker->lastDir != dir &&
-
712 (((axisAligned && stroker->lastAxisAligned) &&
-
713 stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
-
714 (qAbs(stroker->lastPixel.x - first.x) > 1 ||
-
715 qAbs(stroker->lastPixel.y - first.y) > 1))) {
-
716 -
717 if (swapped) {
-
718 ++ys; -
719 } else {
-
720 --y; -
721 x -= xinc; -
722 }
-
723 } -
724 } -
725 stroker->lastDir = dir; -
726 stroker->lastAxisAligned = axisAligned; -
727 -
728 Dasher dasher(stroker, swapped, y << 6, ys << 6); -
729 -
730 do { -
731 if (dasher.on())
-
732 drawPixel(stroker, x >> 16, y, 255);
-
733 dasher.adjust(); -
734 x += xinc; -
735 } while (++y < ys);
-
736 }
-
737 } else {
-
738 -
739 if (!dx)
-
740 return;
-
741 -
742 QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight; -
743 -
744 bool swapped = false; -
745 if (x1 > x2) {
-
746 swapped = true; -
747 qSwap(x1, x2); -
748 qSwap(y1, y2); -
749 caps = swapCaps(caps); -
750 dir = QCosmeticStroker::RightToLeft; -
751 }
-
752 int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1); -
753 int y = y1 << 10; -
754 -
755 if ((stroker->lastDir ^ QCosmeticStroker::HorizontalMask) == dir)
-
756 caps |= swapped ? QCosmeticStroker::CapEnd : QCosmeticStroker::CapBegin;
-
757 -
758 capAdjust(caps, x1, x2, y, yinc); -
759 -
760 int x = (x1 + 32) >> 6; -
761 int xs = (x2 + 32) >> 6; -
762 -
763 if (x != xs) {
-
764 y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6; -
765 -
766 -
767 QCosmeticStroker::Point first; -
768 first.x = x; -
769 first.y = y >> 16; -
770 last.x = xs - 1; -
771 last.y = (y + (xs - x - 1)*yinc) >> 16; -
772 if (swapped)
-
773 qSwap(first, last);
-
774 -
775 bool axisAligned = qAbs(yinc) < (1 << 14); -
776 if (stroker->lastPixel.x >= 0) {
-
777 if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
-
778 -
779 if (swapped) {
-
780 --xs; -
781 } else {
-
782 ++x; -
783 y += yinc; -
784 }
-
785 } else if (stroker->lastDir != dir &&
-
786 (((axisAligned && stroker->lastAxisAligned) &&
-
787 stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
-
788 (qAbs(stroker->lastPixel.x - first.x) > 1 ||
-
789 qAbs(stroker->lastPixel.y - first.y) > 1))) {
-
790 -
791 if (swapped) {
-
792 ++xs; -
793 } else {
-
794 --x; -
795 y -= yinc; -
796 }
-
797 } -
798 } -
799 stroker->lastDir = dir; -
800 stroker->lastAxisAligned = axisAligned; -
801 -
802 Dasher dasher(stroker, swapped, x << 6, xs << 6); -
803 -
804 do { -
805 if (dasher.on())
-
806 drawPixel(stroker, x, y >> 16, 255);
-
807 dasher.adjust(); -
808 y += yinc; -
809 } while (++x < xs);
-
810 }
-
811 }
-
812 stroker->lastPixel = last; -
813}
-
814 -
815 -
816template<DrawPixel drawPixel, class Dasher> -
817static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps) -
818{ -
819 if (stroker->clipLine(rx1, ry1, rx2, ry2))
-
820 return;
-
821 -
822 int x1 = ((int)((rx1)*64.)); -
823 int y1 = ((int)((ry1)*64.)); -
824 int x2 = ((int)((rx2)*64.)); -
825 int y2 = ((int)((ry2)*64.)); -
826 -
827 int dx = x2 - x1; -
828 int dy = y2 - y1; -
829 -
830 if (qAbs(dx) < qAbs(dy)) {
-
831 -
832 -
833 int xinc = F16Dot16FixedDiv(dx, dy); -
834 -
835 bool swapped = false; -
836 if (y1 > y2) {
-
837 qSwap(y1, y2); -
838 qSwap(x1, x2); -
839 swapped = true; -
840 caps = swapCaps(caps); -
841 }
-
842 -
843 int x = (x1 - 32) << 10; -
844 x -= ( ((y1 & 63) - 32) * xinc ) >> 6; -
845 -
846 capAdjust(caps, y1, y2, x, xinc); -
847 -
848 Dasher dasher(stroker, swapped, y1, y2); -
849 -
850 int y = y1 >> 6; -
851 int ys = y2 >> 6; -
852 -
853 int alphaStart, alphaEnd; -
854 if (y == ys) {
-
855 alphaStart = y2 - y1; -
856 qt_noop(); -
857 alphaEnd = 0; -
858 } else {
-
859 alphaStart = 64 - (y1 & 63); -
860 alphaEnd = (y2 & 63); -
861 }
-
862 -
863 -
864 -
865 -
866 if (dasher.on()) {
-
867 uint alpha = (quint8)(x >> 8); -
868 drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6); -
869 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6); -
870 }
-
871 dasher.adjust(); -
872 x += xinc; -
873 ++y; -
874 if (y < ys) {
-
875 do { -
876 if (dasher.on()) {
-
877 uint alpha = (quint8)(x >> 8); -
878 drawPixel(stroker, x>>16, y, (255-alpha)); -
879 drawPixel(stroker, (x>>16) + 1, y, alpha); -
880 }
-
881 dasher.adjust(); -
882 x += xinc; -
883 } while (++y < ys);
-
884 }
-
885 -
886 if (alphaEnd && dasher.on()) {
-
887 uint alpha = (quint8)(x >> 8); -
888 drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6); -
889 drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6); -
890 }
-
891 } else {
-
892 -
893 if (!dx)
-
894 return;
-
895 -
896 int yinc = F16Dot16FixedDiv(dy, dx); -
897 -
898 bool swapped = false; -
899 if (x1 > x2) {
-
900 qSwap(x1, x2); -
901 qSwap(y1, y2); -
902 swapped = true; -
903 caps = swapCaps(caps); -
904 }
-
905 -
906 int y = (y1 - 32) << 10; -
907 y -= ( ((x1 & 63) - 32) * yinc ) >> 6; -
908 -
909 capAdjust(caps, x1, x2, y, yinc); -
910 -
911 Dasher dasher(stroker, swapped, x1, x2); -
912 -
913 int x = x1 >> 6; -
914 int xs = x2 >> 6; -
915 -
916 -
917 -
918 int alphaStart, alphaEnd; -
919 if (x == xs) {
-
920 alphaStart = x2 - x1; -
921 qt_noop(); -
922 alphaEnd = 0; -
923 } else {
-
924 alphaStart = 64 - (x1 & 63); -
925 alphaEnd = (x2 & 63); -
926 }
-
927 -
928 -
929 if (dasher.on()) {
-
930 uint alpha = (quint8)(y >> 8); -
931 drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6); -
932 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6); -
933 }
-
934 dasher.adjust(); -
935 y += yinc; -
936 ++x; -
937 -
938 if (x < xs) {
-
939 do { -
940 if (dasher.on()) {
-
941 uint alpha = (quint8)(y >> 8); -
942 drawPixel(stroker, x, y>>16, (255-alpha)); -
943 drawPixel(stroker, x, (y>>16) + 1, alpha); -
944 }
-
945 dasher.adjust(); -
946 y += yinc; -
947 } while (++x < xs);
-
948 }
-
949 -
950 if (alphaEnd && dasher.on()) {
-
951 uint alpha = (quint8)(y >> 8); -
952 drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6); -
953 drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6); -
954 }
-
955 }
-
956} -
957 -
958 -
959 -
Switch to Source codePreprocessed file

Generated by Squish Coco Non-Commercial