1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "private/qpaintengine_p.h"
41 #include "private/qpainter_p.h"
42 #include "private/qpicture_p.h"
43 #include "private/qfont_p.h"
44
45 #ifndef QT_NO_PICTURE
46
47 #include "qbuffer.h"
48 #include "qbytearray.h"
49 #include "qdatastream.h"
50 #include "qmath.h"
51 #include "qpaintengine_pic_p.h"
52 #include "qpicture.h"
53 #include "qpolygon.h"
54 #include "qrect.h"
55 #include <private/qtextengine_p.h>
56
57 //#define QT_PICTURE_DEBUG
58 #include <qdebug.h>
59
60
61 QT_BEGIN_NAMESPACE
62
63 class QPicturePaintEnginePrivate : public QPaintEnginePrivate
64 {
65 Q_DECLARE_PUBLIC(QPicturePaintEngine)
66 public:
67 QDataStream s;
68 QPainter *pt;
69 QPicturePrivate *pic_d;
70 };
71
QPicturePaintEngine()72 QPicturePaintEngine::QPicturePaintEngine()
73 : QPaintEngine(*(new QPicturePaintEnginePrivate), AllFeatures)
74 {
75 Q_D(QPicturePaintEngine);
76 d->pt = nullptr;
77 }
78
QPicturePaintEngine(QPaintEnginePrivate & dptr)79 QPicturePaintEngine::QPicturePaintEngine(QPaintEnginePrivate &dptr)
80 : QPaintEngine(dptr, AllFeatures)
81 {
82 Q_D(QPicturePaintEngine);
83 d->pt = nullptr;
84 }
85
~QPicturePaintEngine()86 QPicturePaintEngine::~QPicturePaintEngine()
87 {
88 }
89
begin(QPaintDevice * pd)90 bool QPicturePaintEngine::begin(QPaintDevice *pd)
91 {
92 Q_D(QPicturePaintEngine);
93 #ifdef QT_PICTURE_DEBUG
94 qDebug("QPicturePaintEngine::begin()");
95 #endif
96 Q_ASSERT(pd);
97 QPicture *pic = static_cast<QPicture *>(pd);
98
99 d->pdev = pd;
100 d->pic_d = pic->d_func();
101 Q_ASSERT(d->pic_d);
102
103 d->s.setDevice(&d->pic_d->pictb);
104 d->s.setVersion(d->pic_d->formatMajor);
105
106 d->pic_d->pictb.open(QIODevice::WriteOnly | QIODevice::Truncate);
107 d->s.writeRawData(qt_mfhdr_tag, 4);
108 d->s << (quint16) 0 << (quint16) d->pic_d->formatMajor << (quint16) d->pic_d->formatMinor;
109 d->s << (quint8) QPicturePrivate::PdcBegin << (quint8) sizeof(qint32);
110 d->pic_d->brect = QRect();
111 if (d->pic_d->formatMajor >= 4) {
112 QRect r = pic->boundingRect();
113 d->s << (qint32) r.left() << (qint32) r.top() << (qint32) r.width()
114 << (qint32) r.height();
115 }
116 d->pic_d->trecs = 0;
117 d->s << (quint32)d->pic_d->trecs; // total number of records
118 d->pic_d->formatOk = false;
119 setActive(true);
120 return true;
121 }
122
end()123 bool QPicturePaintEngine::end()
124 {
125 Q_D(QPicturePaintEngine);
126 #ifdef QT_PICTURE_DEBUG
127 qDebug("QPicturePaintEngine::end()");
128 #endif
129 d->pic_d->trecs++;
130 d->s << (quint8) QPicturePrivate::PdcEnd << (quint8) 0;
131 int cs_start = sizeof(quint32); // pos of checksum word
132 int data_start = cs_start + sizeof(quint16);
133 int brect_start = data_start + 2*sizeof(qint16) + 2*sizeof(quint8);
134 int pos = d->pic_d->pictb.pos();
135 d->pic_d->pictb.seek(brect_start);
136 if (d->pic_d->formatMajor >= 4) { // bounding rectangle
137 QRect r = static_cast<QPicture *>(d->pdev)->boundingRect();
138 d->s << (qint32) r.left() << (qint32) r.top() << (qint32) r.width()
139 << (qint32) r.height();
140 }
141 d->s << (quint32) d->pic_d->trecs; // write number of records
142 d->pic_d->pictb.seek(cs_start);
143 QByteArray buf = d->pic_d->pictb.buffer();
144 quint16 cs = (quint16) qChecksum(buf.constData() + data_start, pos - data_start);
145 d->s << cs; // write checksum
146 d->pic_d->pictb.close();
147 setActive(false);
148 return true;
149 }
150
151 #define SERIALIZE_CMD(c) \
152 d->pic_d->trecs++; \
153 d->s << (quint8) c; \
154 d->s << (quint8) 0; \
155 pos = d->pic_d->pictb.pos()
156
updatePen(const QPen & pen)157 void QPicturePaintEngine::updatePen(const QPen &pen)
158 {
159 Q_D(QPicturePaintEngine);
160 #ifdef QT_PICTURE_DEBUG
161 qDebug() << " -> updatePen(): width:" << pen.width() << "style:"
162 << pen.style() << "color:" << pen.color();
163 #endif
164 int pos;
165 SERIALIZE_CMD(QPicturePrivate::PdcSetPen);
166 if (d->pic_d->in_memory_only) {
167 int index = d->pic_d->pen_list.size();
168 d->pic_d->pen_list.append(pen);
169 d->s << index;
170 } else {
171 d->s << pen;
172 }
173 writeCmdLength(pos, QRect(), false);
174 }
175
updateCompositionMode(QPainter::CompositionMode cmode)176 void QPicturePaintEngine::updateCompositionMode(QPainter::CompositionMode cmode)
177 {
178 Q_D(QPicturePaintEngine);
179 #ifdef QT_PICTURE_DEBUG
180 qDebug() << " -> updateCompositionMode():" << cmode;
181 #endif
182 int pos;
183 SERIALIZE_CMD(QPicturePrivate::PdcSetCompositionMode);
184 d->s << (qint32)cmode;
185 writeCmdLength(pos, QRectF(), false);
186 }
187
updateClipEnabled(bool enabled)188 void QPicturePaintEngine::updateClipEnabled(bool enabled)
189 {
190 Q_D(QPicturePaintEngine);
191 #ifdef QT_PICTURE_DEBUG
192 qDebug() << " -> updateClipEnabled():" << enabled;
193 #endif
194 int pos;
195 SERIALIZE_CMD(QPicturePrivate::PdcSetClipEnabled);
196 d->s << enabled;
197 writeCmdLength(pos, QRectF(), false);
198 }
199
updateOpacity(qreal opacity)200 void QPicturePaintEngine::updateOpacity(qreal opacity)
201 {
202 Q_D(QPicturePaintEngine);
203 #ifdef QT_PICTURE_DEBUG
204 qDebug() << " -> updateOpacity():" << opacity;
205 #endif
206 int pos;
207 SERIALIZE_CMD(QPicturePrivate::PdcSetOpacity);
208 d->s << double(opacity);
209 writeCmdLength(pos, QRectF(), false);
210 }
211
updateBrush(const QBrush & brush)212 void QPicturePaintEngine::updateBrush(const QBrush &brush)
213 {
214 Q_D(QPicturePaintEngine);
215 #ifdef QT_PICTURE_DEBUG
216 qDebug() << " -> updateBrush(): style:" << brush.style();
217 #endif
218 int pos;
219 SERIALIZE_CMD(QPicturePrivate::PdcSetBrush);
220 if (d->pic_d->in_memory_only) {
221 int index = d->pic_d->brush_list.size();
222 d->pic_d->brush_list.append(brush);
223 d->s << index;
224 } else {
225 d->s << brush;
226 }
227 writeCmdLength(pos, QRect(), false);
228 }
229
updateBrushOrigin(const QPointF & p)230 void QPicturePaintEngine::updateBrushOrigin(const QPointF &p)
231 {
232 Q_D(QPicturePaintEngine);
233 #ifdef QT_PICTURE_DEBUG
234 qDebug() << " -> updateBrushOrigin(): " << p;
235 #endif
236 int pos;
237 SERIALIZE_CMD(QPicturePrivate::PdcSetBrushOrigin);
238 d->s << p;
239 writeCmdLength(pos, QRect(), false);
240 }
241
updateFont(const QFont & font)242 void QPicturePaintEngine::updateFont(const QFont &font)
243 {
244 Q_D(QPicturePaintEngine);
245 #ifdef QT_PICTURE_DEBUG
246 qDebug() << " -> updateFont(): pt sz:" << font.pointSize();
247 #endif
248 int pos;
249 SERIALIZE_CMD(QPicturePrivate::PdcSetFont);
250 QFont fnt = font;
251 d->s << fnt;
252 writeCmdLength(pos, QRectF(), false);
253 }
254
updateBackground(Qt::BGMode bgMode,const QBrush & bgBrush)255 void QPicturePaintEngine::updateBackground(Qt::BGMode bgMode, const QBrush &bgBrush)
256 {
257 Q_D(QPicturePaintEngine);
258 #ifdef QT_PICTURE_DEBUG
259 qDebug() << " -> updateBackground(): mode:" << bgMode << "style:" << bgBrush.style();
260 #endif
261 int pos;
262 SERIALIZE_CMD(QPicturePrivate::PdcSetBkColor);
263 d->s << bgBrush.color();
264 writeCmdLength(pos, QRect(), false);
265
266 SERIALIZE_CMD(QPicturePrivate::PdcSetBkMode);
267 d->s << (qint8) bgMode;
268 writeCmdLength(pos, QRectF(), false);
269 }
270
updateMatrix(const QTransform & matrix)271 void QPicturePaintEngine::updateMatrix(const QTransform &matrix)
272 {
273 Q_D(QPicturePaintEngine);
274 #ifdef QT_PICTURE_DEBUG
275 qDebug() << " -> updateMatrix():" << matrix;
276 #endif
277 int pos;
278 SERIALIZE_CMD(QPicturePrivate::PdcSetWMatrix);
279 d->s << matrix << (qint8) false;
280 writeCmdLength(pos, QRectF(), false);
281 }
282
updateClipRegion(const QRegion & region,Qt::ClipOperation op)283 void QPicturePaintEngine::updateClipRegion(const QRegion ®ion, Qt::ClipOperation op)
284 {
285 Q_D(QPicturePaintEngine);
286 #ifdef QT_PICTURE_DEBUG
287 qDebug() << " -> updateClipRegion(): op:" << op
288 << "bounding rect:" << region.boundingRect();
289 #endif
290 int pos;
291 SERIALIZE_CMD(QPicturePrivate::PdcSetClipRegion);
292 d->s << region << qint8(op);
293 writeCmdLength(pos, QRectF(), false);
294 }
295
updateClipPath(const QPainterPath & path,Qt::ClipOperation op)296 void QPicturePaintEngine::updateClipPath(const QPainterPath &path, Qt::ClipOperation op)
297 {
298 Q_D(QPicturePaintEngine);
299 #ifdef QT_PICTURE_DEBUG
300 qDebug() << " -> updateClipPath(): op:" << op
301 << "bounding rect:" << path.boundingRect();
302 #endif
303 int pos;
304
305 SERIALIZE_CMD(QPicturePrivate::PdcSetClipPath);
306 d->s << path << qint8(op);
307 writeCmdLength(pos, QRectF(), false);
308 }
309
updateRenderHints(QPainter::RenderHints hints)310 void QPicturePaintEngine::updateRenderHints(QPainter::RenderHints hints)
311 {
312 Q_D(QPicturePaintEngine);
313 #ifdef QT_PICTURE_DEBUG
314 qDebug() << " -> updateRenderHints(): " << hints;
315 #endif
316 int pos;
317 SERIALIZE_CMD(QPicturePrivate::PdcSetRenderHint);
318 d->s << (quint32) hints;
319 writeCmdLength(pos, QRect(), false);
320 }
321
writeCmdLength(int pos,const QRectF & r,bool corr)322 void QPicturePaintEngine::writeCmdLength(int pos, const QRectF &r, bool corr)
323 {
324 Q_D(QPicturePaintEngine);
325 int newpos = d->pic_d->pictb.pos(); // new position
326 int length = newpos - pos;
327 QRectF br(r);
328
329 if (length < 255) { // write 8-bit length
330 d->pic_d->pictb.seek(pos - 1); // position to right index
331 d->s << (quint8)length;
332 } else { // write 32-bit length
333 d->s << (quint32)0; // extend the buffer
334 d->pic_d->pictb.seek(pos - 1); // position to right index
335 d->s << (quint8)255; // indicate 32-bit length
336 char *p = d->pic_d->pictb.buffer().data();
337 memmove(p+pos+4, p+pos, length); // make room for 4 byte
338 d->s << (quint32)length;
339 newpos += 4;
340 }
341 d->pic_d->pictb.seek(newpos); // set to new position
342
343 if (br.width() > 0.0 || br.height() > 0.0) {
344 if (corr) { // widen bounding rect
345 int w2 = painter()->pen().width() / 2;
346 br.setCoords(br.left() - w2, br.top() - w2,
347 br.right() + w2, br.bottom() + w2);
348 }
349 br = painter()->transform().mapRect(br);
350 if (painter()->hasClipping()) {
351 QRectF cr = painter()->clipBoundingRect();
352 br &= cr;
353 }
354
355 if (br.width() > 0.0 || br.height() > 0.0) {
356 int minx = qFloor(br.left());
357 int miny = qFloor(br.top());
358 int maxx = qCeil(br.right());
359 int maxy = qCeil(br.bottom());
360
361 if (d->pic_d->brect.width() > 0 || d->pic_d->brect.height() > 0) {
362 minx = qMin(minx, d->pic_d->brect.left());
363 miny = qMin(miny, d->pic_d->brect.top());
364 maxx = qMax(maxx, d->pic_d->brect.x() + d->pic_d->brect.width());
365 maxy = qMax(maxy, d->pic_d->brect.y() + d->pic_d->brect.height());
366 d->pic_d->brect = QRect(minx, miny, maxx - minx, maxy - miny);
367 } else {
368 d->pic_d->brect = QRect(minx, miny, maxx - minx, maxy - miny);
369 }
370 }
371 }
372 }
373
drawEllipse(const QRectF & rect)374 void QPicturePaintEngine::drawEllipse(const QRectF &rect)
375 {
376 Q_D(QPicturePaintEngine);
377 #ifdef QT_PICTURE_DEBUG
378 qDebug() << " -> drawEllipse():" << rect;
379 #endif
380 int pos;
381 SERIALIZE_CMD(QPicturePrivate::PdcDrawEllipse);
382 d->s << rect;
383 writeCmdLength(pos, rect, true);
384 }
385
drawPath(const QPainterPath & path)386 void QPicturePaintEngine::drawPath(const QPainterPath &path)
387 {
388 Q_D(QPicturePaintEngine);
389 #ifdef QT_PICTURE_DEBUG
390 qDebug() << " -> drawPath():" << path.boundingRect();
391 #endif
392 int pos;
393 SERIALIZE_CMD(QPicturePrivate::PdcDrawPath);
394 d->s << path;
395 writeCmdLength(pos, path.boundingRect(), true);
396 }
397
drawPolygon(const QPointF * points,int numPoints,PolygonDrawMode mode)398 void QPicturePaintEngine::drawPolygon(const QPointF *points, int numPoints, PolygonDrawMode mode)
399 {
400 Q_D(QPicturePaintEngine);
401 #ifdef QT_PICTURE_DEBUG
402 qDebug() << " -> drawPolygon(): size=" << numPoints;
403 #endif
404 int pos;
405
406 QPolygonF polygon;
407 polygon.reserve(numPoints);
408 for (int i=0; i<numPoints; ++i)
409 polygon << points[i];
410
411 if (mode == PolylineMode) {
412 SERIALIZE_CMD(QPicturePrivate::PdcDrawPolyline);
413 d->s << polygon;
414 } else {
415 SERIALIZE_CMD(QPicturePrivate::PdcDrawPolygon);
416 d->s << polygon;
417 d->s << (qint8)(mode == OddEvenMode ? 0 : 1);
418 }
419
420 writeCmdLength(pos, polygon.boundingRect(), true);
421 }
422
drawPixmap(const QRectF & r,const QPixmap & pm,const QRectF & sr)423 void QPicturePaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
424 {
425 Q_D(QPicturePaintEngine);
426 #ifdef QT_PICTURE_DEBUG
427 qDebug() << " -> drawPixmap():" << r;
428 #endif
429 int pos;
430 SERIALIZE_CMD(QPicturePrivate::PdcDrawPixmap);
431
432 if (d->pic_d->in_memory_only) {
433 int index = d->pic_d->pixmap_list.size();
434 d->pic_d->pixmap_list.append(pm);
435 d->s << r << index << sr;
436 } else {
437 d->s << r << pm << sr;
438 }
439 writeCmdLength(pos, r, false);
440 }
441
drawTiledPixmap(const QRectF & r,const QPixmap & pixmap,const QPointF & s)442 void QPicturePaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
443 {
444 Q_D(QPicturePaintEngine);
445 #ifdef QT_PICTURE_DEBUG
446 qDebug() << " -> drawTiledPixmap():" << r << s;
447 #endif
448 int pos;
449 SERIALIZE_CMD(QPicturePrivate::PdcDrawTiledPixmap);
450 if (d->pic_d->in_memory_only) {
451 int index = d->pic_d->pixmap_list.size();
452 d->pic_d->pixmap_list.append(pixmap);
453 d->s << r << index << s;
454 } else {
455 d->s << r << pixmap << s;
456 }
457 writeCmdLength(pos, r, false);
458 }
459
drawImage(const QRectF & r,const QImage & image,const QRectF & sr,Qt::ImageConversionFlags flags)460 void QPicturePaintEngine::drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
461 Qt::ImageConversionFlags flags)
462 {
463 Q_D(QPicturePaintEngine);
464 #ifdef QT_PICTURE_DEBUG
465 qDebug() << " -> drawImage():" << r << sr;
466 #endif
467 int pos;
468 SERIALIZE_CMD(QPicturePrivate::PdcDrawImage);
469 if (d->pic_d->in_memory_only) {
470 int index = d->pic_d->image_list.size();
471 d->pic_d->image_list.append(image);
472 d->s << r << index << sr << (quint32) flags;
473 } else {
474 d->s << r << image << sr << (quint32) flags;
475 }
476 writeCmdLength(pos, r, false);
477 }
478
drawTextItem(const QPointF & p,const QTextItem & ti)479 void QPicturePaintEngine::drawTextItem(const QPointF &p , const QTextItem &ti)
480 {
481 Q_D(QPicturePaintEngine);
482 #ifdef QT_PICTURE_DEBUG
483 qDebug() << " -> drawTextItem():" << p << ti.text();
484 #endif
485
486 const QTextItemInt &si = static_cast<const QTextItemInt &>(ti);
487 if (si.chars == nullptr)
488 QPaintEngine::drawTextItem(p, ti); // Draw as path
489
490 if (d->pic_d->formatMajor >= 9) {
491 int pos;
492 SERIALIZE_CMD(QPicturePrivate::PdcDrawTextItem);
493 QFont fnt = ti.font();
494 fnt.setUnderline(false);
495 fnt.setStrikeOut(false);
496 fnt.setOverline(false);
497
498 qreal justificationWidth = 0;
499 if (si.justified)
500 justificationWidth = si.width.toReal();
501
502 d->s << p << ti.text() << fnt << ti.renderFlags() << double(fnt.d->dpi)/qt_defaultDpi() << justificationWidth;
503 writeCmdLength(pos, /*brect=*/QRectF(), /*corr=*/false);
504 } else if (d->pic_d->formatMajor >= 8) {
505 // old old (buggy) format
506 int pos;
507 SERIALIZE_CMD(QPicturePrivate::PdcDrawTextItem);
508 d->s << QPointF(p.x(), p.y() - ti.ascent()) << ti.text() << ti.font() << ti.renderFlags();
509 writeCmdLength(pos, /*brect=*/QRectF(), /*corr=*/false);
510 } else {
511 // old (buggy) format
512 int pos;
513 SERIALIZE_CMD(QPicturePrivate::PdcDrawText2);
514 d->s << p << ti.text();
515 writeCmdLength(pos, QRectF(p, QSizeF(1,1)), true);
516 }
517 }
518
updateState(const QPaintEngineState & state)519 void QPicturePaintEngine::updateState(const QPaintEngineState &state)
520 {
521 QPaintEngine::DirtyFlags flags = state.state();
522 if (flags & DirtyPen) updatePen(state.pen());
523 if (flags & DirtyBrush) updateBrush(state.brush());
524 if (flags & DirtyBrushOrigin) updateBrushOrigin(state.brushOrigin());
525 if (flags & DirtyFont) updateFont(state.font());
526 if (flags & DirtyBackground) updateBackground(state.backgroundMode(), state.backgroundBrush());
527 if (flags & DirtyTransform) updateMatrix(state.transform());
528 if (flags & DirtyClipEnabled) updateClipEnabled(state.isClipEnabled());
529 if (flags & DirtyClipRegion) updateClipRegion(state.clipRegion(), state.clipOperation());
530 if (flags & DirtyClipPath) updateClipPath(state.clipPath(), state.clipOperation());
531 if (flags & DirtyHints) updateRenderHints(state.renderHints());
532 if (flags & DirtyCompositionMode) updateCompositionMode(state.compositionMode());
533 if (flags & DirtyOpacity) updateOpacity(state.opacity());
534 }
535
536 QT_END_NAMESPACE
537
538 #endif // QT_NO_PICTURE
539