GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
octave-qsvghandler.h
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt SVG module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 // --------------------------------------------------------------------------
41 // Build a QPainterPath from the "d" attribute of a path element
42 // These functions were originally extracted from Qt-5.12 sources
43 // (qsvghandler.cpp)
44 // Modifications:
45 // * use static_cast<qreal> to avoid old style cast warning.
46 // Some portions are extracted from Qt6.5:
47 // https://github.com/qt/qtsvg/blob/6.5.0/src/svg/qsvghandler.cpp
48 // --------------------------------------------------------------------------
49 
50 #include <cmath>
51 
52 #include <QPainterPath>
53 
54 static inline bool isDigit(ushort ch)
55 {
56  static quint16 magic = 0x3ff;
57  return ((ch >> 4) == 3) && (magic >> (ch & 15));
58 }
59 
60 static qreal toDouble(const QChar *&str)
61 {
62  const int maxLen = 255;//technically doubles can go til 308+ but whatever
63  char temp[maxLen+1];
64  int pos = 0;
65 
66  if (*str == QLatin1Char('-')) {
67  temp[pos++] = '-';
68  ++str;
69  } else if (*str == QLatin1Char('+')) {
70  ++str;
71  }
72  while (isDigit(str->unicode()) && pos < maxLen) {
73  temp[pos++] = str->toLatin1();
74  ++str;
75  }
76  if (*str == QLatin1Char('.') && pos < maxLen) {
77  temp[pos++] = '.';
78  ++str;
79  }
80  while (isDigit(str->unicode()) && pos < maxLen) {
81  temp[pos++] = str->toLatin1();
82  ++str;
83  }
84  bool exponent = false;
85  if ((*str == QLatin1Char('e') || *str == QLatin1Char('E')) && pos < maxLen) {
86  exponent = true;
87  temp[pos++] = 'e';
88  ++str;
89  if ((*str == QLatin1Char('-') || *str == QLatin1Char('+')) && pos < maxLen) {
90  temp[pos++] = str->toLatin1();
91  ++str;
92  }
93  while (isDigit(str->unicode()) && pos < maxLen) {
94  temp[pos++] = str->toLatin1();
95  ++str;
96  }
97  }
98 
99  temp[pos] = '\0';
100 
101  qreal val;
102  if (!exponent && pos < 10) {
103  int ival = 0;
104  const char *t = temp;
105  bool neg = false;
106  if(*t == '-') {
107  neg = true;
108  ++t;
109  }
110  while(*t && *t != '.') {
111  ival *= 10;
112  ival += (*t) - '0';
113  ++t;
114  }
115  if(*t == '.') {
116  ++t;
117  int div = 1;
118  while(*t) {
119  ival *= 10;
120  ival += (*t) - '0';
121  div *= 10;
122  ++t;
123  }
124  val = static_cast<qreal> (ival)/static_cast<qreal> (div);
125  } else {
126  val = ival;
127  }
128  if (neg)
129  val = -val;
130  } else {
131  val = QByteArray::fromRawData(temp, pos).toDouble();
132  // Do not tolerate values too wild to be represented normally by floats
133  if (std::fpclassify (static_cast<float> (val)) != FP_NORMAL)
134  val = 0;
135  }
136  return val;
137 
138 }
139 
140 static inline void parseNumbersArray(const QChar *&str, QVarLengthArray<qreal, 8> &points,
141  const char *pattern = nullptr)
142 {
143  const size_t patternLen = qstrlen(pattern);
144  while (str->isSpace())
145  ++str;
146  while (isDigit(str->unicode()) ||
147  *str == QLatin1Char('-') || *str == QLatin1Char('+') ||
148  *str == QLatin1Char('.')) {
149 
150  if (patternLen && pattern[points.size() % patternLen] == 'f') {
151  // flag expected, may only be 0 or 1
152  if (*str != QLatin1Char('0') && *str != QLatin1Char('1'))
153  return;
154  points.append(*str == QLatin1Char('0') ? 0.0 : 1.0);
155  ++str;
156  } else {
157  points.append(toDouble(str));
158  }
159 
160  while (str->isSpace())
161  ++str;
162  if (*str == QLatin1Char(','))
163  ++str;
164 
165  //eat the rest of space
166  while (str->isSpace())
167  ++str;
168  }
169 }
170 
171 static void pathArcSegment(QPainterPath &path,
172  qreal xc, qreal yc,
173  qreal th0, qreal th1,
174  qreal rx, qreal ry, qreal xAxisRotation)
175 {
176  qreal sinTh, cosTh;
177  qreal a00, a01, a10, a11;
178  qreal x1, y1, x2, y2, x3, y3;
179  qreal t;
180  qreal thHalf;
181 
182  sinTh = qSin(xAxisRotation * (3.141592653589793 / 180.0));
183  cosTh = qCos(xAxisRotation * (3.141592653589793 / 180.0));
184 
185  a00 = cosTh * rx;
186  a01 = -sinTh * ry;
187  a10 = sinTh * rx;
188  a11 = cosTh * ry;
189 
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);
194  x3 = xc + qCos(th1);
195  y3 = yc + qSin(th1);
196  x2 = x3 + t * qSin(th1);
197  y2 = y3 - t * qCos(th1);
198 
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);
202 }
203 
204 // the arc handling code underneath is from XSVG (BSD license)
205 /*
206  * Copyright 2002 USC/Information Sciences Institute
207  *
208  * Permission to use, copy, modify, distribute, and sell this software
209  * and its documentation for any purpose is hereby granted without
210  * fee, provided that the above copyright notice appear in all copies
211  * and that both that copyright notice and this permission notice
212  * appear in supporting documentation, and that the name of
213  * Information Sciences Institute not be used in advertising or
214  * publicity pertaining to distribution of the software without
215  * specific, written prior permission. Information Sciences Institute
216  * makes no representations about the suitability of this software for
217  * any purpose. It is provided "as is" without express or implied
218  * warranty.
219  *
220  * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
221  * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
222  * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
223  * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
224  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
225  * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
226  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
227  * PERFORMANCE OF THIS SOFTWARE.
228  *
229  */
230 static void pathArc(QPainterPath &path,
231  qreal rx,
232  qreal ry,
233  qreal x_axis_rotation,
234  int large_arc_flag,
235  int sweep_flag,
236  qreal x,
237  qreal y,
238  qreal curx, qreal cury)
239 {
240  const qreal Pr1 = rx * rx;
241  const qreal Pr2 = ry * ry;
242 
243  if (!Pr1 || !Pr2)
244  return;
245 
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;
251  int i, n_segs;
252  qreal dx, dy, dx1, dy1, Px, Py, check;
253 
254  rx = qAbs(rx);
255  ry = qAbs(ry);
256 
257  sin_th = qSin(x_axis_rotation * (3.141592653589793 / 180.0));
258  cos_th = qCos(x_axis_rotation * (3.141592653589793 / 180.0));
259 
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;
264  Px = dx1 * dx1;
265  Py = dy1 * dy1;
266  /* Spec : check if radii are large enough */
267  check = Px / Pr1 + Py / Pr2;
268  if (check > 1) {
269  rx = rx * qSqrt(check);
270  ry = ry * qSqrt(check);
271  }
272 
273  a00 = cos_th / rx;
274  a01 = sin_th / rx;
275  a10 = -sin_th / ry;
276  a11 = cos_th / ry;
277  x0 = a00 * curx + a01 * cury;
278  y0 = a10 * curx + a11 * cury;
279  x1 = a00 * x + a01 * y;
280  y1 = a10 * x + a11 * y;
281  /* (x0, y0) is current point in transformed coordinate space.
282  (x1, y1) is new point in transformed coordinate space.
283 
284  The arc fits a unit-radius circle in this space.
285  */
286  d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
287  if (!d)
288  return;
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);
295  /* (xc, yc) is center of the circle. */
296 
297  th0 = qAtan2(y0 - yc, x0 - xc);
298  th1 = qAtan2(y1 - yc, x1 - xc);
299 
300  th_arc = th1 - th0;
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;
305 
306  n_segs = qCeil(qAbs(th_arc / (3.141592653589793 * 0.5 + 0.001)));
307 
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);
313  }
314 }
315 
316 #if HAVE_QSTRINGVIEW
317 static QTransform parseTransformationMatrix(QStringView value)
318 #else
319 static QTransform parseTransformationMatrix(const QStringRef &value)
320 #endif
321 {
322  if (value.isEmpty())
323  return QTransform();
324 
325  QTransform matrix;
326 #if HAVE_QSTRINGVIEW
327  const QChar *str = value.data();
328  const QChar *end = str + value.size();
329 #else
330  const QChar *str = value.constData();
331  const QChar *end = str + value.length();
332 #endif
333 
334  while (str < end) {
335  if (str->isSpace() || *str == QLatin1Char(',')) {
336  ++str;
337  continue;
338  }
339  enum State {
340  Matrix,
341  Translate,
342  Rotate,
343  Scale,
344  SkewX,
345  SkewY
346  };
347  State state = Matrix;
348  if (*str == QLatin1Char('m')) { //matrix
349  const char *ident = "atrix";
350  for (int i = 0; i < 5; ++i)
351  if (*(++str) != QLatin1Char(ident[i]))
352  goto error;
353  ++str;
354  state = Matrix;
355  } else if (*str == QLatin1Char('t')) { //translate
356  const char *ident = "ranslate";
357  for (int i = 0; i < 8; ++i)
358  if (*(++str) != QLatin1Char(ident[i]))
359  goto error;
360  ++str;
361  state = Translate;
362  } else if (*str == QLatin1Char('r')) { //rotate
363  const char *ident = "otate";
364  for (int i = 0; i < 5; ++i)
365  if (*(++str) != QLatin1Char(ident[i]))
366  goto error;
367  ++str;
368  state = Rotate;
369  } else if (*str == QLatin1Char('s')) { //scale, skewX, skewY
370  ++str;
371  if (*str == QLatin1Char('c')) {
372  const char *ident = "ale";
373  for (int i = 0; i < 3; ++i)
374  if (*(++str) != QLatin1Char(ident[i]))
375  goto error;
376  ++str;
377  state = Scale;
378  } else if (*str == QLatin1Char('k')) {
379  if (*(++str) != QLatin1Char('e'))
380  goto error;
381  if (*(++str) != QLatin1Char('w'))
382  goto error;
383  ++str;
384  if (*str == QLatin1Char('X'))
385  state = SkewX;
386  else if (*str == QLatin1Char('Y'))
387  state = SkewY;
388  else
389  goto error;
390  ++str;
391  } else {
392  goto error;
393  }
394  } else {
395  goto error;
396  }
397 
398 
399  while (str < end && str->isSpace())
400  ++str;
401  if (*str != QLatin1Char('('))
402  goto error;
403  ++str;
404  QVarLengthArray<qreal, 8> points;
405  parseNumbersArray(str, points);
406  if (*str != QLatin1Char(')'))
407  goto error;
408  ++str;
409 
410  if(state == Matrix) {
411  if(points.count() != 6)
412  goto error;
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]);
421  else
422  goto error;
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]);
430  } else {
431  goto error;
432  }
433  } else if (state == Scale) {
434  if (points.count() < 1 || points.count() > 2)
435  goto error;
436  qreal sx = points[0];
437  qreal sy = sx;
438  if(points.count() == 2)
439  sy = points[1];
440  matrix.scale(sx, sy);
441  } else if (state == SkewX) {
442  if (points.count() != 1)
443  goto error;
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)
448  goto error;
449  const qreal deg2rad = qreal(0.017453292519943295769);
450  matrix.shear(0, qTan(points[0]*deg2rad));
451  }
452  }
453  error:
454  return matrix;
455 }
456 
457 #if HAVE_QSTRINGVIEW
458 static bool parsePathDataFast(QStringView dataStr, QPainterPath &path)
459 #else
460 static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path)
461 #endif
462 {
463  const int maxElementCount = 0x7fff; // Assume file corruption if more path elements than this
464  qreal x0 = 0, y0 = 0; // starting point
465  qreal x = 0, y = 0; // current point
466  char lastMode = 0;
467  QPointF ctrlPt;
468 #if HAVE_QSTRINGVIEW
469  const QChar *str = dataStr.data();
470 #else
471  const QChar *str = dataStr.constData();
472 #endif
473  const QChar *end = str + dataStr.size();
474 
475  bool ok = true;
476  while (ok && str != end) {
477  while (str->isSpace() && (str + 1) != end)
478  ++str;
479  QChar pathElem = *str;
480  ++str;
481  QChar endc = *end;
482  *const_cast<QChar *>(end) = u'\0'; // parseNumbersArray requires 0-termination that QStringView cannot guarantee
483  const char *pattern = nullptr;
484  if (pathElem == QLatin1Char('a') || pathElem == QLatin1Char('A'))
485  pattern = "rrrffrr";
486  QVarLengthArray<qreal, 8> arg;
487  parseNumbersArray(str, arg, pattern);
488  *const_cast<QChar *>(end) = endc;
489  if (pathElem == QLatin1Char('z') || pathElem == QLatin1Char('Z'))
490  arg.append(0);//dummy
491  const qreal *num = arg.constData();
492  int count = arg.count();
493  while (ok && count > 0) {
494  qreal offsetX = x; // correction offsets
495  qreal offsetY = y; // for relative commands
496  switch (pathElem.unicode()) {
497  case 'm': {
498  if (count < 2) {
499  ok = false;
500  break;
501  }
502  x = x0 = num[0] + offsetX;
503  y = y0 = num[1] + offsetY;
504  num += 2;
505  count -= 2;
506  path.moveTo(x0, y0);
507 
508  // As per 1.2 spec 8.3.2 The "moveto" commands
509  // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
510  // the subsequent pairs shall be treated as implicit 'lineto' commands.
511  pathElem = QLatin1Char('l');
512  }
513  break;
514  case 'M': {
515  if (count < 2) {
516  ok = false;
517  break;
518  }
519  x = x0 = num[0];
520  y = y0 = num[1];
521  num += 2;
522  count -= 2;
523  path.moveTo(x0, y0);
524 
525  // As per 1.2 spec 8.3.2 The "moveto" commands
526  // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands,
527  // the subsequent pairs shall be treated as implicit 'lineto' commands.
528  pathElem = QLatin1Char('L');
529  }
530  break;
531  case 'z':
532  case 'Z': {
533  x = x0;
534  y = y0;
535  count--; // skip dummy
536  num++;
537  path.closeSubpath();
538  }
539  break;
540  case 'l': {
541  if (count < 2) {
542  ok = false;
543  break;
544  }
545  x = num[0] + offsetX;
546  y = num[1] + offsetY;
547  num += 2;
548  count -= 2;
549  path.lineTo(x, y);
550 
551  }
552  break;
553  case 'L': {
554  if (count < 2) {
555  ok = false;
556  break;
557  }
558  x = num[0];
559  y = num[1];
560  num += 2;
561  count -= 2;
562  path.lineTo(x, y);
563  }
564  break;
565  case 'h': {
566  x = num[0] + offsetX;
567  num++;
568  count--;
569  path.lineTo(x, y);
570  }
571  break;
572  case 'H': {
573  x = num[0];
574  num++;
575  count--;
576  path.lineTo(x, y);
577  }
578  break;
579  case 'v': {
580  y = num[0] + offsetY;
581  num++;
582  count--;
583  path.lineTo(x, y);
584  }
585  break;
586  case 'V': {
587  y = num[0];
588  num++;
589  count--;
590  path.lineTo(x, y);
591  }
592  break;
593  case 'c': {
594  if (count < 6) {
595  ok = false;
596  break;
597  }
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);
601  num += 6;
602  count -= 6;
603  path.cubicTo(c1, c2, e);
604  ctrlPt = c2;
605  x = e.x();
606  y = e.y();
607  break;
608  }
609  case 'C': {
610  if (count < 6) {
611  ok = false;
612  break;
613  }
614  QPointF c1(num[0], num[1]);
615  QPointF c2(num[2], num[3]);
616  QPointF e(num[4], num[5]);
617  num += 6;
618  count -= 6;
619  path.cubicTo(c1, c2, e);
620  ctrlPt = c2;
621  x = e.x();
622  y = e.y();
623  break;
624  }
625  case 's': {
626  if (count < 4) {
627  ok = false;
628  break;
629  }
630  QPointF c1;
631  if (lastMode == 'c' || lastMode == 'C' ||
632  lastMode == 's' || lastMode == 'S')
633  c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
634  else
635  c1 = QPointF(x, y);
636  QPointF c2(num[0] + offsetX, num[1] + offsetY);
637  QPointF e(num[2] + offsetX, num[3] + offsetY);
638  num += 4;
639  count -= 4;
640  path.cubicTo(c1, c2, e);
641  ctrlPt = c2;
642  x = e.x();
643  y = e.y();
644  break;
645  }
646  case 'S': {
647  if (count < 4) {
648  ok = false;
649  break;
650  }
651  QPointF c1;
652  if (lastMode == 'c' || lastMode == 'C' ||
653  lastMode == 's' || lastMode == 'S')
654  c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
655  else
656  c1 = QPointF(x, y);
657  QPointF c2(num[0], num[1]);
658  QPointF e(num[2], num[3]);
659  num += 4;
660  count -= 4;
661  path.cubicTo(c1, c2, e);
662  ctrlPt = c2;
663  x = e.x();
664  y = e.y();
665  break;
666  }
667  case 'q': {
668  if (count < 4) {
669  ok = false;
670  break;
671  }
672  QPointF c(num[0] + offsetX, num[1] + offsetY);
673  QPointF e(num[2] + offsetX, num[3] + offsetY);
674  num += 4;
675  count -= 4;
676  path.quadTo(c, e);
677  ctrlPt = c;
678  x = e.x();
679  y = e.y();
680  break;
681  }
682  case 'Q': {
683  if (count < 4) {
684  ok = false;
685  break;
686  }
687  QPointF c(num[0], num[1]);
688  QPointF e(num[2], num[3]);
689  num += 4;
690  count -= 4;
691  path.quadTo(c, e);
692  ctrlPt = c;
693  x = e.x();
694  y = e.y();
695  break;
696  }
697  case 't': {
698  if (count < 2) {
699  ok = false;
700  break;
701  }
702  QPointF e(num[0] + offsetX, num[1] + offsetY);
703  num += 2;
704  count -= 2;
705  QPointF c;
706  if (lastMode == 'q' || lastMode == 'Q' ||
707  lastMode == 't' || lastMode == 'T')
708  c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
709  else
710  c = QPointF(x, y);
711  path.quadTo(c, e);
712  ctrlPt = c;
713  x = e.x();
714  y = e.y();
715  break;
716  }
717  case 'T': {
718  if (count < 2) {
719  ok = false;
720  break;
721  }
722  QPointF e(num[0], num[1]);
723  num += 2;
724  count -= 2;
725  QPointF c;
726  if (lastMode == 'q' || lastMode == 'Q' ||
727  lastMode == 't' || lastMode == 'T')
728  c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y());
729  else
730  c = QPointF(x, y);
731  path.quadTo(c, e);
732  ctrlPt = c;
733  x = e.x();
734  y = e.y();
735  break;
736  }
737  case 'a': {
738  if (count < 7) {
739  ok = false;
740  break;
741  }
742  qreal rx = (*num++);
743  qreal ry = (*num++);
744  qreal xAxisRotation = (*num++);
745  qreal largeArcFlag = (*num++);
746  qreal sweepFlag = (*num++);
747  qreal ex = (*num++) + offsetX;
748  qreal ey = (*num++) + offsetY;
749  count -= 7;
750  qreal curx = x;
751  qreal cury = y;
752  pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
753  int(sweepFlag), ex, ey, curx, cury);
754 
755  x = ex;
756  y = ey;
757  }
758  break;
759  case 'A': {
760  if (count < 7) {
761  ok = false;
762  break;
763  }
764  qreal rx = (*num++);
765  qreal ry = (*num++);
766  qreal xAxisRotation = (*num++);
767  qreal largeArcFlag = (*num++);
768  qreal sweepFlag = (*num++);
769  qreal ex = (*num++);
770  qreal ey = (*num++);
771  count -= 7;
772  qreal curx = x;
773  qreal cury = y;
774  pathArc(path, rx, ry, xAxisRotation, int(largeArcFlag),
775  int(sweepFlag), ex, ey, curx, cury);
776 
777  x = ex;
778  y = ey;
779  }
780  break;
781  default:
782  ok = false;
783  break;
784  }
785  lastMode = pathElem.toLatin1();
786  if (path.elementCount() > maxElementCount)
787  ok = false;
788  }
789  }
790  return ok;
791 }
Definition: dMatrix.h:42
void() error(const char *fmt,...)
Definition: error.cc:988
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x