52 #include <QPainterPath>
54 static inline bool isDigit(ushort ch)
56 static quint16 magic = 0x3ff;
57 return ((ch >> 4) == 3) && (magic >> (ch & 15));
60 static qreal toDouble(
const QChar *&str)
62 const int maxLen = 255;
66 if (*str == QLatin1Char(
'-')) {
69 }
else if (*str == QLatin1Char(
'+')) {
72 while (isDigit(str->unicode()) && pos < maxLen) {
73 temp[pos++] = str->toLatin1();
76 if (*str == QLatin1Char(
'.') && pos < maxLen) {
80 while (isDigit(str->unicode()) && pos < maxLen) {
81 temp[pos++] = str->toLatin1();
84 bool exponent =
false;
85 if ((*str == QLatin1Char(
'e') || *str == QLatin1Char(
'E')) && pos < maxLen) {
89 if ((*str == QLatin1Char(
'-') || *str == QLatin1Char(
'+')) && pos < maxLen) {
90 temp[pos++] = str->toLatin1();
93 while (isDigit(str->unicode()) && pos < maxLen) {
94 temp[pos++] = str->toLatin1();
102 if (!exponent && pos < 10) {
104 const char *t = temp;
110 while(*t && *t !=
'.') {
124 val =
static_cast<qreal
> (ival)/
static_cast<qreal
> (div);
131 val = QByteArray::fromRawData(temp, pos).toDouble();
133 if (std::fpclassify (
static_cast<float> (val)) != FP_NORMAL)
140 static inline void parseNumbersArray(
const QChar *&str, QVarLengthArray<qreal, 8> &points,
141 const char *pattern =
nullptr)
143 const size_t patternLen = qstrlen(pattern);
144 while (str->isSpace())
146 while (isDigit(str->unicode()) ||
147 *str == QLatin1Char(
'-') || *str == QLatin1Char(
'+') ||
148 *str == QLatin1Char(
'.')) {
150 if (patternLen && pattern[points.size() % patternLen] ==
'f') {
152 if (*str != QLatin1Char(
'0') && *str != QLatin1Char(
'1'))
154 points.append(*str == QLatin1Char(
'0') ? 0.0 : 1.0);
157 points.append(toDouble(str));
160 while (str->isSpace())
162 if (*str == QLatin1Char(
','))
166 while (str->isSpace())
171 static void pathArcSegment(QPainterPath &path,
173 qreal th0, qreal th1,
174 qreal rx, qreal ry, qreal xAxisRotation)
177 qreal a00, a01, a10, a11;
178 qreal x1, y1, x2, y2, x3, y3;
182 sinTh = qSin(xAxisRotation * (3.141592653589793 / 180.0));
183 cosTh = qCos(xAxisRotation * (3.141592653589793 / 180.0));
190 thHalf = 0.5 * (th1 - th0);
191 t = (8.0 / 3.0) * qSin(thHalf * 0.5) * qSin(thHalf * 0.5) / qSin(thHalf);
192 x1 = xc + qCos(th0) - t * qSin(th0);
193 y1 = yc + qSin(th0) + t * qCos(th0);
196 x2 = x3 + t * qSin(th1);
197 y2 = y3 - t * qCos(th1);
199 path.cubicTo(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
200 a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
201 a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
230 static void pathArc(QPainterPath &path,
233 qreal x_axis_rotation,
238 qreal curx, qreal cury)
240 const qreal Pr1 = rx * rx;
241 const qreal Pr2 = ry * ry;
246 qreal sin_th, cos_th;
247 qreal a00, a01, a10, a11;
248 qreal x0, y0, x1, y1, xc, yc;
249 qreal
d, sfactor, sfactor_sq;
250 qreal th0, th1, th_arc;
252 qreal dx, dy, dx1, dy1, Px, Py, check;
257 sin_th = qSin(x_axis_rotation * (3.141592653589793 / 180.0));
258 cos_th = qCos(x_axis_rotation * (3.141592653589793 / 180.0));
260 dx = (curx -
x) / 2.0;
261 dy = (cury - y) / 2.0;
262 dx1 = cos_th * dx + sin_th * dy;
263 dy1 = -sin_th * dx + cos_th * dy;
267 check = Px / Pr1 + Py / Pr2;
269 rx = rx * qSqrt(check);
270 ry = ry * qSqrt(check);
277 x0 = a00 * curx + a01 * cury;
278 y0 = a10 * curx + a11 * cury;
279 x1 = a00 *
x + a01 * y;
280 y1 = a10 *
x + a11 * y;
286 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
289 sfactor_sq = 1.0 /
d - 0.25;
290 if (sfactor_sq < 0) sfactor_sq = 0;
291 sfactor = qSqrt(sfactor_sq);
292 if (sweep_flag == large_arc_flag) sfactor = -sfactor;
293 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
294 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
297 th0 = qAtan2(y0 - yc, x0 - xc);
298 th1 = qAtan2(y1 - yc, x1 - xc);
301 if (th_arc < 0 && sweep_flag)
302 th_arc += 2 * 3.141592653589793;
303 else if (th_arc > 0 && !sweep_flag)
304 th_arc -= 2 * 3.141592653589793;
306 n_segs = qCeil(qAbs(th_arc / (3.141592653589793 * 0.5 + 0.001)));
308 for (i = 0; i < n_segs; i++) {
309 pathArcSegment(path, xc, yc,
310 th0 + i * th_arc / n_segs,
311 th0 + (i + 1) * th_arc / n_segs,
312 rx, ry, x_axis_rotation);
317 static QTransform parseTransformationMatrix(QStringView value)
319 static QTransform parseTransformationMatrix(
const QStringRef &value)
327 const QChar *str = value.data();
328 const QChar *end = str + value.size();
330 const QChar *str = value.constData();
331 const QChar *end = str + value.length();
335 if (str->isSpace() || *str == QLatin1Char(
',')) {
348 if (*str == QLatin1Char(
'm')) {
349 const char *ident =
"atrix";
350 for (
int i = 0; i < 5; ++i)
351 if (*(++str) != QLatin1Char(ident[i]))
355 }
else if (*str == QLatin1Char(
't')) {
356 const char *ident =
"ranslate";
357 for (
int i = 0; i < 8; ++i)
358 if (*(++str) != QLatin1Char(ident[i]))
362 }
else if (*str == QLatin1Char(
'r')) {
363 const char *ident =
"otate";
364 for (
int i = 0; i < 5; ++i)
365 if (*(++str) != QLatin1Char(ident[i]))
369 }
else if (*str == QLatin1Char(
's')) {
371 if (*str == QLatin1Char(
'c')) {
372 const char *ident =
"ale";
373 for (
int i = 0; i < 3; ++i)
374 if (*(++str) != QLatin1Char(ident[i]))
378 }
else if (*str == QLatin1Char(
'k')) {
379 if (*(++str) != QLatin1Char(
'e'))
381 if (*(++str) != QLatin1Char(
'w'))
384 if (*str == QLatin1Char(
'X'))
386 else if (*str == QLatin1Char(
'Y'))
399 while (str < end && str->isSpace())
401 if (*str != QLatin1Char(
'('))
404 QVarLengthArray<qreal, 8> points;
405 parseNumbersArray(str, points);
406 if (*str != QLatin1Char(
')'))
411 if(points.count() != 6)
413 matrix = QTransform(points[0], points[1],
414 points[2], points[3],
415 points[4], points[5]) * matrix;
416 }
else if (state == Translate) {
417 if (points.count() == 1)
418 matrix.translate(points[0], 0);
419 else if (points.count() == 2)
420 matrix.translate(points[0], points[1]);
423 }
else if (state == Rotate) {
424 if(points.count() == 1) {
425 matrix.rotate(points[0]);
426 }
else if (points.count() == 3) {
427 matrix.translate(points[1], points[2]);
428 matrix.rotate(points[0]);
429 matrix.translate(-points[1], -points[2]);
433 }
else if (state == Scale) {
434 if (points.count() < 1 || points.count() > 2)
436 qreal sx = points[0];
438 if(points.count() == 2)
440 matrix.scale(sx, sy);
441 }
else if (state == SkewX) {
442 if (points.count() != 1)
444 const qreal deg2rad = qreal(0.017453292519943295769);
445 matrix.shear(qTan(points[0]*deg2rad), 0);
446 }
else if (state == SkewY) {
447 if (points.count() != 1)
449 const qreal deg2rad = qreal(0.017453292519943295769);
450 matrix.shear(0, qTan(points[0]*deg2rad));
458 static bool parsePathDataFast(QStringView dataStr, QPainterPath &path)
460 static bool parsePathDataFast(
const QStringRef &dataStr, QPainterPath &path)
463 const int maxElementCount = 0x7fff;
464 qreal x0 = 0, y0 = 0;
469 const QChar *str = dataStr.data();
471 const QChar *str = dataStr.constData();
473 const QChar *end = str + dataStr.size();
476 while (ok && str != end) {
477 while (str->isSpace() && (str + 1) != end)
479 QChar pathElem = *str;
482 *
const_cast<QChar *
>(end) = u
'\0';
483 const char *pattern =
nullptr;
484 if (pathElem == QLatin1Char(
'a') || pathElem == QLatin1Char(
'A'))
486 QVarLengthArray<qreal, 8> arg;
487 parseNumbersArray(str, arg, pattern);
488 *
const_cast<QChar *
>(end) = endc;
489 if (pathElem == QLatin1Char(
'z') || pathElem == QLatin1Char(
'Z'))
491 const qreal *num = arg.constData();
492 int count = arg.count();
493 while (ok && count > 0) {
496 switch (pathElem.unicode()) {
502 x = x0 = num[0] + offsetX;
503 y = y0 = num[1] + offsetY;
511 pathElem = QLatin1Char(
'l');
528 pathElem = QLatin1Char(
'L');
545 x = num[0] + offsetX;
546 y = num[1] + offsetY;
566 x = num[0] + offsetX;
580 y = num[0] + offsetY;
598 QPointF c1(num[0] + offsetX, num[1] + offsetY);
599 QPointF c2(num[2] + offsetX, num[3] + offsetY);
600 QPointF e(num[4] + offsetX, num[5] + offsetY);
603 path.cubicTo(c1, c2, e);
614 QPointF c1(num[0], num[1]);
615 QPointF c2(num[2], num[3]);
616 QPointF e(num[4], num[5]);
619 path.cubicTo(c1, c2, e);
631 if (lastMode ==
'c' || lastMode ==
'C' ||
632 lastMode ==
's' || lastMode ==
'S')
633 c1 = QPointF(2*
x-ctrlPt.x(), 2*y-ctrlPt.y());
636 QPointF c2(num[0] + offsetX, num[1] + offsetY);
637 QPointF e(num[2] + offsetX, num[3] + offsetY);
640 path.cubicTo(c1, c2, e);
652 if (lastMode ==
'c' || lastMode ==
'C' ||
653 lastMode ==
's' || lastMode ==
'S')
654 c1 = QPointF(2*
x-ctrlPt.x(), 2*y-ctrlPt.y());
657 QPointF c2(num[0], num[1]);
658 QPointF e(num[2], num[3]);
661 path.cubicTo(c1, c2, e);
672 QPointF c(num[0] + offsetX, num[1] + offsetY);
673 QPointF e(num[2] + offsetX, num[3] + offsetY);
687 QPointF c(num[0], num[1]);
688 QPointF e(num[2], num[3]);
702 QPointF e(num[0] + offsetX, num[1] + offsetY);
706 if (lastMode ==
'q' || lastMode ==
'Q' ||
707 lastMode ==
't' || lastMode ==
'T')
708 c = QPointF(2*
x-ctrlPt.x(), 2*y-ctrlPt.y());
722 QPointF e(num[0], num[1]);
726 if (lastMode ==
'q' || lastMode ==
'Q' ||
727 lastMode ==
't' || lastMode ==
'T')
728 c = QPointF(2*
x-ctrlPt.x(), 2*y-ctrlPt.y());
744 qreal xAxisRotation = (*num++);
745 qreal largeArcFlag = (*num++);
746 qreal sweepFlag = (*num++);
747 qreal ex = (*num++) + offsetX;
748 qreal ey = (*num++) + offsetY;
752 pathArc(path, rx, ry, xAxisRotation,
int(largeArcFlag),
753 int(sweepFlag), ex, ey, curx, cury);
766 qreal xAxisRotation = (*num++);
767 qreal largeArcFlag = (*num++);
768 qreal sweepFlag = (*num++);
774 pathArc(path, rx, ry, xAxisRotation,
int(largeArcFlag),
775 int(sweepFlag), ex, ey, curx, cury);
785 lastMode = pathElem.toLatin1();
786 if (path.elementCount() > maxElementCount)
void() error(const char *fmt,...)
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x