|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtGui module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qpaintengineex_p.h" |
|
43 #include "qpainter_p.h" |
|
44 #include "qstroker_p.h" |
|
45 #include "qbezier_p.h" |
|
46 #include <private/qpainterpath_p.h> |
|
47 |
|
48 #include <qvarlengtharray.h> |
|
49 #include <qdebug.h> |
|
50 |
|
51 |
|
52 QT_BEGIN_NAMESPACE |
|
53 |
|
54 /******************************************************************************* |
|
55 * |
|
56 * class QVectorPath |
|
57 * |
|
58 */ |
|
59 |
|
60 QRectF QVectorPath::controlPointRect() const |
|
61 { |
|
62 if (m_hints & ControlPointRect) |
|
63 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2)); |
|
64 |
|
65 if (m_count == 0) { |
|
66 m_cp_rect.x1 = m_cp_rect.x2 = m_cp_rect.y1 = m_cp_rect.y2 = 0; |
|
67 m_hints |= ControlPointRect; |
|
68 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2)); |
|
69 } |
|
70 Q_ASSERT(m_points && m_count > 0); |
|
71 |
|
72 const qreal *pts = m_points; |
|
73 m_cp_rect.x1 = m_cp_rect.x2 = *pts; |
|
74 ++pts; |
|
75 m_cp_rect.y1 = m_cp_rect.y2 = *pts; |
|
76 ++pts; |
|
77 |
|
78 const qreal *epts = m_points + (m_count << 1); |
|
79 while (pts < epts) { |
|
80 qreal x = *pts; |
|
81 if (x < m_cp_rect.x1) m_cp_rect.x1 = x; |
|
82 else if (x > m_cp_rect.x2) m_cp_rect.x2 = x; |
|
83 ++pts; |
|
84 |
|
85 qreal y = *pts; |
|
86 if (y < m_cp_rect.y1) m_cp_rect.y1 = y; |
|
87 else if (y > m_cp_rect.y2) m_cp_rect.y2 = y; |
|
88 ++pts; |
|
89 } |
|
90 |
|
91 m_hints |= ControlPointRect; |
|
92 return QRectF(QPointF(m_cp_rect.x1, m_cp_rect.y1), QPointF(m_cp_rect.x2, m_cp_rect.y2)); |
|
93 } |
|
94 |
|
95 const QVectorPath &qtVectorPathForPath(const QPainterPath &path) |
|
96 { |
|
97 Q_ASSERT(path.d_func()); |
|
98 return path.d_func()->vectorPath(); |
|
99 } |
|
100 |
|
101 #ifndef QT_NO_DEBUG_STREAM |
|
102 QDebug Q_GUI_EXPORT &operator<<(QDebug &s, const QVectorPath &path) |
|
103 { |
|
104 QRectF rf = path.controlPointRect(); |
|
105 s << "QVectorPath(size:" << path.elementCount() |
|
106 << " hints:" << hex << path.hints() |
|
107 << rf << ')'; |
|
108 return s; |
|
109 } |
|
110 #endif |
|
111 |
|
112 /******************************************************************************* |
|
113 * |
|
114 * class QPaintEngineExPrivate: |
|
115 * |
|
116 */ |
|
117 |
|
118 |
|
119 struct StrokeHandler { |
|
120 QDataBuffer<qreal> pts; |
|
121 QDataBuffer<QPainterPath::ElementType> types; |
|
122 }; |
|
123 |
|
124 |
|
125 QPaintEngineExPrivate::QPaintEngineExPrivate() |
|
126 : dasher(&stroker), |
|
127 strokeHandler(0), |
|
128 activeStroker(0), |
|
129 strokerPen(Qt::NoPen) |
|
130 { |
|
131 } |
|
132 |
|
133 |
|
134 QPaintEngineExPrivate::~QPaintEngineExPrivate() |
|
135 { |
|
136 delete strokeHandler; |
|
137 } |
|
138 |
|
139 |
|
140 void QPaintEngineExPrivate::replayClipOperations() |
|
141 { |
|
142 Q_Q(QPaintEngineEx); |
|
143 |
|
144 QPainter *p = q->painter(); |
|
145 if (!p || !p->d_ptr) |
|
146 return; |
|
147 |
|
148 QList<QPainterClipInfo> clipInfo = p->d_ptr->state->clipInfo; |
|
149 |
|
150 QTransform transform = q->state()->matrix; |
|
151 |
|
152 for (int i = 0; i < clipInfo.size(); ++i) { |
|
153 const QPainterClipInfo &info = clipInfo.at(i); |
|
154 |
|
155 if (info.matrix != q->state()->matrix) { |
|
156 q->state()->matrix = info.matrix; |
|
157 q->transformChanged(); |
|
158 } |
|
159 |
|
160 switch (info.clipType) { |
|
161 case QPainterClipInfo::RegionClip: |
|
162 q->clip(info.region, info.operation); |
|
163 break; |
|
164 case QPainterClipInfo::PathClip: |
|
165 q->clip(info.path, info.operation); |
|
166 break; |
|
167 case QPainterClipInfo::RectClip: |
|
168 q->clip(info.rect, info.operation); |
|
169 break; |
|
170 case QPainterClipInfo::RectFClip: { |
|
171 qreal right = info.rectf.x() + info.rectf.width(); |
|
172 qreal bottom = info.rectf.y() + info.rectf.height(); |
|
173 qreal pts[] = { info.rectf.x(), info.rectf.y(), |
|
174 right, info.rectf.y(), |
|
175 right, bottom, |
|
176 info.rectf.x(), bottom }; |
|
177 QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint); |
|
178 q->clip(vp, info.operation); |
|
179 break; |
|
180 } |
|
181 } |
|
182 } |
|
183 |
|
184 if (transform != q->state()->matrix) { |
|
185 q->state()->matrix = transform; |
|
186 q->transformChanged(); |
|
187 } |
|
188 } |
|
189 |
|
190 |
|
191 bool QPaintEngineExPrivate::hasClipOperations() const |
|
192 { |
|
193 Q_Q(const QPaintEngineEx); |
|
194 |
|
195 QPainter *p = q->painter(); |
|
196 if (!p || !p->d_ptr) |
|
197 return false; |
|
198 |
|
199 QList<QPainterClipInfo> clipInfo = p->d_ptr->state->clipInfo; |
|
200 |
|
201 return !clipInfo.isEmpty(); |
|
202 } |
|
203 |
|
204 /******************************************************************************* |
|
205 * |
|
206 * class QPaintEngineEx: |
|
207 * |
|
208 */ |
|
209 |
|
210 static QPainterPath::ElementType qpaintengineex_ellipse_types[] = { |
|
211 QPainterPath::MoveToElement, |
|
212 QPainterPath::CurveToElement, |
|
213 QPainterPath::CurveToDataElement, |
|
214 QPainterPath::CurveToDataElement, |
|
215 |
|
216 QPainterPath::CurveToElement, |
|
217 QPainterPath::CurveToDataElement, |
|
218 QPainterPath::CurveToDataElement, |
|
219 |
|
220 QPainterPath::CurveToElement, |
|
221 QPainterPath::CurveToDataElement, |
|
222 QPainterPath::CurveToDataElement, |
|
223 |
|
224 QPainterPath::CurveToElement, |
|
225 QPainterPath::CurveToDataElement, |
|
226 QPainterPath::CurveToDataElement |
|
227 }; |
|
228 |
|
229 static QPainterPath::ElementType qpaintengineex_line_types_16[] = { |
|
230 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
231 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
232 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
233 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
234 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
235 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
236 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
237 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
238 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
239 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
240 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
241 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
242 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
243 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
244 QPainterPath::MoveToElement, QPainterPath::LineToElement, |
|
245 QPainterPath::MoveToElement, QPainterPath::LineToElement |
|
246 }; |
|
247 |
|
248 static QPainterPath::ElementType qpaintengineex_rect4_types_32[] = { |
|
249 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 1 |
|
250 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 2 |
|
251 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 3 |
|
252 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 4 |
|
253 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 5 |
|
254 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 6 |
|
255 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 7 |
|
256 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 8 |
|
257 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 9 |
|
258 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 10 |
|
259 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 11 |
|
260 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 12 |
|
261 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 13 |
|
262 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 14 |
|
263 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 15 |
|
264 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 16 |
|
265 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 17 |
|
266 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 18 |
|
267 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 19 |
|
268 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 20 |
|
269 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 21 |
|
270 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 22 |
|
271 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 23 |
|
272 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 24 |
|
273 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 25 |
|
274 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 26 |
|
275 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 27 |
|
276 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 28 |
|
277 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 29 |
|
278 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 30 |
|
279 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 31 |
|
280 QPainterPath::MoveToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, QPainterPath::LineToElement, // 32 |
|
281 }; |
|
282 |
|
283 |
|
284 static QPainterPath::ElementType qpaintengineex_roundedrect_types[] = { |
|
285 QPainterPath::MoveToElement, |
|
286 QPainterPath::LineToElement, |
|
287 QPainterPath::CurveToElement, |
|
288 QPainterPath::CurveToDataElement, |
|
289 QPainterPath::CurveToDataElement, |
|
290 QPainterPath::LineToElement, |
|
291 QPainterPath::CurveToElement, |
|
292 QPainterPath::CurveToDataElement, |
|
293 QPainterPath::CurveToDataElement, |
|
294 QPainterPath::LineToElement, |
|
295 QPainterPath::CurveToElement, |
|
296 QPainterPath::CurveToDataElement, |
|
297 QPainterPath::CurveToDataElement, |
|
298 QPainterPath::LineToElement, |
|
299 QPainterPath::CurveToElement, |
|
300 QPainterPath::CurveToDataElement, |
|
301 QPainterPath::CurveToDataElement |
|
302 }; |
|
303 |
|
304 |
|
305 |
|
306 static void qpaintengineex_moveTo(qreal x, qreal y, void *data) { |
|
307 ((StrokeHandler *) data)->pts.add(x); |
|
308 ((StrokeHandler *) data)->pts.add(y); |
|
309 ((StrokeHandler *) data)->types.add(QPainterPath::MoveToElement); |
|
310 } |
|
311 |
|
312 static void qpaintengineex_lineTo(qreal x, qreal y, void *data) { |
|
313 ((StrokeHandler *) data)->pts.add(x); |
|
314 ((StrokeHandler *) data)->pts.add(y); |
|
315 ((StrokeHandler *) data)->types.add(QPainterPath::LineToElement); |
|
316 } |
|
317 |
|
318 static void qpaintengineex_cubicTo(qreal c1x, qreal c1y, qreal c2x, qreal c2y, qreal ex, qreal ey, void *data) { |
|
319 ((StrokeHandler *) data)->pts.add(c1x); |
|
320 ((StrokeHandler *) data)->pts.add(c1y); |
|
321 ((StrokeHandler *) data)->types.add(QPainterPath::CurveToElement); |
|
322 |
|
323 ((StrokeHandler *) data)->pts.add(c2x); |
|
324 ((StrokeHandler *) data)->pts.add(c2y); |
|
325 ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement); |
|
326 |
|
327 ((StrokeHandler *) data)->pts.add(ex); |
|
328 ((StrokeHandler *) data)->pts.add(ey); |
|
329 ((StrokeHandler *) data)->types.add(QPainterPath::CurveToDataElement); |
|
330 } |
|
331 |
|
332 QPaintEngineEx::QPaintEngineEx() |
|
333 : QPaintEngine(*new QPaintEngineExPrivate, AllFeatures) |
|
334 { |
|
335 extended = true; |
|
336 } |
|
337 |
|
338 QPaintEngineEx::QPaintEngineEx(QPaintEngineExPrivate &data) |
|
339 : QPaintEngine(data, AllFeatures) |
|
340 { |
|
341 extended = true; |
|
342 } |
|
343 |
|
344 QPainterState *QPaintEngineEx::createState(QPainterState *orig) const |
|
345 { |
|
346 if (!orig) |
|
347 return new QPainterState; |
|
348 return new QPainterState(orig); |
|
349 } |
|
350 |
|
351 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp |
|
352 |
|
353 void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) |
|
354 { |
|
355 #ifdef QT_DEBUG_DRAW |
|
356 qDebug() << "QPaintEngineEx::stroke()" << pen; |
|
357 #endif |
|
358 |
|
359 Q_D(QPaintEngineEx); |
|
360 |
|
361 if (path.isEmpty()) |
|
362 return; |
|
363 |
|
364 if (!d->strokeHandler) { |
|
365 d->strokeHandler = new StrokeHandler; |
|
366 d->stroker.setMoveToHook(qpaintengineex_moveTo); |
|
367 d->stroker.setLineToHook(qpaintengineex_lineTo); |
|
368 d->stroker.setCubicToHook(qpaintengineex_cubicTo); |
|
369 } |
|
370 |
|
371 if (!qpen_fast_equals(pen, d->strokerPen)) { |
|
372 d->strokerPen = pen; |
|
373 d->stroker.setJoinStyle(pen.joinStyle()); |
|
374 d->stroker.setCapStyle(pen.capStyle()); |
|
375 d->stroker.setMiterLimit(pen.miterLimit()); |
|
376 qreal penWidth = pen.widthF(); |
|
377 if (penWidth == 0) |
|
378 d->stroker.setStrokeWidth(1); |
|
379 else |
|
380 d->stroker.setStrokeWidth(penWidth); |
|
381 |
|
382 Qt::PenStyle style = pen.style(); |
|
383 if (style == Qt::SolidLine) { |
|
384 d->activeStroker = &d->stroker; |
|
385 } else if (style == Qt::NoPen) { |
|
386 d->activeStroker = 0; |
|
387 } else { |
|
388 // ### re-enable... |
|
389 if (pen.isCosmetic()) { |
|
390 d->dasher.setClipRect(d->exDeviceRect); |
|
391 } else { |
|
392 QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect)); |
|
393 d->dasher.setClipRect(clipRect); |
|
394 } |
|
395 d->dasher.setDashPattern(pen.dashPattern()); |
|
396 d->dasher.setDashOffset(pen.dashOffset()); |
|
397 d->activeStroker = &d->dasher; |
|
398 } |
|
399 } |
|
400 |
|
401 if (!d->activeStroker) { |
|
402 return; |
|
403 } |
|
404 |
|
405 const QPainterPath::ElementType *types = path.elements(); |
|
406 const qreal *points = path.points(); |
|
407 int pointCount = path.elementCount(); |
|
408 |
|
409 const qreal *lastPoint = points + (pointCount<<1); |
|
410 |
|
411 d->strokeHandler->types.reset(); |
|
412 d->strokeHandler->pts.reset(); |
|
413 |
|
414 // Some engines might decide to optimize for the non-shape hint later on... |
|
415 uint flags = QVectorPath::WindingFill; |
|
416 if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin) |
|
417 flags |= QVectorPath::CurvedShapeHint; |
|
418 |
|
419 // ### Perspective Xforms are currently not supported... |
|
420 if (!pen.isCosmetic()) { |
|
421 // We include cosmetic pens in this case to avoid having to |
|
422 // change the current transform. Normal transformed, |
|
423 // non-cosmetic pens will be transformed as part of fill |
|
424 // later, so they are also covered here.. |
|
425 d->activeStroker->begin(d->strokeHandler); |
|
426 if (types) { |
|
427 while (points < lastPoint) { |
|
428 switch (*types) { |
|
429 case QPainterPath::MoveToElement: |
|
430 d->activeStroker->moveTo(points[0], points[1]); |
|
431 points += 2; |
|
432 ++types; |
|
433 break; |
|
434 case QPainterPath::LineToElement: |
|
435 d->activeStroker->lineTo(points[0], points[1]); |
|
436 points += 2; |
|
437 ++types; |
|
438 break; |
|
439 case QPainterPath::CurveToElement: |
|
440 d->activeStroker->cubicTo(points[0], points[1], |
|
441 points[2], points[3], |
|
442 points[4], points[5]); |
|
443 points += 6; |
|
444 types += 3; |
|
445 flags |= QVectorPath::CurvedShapeHint; |
|
446 break; |
|
447 default: |
|
448 break; |
|
449 } |
|
450 } |
|
451 if (path.hasImplicitClose()) |
|
452 d->activeStroker->lineTo(path.points()[0], path.points()[1]); |
|
453 |
|
454 } else { |
|
455 d->activeStroker->moveTo(points[0], points[1]); |
|
456 points += 2; |
|
457 ++types; |
|
458 while (points < lastPoint) { |
|
459 d->activeStroker->lineTo(points[0], points[1]); |
|
460 points += 2; |
|
461 ++types; |
|
462 } |
|
463 if (path.hasImplicitClose()) |
|
464 d->activeStroker->lineTo(path.points()[0], path.points()[1]); |
|
465 } |
|
466 d->activeStroker->end(); |
|
467 |
|
468 if (!d->strokeHandler->types.size()) // an empty path... |
|
469 return; |
|
470 |
|
471 QVectorPath strokePath(d->strokeHandler->pts.data(), |
|
472 d->strokeHandler->types.size(), |
|
473 d->strokeHandler->types.data(), |
|
474 flags); |
|
475 fill(strokePath, pen.brush()); |
|
476 } else { |
|
477 // For cosmetic pens we need a bit of trickery... We to process xform the input points |
|
478 if (state()->matrix.type() >= QTransform::TxProject) { |
|
479 QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath()); |
|
480 d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform()); |
|
481 } else { |
|
482 d->activeStroker->begin(d->strokeHandler); |
|
483 if (types) { |
|
484 while (points < lastPoint) { |
|
485 switch (*types) { |
|
486 case QPainterPath::MoveToElement: { |
|
487 QPointF pt = (*(QPointF *) points) * state()->matrix; |
|
488 d->activeStroker->moveTo(pt.x(), pt.y()); |
|
489 points += 2; |
|
490 ++types; |
|
491 break; |
|
492 } |
|
493 case QPainterPath::LineToElement: { |
|
494 QPointF pt = (*(QPointF *) points) * state()->matrix; |
|
495 d->activeStroker->lineTo(pt.x(), pt.y()); |
|
496 points += 2; |
|
497 ++types; |
|
498 break; |
|
499 } |
|
500 case QPainterPath::CurveToElement: { |
|
501 QPointF c1 = ((QPointF *) points)[0] * state()->matrix; |
|
502 QPointF c2 = ((QPointF *) points)[1] * state()->matrix; |
|
503 QPointF e = ((QPointF *) points)[2] * state()->matrix; |
|
504 d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y()); |
|
505 points += 6; |
|
506 types += 3; |
|
507 flags |= QVectorPath::CurvedShapeHint; |
|
508 break; |
|
509 } |
|
510 default: |
|
511 break; |
|
512 } |
|
513 } |
|
514 if (path.hasImplicitClose()) { |
|
515 QPointF pt = * ((QPointF *) path.points()) * state()->matrix; |
|
516 d->activeStroker->lineTo(pt.x(), pt.y()); |
|
517 } |
|
518 |
|
519 } else { |
|
520 QPointF p = ((QPointF *)points)[0] * state()->matrix; |
|
521 d->activeStroker->moveTo(p.x(), p.y()); |
|
522 points += 2; |
|
523 ++types; |
|
524 while (points < lastPoint) { |
|
525 QPointF p = ((QPointF *)points)[0] * state()->matrix; |
|
526 d->activeStroker->lineTo(p.x(), p.y()); |
|
527 points += 2; |
|
528 ++types; |
|
529 } |
|
530 if (path.hasImplicitClose()) |
|
531 d->activeStroker->lineTo(p.x(), p.y()); |
|
532 } |
|
533 d->activeStroker->end(); |
|
534 } |
|
535 |
|
536 QVectorPath strokePath(d->strokeHandler->pts.data(), |
|
537 d->strokeHandler->types.size(), |
|
538 d->strokeHandler->types.data(), |
|
539 flags); |
|
540 |
|
541 QTransform xform = state()->matrix; |
|
542 state()->matrix = QTransform(); |
|
543 transformChanged(); |
|
544 |
|
545 QBrush brush = pen.brush(); |
|
546 if (qbrush_style(brush) != Qt::SolidPattern) |
|
547 brush.setTransform(brush.transform() * xform); |
|
548 |
|
549 fill(strokePath, brush); |
|
550 |
|
551 state()->matrix = xform; |
|
552 transformChanged(); |
|
553 } |
|
554 } |
|
555 |
|
556 void QPaintEngineEx::draw(const QVectorPath &path) |
|
557 { |
|
558 const QBrush &brush = state()->brush; |
|
559 if (qbrush_style(brush) != Qt::NoBrush) |
|
560 fill(path, brush); |
|
561 |
|
562 const QPen &pen = state()->pen; |
|
563 if (qpen_style(pen) != Qt::NoPen && qbrush_style(qpen_brush(pen)) != Qt::NoBrush) |
|
564 stroke(path, pen); |
|
565 } |
|
566 |
|
567 |
|
568 void QPaintEngineEx::clip(const QRect &r, Qt::ClipOperation op) |
|
569 { |
|
570 qreal right = r.x() + r.width(); |
|
571 qreal bottom = r.y() + r.height(); |
|
572 qreal pts[] = { r.x(), r.y(), |
|
573 right, r.y(), |
|
574 right, bottom, |
|
575 r.x(), bottom, |
|
576 r.x(), r.y() }; |
|
577 QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint); |
|
578 clip(vp, op); |
|
579 } |
|
580 |
|
581 void QPaintEngineEx::clip(const QRegion ®ion, Qt::ClipOperation op) |
|
582 { |
|
583 if (region.numRects() == 1) |
|
584 clip(region.boundingRect(), op); |
|
585 |
|
586 QVector<QRect> rects = region.rects(); |
|
587 if (rects.size() <= 32) { |
|
588 qreal pts[2*32*4]; |
|
589 int pos = 0; |
|
590 for (QVector<QRect>::const_iterator i = rects.constBegin(); i != rects.constEnd(); ++i) { |
|
591 qreal x1 = i->x(); |
|
592 qreal y1 = i->y(); |
|
593 qreal x2 = i->x() + i->width(); |
|
594 qreal y2 = i->y() + i->height(); |
|
595 |
|
596 pts[pos++] = x1; |
|
597 pts[pos++] = y1; |
|
598 |
|
599 pts[pos++] = x2; |
|
600 pts[pos++] = y1; |
|
601 |
|
602 pts[pos++] = x2; |
|
603 pts[pos++] = y2; |
|
604 |
|
605 pts[pos++] = x1; |
|
606 pts[pos++] = y2; |
|
607 } |
|
608 QVectorPath vp(pts, rects.size() * 4, qpaintengineex_rect4_types_32); |
|
609 clip(vp, op); |
|
610 } else { |
|
611 QVarLengthArray<qreal> pts(rects.size() * 2 * 4); |
|
612 QVarLengthArray<QPainterPath::ElementType> types(rects.size() * 4); |
|
613 int ppos = 0; |
|
614 int tpos = 0; |
|
615 |
|
616 for (QVector<QRect>::const_iterator i = rects.constBegin(); i != rects.constEnd(); ++i) { |
|
617 qreal x1 = i->x(); |
|
618 qreal y1 = i->y(); |
|
619 qreal x2 = i->x() + i->width(); |
|
620 qreal y2 = i->y() + i->height(); |
|
621 |
|
622 pts[ppos++] = x1; |
|
623 pts[ppos++] = y1; |
|
624 |
|
625 pts[ppos++] = x2; |
|
626 pts[ppos++] = y1; |
|
627 |
|
628 pts[ppos++] = x2; |
|
629 pts[ppos++] = y2; |
|
630 |
|
631 pts[ppos++] = x1; |
|
632 pts[ppos++] = y2; |
|
633 |
|
634 types[tpos++] = QPainterPath::MoveToElement; |
|
635 types[tpos++] = QPainterPath::LineToElement; |
|
636 types[tpos++] = QPainterPath::LineToElement; |
|
637 types[tpos++] = QPainterPath::LineToElement; |
|
638 } |
|
639 |
|
640 QVectorPath vp(pts.data(), rects.size() * 4, types.data()); |
|
641 clip(vp, op); |
|
642 } |
|
643 |
|
644 } |
|
645 |
|
646 void QPaintEngineEx::clip(const QPainterPath &path, Qt::ClipOperation op) |
|
647 { |
|
648 if (path.isEmpty()) { |
|
649 QVectorPath vp(0, 0); |
|
650 clip(vp, op); |
|
651 } else { |
|
652 clip(qtVectorPathForPath(path), op); |
|
653 } |
|
654 } |
|
655 |
|
656 void QPaintEngineEx::fillRect(const QRectF &r, const QBrush &brush) |
|
657 { |
|
658 qreal pts[] = { r.x(), r.y(), r.x() + r.width(), r.y(), |
|
659 r.x() + r.width(), r.y() + r.height(), r.x(), r.y() + r.height() }; |
|
660 QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint); |
|
661 fill(vp, brush); |
|
662 } |
|
663 |
|
664 void QPaintEngineEx::fillRect(const QRectF &r, const QColor &color) |
|
665 { |
|
666 fillRect(r, QBrush(color)); |
|
667 } |
|
668 |
|
669 void QPaintEngineEx::drawRects(const QRect *rects, int rectCount) |
|
670 { |
|
671 for (int i=0; i<rectCount; ++i) { |
|
672 const QRect &r = rects[i]; |
|
673 // ### Is there a one off here? |
|
674 qreal right = r.x() + r.width(); |
|
675 qreal bottom = r.y() + r.height(); |
|
676 qreal pts[] = { r.x(), r.y(), |
|
677 right, r.y(), |
|
678 right, bottom, |
|
679 r.x(), bottom, |
|
680 r.x(), r.y() }; |
|
681 QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint); |
|
682 draw(vp); |
|
683 } |
|
684 } |
|
685 |
|
686 void QPaintEngineEx::drawRects(const QRectF *rects, int rectCount) |
|
687 { |
|
688 for (int i=0; i<rectCount; ++i) { |
|
689 const QRectF &r = rects[i]; |
|
690 qreal right = r.x() + r.width(); |
|
691 qreal bottom = r.y() + r.height(); |
|
692 qreal pts[] = { r.x(), r.y(), |
|
693 right, r.y(), |
|
694 right, bottom, |
|
695 r.x(), bottom, |
|
696 r.x(), r.y() }; |
|
697 QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint); |
|
698 draw(vp); |
|
699 } |
|
700 } |
|
701 |
|
702 |
|
703 void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, |
|
704 Qt::SizeMode mode) |
|
705 { |
|
706 qreal x1 = rect.left(); |
|
707 qreal x2 = rect.right(); |
|
708 qreal y1 = rect.top(); |
|
709 qreal y2 = rect.bottom(); |
|
710 |
|
711 if (mode == Qt::RelativeSize) { |
|
712 xRadius = xRadius * rect.width() / 200.; |
|
713 yRadius = yRadius * rect.height() / 200.; |
|
714 } |
|
715 |
|
716 xRadius = qMin(xRadius, rect.width() / 2); |
|
717 yRadius = qMin(yRadius, rect.height() / 2); |
|
718 |
|
719 qreal pts[] = { |
|
720 x1 + xRadius, y1, // MoveTo |
|
721 x2 - xRadius, y1, // LineTo |
|
722 x2 - (1 - KAPPA) * xRadius, y1, // CurveTo |
|
723 x2, y1 + (1 - KAPPA) * yRadius, |
|
724 x2, y1 + yRadius, |
|
725 x2, y2 - yRadius, // LineTo |
|
726 x2, y2 - (1 - KAPPA) * yRadius, // CurveTo |
|
727 x2 - (1 - KAPPA) * xRadius, y2, |
|
728 x2 - xRadius, y2, |
|
729 x1 + xRadius, y2, // LineTo |
|
730 x1 + (1 - KAPPA) * xRadius, y2, // CurveTo |
|
731 x1, y2 - (1 - KAPPA) * yRadius, |
|
732 x1, y2 - yRadius, |
|
733 x1, y1 + yRadius, // LineTo |
|
734 x1, y1 + KAPPA * yRadius, // CurveTo |
|
735 x1 + (1 - KAPPA) * xRadius, y1, |
|
736 x1 + xRadius, y1 |
|
737 }; |
|
738 |
|
739 QVectorPath path(pts, 17, qpaintengineex_roundedrect_types); |
|
740 draw(path); |
|
741 } |
|
742 |
|
743 |
|
744 |
|
745 void QPaintEngineEx::drawLines(const QLine *lines, int lineCount) |
|
746 { |
|
747 int elementCount = lineCount << 1; |
|
748 while (elementCount > 0) { |
|
749 int count = qMin(elementCount, 32); |
|
750 |
|
751 qreal pts[64]; |
|
752 int count2 = count<<1; |
|
753 #ifdef Q_WS_MAC |
|
754 for (int i=0; i<count2; i+=2) { |
|
755 pts[i] = ((int *) lines)[i+1]; |
|
756 pts[i+1] = ((int *) lines)[i]; |
|
757 } |
|
758 #else |
|
759 for (int i=0; i<count2; ++i) |
|
760 pts[i] = ((int *) lines)[i]; |
|
761 #endif |
|
762 |
|
763 QVectorPath path(pts, count, qpaintengineex_line_types_16, QVectorPath::LinesHint); |
|
764 stroke(path, state()->pen); |
|
765 |
|
766 elementCount -= 32; |
|
767 lines += 16; |
|
768 } |
|
769 } |
|
770 |
|
771 void QPaintEngineEx::drawLines(const QLineF *lines, int lineCount) |
|
772 { |
|
773 int elementCount = lineCount << 1; |
|
774 while (elementCount > 0) { |
|
775 int count = qMin(elementCount, 32); |
|
776 |
|
777 QVectorPath path((qreal *) lines, count, qpaintengineex_line_types_16, |
|
778 QVectorPath::LinesHint); |
|
779 stroke(path, state()->pen); |
|
780 |
|
781 elementCount -= 32; |
|
782 lines += 16; |
|
783 } |
|
784 } |
|
785 |
|
786 void QPaintEngineEx::drawEllipse(const QRectF &r) |
|
787 { |
|
788 qreal pts[26]; // QPointF[13] without constructors... |
|
789 union { |
|
790 qreal *ptr; |
|
791 QPointF *points; |
|
792 } x; |
|
793 x.ptr = pts; |
|
794 |
|
795 int point_count = 0; |
|
796 x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count); |
|
797 QVectorPath vp((qreal *) pts, 13, qpaintengineex_ellipse_types, QVectorPath::EllipseHint); |
|
798 draw(vp); |
|
799 } |
|
800 |
|
801 void QPaintEngineEx::drawEllipse(const QRect &r) |
|
802 { |
|
803 drawEllipse(QRectF(r)); |
|
804 } |
|
805 |
|
806 void QPaintEngineEx::drawPath(const QPainterPath &path) |
|
807 { |
|
808 if (!path.isEmpty()) |
|
809 draw(qtVectorPathForPath(path)); |
|
810 } |
|
811 |
|
812 |
|
813 void QPaintEngineEx::drawPoints(const QPointF *points, int pointCount) |
|
814 { |
|
815 QPen pen = state()->pen; |
|
816 if (pen.capStyle() == Qt::FlatCap) |
|
817 pen.setCapStyle(Qt::SquareCap); |
|
818 |
|
819 if (pen.brush().isOpaque()) { |
|
820 while (pointCount > 0) { |
|
821 int count = qMin(pointCount, 16); |
|
822 qreal pts[64]; |
|
823 int oset = -1; |
|
824 for (int i=0; i<count; ++i) { |
|
825 pts[++oset] = points[i].x(); |
|
826 pts[++oset] = points[i].y(); |
|
827 pts[++oset] = points[i].x() + 0.001; |
|
828 pts[++oset] = points[i].y(); |
|
829 } |
|
830 QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::NonCurvedShapeHint); |
|
831 stroke(path, pen); |
|
832 pointCount -= 16; |
|
833 points += 16; |
|
834 } |
|
835 } else { |
|
836 for (int i=0; i<pointCount; ++i) { |
|
837 qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + 0.001, points[i].y() }; |
|
838 QVectorPath path(pts, 2, 0); |
|
839 stroke(path, pen); |
|
840 } |
|
841 } |
|
842 } |
|
843 |
|
844 void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount) |
|
845 { |
|
846 QPen pen = state()->pen; |
|
847 if (pen.capStyle() == Qt::FlatCap) |
|
848 pen.setCapStyle(Qt::SquareCap); |
|
849 |
|
850 if (pen.brush().isOpaque()) { |
|
851 while (pointCount > 0) { |
|
852 int count = qMin(pointCount, 16); |
|
853 qreal pts[64]; |
|
854 int oset = -1; |
|
855 for (int i=0; i<count; ++i) { |
|
856 pts[++oset] = points[i].x(); |
|
857 pts[++oset] = points[i].y(); |
|
858 pts[++oset] = points[i].x() + 0.001; |
|
859 pts[++oset] = points[i].y(); |
|
860 } |
|
861 QVectorPath path(pts, count * 2, qpaintengineex_line_types_16, QVectorPath::NonCurvedShapeHint); |
|
862 stroke(path, pen); |
|
863 pointCount -= 16; |
|
864 points += 16; |
|
865 } |
|
866 } else { |
|
867 for (int i=0; i<pointCount; ++i) { |
|
868 qreal pts[] = { points[i].x(), points[i].y(), points[i].x() + 0.001, points[i].y() }; |
|
869 QVectorPath path(pts, 2, 0); |
|
870 stroke(path, pen); |
|
871 } |
|
872 } |
|
873 } |
|
874 |
|
875 |
|
876 void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) |
|
877 { |
|
878 QVectorPath path((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode)); |
|
879 |
|
880 if (mode == PolylineMode) |
|
881 stroke(path, state()->pen); |
|
882 else |
|
883 draw(path); |
|
884 } |
|
885 |
|
886 void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) |
|
887 { |
|
888 int count = pointCount<<1; |
|
889 QVarLengthArray<qreal> pts(count); |
|
890 |
|
891 #ifdef Q_WS_MAC |
|
892 for (int i=0; i<count; i+=2) { |
|
893 pts[i] = ((int *) points)[i+1]; |
|
894 pts[i+1] = ((int *) points)[i]; |
|
895 } |
|
896 #else |
|
897 for (int i=0; i<count; ++i) |
|
898 pts[i] = ((int *) points)[i]; |
|
899 #endif |
|
900 |
|
901 QVectorPath path(pts.data(), pointCount, 0, QVectorPath::polygonFlags(mode)); |
|
902 |
|
903 if (mode == PolylineMode) |
|
904 stroke(path, state()->pen); |
|
905 else |
|
906 draw(path); |
|
907 |
|
908 } |
|
909 |
|
910 void QPaintEngineEx::drawPixmap(const QPointF &pos, const QPixmap &pm) |
|
911 { |
|
912 drawPixmap(QRectF(pos, pm.size()), pm, pm.rect()); |
|
913 } |
|
914 |
|
915 void QPaintEngineEx::drawImage(const QPointF &pos, const QImage &image) |
|
916 { |
|
917 drawImage(QRectF(pos, image.size()), image, image.rect()); |
|
918 } |
|
919 |
|
920 void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s) |
|
921 { |
|
922 QBrush brush(state()->pen.color(), pixmap); |
|
923 QTransform xform = QTransform::fromTranslate(r.x() - s.x(), r.y() - s.y()); |
|
924 brush.setTransform(xform); |
|
925 |
|
926 qreal pts[] = { r.x(), r.y(), |
|
927 r.x() + r.width(), r.y(), |
|
928 r.x() + r.width(), r.y() + r.height(), |
|
929 r.x(), r.y() + r.height() }; |
|
930 |
|
931 QVectorPath path(pts, 4, 0, QVectorPath::RectangleHint); |
|
932 fill(path, brush); |
|
933 } |
|
934 |
|
935 void QPaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints /*hints*/) |
|
936 { |
|
937 qreal oldOpacity = state()->opacity; |
|
938 QTransform oldTransform = state()->matrix; |
|
939 |
|
940 for (int i = 0; i < dataCount; ++i) { |
|
941 QTransform transform = oldTransform; |
|
942 transform.translate(drawingData[i].point.x(), drawingData[i].point.y()); |
|
943 transform.rotate(drawingData[i].rotation); |
|
944 state()->opacity = oldOpacity * drawingData[i].opacity; |
|
945 state()->matrix = transform; |
|
946 opacityChanged(); |
|
947 transformChanged(); |
|
948 |
|
949 qreal w = drawingData[i].scaleX * drawingData[i].source.width(); |
|
950 qreal h = drawingData[i].scaleY * drawingData[i].source.height(); |
|
951 drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source); |
|
952 } |
|
953 |
|
954 state()->opacity = oldOpacity; |
|
955 state()->matrix = oldTransform; |
|
956 opacityChanged(); |
|
957 transformChanged(); |
|
958 } |
|
959 |
|
960 void QPaintEngineEx::setState(QPainterState *s) |
|
961 { |
|
962 QPaintEngine::state = s; |
|
963 } |
|
964 |
|
965 |
|
966 void QPaintEngineEx::updateState(const QPaintEngineState &) |
|
967 { |
|
968 // do nothing... |
|
969 } |
|
970 |
|
971 QT_END_NAMESPACE |