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
61QT_BEGIN_NAMESPACE
62
63class QPicturePaintEnginePrivate : public QPaintEnginePrivate
64{
65 Q_DECLARE_PUBLIC(QPicturePaintEngine)
66public:
67 QDataStream s;
68 QPainter *pt;
69 QPicturePrivate *pic_d;
70};
71
72QPicturePaintEngine::QPicturePaintEngine()
73 : QPaintEngine(*(new QPicturePaintEnginePrivate), AllFeatures)
74{
75 Q_D(QPicturePaintEngine);
76 d->pt = 0;
77}
78
79QPicturePaintEngine::QPicturePaintEngine(QPaintEnginePrivate &dptr)
80 : QPaintEngine(dptr, AllFeatures)
81{
82 Q_D(QPicturePaintEngine);
83 d->pt = 0;
84}
85
86QPicturePaintEngine::~QPicturePaintEngine()
87{
88}
89
90bool 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
123bool 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
157void 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
176void 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
188void 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
200void 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
212void 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
230void 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
242void 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
255void 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
271void 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
283void QPicturePaintEngine::updateClipRegion(const QRegion &region, 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
296void 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
310void 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
322void 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
374void 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
386void 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
398void 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
423void 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
442void 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
460void 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
479void 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 == 0)
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
519void 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
536QT_END_NAMESPACE
537
538#endif // QT_NO_PICTURE
539