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

source code of qtbase/src/gui/painting/qpaintengine_blitter.cpp