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_blitter_p.h" |
41 | |
42 | #include "private/qblittable_p.h" |
43 | #include "private/qpaintengine_raster_p.h" |
44 | #include "private/qpainter_p.h" |
45 | #include "private/qpixmap_blitter_p.h" |
46 | |
47 | #ifndef QT_NO_BLITTABLE |
48 | QT_BEGIN_NAMESPACE |
49 | |
50 | #define STATE_XFORM_SCALE 0x00000001 |
51 | #define STATE_XFORM_COMPLEX 0x00000002 |
52 | |
53 | #define STATE_BRUSH_PATTERN 0x00000010 |
54 | #define STATE_BRUSH_ALPHA 0x00000020 |
55 | |
56 | #define STATE_PEN_ENABLED 0x00000100 |
57 | |
58 | #define STATE_ANTIALIASING 0x00001000 |
59 | #define STATE_ALPHA 0x00002000 |
60 | #define STATE_BLENDING_COMPLEX 0x00004000 |
61 | |
62 | #define STATE_CLIPSYS_COMPLEX 0x00010000 |
63 | #define STATE_CLIP_COMPLEX 0x00020000 |
64 | |
65 | |
66 | class CapabilitiesToStateMask |
67 | { |
68 | public: |
69 | CapabilitiesToStateMask(QBlittable::Capabilities capabilities) |
70 | : m_capabilities(capabilities) |
71 | , fillRectMask(0) |
72 | , drawRectMask(0) |
73 | , drawPixmapMask(0) |
74 | , alphaFillRectMask(0) |
75 | , opacityPixmapMask(0) |
76 | , capabillitiesState(0) |
77 | { |
78 | if (capabilities & QBlittable::SolidRectCapability) |
79 | setFillRectMask(); |
80 | if (capabilities & QBlittable::SourcePixmapCapability) |
81 | setSourcePixmapMask(); |
82 | if (capabilities & QBlittable::SourceOverPixmapCapability) |
83 | setSourceOverPixmapMask(); |
84 | if (capabilities & QBlittable::SourceOverScaledPixmapCapability) |
85 | setSourceOverScaledPixmapMask(); |
86 | if (capabilities & QBlittable::AlphaFillRectCapability) |
87 | setAlphaFillRectMask(); |
88 | if (capabilities & QBlittable::OpacityPixmapCapability) |
89 | setOpacityPixmapMask(); |
90 | } |
91 | |
92 | inline bool canBlitterFillRect() const |
93 | { |
94 | return checkStateAgainstMask(capabillitiesState, fillRectMask); |
95 | } |
96 | |
97 | inline bool canBlitterAlphaFillRect() const |
98 | { |
99 | return checkStateAgainstMask(capabillitiesState, alphaFillRectMask); |
100 | } |
101 | |
102 | inline bool canBlitterDrawRectMask() const |
103 | { |
104 | return checkStateAgainstMask(capabillitiesState, drawRectMask); |
105 | } |
106 | |
107 | bool canBlitterDrawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) const |
108 | { |
109 | if (pm.handle()->classId() != QPlatformPixmap::BlitterClass) |
110 | return false; |
111 | if (checkStateAgainstMask(capabillitiesState, drawPixmapMask)) { |
112 | if (m_capabilities & (QBlittable::SourceOverPixmapCapability |
113 | | QBlittable::SourceOverScaledPixmapCapability)) { |
114 | if (r.size() != sr.size()) |
115 | return m_capabilities & QBlittable::SourceOverScaledPixmapCapability; |
116 | else |
117 | return m_capabilities & QBlittable::SourceOverPixmapCapability; |
118 | } |
119 | if ((m_capabilities & QBlittable::SourcePixmapCapability) && r.size() == sr.size() && !pm.hasAlphaChannel()) |
120 | return m_capabilities & QBlittable::SourcePixmapCapability; |
121 | } |
122 | return false; |
123 | } |
124 | |
125 | bool canBlitterDrawPixmapOpacity(const QPixmap &pm) const |
126 | { |
127 | if (pm.handle()->classId() != QPlatformPixmap::BlitterClass) |
128 | return false; |
129 | |
130 | return checkStateAgainstMask(capabillitiesState, opacityPixmapMask); |
131 | } |
132 | |
133 | bool canBlitterDrawCachedGlyphs(const QTransform &transform, QFontEngine::GlyphFormat requestedGlyphFormat, bool complexClip) const |
134 | { |
135 | if (transform.type() > QTransform::TxScale) |
136 | return false; |
137 | if (!(m_capabilities & QBlittable::DrawScaledCachedGlyphsCapability)) |
138 | return false; |
139 | if (requestedGlyphFormat == QFontEngine::Format_ARGB && !(m_capabilities & QBlittable::SubPixelGlyphsCapability)) |
140 | return false; |
141 | if (complexClip && !(m_capabilities & QBlittable::ComplexClipCapability)) |
142 | return false; |
143 | return true; |
144 | } |
145 | |
146 | inline void updateState(uint mask, bool on) { |
147 | updateStateBits(&capabillitiesState, mask, on); |
148 | } |
149 | |
150 | private: |
151 | |
152 | static inline void updateStateBits(uint *state, uint mask, bool on) |
153 | { |
154 | *state = on ? (*state | mask) : (*state & ~mask); |
155 | } |
156 | |
157 | static inline bool checkStateAgainstMask(uint state, uint mask) |
158 | { |
159 | return !state || (state & mask && !(state & ~mask)); |
160 | } |
161 | |
162 | void setFillRectMask() { |
163 | updateStateBits(&fillRectMask, STATE_XFORM_SCALE, false); |
164 | updateStateBits(&fillRectMask, STATE_XFORM_COMPLEX, false); |
165 | |
166 | updateStateBits(&fillRectMask, STATE_BRUSH_PATTERN, false); |
167 | updateStateBits(&fillRectMask, STATE_BRUSH_ALPHA, false); |
168 | |
169 | updateStateBits(&fillRectMask, STATE_PEN_ENABLED, true); |
170 | |
171 | //Sub-pixel aliasing should not be sent to the blitter |
172 | updateStateBits(&fillRectMask, STATE_ANTIALIASING, true); |
173 | updateStateBits(&fillRectMask, STATE_ALPHA, false); |
174 | updateStateBits(&fillRectMask, STATE_BLENDING_COMPLEX, false); |
175 | |
176 | updateStateBits(&fillRectMask, STATE_CLIPSYS_COMPLEX, false); |
177 | updateStateBits(&fillRectMask, STATE_CLIP_COMPLEX, false); |
178 | } |
179 | |
180 | void setAlphaFillRectMask() { |
181 | updateStateBits(&alphaFillRectMask, STATE_XFORM_SCALE, false); |
182 | updateStateBits(&alphaFillRectMask, STATE_XFORM_COMPLEX, false); |
183 | |
184 | updateStateBits(&alphaFillRectMask, STATE_BRUSH_PATTERN, false); |
185 | updateStateBits(&alphaFillRectMask, STATE_BRUSH_ALPHA, true); |
186 | |
187 | updateStateBits(&alphaFillRectMask, STATE_PEN_ENABLED, true); |
188 | |
189 | //Sub-pixel aliasing should not be sent to the blitter |
190 | updateStateBits(&alphaFillRectMask, STATE_ANTIALIASING, true); |
191 | updateStateBits(&alphaFillRectMask, STATE_ALPHA, false); |
192 | updateStateBits(&alphaFillRectMask, STATE_BLENDING_COMPLEX, false); |
193 | |
194 | updateStateBits(&alphaFillRectMask, STATE_CLIPSYS_COMPLEX, false); |
195 | updateStateBits(&alphaFillRectMask, STATE_CLIP_COMPLEX, false); |
196 | } |
197 | |
198 | void setSourcePixmapMask() { |
199 | updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, false); |
200 | updateStateBits(&drawPixmapMask, STATE_XFORM_COMPLEX, false); |
201 | |
202 | updateStateBits(&drawPixmapMask, STATE_BRUSH_PATTERN, true); |
203 | updateStateBits(&drawPixmapMask, STATE_BRUSH_ALPHA, false); |
204 | |
205 | updateStateBits(&drawPixmapMask, STATE_PEN_ENABLED, true); |
206 | |
207 | updateStateBits(&drawPixmapMask, STATE_ANTIALIASING, true); |
208 | updateStateBits(&drawPixmapMask, STATE_ALPHA, false); |
209 | updateStateBits(&drawPixmapMask, STATE_BLENDING_COMPLEX, false); |
210 | |
211 | updateStateBits(&drawPixmapMask, STATE_CLIPSYS_COMPLEX, false); |
212 | updateStateBits(&drawPixmapMask, STATE_CLIP_COMPLEX, false); |
213 | } |
214 | |
215 | void setSourceOverPixmapMask() { |
216 | setSourcePixmapMask(); |
217 | } |
218 | |
219 | void setSourceOverScaledPixmapMask() { |
220 | setSourceOverPixmapMask(); |
221 | updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, true); |
222 | } |
223 | |
224 | void setOpacityPixmapMask() { |
225 | updateStateBits(&opacityPixmapMask, STATE_XFORM_SCALE, true); |
226 | updateStateBits(&opacityPixmapMask, STATE_XFORM_COMPLEX, false); |
227 | |
228 | updateStateBits(&opacityPixmapMask, STATE_BRUSH_PATTERN, true); |
229 | updateStateBits(&opacityPixmapMask, STATE_BRUSH_ALPHA, true); |
230 | |
231 | updateStateBits(&opacityPixmapMask, STATE_PEN_ENABLED, true); |
232 | |
233 | updateStateBits(&opacityPixmapMask, STATE_ANTIALIASING, true); |
234 | updateStateBits(&opacityPixmapMask, STATE_ALPHA, true); |
235 | updateStateBits(&opacityPixmapMask, STATE_BLENDING_COMPLEX, false); |
236 | |
237 | updateStateBits(&opacityPixmapMask, STATE_CLIPSYS_COMPLEX, false); |
238 | updateStateBits(&opacityPixmapMask, STATE_CLIP_COMPLEX, false); |
239 | } |
240 | |
241 | QBlittable::Capabilities m_capabilities; |
242 | uint fillRectMask; |
243 | uint drawRectMask; |
244 | uint drawPixmapMask; |
245 | uint alphaFillRectMask; |
246 | uint opacityPixmapMask; |
247 | uint capabillitiesState; |
248 | }; |
249 | |
250 | class QBlitterPaintEnginePrivate : public QRasterPaintEnginePrivate |
251 | { |
252 | Q_DECLARE_PUBLIC(QBlitterPaintEngine) |
253 | public: |
254 | QBlitterPaintEnginePrivate(QBlittablePlatformPixmap *p) |
255 | : QRasterPaintEnginePrivate() |
256 | , pmData(p) |
257 | , caps(pmData->blittable()->capabilities()) |
258 | , hasXForm(false) |
259 | |
260 | {} |
261 | |
262 | void lock(); |
263 | void unlock(); |
264 | void fillRect(const QRectF &rect, const QColor &color, bool alpha); |
265 | void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr, bool opacity); |
266 | |
267 | |
268 | void updateCompleteState(QPainterState *s); |
269 | void updatePenState(QPainterState *s); |
270 | void updateBrushState(QPainterState *s); |
271 | void updateOpacityState(QPainterState *s); |
272 | void updateCompositionModeState(QPainterState *s); |
273 | void updateRenderHintsState(QPainterState *s); |
274 | void updateTransformState(QPainterState *s); |
275 | void updateClipState(QPainterState *s); |
276 | |
277 | QBlittablePlatformPixmap *pmData; |
278 | CapabilitiesToStateMask caps; |
279 | uint hasXForm; |
280 | }; |
281 | |
282 | |
283 | inline void QBlitterPaintEnginePrivate::lock() |
284 | { |
285 | if (!pmData->blittable()->isLocked()) |
286 | rasterBuffer->prepare(pmData->buffer()); |
287 | } |
288 | |
289 | inline void QBlitterPaintEnginePrivate::unlock() |
290 | { |
291 | pmData->blittable()->unlock(); |
292 | } |
293 | |
294 | // State tracking to make decisions |
295 | void QBlitterPaintEnginePrivate::updateCompleteState(QPainterState *s) |
296 | { |
297 | updatePenState(s); |
298 | updateBrushState(s); |
299 | updateOpacityState(s); |
300 | updateCompositionModeState(s); |
301 | updateRenderHintsState(s); |
302 | updateTransformState(s); |
303 | updateClipState(s); |
304 | } |
305 | |
306 | void QBlitterPaintEnginePrivate::updatePenState(QPainterState *s) |
307 | { |
308 | caps.updateState(STATE_PEN_ENABLED, qpen_style(s->pen) != Qt::NoPen); |
309 | } |
310 | |
311 | void QBlitterPaintEnginePrivate::updateBrushState(QPainterState *s) |
312 | { |
313 | Qt::BrushStyle style = qbrush_style(s->brush); |
314 | |
315 | caps.updateState(STATE_BRUSH_PATTERN, style != Qt::SolidPattern); |
316 | caps.updateState(STATE_BRUSH_ALPHA, |
317 | qbrush_color(s->brush).alpha() < 255); |
318 | } |
319 | |
320 | void QBlitterPaintEnginePrivate::updateOpacityState(QPainterState *s) |
321 | { |
322 | bool translucent = s->opacity < 1; |
323 | caps.updateState(STATE_ALPHA, translucent); |
324 | } |
325 | |
326 | void QBlitterPaintEnginePrivate::updateCompositionModeState(QPainterState *s) |
327 | { |
328 | bool nonTrivial = s->composition_mode != QPainter::CompositionMode_SourceOver |
329 | && s->composition_mode != QPainter::CompositionMode_Source; |
330 | |
331 | caps.updateState(STATE_BLENDING_COMPLEX, nonTrivial); |
332 | } |
333 | |
334 | void QBlitterPaintEnginePrivate::updateRenderHintsState(QPainterState *s) |
335 | { |
336 | bool aa = s->renderHints & QPainter::Antialiasing; |
337 | caps.updateState(STATE_ANTIALIASING, aa); |
338 | } |
339 | |
340 | void QBlitterPaintEnginePrivate::updateTransformState(QPainterState *s) |
341 | { |
342 | QTransform::TransformationType type = s->matrix.type(); |
343 | |
344 | // consider scaling operations with a negative factor as "complex" for now. |
345 | // as some blitters could handle axisymmetrical operations, we should improve blitter |
346 | // paint engine to handle them as a capability |
347 | caps.updateState(STATE_XFORM_COMPLEX, (type > QTransform::TxScale) || |
348 | ((type == QTransform::TxScale) && ((s->matrix.m11() < 0.0) || (s->matrix.m22() < 0.0)))); |
349 | caps.updateState(STATE_XFORM_SCALE, type > QTransform::TxTranslate); |
350 | |
351 | hasXForm = type >= QTransform::TxTranslate; |
352 | } |
353 | |
354 | void QBlitterPaintEnginePrivate::updateClipState(QPainterState *) |
355 | { |
356 | const QClipData *clipData = clip(); |
357 | bool complexClip = clipData && !(clipData->hasRectClip || clipData->hasRegionClip); |
358 | caps.updateState(STATE_CLIP_COMPLEX, complexClip); |
359 | } |
360 | |
361 | void QBlitterPaintEnginePrivate::fillRect(const QRectF &rect, const QColor &color, bool alpha) |
362 | { |
363 | Q_Q(QBlitterPaintEngine); |
364 | pmData->unmarkRasterOverlay(rect); |
365 | QRectF targetRect = rect; |
366 | if (hasXForm) |
367 | targetRect = q->state()->matrix.mapRect(rect); |
368 | const QClipData *clipData = clip(); |
369 | if (clipData) { |
370 | if (clipData->hasRectClip) { |
371 | unlock(); |
372 | if (alpha) |
373 | pmData->blittable()->alphaFillRect(targetRect & clipData->clipRect, color, q->state()->compositionMode()); |
374 | else |
375 | pmData->blittable()->fillRect(targetRect & clipData->clipRect, color); |
376 | } else if (clipData->hasRegionClip) { |
377 | for (const QRect &rect : clipData->clipRegion) { |
378 | QRect intersectRect = rect.intersected(targetRect.toRect()); |
379 | if (!intersectRect.isEmpty()) { |
380 | unlock(); |
381 | if (alpha) |
382 | pmData->blittable()->alphaFillRect(intersectRect, color, q->state()->compositionMode()); |
383 | else |
384 | pmData->blittable()->fillRect(intersectRect, color); |
385 | } |
386 | } |
387 | } |
388 | } else { |
389 | if (targetRect.x() >= 0 && targetRect.y() >= 0 |
390 | && targetRect.width() <= q->paintDevice()->width() |
391 | && targetRect.height() <= q->paintDevice()->height()) { |
392 | unlock(); |
393 | if (alpha) |
394 | pmData->blittable()->alphaFillRect(targetRect, color, q->state()->compositionMode()); |
395 | else |
396 | pmData->blittable()->fillRect(targetRect, color); |
397 | } else { |
398 | QRectF deviceRect(0, 0, q->paintDevice()->width(), q->paintDevice()->height()); |
399 | unlock(); |
400 | if (alpha) |
401 | pmData->blittable()->alphaFillRect(deviceRect & targetRect, color, q->state()->compositionMode()); |
402 | else |
403 | pmData->blittable()->fillRect(deviceRect & targetRect, color); |
404 | } |
405 | } |
406 | } |
407 | |
408 | void QBlitterPaintEnginePrivate::clipAndDrawPixmap(const QRectF &clip, |
409 | const QRectF &target, |
410 | const QPixmap &pm, |
411 | const QRectF &sr, |
412 | bool opacity) |
413 | { |
414 | Q_Q(QBlitterPaintEngine); |
415 | QRectF intersectedRect = clip.intersected(target); |
416 | if (intersectedRect.isEmpty()) |
417 | return; |
418 | QRectF source = sr; |
419 | if (intersectedRect.size() != target.size()) { |
420 | if (sr.size() == target.size()) { |
421 | // no resize |
422 | qreal deltaTop = target.top() - intersectedRect.top(); |
423 | qreal deltaLeft = target.left() - intersectedRect.left(); |
424 | qreal deltaBottom = target.bottom() - intersectedRect.bottom(); |
425 | qreal deltaRight = target.right() - intersectedRect.right(); |
426 | source.adjust(-deltaLeft, -deltaTop, -deltaRight, -deltaBottom); |
427 | } else { |
428 | // resize case |
429 | qreal hFactor = sr.size().width() / target.size().width(); |
430 | qreal vFactor = sr.size().height() / target.size().height(); |
431 | qreal deltaTop = (target.top() - intersectedRect.top()) * vFactor; |
432 | qreal deltaLeft = (target.left() - intersectedRect.left()) * hFactor; |
433 | qreal deltaBottom = (target.bottom() - intersectedRect.bottom()) * vFactor; |
434 | qreal deltaRight = (target.right() - intersectedRect.right()) * hFactor; |
435 | source.adjust(-deltaLeft, -deltaTop, -deltaRight, -deltaBottom); |
436 | } |
437 | } |
438 | pmData->unmarkRasterOverlay(intersectedRect); |
439 | if (opacity) |
440 | pmData->blittable()->drawPixmapOpacity(intersectedRect, pm, source, q->state()->compositionMode(), q->state()->opacity); |
441 | else |
442 | pmData->blittable()->drawPixmap(intersectedRect, pm, source); |
443 | } |
444 | |
445 | QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePlatformPixmap *p) |
446 | : QRasterPaintEngine(*(new QBlitterPaintEnginePrivate(p)), p->buffer()) |
447 | {} |
448 | |
449 | // State tracking |
450 | void QBlitterPaintEngine::penChanged() |
451 | { |
452 | Q_D(QBlitterPaintEngine); |
453 | |
454 | QRasterPaintEngine::penChanged(); |
455 | d->updatePenState(state()); |
456 | } |
457 | |
458 | void QBlitterPaintEngine::brushChanged() |
459 | { |
460 | Q_D(QBlitterPaintEngine); |
461 | |
462 | QRasterPaintEngine::brushChanged(); |
463 | d->updateBrushState(state()); |
464 | } |
465 | |
466 | void QBlitterPaintEngine::opacityChanged() |
467 | { |
468 | Q_D(QBlitterPaintEngine); |
469 | |
470 | QRasterPaintEngine::opacityChanged(); |
471 | d->updateOpacityState(state()); |
472 | } |
473 | |
474 | void QBlitterPaintEngine::compositionModeChanged() |
475 | { |
476 | Q_D(QBlitterPaintEngine); |
477 | |
478 | QRasterPaintEngine::compositionModeChanged(); |
479 | d->updateCompositionModeState(state()); |
480 | } |
481 | |
482 | void QBlitterPaintEngine::renderHintsChanged() |
483 | { |
484 | Q_D(QBlitterPaintEngine); |
485 | |
486 | QRasterPaintEngine::renderHintsChanged(); |
487 | d->updateRenderHintsState(state()); |
488 | } |
489 | |
490 | void QBlitterPaintEngine::transformChanged() |
491 | { |
492 | Q_D(QBlitterPaintEngine); |
493 | |
494 | QRasterPaintEngine::transformChanged(); |
495 | d->updateTransformState(state()); |
496 | } |
497 | |
498 | void QBlitterPaintEngine::clipEnabledChanged() |
499 | { |
500 | Q_D(QBlitterPaintEngine); |
501 | QRasterPaintEngine::clipEnabledChanged(); |
502 | d->updateClipState(state()); |
503 | } |
504 | |
505 | bool QBlitterPaintEngine::begin(QPaintDevice *pdev) |
506 | { |
507 | Q_D(QBlitterPaintEngine); |
508 | bool ok = QRasterPaintEngine::begin(pdev); |
509 | #ifdef QT_BLITTER_RASTEROVERLAY |
510 | d->pmData->unmergeOverlay(); |
511 | #endif |
512 | d->pdev = pdev; |
513 | return ok; |
514 | } |
515 | |
516 | bool QBlitterPaintEngine::end() |
517 | { |
518 | #ifdef QT_BLITTER_RASTEROVERLAY |
519 | Q_D(QBlitterPaintEngine); |
520 | d->pmData->mergeOverlay(); |
521 | #endif |
522 | |
523 | return QRasterPaintEngine::end(); |
524 | } |
525 | |
526 | void QBlitterPaintEngine::setState(QPainterState *s) |
527 | { |
528 | Q_D(QBlitterPaintEngine); |
529 | |
530 | QRasterPaintEngine::setState(s); |
531 | d->updateCompleteState(s); |
532 | } |
533 | |
534 | // Accelerated paths |
535 | void QBlitterPaintEngine::fill(const QVectorPath &path, const QBrush &brush) |
536 | { |
537 | Q_D(QBlitterPaintEngine); |
538 | if (path.shape() == QVectorPath::RectangleHint) { |
539 | QRectF rect(((const QPointF *) path.points())[0], ((const QPointF *) path.points())[2]); |
540 | fillRect(rect, brush); |
541 | } else { |
542 | d->lock(); |
543 | d->pmData->markRasterOverlay(path); |
544 | QRasterPaintEngine::fill(path, brush); |
545 | } |
546 | } |
547 | |
548 | void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color) |
549 | { |
550 | Q_D(QBlitterPaintEngine); |
551 | if (d->caps.canBlitterAlphaFillRect()) { |
552 | d->fillRect(rect, color, true); |
553 | } else if (d->caps.canBlitterFillRect() && color.alpha() == 0xff) { |
554 | d->fillRect(rect, color, false); |
555 | } else { |
556 | d->lock(); |
557 | d->pmData->markRasterOverlay(rect); |
558 | QRasterPaintEngine::fillRect(rect, color); |
559 | } |
560 | } |
561 | |
562 | void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) |
563 | { |
564 | if (rect.size().isEmpty()) |
565 | return; |
566 | |
567 | Q_D(QBlitterPaintEngine); |
568 | |
569 | if (qbrush_style(brush) == Qt::SolidPattern |
570 | && d->caps.canBlitterAlphaFillRect()) { |
571 | d->fillRect(rect, qbrush_color(brush), true); |
572 | } else if (qbrush_style(brush) == Qt::SolidPattern |
573 | && qbrush_color(brush).alpha() == 0xff |
574 | && d->caps.canBlitterFillRect()) { |
575 | d->fillRect(rect, qbrush_color(brush), false); |
576 | } else if ((brush.style() == Qt::TexturePattern) && |
577 | (brush.transform().type() <= QTransform::TxTranslate) && |
578 | ((d->caps.canBlitterDrawPixmapOpacity(brush.texture())) || |
579 | (d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)))) { |
580 | bool rectIsFilled = false; |
581 | QRectF transformedRect = state()->matrix.mapRect(rect); |
582 | qreal x = transformedRect.x(); |
583 | qreal y = transformedRect.y(); |
584 | QPixmap pm = brush.texture(); |
585 | d->unlock(); |
586 | int srcX = int(rect.x() - state()->brushOrigin.x() - brush.transform().dx()) % pm.width(); |
587 | if (srcX < 0) |
588 | srcX = pm.width() + srcX; |
589 | const int startX = srcX; |
590 | int srcY = int(rect.y() - state()->brushOrigin.y() - brush.transform().dy()) % pm.height(); |
591 | if (srcY < 0) |
592 | srcY = pm.height() + srcY; |
593 | while (!rectIsFilled) { |
594 | qreal blitWidth = (pm.width() ) - srcX; |
595 | qreal blitHeight = (pm.height() ) - srcY; |
596 | if (x + blitWidth > transformedRect.right()) |
597 | blitWidth = transformedRect.right() -x; |
598 | if (y + blitHeight > transformedRect.bottom()) |
599 | blitHeight = transformedRect.bottom() - y; |
600 | const QClipData *clipData = d->clip(); |
601 | if (clipData->hasRectClip) { |
602 | QRect targetRect = QRect(x, y, blitWidth, blitHeight).intersected(clipData->clipRect); |
603 | if (targetRect.isValid()) { |
604 | int tmpSrcX = srcX + (targetRect.x() - x); |
605 | int tmpSrcY = srcY + (targetRect.y() - y); |
606 | QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height()); |
607 | d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect); |
608 | } |
609 | } else if (clipData->hasRegionClip) { |
610 | QRect unclippedTargetRect(x, y, blitWidth, blitHeight); |
611 | const QRegion targetRegion = clipData->clipRegion.intersected(unclippedTargetRect); |
612 | for (const QRect &targetRect : targetRegion) { |
613 | if (!targetRect.isValid() || targetRect.isEmpty()) |
614 | continue; |
615 | int tmpSrcX = srcX + (targetRect.x() - x); |
616 | int tmpSrcY = srcY + (targetRect.y() - y); |
617 | QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height()); |
618 | d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect); |
619 | } |
620 | } |
621 | x+=blitWidth; |
622 | if (qFuzzyCompare(x, transformedRect.right())) { |
623 | x = transformedRect.x(); |
624 | srcX = startX; |
625 | srcY = 0; |
626 | y += blitHeight; |
627 | if (qFuzzyCompare(y, transformedRect.bottom())) |
628 | rectIsFilled = true; |
629 | } else |
630 | srcX = 0; |
631 | } |
632 | } else { |
633 | d->lock(); |
634 | d->pmData->markRasterOverlay(rect); |
635 | QRasterPaintEngine::fillRect(rect, brush); |
636 | } |
637 | |
638 | } |
639 | |
640 | void QBlitterPaintEngine::drawRects(const QRect *rects, int rectCount) |
641 | { |
642 | Q_D(QBlitterPaintEngine); |
643 | if (d->caps.canBlitterDrawRectMask()) { |
644 | for (int i=0; i<rectCount; ++i) |
645 | d->fillRect(rects[i], qbrush_color(state()->brush), false); |
646 | } else { |
647 | d->pmData->markRasterOverlay(rects, rectCount); |
648 | QRasterPaintEngine::drawRects(rects, rectCount); |
649 | } |
650 | } |
651 | |
652 | void QBlitterPaintEngine::drawRects(const QRectF *rects, int rectCount) |
653 | { |
654 | Q_D(QBlitterPaintEngine); |
655 | if (d->caps.canBlitterDrawRectMask()) { |
656 | for (int i = 0; i < rectCount; ++i) |
657 | d->fillRect(rects[i], qbrush_color(state()->brush), false); |
658 | } else { |
659 | d->pmData->markRasterOverlay(rects, rectCount); |
660 | QRasterPaintEngine::drawRects(rects, rectCount); |
661 | } |
662 | } |
663 | |
664 | void QBlitterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) |
665 | { |
666 | drawPixmap(QRectF(pos, pm.size()), pm, pm.rect()); |
667 | } |
668 | |
669 | void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) |
670 | { |
671 | Q_D(QBlitterPaintEngine); |
672 | bool canDrawOpacity; |
673 | |
674 | canDrawOpacity = d->caps.canBlitterDrawPixmapOpacity(pm); |
675 | if (canDrawOpacity || (d->caps.canBlitterDrawPixmap(r, pm, sr))) { |
676 | |
677 | d->unlock(); |
678 | QRectF targetRect = r; |
679 | if (d->hasXForm) |
680 | targetRect = state()->matrix.mapRect(r); |
681 | const QClipData *clipData = d->clip(); |
682 | if (clipData) { |
683 | if (clipData->hasRectClip) { |
684 | d->clipAndDrawPixmap(clipData->clipRect, targetRect, pm, sr, canDrawOpacity); |
685 | } else if (clipData->hasRegionClip) { |
686 | for (const QRect &rect : clipData->clipRegion) |
687 | d->clipAndDrawPixmap(rect, targetRect, pm, sr, canDrawOpacity); |
688 | } |
689 | } else { |
690 | QRectF deviceRect(0, 0, paintDevice()->width(), paintDevice()->height()); |
691 | d->clipAndDrawPixmap(deviceRect, targetRect, pm, sr, canDrawOpacity); |
692 | } |
693 | }else { |
694 | d->lock(); |
695 | d->pmData->markRasterOverlay(r); |
696 | QRasterPaintEngine::drawPixmap(r, pm, sr); |
697 | } |
698 | } |
699 | |
700 | // Overridden methods to lock the graphics memory |
701 | void QBlitterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) |
702 | { |
703 | Q_D(QBlitterPaintEngine); |
704 | d->lock(); |
705 | d->pmData->markRasterOverlay(points, pointCount); |
706 | QRasterPaintEngine::drawPolygon(points, pointCount, mode); |
707 | } |
708 | |
709 | void QBlitterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) |
710 | { |
711 | Q_D(QBlitterPaintEngine); |
712 | d->lock(); |
713 | d->pmData->markRasterOverlay(points, pointCount); |
714 | QRasterPaintEngine::drawPolygon(points, pointCount, mode); |
715 | } |
716 | |
717 | void QBlitterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData) |
718 | { |
719 | Q_D(QBlitterPaintEngine); |
720 | d->lock(); |
721 | d->pmData->markRasterOverlay(path); |
722 | QRasterPaintEngine::fillPath(path, fillData); |
723 | } |
724 | |
725 | void QBlitterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) |
726 | { |
727 | Q_D(QBlitterPaintEngine); |
728 | d->lock(); |
729 | d->pmData->markRasterOverlay(points, pointCount); |
730 | QRasterPaintEngine::fillPolygon(points, pointCount, mode); |
731 | } |
732 | |
733 | void QBlitterPaintEngine::drawEllipse(const QRectF &r) |
734 | { |
735 | Q_D(QBlitterPaintEngine); |
736 | d->lock(); |
737 | d->pmData->markRasterOverlay(r); |
738 | QRasterPaintEngine::drawEllipse(r); |
739 | } |
740 | |
741 | void QBlitterPaintEngine::drawImage(const QPointF &pos, const QImage &image) |
742 | { |
743 | drawImage(QRectF(pos, image.size()), image, image.rect()); |
744 | } |
745 | |
746 | void QBlitterPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, |
747 | Qt::ImageConversionFlags flags) |
748 | { |
749 | Q_D(QBlitterPaintEngine); |
750 | d->lock(); |
751 | d->pmData->markRasterOverlay(r); |
752 | QRasterPaintEngine::drawImage(r, pm, sr, flags); |
753 | } |
754 | |
755 | void QBlitterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr) |
756 | { |
757 | Q_D(QBlitterPaintEngine); |
758 | d->lock(); |
759 | d->pmData->markRasterOverlay(r); |
760 | QRasterPaintEngine::drawTiledPixmap(r, pm, sr); |
761 | } |
762 | |
763 | void QBlitterPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &ti) |
764 | { |
765 | Q_D(QBlitterPaintEngine); |
766 | d->lock(); |
767 | d->pmData->markRasterOverlay(pos, ti); |
768 | QRasterPaintEngine::drawTextItem(pos, ti); |
769 | } |
770 | |
771 | void QBlitterPaintEngine::drawPoints(const QPointF *points, int pointCount) |
772 | { |
773 | Q_D(QBlitterPaintEngine); |
774 | d->lock(); |
775 | d->pmData->markRasterOverlay(points, pointCount); |
776 | QRasterPaintEngine::drawPoints(points, pointCount); |
777 | } |
778 | |
779 | void QBlitterPaintEngine::drawPoints(const QPoint *points, int pointCount) |
780 | { |
781 | Q_D(QBlitterPaintEngine); |
782 | d->lock(); |
783 | d->pmData->markRasterOverlay(points, pointCount); |
784 | QRasterPaintEngine::drawPoints(points, pointCount); |
785 | } |
786 | |
787 | void QBlitterPaintEngine::stroke(const QVectorPath &path, const QPen &pen) |
788 | { |
789 | Q_D(QBlitterPaintEngine); |
790 | d->lock(); |
791 | d->pmData->markRasterOverlay(path); |
792 | QRasterPaintEngine::stroke(path, pen); |
793 | } |
794 | |
795 | void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti) |
796 | { |
797 | Q_D(QBlitterPaintEngine); |
798 | d->lock(); |
799 | QRasterPaintEngine::drawStaticTextItem(sti); |
800 | |
801 | #ifdef QT_BLITTER_RASTEROVERLAY |
802 | //#### d->pmData->markRasterOverlay(sti); |
803 | qWarning("not implemented: markRasterOverlay for QStaticTextItem" ); |
804 | #endif |
805 | } |
806 | |
807 | bool QBlitterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) |
808 | { |
809 | Q_D(QBlitterPaintEngine); |
810 | QFontEngine::GlyphFormat glyphFormat = d->glyphCacheFormat; |
811 | if (fontEngine->glyphFormat != QFontEngine::Format_None) |
812 | glyphFormat = fontEngine->glyphFormat; |
813 | |
814 | const QClipData *clipData = d->clip(); |
815 | const bool complexClip = clipData && !clipData->hasRectClip; |
816 | |
817 | const QPainterState *s = state(); |
818 | if (d->caps.canBlitterDrawCachedGlyphs(s->transform(), glyphFormat, complexClip)) { |
819 | d->unlock(); |
820 | const bool result = d->pmData->blittable()->drawCachedGlyphs(s, glyphFormat, numGlyphs, glyphs, positions, fontEngine); |
821 | // Lock again as the raster paint engine might draw decorations now. |
822 | d->lock(); |
823 | return result; |
824 | } else { |
825 | return QRasterPaintEngine::drawCachedGlyphs(numGlyphs, glyphs, positions, fontEngine); |
826 | } |
827 | } |
828 | |
829 | QT_END_NAMESPACE |
830 | #endif //QT_NO_BLITTABLE |
831 | |
832 | |