qpathclipper.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/painting/qpathclipper.cpp
Switch to Source codePreprocessed file
LineSourceCount
1-
2-
3-
4-
5static inline bool fuzzyIsNull(qreal d)-
6{-
7 if (sizeof(qreal) == sizeof(double))-
8 return qAbs(d) <= 1e-12;-
9 else-
10 return qAbs(d) <= 1e-5f;-
11}-
12-
13static inline bool comparePoints(const QPointF &a, const QPointF &b)-
14{-
15 return fuzzyIsNull(a.x() - b.x())-
16 && fuzzyIsNull(a.y() - b.y());-
17}-
18-
19-
20static qreal dot(const QPointF &a, const QPointF &b)-
21{-
22 return a.x() * b.x() + a.y() * b.y();-
23}-
24-
25static void normalize(double &x, double &y)-
26{-
27 double reciprocal = 1 / qSqrt(x * x + y * y);-
28 x *= reciprocal;-
29 y *= reciprocal;-
30}-
31-
32struct QIntersection-
33{-
34 qreal alphaA;-
35 qreal alphaB;-
36-
37 QPointF pos;-
38};-
39-
40class QIntersectionFinder-
41{-
42public:-
43 void produceIntersections(QPathSegments &segments);-
44 bool hasIntersections(const QPathSegments &a, const QPathSegments &b) const;-
45-
46private:-
47 bool linesIntersect(const QLineF &a, const QLineF &b) const;-
48};-
49-
50bool QIntersectionFinder::linesIntersect(const QLineF &a, const QLineF &b) const-
51{-
52 const QPointF p1 = a.p1();-
53 const QPointF p2 = a.p2();-
54-
55 const QPointF q1 = b.p1();-
56 const QPointF q2 = b.p2();-
57-
58 if (comparePoints(p1, p2) || comparePoints(q1, q2))-
59 return false;-
60-
61 const bool p1_equals_q1 = comparePoints(p1, q1);-
62 const bool p2_equals_q2 = comparePoints(p2, q2);-
63-
64 if (p1_equals_q1 && p2_equals_q2)-
65 return true;-
66-
67 const bool p1_equals_q2 = comparePoints(p1, q2);-
68 const bool p2_equals_q1 = comparePoints(p2, q1);-
69-
70 if (p1_equals_q2 && p2_equals_q1)-
71 return true;-
72-
73 const QPointF pDelta = p2 - p1;-
74 const QPointF qDelta = q2 - q1;-
75-
76 const qreal par = pDelta.x() * qDelta.y() - pDelta.y() * qDelta.x();-
77-
78 if (qFuzzyIsNull(par)) {-
79 const QPointF normal(-pDelta.y(), pDelta.x());-
80-
81-
82 if (qFuzzyIsNull(dot(normal, q1 - p1))) {-
83 const qreal dp = dot(pDelta, pDelta);-
84-
85 const qreal tq1 = dot(pDelta, q1 - p1);-
86 const qreal tq2 = dot(pDelta, q2 - p1);-
87-
88 if ((tq1 > 0 && tq1 < dp) || (tq2 > 0 && tq2 < dp))-
89 return true;-
90-
91 const qreal dq = dot(qDelta, qDelta);-
92-
93 const qreal tp1 = dot(qDelta, p1 - q1);-
94 const qreal tp2 = dot(qDelta, p2 - q1);-
95-
96 if ((tp1 > 0 && tp1 < dq) || (tp2 > 0 && tp2 < dq))-
97 return true;-
98 }-
99-
100 return false;-
101 }-
102-
103 const qreal invPar = 1 / par;-
104-
105 const qreal tp = (qDelta.y() * (q1.x() - p1.x()) --
106 qDelta.x() * (q1.y() - p1.y())) * invPar;-
107-
108 if (tp < 0 || tp > 1)-
109 return false;-
110-
111 const qreal tq = (pDelta.y() * (q1.x() - p1.x()) --
112 pDelta.x() * (q1.y() - p1.y())) * invPar;-
113-
114 return tq >= 0 && tq <= 1;-
115}-
116-
117bool QIntersectionFinder::hasIntersections(const QPathSegments &a, const QPathSegments &b) const-
118{-
119 if (a.segments() == 0 || b.segments() == 0)-
120 return false;-
121-
122 const QRectF &rb0 = b.elementBounds(0);-
123-
124 qreal minX = rb0.left();-
125 qreal minY = rb0.top();-
126 qreal maxX = rb0.right();-
127 qreal maxY = rb0.bottom();-
128-
129 for (int i = 1; i < b.segments(); ++i) {-
130 const QRectF &r = b.elementBounds(i);-
131 minX = qMin(minX, r.left());-
132 minY = qMin(minY, r.top());-
133 maxX = qMax(maxX, r.right());-
134 maxY = qMax(maxY, r.bottom());-
135 }-
136-
137 QRectF rb(minX, minY, maxX - minX, maxY - minY);-
138-
139 for (int i = 0; i < a.segments(); ++i) {-
140 const QRectF &r1 = a.elementBounds(i);-
141-
142 if (r1.left() > rb.right() || rb.left() > r1.right())-
143 continue;-
144 if (r1.top() > rb.bottom() || rb.top() > r1.bottom())-
145 continue;-
146-
147 for (int j = 0; j < b.segments(); ++j) {-
148 const QRectF &r2 = b.elementBounds(j);-
149-
150 if (r1.left() > r2.right() || r2.left() > r1.right())-
151 continue;-
152 if (r1.top() > r2.bottom() || r2.top() > r1.bottom())-
153 continue;-
154-
155 if (linesIntersect(a.lineAt(i), b.lineAt(j)))-
156 return true;-
157 }-
158 }-
159-
160 return false;-
161}-
162-
163namespace {-
164struct TreeNode-
165{-
166 qreal splitLeft;-
167 qreal splitRight;-
168 bool leaf;-
169-
170 int lowestLeftIndex;-
171 int lowestRightIndex;-
172-
173 union {-
174 struct {-
175 int first;-
176 int last;-
177 } interval;-
178 struct {-
179 int left;-
180 int right;-
181 } children;-
182 } index;-
183};-
184-
185struct RectF-
186{-
187 qreal x1;-
188 qreal y1;-
189 qreal x2;-
190 qreal y2;-
191};-
192-
193class SegmentTree-
194{-
195public:-
196 SegmentTree(QPathSegments &segments);-
197-
198 void produceIntersections(int segment);-
199-
200private:-
201 TreeNode buildTree(int first, int last, int depth, const RectF &bounds);-
202-
203 void produceIntersectionsLeaf(const TreeNode &node, int segment);-
204 void produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis);-
205 void intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections);-
206-
207 QPathSegments &m_segments;-
208 QVector<int> m_index;-
209-
210 RectF m_bounds;-
211-
212 QVector<TreeNode> m_tree;-
213 QDataBuffer<QIntersection> m_intersections;-
214};-
215-
216SegmentTree::SegmentTree(QPathSegments &segments)-
217 : m_segments(segments),-
218 m_intersections(0)-
219{-
220 m_bounds.x1 = qt_inf();-
221 m_bounds.y1 = qt_inf();-
222 m_bounds.x2 = -qt_inf();-
223 m_bounds.y2 = -qt_inf();-
224-
225 m_index.resize(m_segments.segments());-
226-
227 for (int i = 0; i < m_index.size(); ++i) {-
228 m_index[i] = i;-
229-
230 const QRectF &segmentBounds = m_segments.elementBounds(i);-
231-
232 if (segmentBounds.left() < m_bounds.x1)-
233 m_bounds.x1 = segmentBounds.left();-
234 if (segmentBounds.top() < m_bounds.y1)-
235 m_bounds.y1 = segmentBounds.top();-
236 if (segmentBounds.right() > m_bounds.x2)-
237 m_bounds.x2 = segmentBounds.right();-
238 if (segmentBounds.bottom() > m_bounds.y2)-
239 m_bounds.y2 = segmentBounds.bottom();-
240 }-
241-
242 m_tree.resize(1);-
243-
244 TreeNode root = buildTree(0, m_index.size(), 0, m_bounds);-
245 m_tree[0] = root;-
246}-
247-
248static inline qreal coordinate(const QPointF &pos, int axis)-
249{-
250 return axis == 0 ? pos.x() : pos.y();-
251}-
252-
253TreeNode SegmentTree::buildTree(int first, int last, int depth, const RectF &bounds)-
254{-
255 if (depth >= 24 || (last - first) <= 10) {-
256 TreeNode node;-
257 node.leaf = true;-
258 node.index.interval.first = first;-
259 node.index.interval.last = last;-
260-
261 return node;-
262 }-
263-
264 int splitAxis = (depth & 1);-
265-
266 TreeNode node;-
267 node.leaf = false;-
268-
269 qreal split = 0.5f * ((&bounds.x1)[splitAxis] + (&bounds.x2)[splitAxis]);-
270-
271 node.splitLeft = (&bounds.x1)[splitAxis];-
272 node.splitRight = (&bounds.x2)[splitAxis];-
273-
274 node.lowestLeftIndex = 2147483647;-
275 node.lowestRightIndex = 2147483647;-
276-
277 const int treeSize = m_tree.size();-
278-
279 node.index.children.left = treeSize;-
280 node.index.children.right = treeSize + 1;-
281-
282 m_tree.resize(treeSize + 2);-
283-
284 int l = first;-
285 int r = last - 1;-
286-
287-
288 while (l <= r) {-
289 const int index = m_index.at(l);-
290 const QRectF &segmentBounds = m_segments.elementBounds(index);-
291-
292 qreal lowCoordinate = coordinate(segmentBounds.topLeft(), splitAxis);-
293-
294 if (coordinate(segmentBounds.center(), splitAxis) < split) {-
295 qreal highCoordinate = coordinate(segmentBounds.bottomRight(), splitAxis);-
296 if (highCoordinate > node.splitLeft)-
297 node.splitLeft = highCoordinate;-
298 if (index < node.lowestLeftIndex)-
299 node.lowestLeftIndex = index;-
300 ++l;-
301 } else {-
302 if (lowCoordinate < node.splitRight)-
303 node.splitRight = lowCoordinate;-
304 if (index < node.lowestRightIndex)-
305 node.lowestRightIndex = index;-
306 qSwap(m_index[l], m_index[r]);-
307 --r;-
308 }-
309 }-
310-
311 RectF lbounds = bounds;-
312 (&lbounds.x2)[splitAxis] = node.splitLeft;-
313-
314 RectF rbounds = bounds;-
315 (&rbounds.x1)[splitAxis] = node.splitRight;-
316-
317 TreeNode left = buildTree(first, l, depth + 1, lbounds);-
318 m_tree[node.index.children.left] = left;-
319-
320 TreeNode right = buildTree(l, last, depth + 1, rbounds);-
321 m_tree[node.index.children.right] = right;-
322-
323 return node;-
324}-
325-
326void SegmentTree::intersectLines(const QLineF &a, const QLineF &b, QDataBuffer<QIntersection> &intersections)-
327{-
328 const QPointF p1 = a.p1();-
329 const QPointF p2 = a.p2();-
330-
331 const QPointF q1 = b.p1();-
332 const QPointF q2 = b.p2();-
333-
334 if (comparePoints(p1, p2) || comparePoints(q1, q2))-
335 return;-
336-
337 const bool p1_equals_q1 = comparePoints(p1, q1);-
338 const bool p2_equals_q2 = comparePoints(p2, q2);-
339-
340 if (p1_equals_q1 && p2_equals_q2)-
341 return;-
342-
343 const bool p1_equals_q2 = comparePoints(p1, q2);-
344 const bool p2_equals_q1 = comparePoints(p2, q1);-
345-
346 if (p1_equals_q2 && p2_equals_q1)-
347 return;-
348-
349 const QPointF pDelta = p2 - p1;-
350 const QPointF qDelta = q2 - q1;-
351-
352 const qreal par = pDelta.x() * qDelta.y() - pDelta.y() * qDelta.x();-
353-
354 if (qFuzzyIsNull(par)) {-
355 const QPointF normal(-pDelta.y(), pDelta.x());-
356-
357-
358 if (qFuzzyIsNull(dot(normal, q1 - p1))) {-
359 const qreal invDp = 1 / dot(pDelta, pDelta);-
360-
361 const qreal tq1 = dot(pDelta, q1 - p1) * invDp;-
362 const qreal tq2 = dot(pDelta, q2 - p1) * invDp;-
363-
364 if (tq1 > 0 && tq1 < 1) {-
365 QIntersection intersection;-
366 intersection.alphaA = tq1;-
367 intersection.alphaB = 0;-
368 intersection.pos = q1;-
369 intersections.add(intersection);-
370 }-
371-
372 if (tq2 > 0 && tq2 < 1) {-
373 QIntersection intersection;-
374 intersection.alphaA = tq2;-
375 intersection.alphaB = 1;-
376 intersection.pos = q2;-
377 intersections.add(intersection);-
378 }-
379-
380 const qreal invDq = 1 / dot(qDelta, qDelta);-
381-
382 const qreal tp1 = dot(qDelta, p1 - q1) * invDq;-
383 const qreal tp2 = dot(qDelta, p2 - q1) * invDq;-
384-
385 if (tp1 > 0 && tp1 < 1) {-
386 QIntersection intersection;-
387 intersection.alphaA = 0;-
388 intersection.alphaB = tp1;-
389 intersection.pos = p1;-
390 intersections.add(intersection);-
391 }-
392-
393 if (tp2 > 0 && tp2 < 1) {-
394 QIntersection intersection;-
395 intersection.alphaA = 1;-
396 intersection.alphaB = tp2;-
397 intersection.pos = p2;-
398 intersections.add(intersection);-
399 }-
400 }-
401-
402 return;-
403 }-
404-
405-
406-
407 if (p1_equals_q1 || p1_equals_q2 || p2_equals_q1 || p2_equals_q2)-
408 return;-
409-
410-
411 const qreal tp = (qDelta.y() * (q1.x() - p1.x()) --
412 qDelta.x() * (q1.y() - p1.y())) / par;-
413 const qreal tq = (pDelta.y() * (q1.x() - p1.x()) --
414 pDelta.x() * (q1.y() - p1.y())) / par;-
415-
416 if (tp<0 || tp>1 || tq<0 || tq>1)-
417 return;-
418-
419 const bool p_zero = qFuzzyIsNull(tp);-
420 const bool p_one = qFuzzyIsNull(tp - 1);-
421-
422 const bool q_zero = qFuzzyIsNull(tq);-
423 const bool q_one = qFuzzyIsNull(tq - 1);-
424-
425 if ((q_zero || q_one) && (p_zero || p_one))-
426 return;-
427-
428 QPointF pt;-
429 if (p_zero) {-
430 pt = p1;-
431 } else if (p_one) {-
432 pt = p2;-
433 } else if (q_zero) {-
434 pt = q1;-
435 } else if (q_one) {-
436 pt = q2;-
437 } else {-
438 pt = q1 + (q2 - q1) * tq;-
439 }-
440-
441 QIntersection intersection;-
442 intersection.alphaA = tp;-
443 intersection.alphaB = tq;-
444 intersection.pos = pt;-
445 intersections.add(intersection);-
446}-
447-
448void SegmentTree::produceIntersections(int segment)-
449{-
450 const QRectF &segmentBounds = m_segments.elementBounds(segment);-
451-
452 RectF sbounds;-
453 sbounds.x1 = segmentBounds.left();-
454 sbounds.y1 = segmentBounds.top();-
455 sbounds.x2 = segmentBounds.right();-
456 sbounds.y2 = segmentBounds.bottom();-
457-
458 produceIntersections(m_tree.at(0), segment, sbounds, m_bounds, 0);-
459}-
460-
461void SegmentTree::produceIntersectionsLeaf(const TreeNode &node, int segment)-
462{-
463 const QRectF &r1 = m_segments.elementBounds(segment);-
464 const QLineF lineA = m_segments.lineAt(segment);-
465-
466 for (int i = node.index.interval.first; i < node.index.interval.last; ++i) {-
467 const int other = m_index.at(i);-
468 if (other >= segment)-
469 continue;-
470-
471 const QRectF &r2 = m_segments.elementBounds(other);-
472-
473 if (r1.left() > r2.right() || r2.left() > r1.right())-
474 continue;-
475 if (r1.top() > r2.bottom() || r2.top() > r1.bottom())-
476 continue;-
477-
478 m_intersections.reset();-
479-
480 const QLineF lineB = m_segments.lineAt(other);-
481-
482 intersectLines(lineA, lineB, m_intersections);-
483-
484 for (int k = 0; k < m_intersections.size(); ++k) {-
485 QPathSegments::Intersection i_isect, j_isect;-
486 i_isect.t = m_intersections.at(k).alphaA;-
487 j_isect.t = m_intersections.at(k).alphaB;-
488-
489 i_isect.vertex = j_isect.vertex = m_segments.addPoint(m_intersections.at(k).pos);-
490-
491 i_isect.next = 0;-
492 j_isect.next = 0;-
493-
494 m_segments.addIntersection(segment, i_isect);-
495 m_segments.addIntersection(other, j_isect);-
496 }-
497 }-
498}-
499-
500void SegmentTree::produceIntersections(const TreeNode &node, int segment, const RectF &segmentBounds, const RectF &nodeBounds, int axis)-
501{-
502 if (node.leaf) {-
503 produceIntersectionsLeaf(node, segment);-
504 return;-
505 }-
506-
507 RectF lbounds = nodeBounds;-
508 (&lbounds.x2)[axis] = node.splitLeft;-
509-
510 RectF rbounds = nodeBounds;-
511 (&rbounds.x1)[axis] = node.splitRight;-
512-
513 if (segment > node.lowestLeftIndex && (&segmentBounds.x1)[axis] <= node.splitLeft)-
514 produceIntersections(m_tree.at(node.index.children.left), segment, segmentBounds, lbounds, !axis);-
515-
516 if (segment > node.lowestRightIndex && (&segmentBounds.x2)[axis] >= node.splitRight)-
517 produceIntersections(m_tree.at(node.index.children.right), segment, segmentBounds, rbounds, !axis);-
518}-
519-
520}-
521-
522void QIntersectionFinder::produceIntersections(QPathSegments &segments)-
523{-
524 SegmentTree tree(segments);-
525-
526 for (int i = 0; i < segments.segments(); ++i)-
527 tree.produceIntersections(i);-
528}-
529-
530class QKdPointTree-
531{-
532public:-
533 enum Traversal {-
534 TraverseBoth,-
535 TraverseLeft,-
536 TraverseRight,-
537 TraverseNone-
538 };-
539-
540 struct Node {-
541 int point;-
542 int id;-
543-
544 Node *left;-
545 Node *right;-
546 };-
547-
548 QKdPointTree(const QPathSegments &segments)-
549 : m_segments(&segments)-
550 , m_nodes(m_segments->points())-
551 , m_id(0)-
552 {-
553 m_nodes.resize(m_segments->points());-
554-
555 for (int i = 0; i < m_nodes.size(); ++i) {-
556 m_nodes.at(i).point = i;-
557 m_nodes.at(i).id = -1;-
558 }-
559-
560 m_rootNode = build(0, m_nodes.size());-
561 }-
562-
563 int build(int begin, int end, int depth = 0);-
564-
565 Node *rootNode()-
566 {-
567 return &m_nodes.at(m_rootNode);-
568 }-
569-
570 inline int nextId()-
571 {-
572 return m_id++;-
573 }-
574-
575private:-
576 const QPathSegments *m_segments;-
577 QDataBuffer<Node> m_nodes;-
578-
579 int m_rootNode;-
580 int m_id;-
581};-
582-
583template <typename T>-
584void qTraverseKdPointTree(QKdPointTree::Node &node, T &t, int depth = 0)-
585{-
586 QKdPointTree::Traversal status = t(node, depth);-
587-
588 const bool traverseRight = (status == QKdPointTree::TraverseBoth || status == QKdPointTree::TraverseRight);-
589 const bool traverseLeft = (status == QKdPointTree::TraverseBoth || status == QKdPointTree::TraverseLeft);-
590-
591 if (traverseLeft && node.left)-
592 ::qTraverseKdPointTree<T>(*node.left, t, depth + 1);-
593-
594 if (traverseRight && node.right)-
595 ::qTraverseKdPointTree<T>(*node.right, t, depth + 1);-
596}-
597-
598static inline qreal component(const QPointF &point, unsigned int i)-
599{-
600 ((!(i < 2)) ? qt_assert("i < 2",__FILE__,657663) : qt_noop());-
601 const qreal components[] = { point.x(), point.y() };-
602 return components[i];-
603}-
604-
605int QKdPointTree::build(int begin, int end, int depth)-
606{-
607 ((!(end > begin)) ? qt_assert("end > begin",__FILE__,664670) : qt_noop());-
608-
609 const qreal pivot = component(m_segments->pointAt(m_nodes.at(begin).point), depth & 1);-
610-
611 int first = begin + 1;-
612 int last = end - 1;-
613-
614 while (first <= last) {-
615 const qreal value = component(m_segments->pointAt(m_nodes.at(first).point), depth & 1);-
616-
617 if (value < pivot)-
618 ++first;-
619 else {-
620 qSwap(m_nodes.at(first), m_nodes.at(last));-
621 --last;-
622 }-
623 }-
624-
625 qSwap(m_nodes.at(last), m_nodes.at(begin));-
626-
627 if (last > begin)-
628 m_nodes.at(last).left = &m_nodes.at(build(begin, last, depth + 1));-
629 else-
630 m_nodes.at(last).left = 0;-
631-
632 if (last + 1 < end)-
633 m_nodes.at(last).right = &m_nodes.at(build(last + 1, end, depth + 1));-
634 else-
635 m_nodes.at(last).right = 0;-
636-
637 return last;-
638}-
639-
640class QKdPointFinder-
641{-
642public:-
643 QKdPointFinder(int point, const QPathSegments &segments, QKdPointTree &tree)-
644 : m_result(-1)-
645 , m_segments(&segments)-
646 , m_tree(&tree)-
647 {-
648 pointComponents[0] = segments.pointAt(point).x();-
649 pointComponents[1] = segments.pointAt(point).y();-
650 }-
651-
652 inline QKdPointTree::Traversal operator()(QKdPointTree::Node &node, int depth)-
653 {-
654 if (m_result != -1)-
655 return QKdPointTree::TraverseNone;-
656-
657 const QPointF &nodePoint = m_segments->pointAt(node.point);-
658-
659 const qreal pivotComponents[] = { nodePoint.x(), nodePoint.y() };-
660-
661 const qreal pivot = pivotComponents[depth & 1];-
662 const qreal value = pointComponents[depth & 1];-
663-
664 if (fuzzyIsNull(pivot - value)) {-
665 const qreal pivot2 = pivotComponents[(depth + 1) & 1];-
666 const qreal value2 = pointComponents[(depth + 1) & 1];-
667-
668 if (fuzzyIsNull(pivot2 - value2)) {-
669 if (node.id < 0)-
670 node.id = m_tree->nextId();-
671-
672 m_result = node.id;-
673 return QKdPointTree::TraverseNone;-
674 } else-
675 return QKdPointTree::TraverseBoth;-
676 } else if (value < pivot) {-
677 return QKdPointTree::TraverseLeft;-
678 } else {-
679 return QKdPointTree::TraverseRight;-
680 }-
681 }-
682-
683 int result() const-
684 {-
685 return m_result;-
686 }-
687-
688private:-
689 qreal pointComponents[2];-
690 int m_result;-
691 const QPathSegments *m_segments;-
692 QKdPointTree *m_tree;-
693};-
694-
695-
696void QPathSegments::mergePoints()-
697{-
698 QKdPointTree tree(*this);-
699-
700 if (tree.rootNode()) {-
701 QDataBuffer<QPointF> mergedPoints(points());-
702 QDataBuffer<int> pointIndices(points());-
703-
704 for (int i = 0; i < points(); ++i) {-
705 QKdPointFinder finder(i, *this, tree);-
706 ::qTraverseKdPointTree<QKdPointFinder>(*tree.rootNode(), finder);-
707-
708 ((!(finder.result() != -1)) ? qt_assert("finder.result() != -1",__FILE__,765771) : qt_noop());-
709-
710 if (finder.result() >= mergedPoints.size())-
711 mergedPoints << m_points.at(i);-
712-
713 pointIndices << finder.result();-
714 }-
715-
716 for (int i = 0; i < m_segments.size(); ++i) {-
717 m_segments.at(i).va = pointIndices.at(m_segments.at(i).va);-
718 m_segments.at(i).vb = pointIndices.at(m_segments.at(i).vb);-
719 }-
720-
721 for (int i = 0; i < m_intersections.size(); ++i)-
722 m_intersections.at(i).vertex = pointIndices.at(m_intersections.at(i).vertex);-
723-
724 m_points.swap(mergedPoints);-
725 }-
726}-
727-
728void QWingedEdge::intersectAndAdd()-
729{-
730 QIntersectionFinder finder;-
731 finder.produceIntersections(m_segments);-
732-
733 m_segments.mergePoints();-
734-
735 for (int i = 0; i < m_segments.points(); ++i)-
736 addVertex(m_segments.pointAt(i));-
737-
738 QDataBuffer<QPathSegments::Intersection> intersections(m_segments.segments());-
739 for (int i = 0; i < m_segments.segments(); ++i) {-
740 intersections.reset();-
741-
742 int pathId = m_segments.pathId(i);-
743-
744 const QPathSegments::Intersection *isect = m_segments.intersectionAt(i);-
745 while (isect) {-
746 intersections << *isect;-
747-
748 if (isect->next) {-
749 isect += isect->next;-
750 } else {-
751 isect = 0;-
752 }-
753 }-
754-
755 std::sort(intersections.data(), intersections.data() + intersections.size());-
756-
757 int first = m_segments.segmentAt(i).va;-
758 int second = m_segments.segmentAt(i).vb;-
759-
760 int last = first;-
761 for (int j = 0; j < intersections.size(); ++j) {-
762 const QPathSegments::Intersection &isect = intersections.at(j);-
763-
764 QPathEdge *ep = edge(addEdge(last, isect.vertex));-
765-
766 if (ep) {-
767 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(isect.vertex).y() ? 1 : -1;-
768 if (pathId == 0)-
769 ep->windingA += dir;-
770 else-
771 ep->windingB += dir;-
772 }-
773-
774 last = isect.vertex;-
775 }-
776-
777 QPathEdge *ep = edge(addEdge(last, second));-
778-
779 if (ep) {-
780 const int dir = m_segments.pointAt(last).y() < m_segments.pointAt(second).y() ? 1 : -1;-
781 if (pathId == 0)-
782 ep->windingA += dir;-
783 else-
784 ep->windingB += dir;-
785 }-
786 }-
787}-
788-
789QWingedEdge::QWingedEdge() :-
790 m_edges(0),-
791 m_vertices(0),-
792 m_segments(0)-
793{-
794}-
795-
796QWingedEdge::QWingedEdge(const QPainterPath &subject, const QPainterPath &clip) :-
797 m_edges(subject.elementCount()),-
798 m_vertices(subject.elementCount()),-
799 m_segments(subject.elementCount())-
800{-
801 m_segments.setPath(subject);-
802 m_segments.addPath(clip);-
803-
804 intersectAndAdd();-
805}-
806-
807QWingedEdge::TraversalStatus QWingedEdge::next(const QWingedEdge::TraversalStatus &status) const-
808{-
809 const QPathEdge *sp = edge(status.edge);-
810 ((!(sp)) ? qt_assert("sp",__FILE__,867873) : qt_noop());-
811-
812 TraversalStatus result;-
813 result.edge = sp->next(status.traversal, status.direction);-
814 result.traversal = status.traversal;-
815 result.direction = status.direction;-
816-
817 const QPathEdge *rp = edge(result.edge);-
818 ((!(rp)) ? qt_assert("rp",__FILE__,875881) : qt_noop());-
819-
820 if (sp->vertex(status.direction) == rp->vertex(status.direction))-
821 result.flip();-
822-
823 return result;-
824}-
825-
826static bool isLine(const QBezier &bezier)-
827{-
828 const bool equal_1_2 = comparePoints(bezier.pt1(), bezier.pt2());-
829 const bool equal_2_3 = comparePoints(bezier.pt2(), bezier.pt3());-
830 const bool equal_3_4 = comparePoints(bezier.pt3(), bezier.pt4());-
831-
832-
833 if (equal_1_2 && equal_2_3 && equal_3_4)-
834 return true;-
835-
836 if (comparePoints(bezier.pt1(), bezier.pt4()))-
837 return equal_1_2 || equal_3_4;-
838-
839 return (equal_1_2 && equal_3_4) || (equal_1_2 && equal_2_3) || (equal_2_3 && equal_3_4);-
840}-
841-
842void QPathSegments::setPath(const QPainterPath &path)-
843{-
844 m_points.reset();-
845 m_intersections.reset();-
846 m_segments.reset();-
847-
848 m_pathId = 0;-
849-
850 addPath(path);-
851}-
852-
853void QPathSegments::addPath(const QPainterPath &path)-
854{-
855 int firstSegment = m_segments.size();-
856-
857 bool hasMoveTo = false;-
858 int lastMoveTo = 0;-
859 int last = 0;-
860 for (int i = 0; i < path.elementCount(); ++i) {-
861 int current = m_points.size();-
862-
863 QPointF currentPoint;-
864 if (path.elementAt(i).type == QPainterPath::CurveToElement)-
865 currentPoint = path.elementAt(i+2);-
866 else-
867 currentPoint = path.elementAt(i);-
868-
869 if (i > 0 && comparePoints(m_points.at(lastMoveTo), currentPoint))-
870 current = lastMoveTo;-
871 else-
872 m_points << currentPoint;-
873-
874 switch (path.elementAt(i).type) {-
875 case QPainterPath::MoveToElement:-
876 if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo)))-
877 m_segments << Segment(m_pathId, last, lastMoveTo);-
878 hasMoveTo = true;-
879 last = lastMoveTo = current;-
880 break;-
881 case QPainterPath::LineToElement:-
882 m_segments << Segment(m_pathId, last, current);-
883 last = current;-
884 break;-
885 case QPainterPath::CurveToElement:-
886 {-
887 QBezier bezier = QBezier::fromPoints(m_points.at(last), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2));-
888 if (isLine(bezier)) {-
889 m_segments << Segment(m_pathId, last, current);-
890 } else {-
891 QRectF bounds = bezier.bounds();-
892-
893-
894 int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * (2 * qreal(3.14) / 6));-
895-
896 if (threshold < 3) threshold = 3;-
897 qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1);-
898-
899 for (int t = 1; t < threshold - 1; ++t) {-
900 currentPoint = bezier.pointAt(t * one_over_threshold_minus_1);-
901-
902 int index = m_points.size();-
903 m_segments << Segment(m_pathId, last, index);-
904 last = index;-
905-
906 m_points << currentPoint;-
907 }-
908-
909 m_segments << Segment(m_pathId, last, current);-
910 }-
911 }-
912 last = current;-
913 i += 2;-
914 break;-
915 default:-
916 ((!(false)) ? qt_assert("false",__FILE__,973979) : qt_noop());-
917 break;-
918 }-
919 }-
920-
921 if (hasMoveTo && last != lastMoveTo && !comparePoints(m_points.at(last), m_points.at(lastMoveTo)))-
922 m_segments << Segment(m_pathId, last, lastMoveTo);-
923-
924 for (int i = firstSegment; i < m_segments.size(); ++i) {-
925 const QLineF line = lineAt(i);-
926-
927 qreal x1 = line.p1().x();-
928 qreal y1 = line.p1().y();-
929 qreal x2 = line.p2().x();-
930 qreal y2 = line.p2().y();-
931-
932 if (x2 < x1)-
933 qSwap(x1, x2);-
934 if (y2 < y1)-
935 qSwap(y1, y2);-
936-
937 m_segments.at(i).bounds = QRectF(x1, y1, x2 - x1, y2 - y1);-
938 }-
939-
940 ++m_pathId;-
941}-
942-
943qreal QWingedEdge::delta(int vertex, int a, int b) const-
944{-
945 const QPathEdge *ap = edge(a);-
946 const QPathEdge *bp = edge(b);-
947-
948 double a_angle = ap->angle;-
949 double b_angle = bp->angle;-
950-
951 if (vertex == ap->second)-
952 a_angle = ap->invAngle;-
953-
954 if (vertex == bp->second)-
955 b_angle = bp->invAngle;-
956-
957 double result = b_angle - a_angle;-
958-
959 if (result >= 128.)-
960 return result - 128.;-
961 else if (result < 0)-
962 return result + 128.;-
963 else-
964 return result;-
965}-
966-
967QWingedEdge::TraversalStatus QWingedEdge::findInsertStatus(int vi, int ei) const-
968{-
969 const QPathVertex *vp = vertex(vi);-
970-
971 ((!(vp)) ? qt_assert("vp",__FILE__,10281034) : qt_noop());-
972 ((!(ei >= 0)) ? qt_assert("ei >= 0",__FILE__,10291035) : qt_noop());-
973 ((!(vp->edge >= 0)) ? qt_assert("vp->edge >= 0",__FILE__,10301036) : qt_noop());-
974-
975 int position = vp->edge;-
976 qreal d = 128.;-
977-
978 TraversalStatus status;-
979 status.direction = edge(vp->edge)->directionTo(vi);-
980 status.traversal = QPathEdge::RightTraversal;-
981 status.edge = vp->edge;-
982-
983-
984-
985-
986-
987-
988 do {-
989 status = next(status);-
990 status.flip();-
991-
992 ((!(edge(status.edge)->vertex(status.direction) == vi)) ? qt_assert("edge(status.edge)->vertex(status.direction) == vi",__FILE__,10491055) : qt_noop());-
993 qreal d2 = delta(vi, ei, status.edge);-
994-
995-
996-
997-
998-
999-
1000 if (d2 < d) {-
1001 position = status.edge;-
1002 d = d2;-
1003 }-
1004 } while (status.edge != vp->edge);-
1005-
1006 status.traversal = QPathEdge::LeftTraversal;-
1007 status.direction = QPathEdge::Forward;-
1008 status.edge = position;-
1009-
1010 if (edge(status.edge)->vertex(status.direction) != vi)-
1011 status.flip();-
1012-
1013-
1014-
1015-
1016-
1017 ((!(edge(status.edge)->vertex(status.direction) == vi)) ? qt_assert("edge(status.edge)->vertex(status.direction) == vi",__FILE__,10741080) : qt_noop());-
1018-
1019 return status;-
1020}-
1021-
1022void QWingedEdge::removeEdge(int ei)-
1023{-
1024 QPathEdge *ep = edge(ei);-
1025-
1026 TraversalStatus status;-
1027 status.direction = QPathEdge::Forward;-
1028 status.traversal = QPathEdge::RightTraversal;-
1029 status.edge = ei;-
1030-
1031 TraversalStatus forwardRight = next(status);-
1032 forwardRight.flipDirection();-
1033-
1034 status.traversal = QPathEdge::LeftTraversal;-
1035 TraversalStatus forwardLeft = next(status);-
1036 forwardLeft.flipDirection();-
1037-
1038 status.direction = QPathEdge::Backward;-
1039 TraversalStatus backwardLeft = next(status);-
1040 backwardLeft.flipDirection();-
1041-
1042 status.traversal = QPathEdge::RightTraversal;-
1043 TraversalStatus backwardRight = next(status);-
1044 backwardRight.flipDirection();-
1045-
1046 edge(forwardRight.edge)->setNext(forwardRight.traversal, forwardRight.direction, forwardLeft.edge);-
1047 edge(forwardLeft.edge)->setNext(forwardLeft.traversal, forwardLeft.direction, forwardRight.edge);-
1048-
1049 edge(backwardRight.edge)->setNext(backwardRight.traversal, backwardRight.direction, backwardLeft.edge);-
1050 edge(backwardLeft.edge)->setNext(backwardLeft.traversal, backwardLeft.direction, backwardRight.edge);-
1051-
1052 ep->setNext(QPathEdge::Forward, ei);-
1053 ep->setNext(QPathEdge::Backward, ei);-
1054-
1055 QPathVertex *a = vertex(ep->first);-
1056 QPathVertex *b = vertex(ep->second);-
1057-
1058 a->edge = backwardRight.edge;-
1059 b->edge = forwardRight.edge;-
1060}-
1061-
1062static int commonEdge(const QWingedEdge &list, int a, int b)-
1063{-
1064 const QPathVertex *ap = list.vertex(a);-
1065 ((!(ap)) ? qt_assert("ap",__FILE__,11221128) : qt_noop());-
1066-
1067 const QPathVertex *bp = list.vertex(b);-
1068 ((!(bp)) ? qt_assert("bp",__FILE__,11251131) : qt_noop());-
1069-
1070 if (ap->edge < 0 || bp->edge < 0)-
1071 return -1;-
1072-
1073 QWingedEdge::TraversalStatus status;-
1074 status.edge = ap->edge;-
1075 status.direction = list.edge(status.edge)->directionTo(a);-
1076 status.traversal = QPathEdge::RightTraversal;-
1077-
1078 do {-
1079 const QPathEdge *ep = list.edge(status.edge);-
1080-
1081 if ((ep->first == a && ep->second == b)-
1082 || (ep->first == b && ep->second == a))-
1083 return status.edge;-
1084-
1085 status = list.next(status);-
1086 status.flip();-
1087 } while (status.edge != ap->edge);-
1088-
1089 return -1;-
1090}-
1091-
1092static double computeAngle(const QPointF &v)-
1093{-
1094-
1095 if (v.x() == 0) {-
1096 return v.y() <= 0 ? 0 : 64.;-
1097 } else if (v.y() == 0) {-
1098 return v.x() <= 0 ? 32. : 96.;-
1099 }-
1100-
1101 double vx = v.x();-
1102 double vy = v.y();-
1103 normalize(vx, vy);-
1104 if (vy < 0) {-
1105 if (vx < 0) {-
1106 return -32. * vx;-
1107 } else {-
1108 return 128. - 32. * vx;-
1109 }-
1110 } else {-
1111 return 64. + 32. * vx;-
1112 }-
1113-
1114-
1115-
1116-
1117}-
1118-
1119int QWingedEdge::addEdge(const QPointF &a, const QPointF &b)-
1120{-
1121 int fi = insert(a);-
1122 int si = insert(b);-
1123-
1124 return addEdge(fi, si);-
1125}-
1126-
1127int QWingedEdge::addEdge(int fi, int si)-
1128{-
1129 if (fi == si)-
1130 return -1;-
1131-
1132 int common = commonEdge(*this, fi, si);-
1133 if (common >= 0)-
1134 return common;-
1135-
1136 m_edges << QPathEdge(fi, si);-
1137-
1138 int ei = m_edges.size() - 1;-
1139-
1140 QPathVertex *fp = vertex(fi);-
1141 QPathVertex *sp = vertex(si);-
1142-
1143 QPathEdge *ep = edge(ei);-
1144-
1145 const QPointF tangent = QPointF(*sp) - QPointF(*fp);-
1146 ep->angle = computeAngle(tangent);-
1147 ep->invAngle = ep->angle + 64;-
1148 if (ep->invAngle >= 128)-
1149 ep->invAngle -= 128;-
1150-
1151 QPathVertex *vertices[2] = { fp, sp };-
1152 QPathEdge::Direction dirs[2] = { QPathEdge::Backward, QPathEdge::Forward };-
1153-
1154-
1155-
1156-
1157-
1158 for (int i = 0; i < 2; ++i) {-
1159 QPathVertex *vp = vertices[i];-
1160 if (vp->edge < 0) {-
1161 vp->edge = ei;-
1162 ep->setNext(dirs[i], ei);-
1163 } else {-
1164 int vi = ep->vertex(dirs[i]);-
1165 ((!(vertex(vi) == vertices[i])) ? qt_assert("vertex(vi) == vertices[i]",__FILE__,12221228) : qt_noop());-
1166-
1167 TraversalStatus os = findInsertStatus(vi, ei);-
1168 QPathEdge *op = edge(os.edge);-
1169-
1170 ((!(vertex(op->vertex(os.direction)) == vertices[i])) ? qt_assert("vertex(op->vertex(os.direction)) == vertices[i]",__FILE__,12271233) : qt_noop());-
1171-
1172 TraversalStatus ns = next(os);-
1173 ns.flipDirection();-
1174 QPathEdge *np = edge(ns.edge);-
1175-
1176 op->setNext(os.traversal, os.direction, ei);-
1177 np->setNext(ns.traversal, ns.direction, ei);-
1178-
1179 int oe = os.edge;-
1180 int ne = ns.edge;-
1181-
1182 os = next(os);-
1183 ns = next(ns);-
1184-
1185 os.flipDirection();-
1186 ns.flipDirection();-
1187-
1188 ((!(os.edge == ei)) ? qt_assert("os.edge == ei",__FILE__,12451251) : qt_noop());-
1189 ((!(ns.edge == ei)) ? qt_assert("ns.edge == ei",__FILE__,12461252) : qt_noop());-
1190-
1191 ep->setNext(os.traversal, os.direction, oe);-
1192 ep->setNext(ns.traversal, ns.direction, ne);-
1193 }-
1194 }-
1195-
1196 ((!(ep->next(QPathEdge::RightTraversal, QPathEdge::Forward) >= 0)) ? qt_assert("ep->next(QPathEdge::RightTraversal, QPathEdge::Forward) >= 0",__FILE__,12531259) : qt_noop());-
1197 ((!(ep->next(QPathEdge::RightTraversal, QPathEdge::Backward) >= 0)) ? qt_assert("ep->next(QPathEdge::RightTraversal, QPathEdge::Backward) >= 0",__FILE__,12541260) : qt_noop());-
1198 ((!(ep->next(QPathEdge::LeftTraversal, QPathEdge::Forward) >= 0)) ? qt_assert("ep->next(QPathEdge::LeftTraversal, QPathEdge::Forward) >= 0",__FILE__,12551261) : qt_noop());-
1199 ((!(ep->next(QPathEdge::LeftTraversal, QPathEdge::Backward) >= 0)) ? qt_assert("ep->next(QPathEdge::LeftTraversal, QPathEdge::Backward) >= 0",__FILE__,12561262) : qt_noop());-
1200-
1201 return ei;-
1202}-
1203-
1204int QWingedEdge::insert(const QPathVertex &vertex)-
1205{-
1206 if (!m_vertices.isEmpty()) {-
1207 const QPathVertex &last = m_vertices.last();-
1208 if (vertex.x == last.x && vertex.y == last.y)-
1209 return m_vertices.size() - 1;-
1210-
1211 for (int i = 0; i < m_vertices.size(); ++i) {-
1212 const QPathVertex &v = m_vertices.at(i);-
1213 if (qFuzzyCompare(v.x, vertex.x) && qFuzzyCompare(v.y, vertex.y)) {-
1214 return i;-
1215 }-
1216 }-
1217 }-
1218-
1219 m_vertices << vertex;-
1220 return m_vertices.size() - 1;-
1221}-
1222-
1223static void addLineTo(QPainterPath &path, const QPointF &point)-
1224{-
1225 const int elementCount = path.elementCount();-
1226 if (elementCount >= 2) {-
1227 const QPainterPath::Element &middle = path.elementAt(elementCount - 1);-
1228 if (middle.type == QPainterPath::LineToElement) {-
1229 const QPointF first = path.elementAt(elementCount - 2);-
1230 const QPointF d1 = point - first;-
1231 const QPointF d2 = middle - first;-
1232-
1233 const QPointF p(-d1.y(), d1.x());-
1234-
1235 if (qFuzzyIsNull(dot(p, d2))) {-
1236 path.setElementPositionAt(elementCount - 1, point.x(), point.y());-
1237 return;-
1238 }-
1239 }-
1240 }-
1241-
1242 path.lineTo(point);-
1243}-
1244-
1245static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)-
1246{-
1247 QWingedEdge::TraversalStatus status;-
1248 status.edge = edge;-
1249 status.traversal = traversal;-
1250 status.direction = QPathEdge::Forward;-
1251-
1252 path.moveTo(*list.vertex(list.edge(edge)->first));-
1253-
1254 do {-
1255 const QPathEdge *ep = list.edge(status.edge);-
1256-
1257 addLineTo(path, *list.vertex(ep->vertex(status.direction)));-
1258-
1259 if (status.traversal == QPathEdge::LeftTraversal)-
1260 ep->flag &= ~16;-
1261 else-
1262 ep->flag &= ~32;-
1263-
1264 status = list.next(status);-
1265 } while (status.edge != edge);-
1266}-
1267-
1268void QWingedEdge::simplify()-
1269{-
1270 for (int i = 0; i < edgeCount(); ++i) {-
1271 const QPathEdge *ep = edge(i);-
1272-
1273-
1274 int flag = 0x3 << 4;-
1275 if ((ep->flag & flag) == flag) {-
1276 removeEdge(i);-
1277-
1278 ep->flag &= ~flag;-
1279 }-
1280 }-
1281}-
1282-
1283QPainterPath QWingedEdge::toPath() const-
1284{-
1285 QPainterPath path;-
1286-
1287 for (int i = 0; i < edgeCount(); ++i) {-
1288 const QPathEdge *ep = edge(i);-
1289-
1290 if (ep->flag & 16) {-
1291 add(path, *this, i, QPathEdge::LeftTraversal);-
1292 }-
1293-
1294 if (ep->flag & 32)-
1295 add(path, *this, i, QPathEdge::RightTraversal);-
1296 }-
1297-
1298 return path;-
1299}-
1300-
1301bool QPathClipper::intersect()-
1302{-
1303 if (subjectPath == clipPath)-
1304 return true;-
1305-
1306 QRectF r1 = subjectPath.controlPointRect();-
1307 QRectF r2 = clipPath.controlPointRect();-
1308 if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||-
1309 qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {-
1310-
1311 return false;-
1312 }-
1313-
1314 bool subjectIsRect = pathToRect(subjectPath);-
1315 bool clipIsRect = pathToRect(clipPath);-
1316-
1317 if (subjectIsRect && clipIsRect)-
1318 return true;-
1319 else if (subjectIsRect)-
1320 return clipPath.intersects(r1);-
1321 else if (clipIsRect)-
1322 return subjectPath.intersects(r2);-
1323-
1324 QPathSegments a(subjectPath.elementCount());-
1325 a.setPath(subjectPath);-
1326 QPathSegments b(clipPath.elementCount());-
1327 b.setPath(clipPath);-
1328-
1329 QIntersectionFinder finder;-
1330 if (finder.hasIntersections(a, b))-
1331 return true;-
1332-
1333 for (int i = 0; i < clipPath.elementCount(); ++i) {-
1334 if (clipPath.elementAt(i).type == QPainterPath::MoveToElement) {-
1335 const QPointF point = clipPath.elementAt(i);-
1336 if (r1.contains(point) && subjectPath.contains(point))-
1337 return true;-
1338 }-
1339 }-
1340-
1341 for (int i = 0; i < subjectPath.elementCount(); ++i) {-
1342 if (subjectPath.elementAt(i).type == QPainterPath::MoveToElement) {-
1343 const QPointF point = subjectPath.elementAt(i);-
1344 if (r2.contains(point) && clipPath.contains(point))-
1345 return true;-
1346 }-
1347 }-
1348-
1349 return false;-
1350}-
1351-
1352bool QPathClipper::contains()-
1353{-
1354 if (subjectPath == clipPath)-
1355 return false;-
1356-
1357 QRectF r1 = subjectPath.controlPointRect();-
1358 QRectF r2 = clipPath.controlPointRect();-
1359 if (qMax(r1.x(), r2.x()) > qMin(r1.x() + r1.width(), r2.x() + r2.width()) ||-
1360 qMax(r1.y(), r2.y()) > qMin(r1.y() + r1.height(), r2.y() + r2.height())) {-
1361-
1362 return false;-
1363 }-
1364-
1365 bool clipIsRect = pathToRect(clipPath);-
1366 if (clipIsRect)-
1367 return subjectPath.contains(r2);-
1368-
1369 QPathSegments a(subjectPath.elementCount());-
1370 a.setPath(subjectPath);-
1371 QPathSegments b(clipPath.elementCount());-
1372 b.setPath(clipPath);-
1373-
1374 QIntersectionFinder finder;-
1375 if (finder.hasIntersections(a, b))-
1376 return false;-
1377-
1378 for (int i = 0; i < clipPath.elementCount(); ++i) {-
1379 if (clipPath.elementAt(i).type == QPainterPath::MoveToElement) {-
1380 const QPointF point = clipPath.elementAt(i);-
1381 if (!r1.contains(point) || !subjectPath.contains(point))-
1382 return false;-
1383 }-
1384 }-
1385-
1386 return true;-
1387}-
1388-
1389QPathClipper::QPathClipper(const QPainterPath &subject,-
1390 const QPainterPath &clip)-
1391 : subjectPath(subject)-
1392 , clipPath(clip)-
1393{-
1394 aMask = subjectPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;-
1395 bMask = clipPath.fillRule() == Qt::WindingFill ? ~0x0 : 0x1;-
1396}-
1397-
1398template <typename Iterator, typename Equality>-
1399Iterator qRemoveDuplicates(Iterator begin, Iterator end, Equality eq)-
1400{-
1401 if (begin == end)-
1402 return end;-
1403-
1404 Iterator last = begin;-
1405 ++begin;-
1406 Iterator insert = begin;-
1407 for (Iterator it = begin; it != end; ++it) {-
1408 if (!eq(*it, *last)) {-
1409 *insert++ = *it;-
1410 last = it;-
1411 }-
1412 }-
1413-
1414 return insert;-
1415}-
1416-
1417static void clear(QWingedEdge& list, int edge, QPathEdge::Traversal traversal)-
1418{-
1419 QWingedEdge::TraversalStatus status;-
1420 status.edge = edge;-
1421 status.traversal = traversal;-
1422 status.direction = QPathEdge::Forward;-
1423-
1424 do {-
1425 if (status.traversal == QPathEdge::LeftTraversal)-
1426 list.edge(status.edge)->flag |= 1;-
1427 else-
1428 list.edge(status.edge)->flag |= 2;-
1429-
1430 status = list.next(status);-
1431 } while (status.edge != edge);-
1432}-
1433-
1434template <typename InputIterator>-
1435InputIterator qFuzzyFind(InputIterator first, InputIterator last, qreal val)-
1436{-
1437 while (first != last && !::qFuzzyCompare(qreal(*first), qreal(val)))-
1438 ++first;-
1439 return first;-
1440}-
1441-
1442static bool fuzzyCompare(qreal a, qreal b)-
1443{-
1444 return qFuzzyCompare(a, b);-
1445}-
1446-
1447bool QPathClipper::pathToRect(const QPainterPath &path, QRectF *rect)-
1448{-
1449 if (path.elementCount() != 5)-
1450 return false;-
1451-
1452 const bool mightBeRect = path.elementAt(0).isMoveTo()-
1453 && path.elementAt(1).isLineTo()-
1454 && path.elementAt(2).isLineTo()-
1455 && path.elementAt(3).isLineTo()-
1456 && path.elementAt(4).isLineTo();-
1457-
1458 if (!mightBeRect)-
1459 return false;-
1460-
1461 const qreal x1 = path.elementAt(0).x;-
1462 const qreal y1 = path.elementAt(0).y;-
1463-
1464 const qreal x2 = path.elementAt(1).x;-
1465 const qreal y2 = path.elementAt(2).y;-
1466-
1467 if (path.elementAt(1).y != y1)-
1468 return false;-
1469-
1470 if (path.elementAt(2).x != x2)-
1471 return false;-
1472-
1473 if (path.elementAt(3).x != x1 || path.elementAt(3).y != y2)-
1474 return false;-
1475-
1476 if (path.elementAt(4).x != x1 || path.elementAt(4).y != y1)-
1477 return false;-
1478-
1479 if (rect)-
1480 rect->setCoords(x1, y1, x2, y2);-
1481-
1482 return true;-
1483}-
1484-
1485-
1486QPainterPath QPathClipper::clip(Operation operation)-
1487{-
1488 op = operation;-
1489-
1490 if (op != Simplify) {-
1491 if (subjectPath == clipPath)-
1492 return op == BoolSub ? QPainterPath() : subjectPath;-
1493-
1494 bool subjectIsRect = pathToRect(subjectPath, 0);-
1495 bool clipIsRect = pathToRect(clipPath, 0);-
1496-
1497 const QRectF clipBounds = clipPath.boundingRect();-
1498 const QRectF subjectBounds = subjectPath.boundingRect();-
1499-
1500 if (!clipBounds.intersects(subjectBounds)) {-
1501 switch (op) {-
1502 case BoolSub:-
1503 return subjectPath;-
1504 case BoolAnd:-
1505 return QPainterPath();-
1506 case BoolOr: {-
1507 QPainterPath result = subjectPath;-
1508 if (result.fillRule() == clipPath.fillRule()) {-
1509 result.addPath(clipPath);-
1510 } else if (result.fillRule() == Qt::WindingFill) {-
1511 result = result.simplified();-
1512 result.addPath(clipPath);-
1513 } else {-
1514 result.addPath(clipPath.simplified());-
1515 }-
1516 return result;-
1517 }-
1518 default:-
1519 break;-
1520 }-
1521 }-
1522-
1523 if (clipBounds.contains(subjectBounds)) {-
1524 if (clipIsRect) {-
1525 switch (op) {-
1526 case BoolSub:-
1527 return QPainterPath();-
1528 case BoolAnd:-
1529 return subjectPath;-
1530 case BoolOr:-
1531 return clipPath;-
1532 default:-
1533 break;-
1534 }-
1535 }-
1536 } else if (subjectBounds.contains(clipBounds)) {-
1537 if (subjectIsRect) {-
1538 switch (op) {-
1539 case BoolSub:-
1540 if (clipPath.fillRule() == Qt::OddEvenFill) {-
1541 QPainterPath result = clipPath;-
1542 result.addRect(subjectBounds);-
1543 return result;-
1544 } else {-
1545 QPainterPath result = clipPath.simplified();-
1546 result.addRect(subjectBounds);-
1547 return result;-
1548 }-
1549 case BoolAnd:-
1550 return clipPath;-
1551 case BoolOr:-
1552 return subjectPath;-
1553 default:-
1554 break;-
1555 }-
1556 }-
1557 }-
1558-
1559 if (op == BoolAnd) {-
1560 if (subjectIsRect)-
1561 return intersect(clipPath, subjectBounds);-
1562 else if (clipIsRect)-
1563 return intersect(subjectPath, clipBounds);-
1564 }-
1565 }-
1566-
1567 QWingedEdge list(subjectPath, clipPath);-
1568-
1569 doClip(list, ClipMode);-
1570-
1571 QPainterPath path = list.toPath();-
1572 return path;-
1573}-
1574-
1575bool QPathClipper::doClip(QWingedEdge &list, ClipperMode mode)-
1576{-
1577 QVector<qreal> y_coords;-
1578 y_coords.reserve(list.vertexCount());-
1579 for (int i = 0; i < list.vertexCount()
i < list.vertexCount()Description
TRUEnever evaluated
FALSEnever evaluated
; ++i)
0
1580 y_coords << list.vertex(i)->y;
never executed: y_coords << list.vertex(i)->y;
0
1581-
1582 std::sort(y_coords.begin(), y_coords.end());-
1583 y_coords.resize(qRemoveDuplicates(y_coords.begin(), y_coords.end(), fuzzyCompare) - y_coords.begin());-
1584 bool found;-
1585 do {-
1586 found = false;-
1587 int index = 0;-
1588 qreal maxHeight = 0;-
1589 for (int i = 0; i < list.edgeCount()
i < list.edgeCount()Description
TRUEnever evaluated
FALSEnever evaluated
; ++i) {
0
1590 QPathEdge *edge = list.edge(i);-
1591-
1592-
1593 if ((
(edge->flag & 0x3) == 0x3Description
TRUEnever evaluated
FALSEnever evaluated
edge->flag & 0x3) == 0x3
(edge->flag & 0x3) == 0x3Description
TRUEnever evaluated
FALSEnever evaluated
)
0
1594 continue;
never executed: continue;
0
1595-
1596 QPathVertex *a = list.vertex(edge->first);-
1597 QPathVertex *b = list.vertex(edge->second);-
1598-
1599 if (qFuzzyCompare(a->y, b->y)
qFuzzyCompare(a->y, b->y)Description
TRUEnever evaluated
FALSEnever evaluated
)
0
1600 continue;
never executed: continue;
0
1601-
1602 found = true;-
1603-
1604 qreal height = qAbs(a->y - b->y);-
1605 if (height > maxHeight
height > maxHeightDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
1606 index = i;-
1607 maxHeight = height;-
1608 }
never executed: end of block
0
1609 }
never executed: end of block
0
1610-
1611 if (found
foundDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
1612 QPathEdge *edge = list.edge(index);-
1613-
1614 QPathVertex *a = list.vertex(edge->first);-
1615 QPathVertex *b = list.vertex(edge->second);-
1616-
1617-
1618 const int first = qFuzzyFind(y_coords.begincbegin(), y_coords.endcend(), qMin(a->y, b->y)) - y_coords.begincbegin();-
1619 const int last = qFuzzyFind(y_coords.begincbegin() + first, y_coords.endcend(), qMax(a->y, b->y)) - y_coords.begincbegin();-
1620-
1621 ((!(first < y_coords.size() - 1)) ? qt_assert("first < y_coords.size() - 1",__FILE__,16861692) : qt_noop());-
1622 ((!(last < y_coords.size())) ? qt_assert("last < y_coords.size()",__FILE__,16871693) : qt_noop());-
1623-
1624 qreal bestY = 0.5 * (y_coords[first] + y_coords[first+1]);qreal biggestGap = y_coords[.at(first + 1]) - y_coords[.at(first];);-
1625 int bestIdx = first;-
1626 for (int i = first + 1; i < last
i < lastDescription
TRUEnever evaluated
FALSEnever evaluated
; ++i) {
0
1627 qreal gap = y_coords[.at(i + 1]) - y_coords[.at(i];);-
1628-
1629 if (gap > biggestGap
gap > biggestGapDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
1630 bestIdx = i;-
1631 biggestGap = gap;-
1632 }
never executed: end of block
0
1633 }
never executed: end of block
0
1634 const qreal bestY = 0.5 * (y_coords[i].at(bestIdx) + y_coords[i.at(bestIdx + 1]);-
biggestGap = gap;
}
}));
1635-
1636-
1637-
1638-
1639-
1640 if (handleCrossingEdges(list, bestY, mode)
handleCrossing..., bestY, mode)Description
TRUEnever evaluated
FALSEnever evaluated
&& mode == CheckMode
mode == CheckModeDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
1641 return
never executed: return true;
true;
never executed: return true;
0
1642-
1643 edge->flag |= 0x3;-
1644 }
never executed: end of block
0
1645 }
never executed: end of block
while (found
foundDescription
TRUEnever evaluated
FALSEnever evaluated
);
0
1646-
1647 if (mode == ClipMode
mode == ClipModeDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
1648 list.simplify();
never executed: list.simplify();
0
1649-
1650 return
never executed: return false;
false;
never executed: return false;
0
1651}-
1652-
1653static void traverse(QWingedEdge &list, int edge, QPathEdge::Traversal traversal)-
1654{-
1655 QWingedEdge::TraversalStatus status;-
1656 status.edge = edge;-
1657 status.traversal = traversal;-
1658 status.direction = QPathEdge::Forward;-
1659-
1660 do {-
1661 int flag = status.traversal == QPathEdge::LeftTraversal ? 1 : 2;-
1662-
1663 QPathEdge *ep = list.edge(status.edge);-
1664-
1665 ep->flag |= (flag | (flag << 4));-
1666-
1667-
1668-
1669-
1670-
1671 status = list.next(status);-
1672 } while (status.edge != edge);-
1673}-
1674-
1675struct QCrossingEdge-
1676{-
1677 int edge;-
1678 qreal x;-
1679-
1680 bool operator<(const QCrossingEdge &edge) const-
1681 {-
1682 return x < edge.x;-
1683 }-
1684};-
1685template<> class QTypeInfo<QCrossingEdge > { public: enum { isComplex = (((Q_PRIMITIVE_TYPE) & Q_PRIMITIVE_TYPE) == 0), isStatic = (((Q_PRIMITIVE_TYPE) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), isRelocatable = !isStatic || ((Q_PRIMITIVE_TYPE) & Q_RELOCATABLE_TYPE), isLarge = (sizeof(QCrossingEdge)>sizeof(void*)), isPointer = false, isIntegral = QtPrivate::is_integral< QCrossingEdge >::value, isDummy = (((Q_PRIMITIVE_TYPE) & Q_DUMMY_TYPE) != 0), sizeOf = sizeof(QCrossingEdge) }; static inline const char *name() { return "QCrossingEdge"; } };-
1686-
1687static bool bool_op(bool a, bool b, QPathClipper::Operation op)-
1688{-
1689 switch (op) {-
1690 case QPathClipper::BoolAnd:-
1691 return a && b;-
1692 case QPathClipper::BoolOr:-
1693 case QPathClipper::Simplify:-
1694 return a || b;-
1695 case QPathClipper::BoolSub:-
1696 return a && !b;-
1697 default:-
1698 ((!(false)) ? qt_assert("false",__FILE__,17621769) : qt_noop());-
1699 return false;-
1700 }-
1701}-
1702-
1703bool QWingedEdge::isInside(qreal x, qreal y) const-
1704{-
1705 int winding = 0;-
1706 for (int i = 0; i < edgeCount(); ++i) {-
1707 const QPathEdge *ep = edge(i);-
1708-
1709-
1710 int w = ((ep->flag >> 4) ^ (ep->flag >> 5)) & 1;-
1711-
1712 if (!w)-
1713 continue;-
1714-
1715 QPointF a = *vertex(ep->first);-
1716 QPointF b = *vertex(ep->second);-
1717-
1718 if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {-
1719 qreal intersectionX = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());-
1720-
1721 if (intersectionX > x)-
1722 winding += w;-
1723 }-
1724 }-
1725-
1726 return winding & 1;-
1727}-
1728-
1729static QVector<QCrossingEdge> findCrossings(const QWingedEdge &list, qreal y)-
1730{-
1731 QVector<QCrossingEdge> crossings;-
1732 for (int i = 0; i < list.edgeCount(); ++i) {-
1733 const QPathEdge *edge = list.edge(i);-
1734 QPointF a = *list.vertex(edge->first);-
1735 QPointF b = *list.vertex(edge->second);-
1736-
1737 if ((a.y() < y && b.y() > y) || (a.y() > y && b.y() < y)) {-
1738 const qreal intersection = a.x() + (b.x() - a.x()) * (y - a.y()) / (b.y() - a.y());-
1739 const QCrossingEdge edge = { i, intersection };-
1740 crossings << edge;-
1741 }-
1742 }-
1743 return crossings;-
1744}-
1745-
1746bool QPathClipper::handleCrossingEdges(QWingedEdge &list, qreal y, ClipperMode mode)-
1747{-
1748 QVector<QCrossingEdge> crossings = findCrossings(list, y);-
1749-
1750 ((!(!crossings.isEmpty())) ? qt_assert("!crossings.isEmpty()",__FILE__,18141821) : qt_noop());-
1751 std::sort(crossings.begin(), crossings.end());-
1752-
1753 int windingA = 0;-
1754 int windingB = 0;-
1755-
1756 int windingD = 0;-
1757-
1758-
1759-
1760-
1761 for (int i = 0; i < crossings.size() - 1; ++i) {-
1762 int ei = crossings.at(i).edge;-
1763 const QPathEdge *edge = list.edge(ei);-
1764-
1765 windingA += edge->windingA;-
1766 windingB += edge->windingB;-
1767-
1768 const bool hasLeft = (edge->flag >> 4) & 1;-
1769 const bool hasRight = (edge->flag >> 4) & 2;-
1770-
1771 windingD += hasLeft ^ hasRight;-
1772-
1773 const bool inA = (windingA & aMask) != 0;-
1774 const bool inB = (windingB & bMask) != 0;-
1775 const bool inD = (windingD & 0x1) != 0;-
1776-
1777 const bool inside = bool_op(inA, inB, op);-
1778 const bool add = inD ^ inside;-
1779-
1780-
1781-
1782-
1783-
1784 if (add) {-
1785 if (mode == CheckMode)-
1786 return true;-
1787-
1788 qreal y0 = list.vertex(edge->first)->y;-
1789 qreal y1 = list.vertex(edge->second)->y;-
1790-
1791 if (y0 < y1) {-
1792 if (!(edge->flag & 1))-
1793 traverse(list, ei, QPathEdge::LeftTraversal);-
1794-
1795 if (!(edge->flag & 2))-
1796 clear(list, ei, QPathEdge::RightTraversal);-
1797 } else {-
1798 if (!(edge->flag & 1))-
1799 clear(list, ei, QPathEdge::LeftTraversal);-
1800-
1801 if (!(edge->flag & 2))-
1802 traverse(list, ei, QPathEdge::RightTraversal);-
1803 }-
1804-
1805 ++windingD;-
1806 } else {-
1807 if (!(edge->flag & 1))-
1808 clear(list, ei, QPathEdge::LeftTraversal);-
1809-
1810 if (!(edge->flag & 2))-
1811 clear(list, ei, QPathEdge::RightTraversal);-
1812 }-
1813 }-
1814-
1815 return false;-
1816}-
1817-
1818namespace {-
1819-
1820QVector<QPainterPath> toSubpaths(const QPainterPath &path)-
1821{-
1822-
1823 QVector<QPainterPath> subpaths;-
1824 if (path.isEmpty())-
1825 return subpaths;-
1826-
1827 QPainterPath current;-
1828 for (int i = 0; i < path.elementCount(); ++i) {-
1829 const QPainterPath::Element &e = path.elementAt(i);-
1830 switch (e.type) {-
1831 case QPainterPath::MoveToElement:-
1832 if (current.elementCount() > 1)-
1833 subpaths += current;-
1834 current = QPainterPath();-
1835 current.moveTo(e);-
1836 break;-
1837 case QPainterPath::LineToElement:-
1838 current.lineTo(e);-
1839 break;-
1840 case QPainterPath::CurveToElement: {-
1841 current.cubicTo(e, path.elementAt(i + 1), path.elementAt(i + 2));-
1842 i+=2;-
1843 break;-
1844 }-
1845 case QPainterPath::CurveToDataElement:-
1846 ((!(!"toSubpaths(), bad element type")) ? qt_assert("!\"toSubpaths(), bad element type\"",__FILE__,19101917) : qt_noop());-
1847 break;-
1848 }-
1849 }-
1850-
1851 if (current.elementCount() > 1)-
1852 subpaths << current;-
1853-
1854 return subpaths;-
1855}-
1856-
1857enum Edge-
1858{-
1859 Left, Top, Right, Bottom-
1860};-
1861-
1862static bool isVertical(Edge edge)-
1863{-
1864 return edge == Left || edge == Right;-
1865}-
1866-
1867template <Edge edge>-
1868bool compare(const QPointF &p, qreal t)-
1869{-
1870 switch (edge)-
1871 {-
1872 case Left:-
1873 return p.x() < t;-
1874 case Right:-
1875 return p.x() > t;-
1876 case Top:-
1877 return p.y() < t;-
1878 default:-
1879 return p.y() > t;-
1880 }-
1881}-
1882-
1883template <Edge edge>-
1884QPointF intersectLine(const QPointF &a, const QPointF &b, qreal t)-
1885{-
1886 QLineF line(a, b);-
1887 switch (edge) {-
1888 case Left:-
1889 case Right:-
1890 return line.pointAt((t - a.x()) / (b.x() - a.x()));-
1891 default:-
1892 return line.pointAt((t - a.y()) / (b.y() - a.y()));-
1893 }-
1894}-
1895-
1896void addLine(QPainterPath &path, const QLineF &line)-
1897{-
1898 if (path.elementCount() > 0)-
1899 path.lineTo(line.p1());-
1900 else-
1901 path.moveTo(line.p1());-
1902-
1903 path.lineTo(line.p2());-
1904}-
1905-
1906template <Edge edge>-
1907void clipLine(const QPointF &a, const QPointF &b, qreal t, QPainterPath &result)-
1908{-
1909 bool outA = compare<edge>(a, t);-
1910 bool outB = compare<edge>(b, t);-
1911 if (outA && outB)-
1912 return;-
1913-
1914 if (outA)-
1915 addLine(result, QLineF(intersectLine<edge>(a, b, t), b));-
1916 else if(outB)-
1917 addLine(result, QLineF(a, intersectLine<edge>(a, b, t)));-
1918 else-
1919 addLine(result, QLineF(a, b));-
1920}-
1921-
1922void addBezier(QPainterPath &path, const QBezier &bezier)-
1923{-
1924 if (path.elementCount() > 0)-
1925 path.lineTo(bezier.pt1());-
1926 else-
1927 path.moveTo(bezier.pt1());-
1928-
1929 path.cubicTo(bezier.pt2(), bezier.pt3(), bezier.pt4());-
1930}-
1931-
1932template <Edge edge>-
1933void clipBezier(const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, qreal t, QPainterPath &result)-
1934{-
1935 QBezier bezier = QBezier::fromPoints(a, b, c, d);-
1936-
1937 bool outA = compare<edge>(a, t);-
1938 bool outB = compare<edge>(b, t);-
1939 bool outC = compare<edge>(c, t);-
1940 bool outD = compare<edge>(d, t);-
1941-
1942 int outCount = int(outA) + int(outB) + int(outC) + int(outD);-
1943-
1944 if (outCount == 4)-
1945 return;-
1946-
1947 if (outCount == 0) {-
1948 addBezier(result, bezier);-
1949 return;-
1950 }-
1951-
1952 QTransform flip = isVertical(edge) ? QTransform(0, 1, 1, 0, 0, 0) : QTransform();-
1953 QBezier unflipped = bezier;-
1954 QBezier flipped = bezier.mapBy(flip);-
1955-
1956 qreal t0 = 0, t1 = 1;-
1957 int stationary = flipped.stationaryYPoints(t0, t1);-
1958-
1959 qreal segments[4];-
1960 QPointF points[4];-
1961 points[0] = unflipped.pt1();-
1962 segments[0] = 0;-
1963-
1964 int segmentCount = 0;-
1965 if (stationary > 0) {-
1966 ++segmentCount;-
1967 segments[segmentCount] = t0;-
1968 points[segmentCount] = unflipped.pointAt(t0);-
1969 }-
1970 if (stationary > 1) {-
1971 ++segmentCount;-
1972 segments[segmentCount] = t1;-
1973 points[segmentCount] = unflipped.pointAt(t1);-
1974 }-
1975 ++segmentCount;-
1976 segments[segmentCount] = 1;-
1977 points[segmentCount] = unflipped.pt4();-
1978-
1979 qreal lastIntersection = 0;-
1980 for (int i = 0; i < segmentCount; ++i) {-
1981 outA = compare<edge>(points[i], t);-
1982 outB = compare<edge>(points[i+1], t);-
1983-
1984 if (outA != outB) {-
1985 qreal intersection = flipped.tForY(segments[i], segments[i+1], t);-
1986-
1987 if (outB)-
1988 addBezier(result, unflipped.getSubRange(lastIntersection, intersection));-
1989-
1990 lastIntersection = intersection;-
1991 }-
1992 }-
1993-
1994 if (!outB)-
1995 addBezier(result, unflipped.getSubRange(lastIntersection, 1));-
1996}-
1997-
1998-
1999template <Edge edge>-
2000QPainterPath clip(const QPainterPath &path, qreal t)-
2001{-
2002 QPainterPath result;-
2003 for (int i = 1; i < path.elementCount(); ++i) {-
2004 const QPainterPath::Element &element = path.elementAt(i);-
2005 ((!(!element.isMoveTo())) ? qt_assert("!element.isMoveTo()",__FILE__,20692076) : qt_noop());-
2006 if (element.isLineTo()) {-
2007 clipLine<edge>(path.elementAt(i-1), path.elementAt(i), t, result);-
2008 } else {-
2009 clipBezier<edge>(path.elementAt(i-1), path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), t, result);-
2010 i += 2;-
2011 }-
2012 }-
2013-
2014 int last = path.elementCount() - 1;-
2015 if (QPointF(path.elementAt(last)) != QPointF(path.elementAt(0)))-
2016 clipLine<edge>(path.elementAt(last), path.elementAt(0), t, result);-
2017-
2018 return result;-
2019}-
2020-
2021QPainterPath intersectPath(const QPainterPath &path, const QRectF &rect)-
2022{-
2023 QVector<QPainterPath> subpaths = toSubpaths(path);-
2024-
2025 QPainterPath result;-
2026 result.setFillRule(path.fillRule());-
2027 for (int i = 0; i < subpaths.size(); ++i) {-
2028 QPainterPath subPath = subpaths.at(i);-
2029 QRectF bounds = subPath.boundingRect();-
2030 if (bounds.intersects(rect)) {-
2031 if (bounds.left() < rect.left())-
2032 subPath = clip<Left>(subPath, rect.left());-
2033 if (bounds.right() > rect.right())-
2034 subPath = clip<Right>(subPath, rect.right());-
2035-
2036 bounds = subPath.boundingRect();-
2037-
2038 if (bounds.top() < rect.top())-
2039 subPath = clip<Top>(subPath, rect.top());-
2040 if (bounds.bottom() > rect.bottom())-
2041 subPath = clip<Bottom>(subPath, rect.bottom());-
2042-
2043 if (subPath.elementCount() > 1)-
2044 result.addPath(subPath);-
2045 }-
2046 }-
2047 return result;-
2048}-
2049-
2050}-
2051-
2052QPainterPath QPathClipper::intersect(const QPainterPath &path, const QRectF &rect)-
2053{-
2054 return intersectPath(path, rect);-
2055}-
2056-
2057-
Switch to Source codePreprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9