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
48QT_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
66class CapabilitiesToStateMask
67{
68public:
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(state: capabillitiesState, mask: fillRectMask);
95 }
96
97 inline bool canBlitterAlphaFillRect() const
98 {
99 return checkStateAgainstMask(state: capabillitiesState, mask: alphaFillRectMask);
100 }
101
102 inline bool canBlitterDrawRectMask() const
103 {
104 return checkStateAgainstMask(state: capabillitiesState, mask: 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(state: capabillitiesState, mask: 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(state: capabillitiesState, mask: 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(state: &capabillitiesState, mask, on);
148 }
149
150private:
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(state: &fillRectMask, STATE_XFORM_SCALE, on: false);
164 updateStateBits(state: &fillRectMask, STATE_XFORM_COMPLEX, on: false);
165
166 updateStateBits(state: &fillRectMask, STATE_BRUSH_PATTERN, on: false);
167 updateStateBits(state: &fillRectMask, STATE_BRUSH_ALPHA, on: false);
168
169 updateStateBits(state: &fillRectMask, STATE_PEN_ENABLED, on: true);
170
171 //Sub-pixel aliasing should not be sent to the blitter
172 updateStateBits(state: &fillRectMask, STATE_ANTIALIASING, on: true);
173 updateStateBits(state: &fillRectMask, STATE_ALPHA, on: false);
174 updateStateBits(state: &fillRectMask, STATE_BLENDING_COMPLEX, on: false);
175
176 updateStateBits(state: &fillRectMask, STATE_CLIPSYS_COMPLEX, on: false);
177 updateStateBits(state: &fillRectMask, STATE_CLIP_COMPLEX, on: false);
178 }
179
180 void setAlphaFillRectMask() {
181 updateStateBits(state: &alphaFillRectMask, STATE_XFORM_SCALE, on: false);
182 updateStateBits(state: &alphaFillRectMask, STATE_XFORM_COMPLEX, on: false);
183
184 updateStateBits(state: &alphaFillRectMask, STATE_BRUSH_PATTERN, on: false);
185 updateStateBits(state: &alphaFillRectMask, STATE_BRUSH_ALPHA, on: true);
186
187 updateStateBits(state: &alphaFillRectMask, STATE_PEN_ENABLED, on: true);
188
189 //Sub-pixel aliasing should not be sent to the blitter
190 updateStateBits(state: &alphaFillRectMask, STATE_ANTIALIASING, on: true);
191 updateStateBits(state: &alphaFillRectMask, STATE_ALPHA, on: false);
192 updateStateBits(state: &alphaFillRectMask, STATE_BLENDING_COMPLEX, on: false);
193
194 updateStateBits(state: &alphaFillRectMask, STATE_CLIPSYS_COMPLEX, on: false);
195 updateStateBits(state: &alphaFillRectMask, STATE_CLIP_COMPLEX, on: false);
196 }
197
198 void setSourcePixmapMask() {
199 updateStateBits(state: &drawPixmapMask, STATE_XFORM_SCALE, on: false);
200 updateStateBits(state: &drawPixmapMask, STATE_XFORM_COMPLEX, on: false);
201
202 updateStateBits(state: &drawPixmapMask, STATE_BRUSH_PATTERN, on: true);
203 updateStateBits(state: &drawPixmapMask, STATE_BRUSH_ALPHA, on: false);
204
205 updateStateBits(state: &drawPixmapMask, STATE_PEN_ENABLED, on: true);
206
207 updateStateBits(state: &drawPixmapMask, STATE_ANTIALIASING, on: true);
208 updateStateBits(state: &drawPixmapMask, STATE_ALPHA, on: false);
209 updateStateBits(state: &drawPixmapMask, STATE_BLENDING_COMPLEX, on: false);
210
211 updateStateBits(state: &drawPixmapMask, STATE_CLIPSYS_COMPLEX, on: false);
212 updateStateBits(state: &drawPixmapMask, STATE_CLIP_COMPLEX, on: false);
213 }
214
215 void setSourceOverPixmapMask() {
216 setSourcePixmapMask();
217 }
218
219 void setSourceOverScaledPixmapMask() {
220 setSourceOverPixmapMask();
221 updateStateBits(state: &drawPixmapMask, STATE_XFORM_SCALE, on: true);
222 }
223
224 void setOpacityPixmapMask() {
225 updateStateBits(state: &opacityPixmapMask, STATE_XFORM_SCALE, on: true);
226 updateStateBits(state: &opacityPixmapMask, STATE_XFORM_COMPLEX, on: false);
227
228 updateStateBits(state: &opacityPixmapMask, STATE_BRUSH_PATTERN, on: true);
229 updateStateBits(state: &opacityPixmapMask, STATE_BRUSH_ALPHA, on: true);
230
231 updateStateBits(state: &opacityPixmapMask, STATE_PEN_ENABLED, on: true);
232
233 updateStateBits(state: &opacityPixmapMask, STATE_ANTIALIASING, on: true);
234 updateStateBits(state: &opacityPixmapMask, STATE_ALPHA, on: true);
235 updateStateBits(state: &opacityPixmapMask, STATE_BLENDING_COMPLEX, on: false);
236
237 updateStateBits(state: &opacityPixmapMask, STATE_CLIPSYS_COMPLEX, on: false);
238 updateStateBits(state: &opacityPixmapMask, STATE_CLIP_COMPLEX, on: 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
250class QBlitterPaintEnginePrivate : public QRasterPaintEnginePrivate
251{
252 Q_DECLARE_PUBLIC(QBlitterPaintEngine)
253public:
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
283inline void QBlitterPaintEnginePrivate::lock()
284{
285 if (!pmData->blittable()->isLocked())
286 rasterBuffer->prepare(image: pmData->buffer());
287}
288
289inline void QBlitterPaintEnginePrivate::unlock()
290{
291 pmData->blittable()->unlock();
292}
293
294// State tracking to make decisions
295void 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
306void QBlitterPaintEnginePrivate::updatePenState(QPainterState *s)
307{
308 caps.updateState(STATE_PEN_ENABLED, on: qpen_style(p: s->pen) != Qt::NoPen);
309}
310
311void QBlitterPaintEnginePrivate::updateBrushState(QPainterState *s)
312{
313 Qt::BrushStyle style = qbrush_style(b: s->brush);
314
315 caps.updateState(STATE_BRUSH_PATTERN, on: style != Qt::SolidPattern);
316 caps.updateState(STATE_BRUSH_ALPHA,
317 on: qbrush_color(b: s->brush).alpha() < 255);
318}
319
320void QBlitterPaintEnginePrivate::updateOpacityState(QPainterState *s)
321{
322 bool translucent = s->opacity < 1;
323 caps.updateState(STATE_ALPHA, on: translucent);
324}
325
326void 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, on: nonTrivial);
332}
333
334void QBlitterPaintEnginePrivate::updateRenderHintsState(QPainterState *s)
335{
336 bool aa = s->renderHints & QPainter::Antialiasing;
337 caps.updateState(STATE_ANTIALIASING, on: aa);
338}
339
340void 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, on: (type > QTransform::TxScale) ||
348 ((type == QTransform::TxScale) && ((s->matrix.m11() < 0.0) || (s->matrix.m22() < 0.0))));
349 caps.updateState(STATE_XFORM_SCALE, on: type > QTransform::TxTranslate);
350
351 hasXForm = type >= QTransform::TxTranslate;
352}
353
354void QBlitterPaintEnginePrivate::updateClipState(QPainterState *)
355{
356 const QClipData *clipData = clip();
357 bool complexClip = clipData && !(clipData->hasRectClip || clipData->hasRegionClip);
358 caps.updateState(STATE_CLIP_COMPLEX, on: complexClip);
359}
360
361void 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(rect: targetRect & clipData->clipRect, color, cmode: q->state()->compositionMode());
374 else
375 pmData->blittable()->fillRect(rect: targetRect & clipData->clipRect, color);
376 } else if (clipData->hasRegionClip) {
377 for (const QRect &rect : clipData->clipRegion) {
378 QRect intersectRect = rect.intersected(other: targetRect.toRect());
379 if (!intersectRect.isEmpty()) {
380 unlock();
381 if (alpha)
382 pmData->blittable()->alphaFillRect(rect: intersectRect, color, cmode: q->state()->compositionMode());
383 else
384 pmData->blittable()->fillRect(rect: 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(rect: targetRect, color, cmode: q->state()->compositionMode());
395 else
396 pmData->blittable()->fillRect(rect: targetRect, color);
397 } else {
398 QRectF deviceRect(0, 0, q->paintDevice()->width(), q->paintDevice()->height());
399 unlock();
400 if (alpha)
401 pmData->blittable()->alphaFillRect(rect: deviceRect & targetRect, color, cmode: q->state()->compositionMode());
402 else
403 pmData->blittable()->fillRect(rect: deviceRect & targetRect, color);
404 }
405 }
406}
407
408void 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(r: 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(xp1: -deltaLeft, yp1: -deltaTop, xp2: -deltaRight, yp2: -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(xp1: -deltaLeft, yp1: -deltaTop, xp2: -deltaRight, yp2: -deltaBottom);
436 }
437 }
438 pmData->unmarkRasterOverlay(rect: intersectedRect);
439 if (opacity)
440 pmData->blittable()->drawPixmapOpacity(rect: intersectedRect, pixmap: pm, subrect: source, cmode: q->state()->compositionMode(), opacity: q->state()->opacity);
441 else
442 pmData->blittable()->drawPixmap(rect: intersectedRect, pixmap: pm, subrect: source);
443}
444
445QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePlatformPixmap *p)
446 : QRasterPaintEngine(*(new QBlitterPaintEnginePrivate(p)), p->buffer())
447{}
448
449// State tracking
450void QBlitterPaintEngine::penChanged()
451{
452 Q_D(QBlitterPaintEngine);
453
454 QRasterPaintEngine::penChanged();
455 d->updatePenState(s: state());
456}
457
458void QBlitterPaintEngine::brushChanged()
459{
460 Q_D(QBlitterPaintEngine);
461
462 QRasterPaintEngine::brushChanged();
463 d->updateBrushState(s: state());
464}
465
466void QBlitterPaintEngine::opacityChanged()
467{
468 Q_D(QBlitterPaintEngine);
469
470 QRasterPaintEngine::opacityChanged();
471 d->updateOpacityState(s: state());
472}
473
474void QBlitterPaintEngine::compositionModeChanged()
475{
476 Q_D(QBlitterPaintEngine);
477
478 QRasterPaintEngine::compositionModeChanged();
479 d->updateCompositionModeState(s: state());
480}
481
482void QBlitterPaintEngine::renderHintsChanged()
483{
484 Q_D(QBlitterPaintEngine);
485
486 QRasterPaintEngine::renderHintsChanged();
487 d->updateRenderHintsState(s: state());
488}
489
490void QBlitterPaintEngine::transformChanged()
491{
492 Q_D(QBlitterPaintEngine);
493
494 QRasterPaintEngine::transformChanged();
495 d->updateTransformState(s: state());
496}
497
498void QBlitterPaintEngine::clipEnabledChanged()
499{
500 Q_D(QBlitterPaintEngine);
501 QRasterPaintEngine::clipEnabledChanged();
502 d->updateClipState(state());
503}
504
505bool QBlitterPaintEngine::begin(QPaintDevice *pdev)
506{
507 Q_D(QBlitterPaintEngine);
508 bool ok = QRasterPaintEngine::begin(device: pdev);
509#ifdef QT_BLITTER_RASTEROVERLAY
510 d->pmData->unmergeOverlay();
511#endif
512 d->pdev = pdev;
513 return ok;
514}
515
516bool 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
526void QBlitterPaintEngine::setState(QPainterState *s)
527{
528 Q_D(QBlitterPaintEngine);
529
530 QRasterPaintEngine::setState(s);
531 d->updateCompleteState(s);
532}
533
534// Accelerated paths
535void 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
548void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color)
549{
550 Q_D(QBlitterPaintEngine);
551 if (d->caps.canBlitterAlphaFillRect()) {
552 d->fillRect(rect, color, alpha: true);
553 } else if (d->caps.canBlitterFillRect() && color.alpha() == 0xff) {
554 d->fillRect(rect, color, alpha: false);
555 } else {
556 d->lock();
557 d->pmData->markRasterOverlay(rect);
558 QRasterPaintEngine::fillRect(rect, color);
559 }
560}
561
562void 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(b: brush) == Qt::SolidPattern
570 && d->caps.canBlitterAlphaFillRect()) {
571 d->fillRect(rect, color: qbrush_color(b: brush), alpha: true);
572 } else if (qbrush_style(b: brush) == Qt::SolidPattern
573 && qbrush_color(b: brush).alpha() == 0xff
574 && d->caps.canBlitterFillRect()) {
575 d->fillRect(rect, color: qbrush_color(b: brush), alpha: false);
576 } else if ((brush.style() == Qt::TexturePattern) &&
577 (brush.transform().type() <= QTransform::TxTranslate) &&
578 ((d->caps.canBlitterDrawPixmapOpacity(pm: brush.texture())) ||
579 (d->caps.canBlitterDrawPixmap(r: rect, pm: brush.texture(), sr: 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(other: 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(rect: targetRect, pixmap: pm, subrect: srcRect);
608 }
609 } else if (clipData->hasRegionClip) {
610 QRect unclippedTargetRect(x, y, blitWidth, blitHeight);
611 const QRegion targetRegion = clipData->clipRegion.intersected(r: 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(rect: targetRect, pixmap: pm, subrect: srcRect);
619 }
620 }
621 x+=blitWidth;
622 if (qFuzzyCompare(p1: x, p2: transformedRect.right())) {
623 x = transformedRect.x();
624 srcX = startX;
625 srcY = 0;
626 y += blitHeight;
627 if (qFuzzyCompare(p1: y, p2: 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
640void 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(rect: rects[i], color: qbrush_color(b: state()->brush), alpha: false);
646 } else {
647 d->pmData->markRasterOverlay(rects, rectCount);
648 QRasterPaintEngine::drawRects(rects, rectCount);
649 }
650}
651
652void 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(rect: rects[i], color: qbrush_color(b: state()->brush), alpha: false);
658 } else {
659 d->pmData->markRasterOverlay(rects, rectCount);
660 QRasterPaintEngine::drawRects(rects, rectCount);
661 }
662}
663
664void QBlitterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
665{
666 drawPixmap(r: QRectF(pos, pm.size()), pm, sr: pm.rect());
667}
668
669void 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(clip: clipData->clipRect, target: targetRect, pm, sr, opacity: canDrawOpacity);
685 } else if (clipData->hasRegionClip) {
686 for (const QRect &rect : clipData->clipRegion)
687 d->clipAndDrawPixmap(clip: rect, target: targetRect, pm, sr, opacity: canDrawOpacity);
688 }
689 } else {
690 QRectF deviceRect(0, 0, paintDevice()->width(), paintDevice()->height());
691 d->clipAndDrawPixmap(clip: deviceRect, target: targetRect, pm, sr, opacity: canDrawOpacity);
692 }
693 }else {
694 d->lock();
695 d->pmData->markRasterOverlay(rect: r);
696 QRasterPaintEngine::drawPixmap(r, pm, sr);
697 }
698}
699
700// Overridden methods to lock the graphics memory
701void 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
709void 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
717void 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
725void 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
733void QBlitterPaintEngine::drawEllipse(const QRectF &r)
734{
735 Q_D(QBlitterPaintEngine);
736 d->lock();
737 d->pmData->markRasterOverlay(rect: r);
738 QRasterPaintEngine::drawEllipse(rect: r);
739}
740
741void QBlitterPaintEngine::drawImage(const QPointF &pos, const QImage &image)
742{
743 drawImage(r: QRectF(pos, image.size()), pm: image, sr: image.rect());
744}
745
746void 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(rect: r);
752 QRasterPaintEngine::drawImage(r, pm, sr, flags);
753}
754
755void QBlitterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr)
756{
757 Q_D(QBlitterPaintEngine);
758 d->lock();
759 d->pmData->markRasterOverlay(rect: r);
760 QRasterPaintEngine::drawTiledPixmap(r, pm, sr);
761}
762
763void 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(p: pos, textItem: ti);
769}
770
771void 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
779void 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
787void 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
795void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti)
796{
797 Q_D(QBlitterPaintEngine);
798 d->lock();
799 QRasterPaintEngine::drawStaticTextItem(textItem: sti);
800
801#ifdef QT_BLITTER_RASTEROVERLAY
802//#### d->pmData->markRasterOverlay(sti);
803 qWarning("not implemented: markRasterOverlay for QStaticTextItem");
804#endif
805}
806
807bool 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(transform: s->transform(), requestedGlyphFormat: glyphFormat, complexClip)) {
819 d->unlock();
820 const bool result = d->pmData->blittable()->drawCachedGlyphs(state: 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
829QT_END_NAMESPACE
830#endif //QT_NO_BLITTABLE
831
832

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