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 | #ifndef QPAINTENGINE_RASTER_P_H |
41 | #define QPAINTENGINE_RASTER_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists for the convenience |
48 | // of other Qt classes. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <QtGui/private/qtguiglobal_p.h> |
55 | #include "private/qpaintengineex_p.h" |
56 | #include "QtGui/qpainterpath.h" |
57 | #include "private/qdatabuffer_p.h" |
58 | #include "private/qdrawhelper_p.h" |
59 | #include "private/qpaintengine_p.h" |
60 | #include "private/qrasterizer_p.h" |
61 | #include "private/qstroker_p.h" |
62 | #include "private/qpainter_p.h" |
63 | #include "private/qtextureglyphcache_p.h" |
64 | #include "private/qoutlinemapper_p.h" |
65 | |
66 | #include <stdlib.h> |
67 | |
68 | QT_BEGIN_NAMESPACE |
69 | |
70 | class QOutlineMapper; |
71 | class QRasterPaintEnginePrivate; |
72 | class QRasterBuffer; |
73 | class QClipData; |
74 | |
75 | class QRasterPaintEngineState : public QPainterState |
76 | { |
77 | public: |
78 | QRasterPaintEngineState(QRasterPaintEngineState &other); |
79 | QRasterPaintEngineState(); |
80 | ~QRasterPaintEngineState(); |
81 | |
82 | |
83 | QPen lastPen; |
84 | QSpanData penData; |
85 | QStrokerOps *stroker; |
86 | uint strokeFlags; |
87 | |
88 | QBrush lastBrush; |
89 | QSpanData brushData; |
90 | uint fillFlags; |
91 | |
92 | uint pixmapFlags; |
93 | int intOpacity; |
94 | |
95 | qreal txscale; |
96 | |
97 | QClipData *clip; |
98 | // QRect clipRect; |
99 | // QRegion clipRegion; |
100 | |
101 | // QPainter::RenderHints hints; |
102 | // QPainter::CompositionMode compositionMode; |
103 | |
104 | uint dirty; |
105 | |
106 | struct Flags { |
107 | uint has_clip_ownership : 1; // should delete the clip member.. |
108 | uint fast_pen : 1; // cosmetic 1-width pens, using midpoint drawlines |
109 | uint non_complex_pen : 1; // can use rasterizer, rather than stroker |
110 | uint antialiased : 1; |
111 | uint bilinear : 1; |
112 | uint legacy_rounding : 1; |
113 | uint fast_text : 1; |
114 | uint int_xform : 1; |
115 | uint tx_noshear : 1; |
116 | uint fast_images : 1; |
117 | }; |
118 | |
119 | union { |
120 | Flags flags; |
121 | uint flag_bits; |
122 | }; |
123 | }; |
124 | |
125 | |
126 | |
127 | |
128 | /******************************************************************************* |
129 | * QRasterPaintEngine |
130 | */ |
131 | class Q_GUI_EXPORT QRasterPaintEngine : public QPaintEngineEx |
132 | { |
133 | Q_DECLARE_PRIVATE(QRasterPaintEngine) |
134 | public: |
135 | |
136 | QRasterPaintEngine(QPaintDevice *device); |
137 | ~QRasterPaintEngine(); |
138 | bool begin(QPaintDevice *device) override; |
139 | bool end() override; |
140 | |
141 | void penChanged() override; |
142 | void brushChanged() override; |
143 | void brushOriginChanged() override; |
144 | void opacityChanged() override; |
145 | void compositionModeChanged() override; |
146 | void renderHintsChanged() override; |
147 | void transformChanged() override; |
148 | void clipEnabledChanged() override; |
149 | |
150 | void setState(QPainterState *s) override; |
151 | QPainterState *createState(QPainterState *orig) const override; |
152 | inline QRasterPaintEngineState *state() { |
153 | return static_cast<QRasterPaintEngineState *>(QPaintEngineEx::state()); |
154 | } |
155 | inline const QRasterPaintEngineState *state() const { |
156 | return static_cast<const QRasterPaintEngineState *>(QPaintEngineEx::state()); |
157 | } |
158 | |
159 | void updateBrush(const QBrush &brush); |
160 | void updatePen(const QPen &pen); |
161 | |
162 | void updateMatrix(const QTransform &matrix); |
163 | |
164 | virtual void fillPath(const QPainterPath &path, QSpanData *fillData); |
165 | virtual void fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); |
166 | |
167 | void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) override; |
168 | void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) override; |
169 | |
170 | void drawEllipse(const QRectF &rect) override; |
171 | |
172 | void fillRect(const QRectF &rect, const QBrush &brush) override; |
173 | void fillRect(const QRectF &rect, const QColor &color) override; |
174 | |
175 | void drawRects(const QRect *rects, int rectCount) override; |
176 | void drawRects(const QRectF *rects, int rectCount) override; |
177 | |
178 | void drawPixmap(const QPointF &p, const QPixmap &pm) override; |
179 | void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override; |
180 | void drawImage(const QPointF &p, const QImage &img) override; |
181 | void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, |
182 | Qt::ImageConversionFlags flags = Qt::AutoColor) override; |
183 | void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr) override; |
184 | void drawTextItem(const QPointF &p, const QTextItem &textItem) override; |
185 | |
186 | void drawLines(const QLine *line, int lineCount) override; |
187 | void drawLines(const QLineF *line, int lineCount) override; |
188 | |
189 | void drawPoints(const QPointF *points, int pointCount) override; |
190 | void drawPoints(const QPoint *points, int pointCount) override; |
191 | |
192 | void stroke(const QVectorPath &path, const QPen &pen) override; |
193 | void fill(const QVectorPath &path, const QBrush &brush) override; |
194 | |
195 | void clip(const QVectorPath &path, Qt::ClipOperation op) override; |
196 | void clip(const QRect &rect, Qt::ClipOperation op) override; |
197 | void clip(const QRegion ®ion, Qt::ClipOperation op) override; |
198 | inline const QClipData *clipData() const; |
199 | |
200 | void drawStaticTextItem(QStaticTextItem *textItem) override; |
201 | virtual bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, |
202 | QFontEngine *fontEngine); |
203 | |
204 | enum ClipType { |
205 | RectClip, |
206 | ComplexClip |
207 | }; |
208 | ClipType clipType() const; |
209 | QRect clipBoundingRect() const; |
210 | |
211 | #ifdef Q_OS_WIN |
212 | void setDC(HDC hdc); |
213 | HDC getDC() const; |
214 | void releaseDC(HDC hdc) const; |
215 | static bool clearTypeFontsEnabled(); |
216 | #endif |
217 | |
218 | QRasterBuffer *rasterBuffer(); |
219 | void alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h, bool useGammaCorrection); |
220 | |
221 | Type type() const override { return Raster; } |
222 | |
223 | QPoint coordinateOffset() const override; |
224 | |
225 | bool requiresPretransformedGlyphPositions(QFontEngine *fontEngine, const QTransform &m) const override; |
226 | bool shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const override; |
227 | |
228 | protected: |
229 | QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *); |
230 | private: |
231 | friend struct QSpanData; |
232 | friend class QBlitterPaintEngine; |
233 | friend class QBlitterPaintEnginePrivate; |
234 | void init(); |
235 | |
236 | void fillRect(const QRectF &rect, QSpanData *data); |
237 | void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); |
238 | |
239 | bool setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op); |
240 | |
241 | QRect toNormalizedFillRect(const QRectF &rect); |
242 | |
243 | inline void ensureBrush(const QBrush &brush) { |
244 | if (!qbrush_fast_equals(state()->lastBrush, brush) || state()->fillFlags) |
245 | updateBrush(brush); |
246 | } |
247 | inline void ensureBrush() { ensureBrush(state()->brush); } |
248 | |
249 | inline void ensurePen(const QPen &pen) { |
250 | if (!qpen_fast_equals(state()->lastPen, pen) || (pen.style() != Qt::NoPen && state()->strokeFlags)) |
251 | updatePen(pen); |
252 | } |
253 | inline void ensurePen() { ensurePen(state()->pen); } |
254 | |
255 | void updateOutlineMapper(); |
256 | inline void ensureOutlineMapper(); |
257 | |
258 | void updateRasterState(); |
259 | inline void ensureRasterState() { |
260 | if (state()->dirty) |
261 | updateRasterState(); |
262 | } |
263 | }; |
264 | |
265 | |
266 | /******************************************************************************* |
267 | * QRasterPaintEnginePrivate |
268 | */ |
269 | class QRasterPaintEnginePrivate : public QPaintEngineExPrivate |
270 | { |
271 | Q_DECLARE_PUBLIC(QRasterPaintEngine) |
272 | public: |
273 | QRasterPaintEnginePrivate(); |
274 | |
275 | void rasterizeLine_dashed(QLineF line, qreal width, |
276 | int *dashIndex, qreal *dashOffset, bool *inDash); |
277 | void rasterize(QT_FT_Outline *outline, ProcessSpans callback, QSpanData *spanData, QRasterBuffer *rasterBuffer); |
278 | void rasterize(QT_FT_Outline *outline, ProcessSpans callback, void *userData, QRasterBuffer *rasterBuffer); |
279 | void updateMatrixData(QSpanData *spanData, const QBrush &brush, const QTransform &brushMatrix); |
280 | |
281 | void systemStateChanged() override; |
282 | |
283 | void drawImage(const QPointF &pt, const QImage &img, SrcOverBlendFunc func, |
284 | const QRect &clip, int alpha, const QRect &sr = QRect()); |
285 | void blitImage(const QPointF &pt, const QImage &img, |
286 | const QRect &clip, const QRect &sr = QRect()); |
287 | |
288 | QTransform brushMatrix() const { |
289 | Q_Q(const QRasterPaintEngine); |
290 | const QRasterPaintEngineState *s = q->state(); |
291 | QTransform m(s->matrix); |
292 | m.translate(s->brushOrigin.x(), s->brushOrigin.y()); |
293 | return m; |
294 | } |
295 | |
296 | bool isUnclipped_normalized(const QRect &rect) const; |
297 | bool isUnclipped(const QRect &rect, int penWidth) const; |
298 | bool isUnclipped(const QRectF &rect, int penWidth) const; |
299 | ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const; |
300 | ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const; |
301 | ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const; |
302 | |
303 | inline const QClipData *clip() const; |
304 | |
305 | void initializeRasterizer(QSpanData *data); |
306 | |
307 | void recalculateFastImages(); |
308 | bool canUseFastImageBlending(QPainter::CompositionMode mode, const QImage &image) const; |
309 | bool canUseImageBlitting(QPainter::CompositionMode mode, const QImage &image, const QPointF &pt, const QRectF &sr) const; |
310 | |
311 | QPaintDevice *device; |
312 | QScopedPointer<QOutlineMapper> outlineMapper; |
313 | QScopedPointer<QRasterBuffer> rasterBuffer; |
314 | |
315 | #if defined (Q_OS_WIN) |
316 | HDC hdc; |
317 | #endif |
318 | |
319 | QRect deviceRect; |
320 | QRect deviceRectUnclipped; |
321 | |
322 | QStroker basicStroker; |
323 | QScopedPointer<QDashStroker> dashStroker; |
324 | |
325 | QScopedPointer<QT_FT_Raster> grayRaster; |
326 | |
327 | QDataBuffer<QLineF> cachedLines; |
328 | QSpanData image_filler; |
329 | QSpanData image_filler_xform; |
330 | QSpanData solid_color_filler; |
331 | |
332 | |
333 | QFontEngine::GlyphFormat glyphCacheFormat; |
334 | |
335 | QScopedPointer<QClipData> baseClip; |
336 | |
337 | int deviceDepth; |
338 | |
339 | uint mono_surface : 1; |
340 | uint outlinemapper_xform_dirty : 1; |
341 | |
342 | QScopedPointer<QRasterizer> rasterizer; |
343 | }; |
344 | |
345 | |
346 | class QClipData { |
347 | public: |
348 | QClipData(int height); |
349 | ~QClipData(); |
350 | |
351 | int clipSpanHeight; |
352 | struct ClipLine { |
353 | int count; |
354 | QSpan *spans; |
355 | } *m_clipLines; |
356 | |
357 | void initialize(); |
358 | |
359 | inline ClipLine *clipLines() { |
360 | if (!m_clipLines) |
361 | initialize(); |
362 | return m_clipLines; |
363 | } |
364 | |
365 | inline QSpan *spans() { |
366 | if (!m_spans) |
367 | initialize(); |
368 | return m_spans; |
369 | } |
370 | |
371 | int allocated; |
372 | int count; |
373 | QSpan *m_spans; |
374 | int xmin, xmax, ymin, ymax; |
375 | |
376 | QRect clipRect; |
377 | QRegion clipRegion; |
378 | |
379 | uint enabled : 1; |
380 | uint hasRectClip : 1; |
381 | uint hasRegionClip : 1; |
382 | |
383 | void appendSpan(int x, int length, int y, int coverage); |
384 | void appendSpans(const QSpan *s, int num); |
385 | |
386 | // ### Should optimize and actually kill the QSpans if the rect is |
387 | // ### a subset of The current region. Thus the "fast" clipspan |
388 | // ### callback can be used |
389 | void setClipRect(const QRect &rect); |
390 | void setClipRegion(const QRegion ®ion); |
391 | void fixup(); |
392 | }; |
393 | |
394 | inline void QClipData::appendSpan(int x, int length, int y, int coverage) |
395 | { |
396 | Q_ASSERT(m_spans); // initialize() has to be called prior to adding spans.. |
397 | |
398 | if (count == allocated) { |
399 | allocated *= 2; |
400 | m_spans = (QSpan *)realloc(m_spans, allocated*sizeof(QSpan)); |
401 | } |
402 | m_spans[count].x = x; |
403 | m_spans[count].len = length; |
404 | m_spans[count].y = y; |
405 | m_spans[count].coverage = coverage; |
406 | ++count; |
407 | } |
408 | |
409 | inline void QClipData::appendSpans(const QSpan *s, int num) |
410 | { |
411 | Q_ASSERT(m_spans); |
412 | |
413 | if (count + num > allocated) { |
414 | do { |
415 | allocated *= 2; |
416 | } while (count + num > allocated); |
417 | m_spans = (QSpan *)realloc(m_spans, allocated*sizeof(QSpan)); |
418 | } |
419 | memcpy(m_spans+count, s, num*sizeof(QSpan)); |
420 | count += num; |
421 | } |
422 | |
423 | /******************************************************************************* |
424 | * QRasterBuffer |
425 | */ |
426 | class QRasterBuffer |
427 | { |
428 | public: |
429 | QRasterBuffer() : m_width(0), m_height(0), m_buffer(nullptr) { init(); } |
430 | |
431 | ~QRasterBuffer(); |
432 | |
433 | void init(); |
434 | |
435 | QImage::Format prepare(QImage *image); |
436 | |
437 | uchar *scanLine(int y) { Q_ASSERT(y>=0); Q_ASSERT(y<m_height); return m_buffer + y * bytes_per_line; } |
438 | |
439 | int width() const { return m_width; } |
440 | int height() const { return m_height; } |
441 | qsizetype bytesPerLine() const { return bytes_per_line; } |
442 | int bytesPerPixel() const { return bytes_per_pixel; } |
443 | template<typename T> |
444 | int stride() { return static_cast<int>(bytes_per_line / sizeof(T)); } |
445 | |
446 | uchar *buffer() const { return m_buffer; } |
447 | |
448 | bool monoDestinationWithClut; |
449 | QRgb destColor0; |
450 | QRgb destColor1; |
451 | |
452 | QPainter::CompositionMode compositionMode; |
453 | QImage::Format format; |
454 | QImage colorizeBitmap(const QImage &image, const QColor &color); |
455 | |
456 | private: |
457 | int m_width; |
458 | int m_height; |
459 | qsizetype bytes_per_line; |
460 | int bytes_per_pixel; |
461 | uchar *m_buffer; |
462 | }; |
463 | |
464 | inline void QRasterPaintEngine::ensureOutlineMapper() { |
465 | if (d_func()->outlinemapper_xform_dirty) |
466 | updateOutlineMapper(); |
467 | } |
468 | |
469 | inline const QClipData *QRasterPaintEnginePrivate::clip() const { |
470 | Q_Q(const QRasterPaintEngine); |
471 | if (q->state() && q->state()->clip && q->state()->clip->enabled) |
472 | return q->state()->clip; |
473 | return baseClip.data(); |
474 | } |
475 | |
476 | inline const QClipData *QRasterPaintEngine::clipData() const { |
477 | Q_D(const QRasterPaintEngine); |
478 | if (state() && state()->clip && state()->clip->enabled) |
479 | return state()->clip; |
480 | return d->baseClip.data(); |
481 | } |
482 | |
483 | QT_END_NAMESPACE |
484 | #endif // QPAINTENGINE_RASTER_P_H |
485 | |