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