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