1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "private/qpaintengine_blitter_p.h"
44 #include "private/qblittable_p.h"
45 #include "private/qpaintengine_raster_p.h"
46 #include "private/qpainter_p.h"
47 #include "private/qpixmap_blitter_p.h"
49 #ifndef QT_NO_BLITTABLE
52 #define STATE_XFORM_SCALE 0x00000001
53 #define STATE_XFORM_COMPLEX 0x00000002
55 #define STATE_BRUSH_PATTERN 0x00000010
56 #define STATE_BRUSH_ALPHA 0x00000020
58 #define STATE_PEN_ENABLED 0x00000100
60 #define STATE_ANTIALIASING 0x00001000
61 #define STATE_ALPHA 0x00002000
62 #define STATE_BLENDING_COMPLEX 0x00004000
64 #define STATE_CLIPSYS_COMPLEX 0x00010000
65 #define STATE_CLIP_COMPLEX 0x00020000
68 class CapabilitiesToStateMask
71 CapabilitiesToStateMask(QBlittable::Capabilities capabilities)
72 : m_capabilities(capabilities)
76 , capabillitiesState(0)
78 if (capabilities & QBlittable::SolidRectCapability)
80 if (capabilities & QBlittable::SourcePixmapCapability)
81 setSourcePixmapMask();
82 if (capabilities & QBlittable::SourceOverPixmapCapability)
83 setSourceOverPixmapMask();
84 if (capabilities & QBlittable::SourceOverScaledPixmapCapability)
85 setSourceOverScaledPixmapMask();
88 inline bool canBlitterFillRect() const
90 return checkStateAgainstMask(capabillitiesState, fillRectMask);
93 inline bool canBlitterDrawRectMask() const
95 return checkStateAgainstMask(capabillitiesState, drawRectMask);
98 bool canBlitterDrawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) const
100 if (pm.handle()->classId() != QPlatformPixmap::BlitterClass)
102 if (checkStateAgainstMask(capabillitiesState, drawPixmapMask)) {
103 if (m_capabilities & (QBlittable::SourceOverPixmapCapability
104 | QBlittable::SourceOverScaledPixmapCapability)) {
105 if (r.size() != sr.size())
106 return m_capabilities & QBlittable::SourceOverScaledPixmapCapability;
108 return m_capabilities & QBlittable::SourceOverPixmapCapability;
110 if ((m_capabilities & QBlittable::SourcePixmapCapability) && r.size() == sr.size() && !pm.hasAlphaChannel())
111 return m_capabilities & QBlittable::SourcePixmapCapability;
116 inline void updateState(uint mask, bool on) {
117 updateStateBits(&capabillitiesState, mask, on);
122 static inline void updateStateBits(uint *state, uint mask, bool on)
124 *state = on ? (*state | mask) : (*state & ~mask);
127 static inline bool checkStateAgainstMask(uint state, uint mask)
129 return !state || (state & mask && !(state & ~mask));
132 void setFillRectMask() {
133 updateStateBits(&fillRectMask, STATE_XFORM_SCALE, false);
134 updateStateBits(&fillRectMask, STATE_XFORM_COMPLEX, false);
136 updateStateBits(&fillRectMask, STATE_BRUSH_PATTERN, false);
137 updateStateBits(&fillRectMask, STATE_BRUSH_ALPHA, false);
139 updateStateBits(&fillRectMask, STATE_PEN_ENABLED, true);
141 //Sub-pixel aliasing should not be sent to the blitter
142 updateStateBits(&fillRectMask, STATE_ANTIALIASING, true);
143 updateStateBits(&fillRectMask, STATE_ALPHA, false);
144 updateStateBits(&fillRectMask, STATE_BLENDING_COMPLEX, false);
146 updateStateBits(&fillRectMask, STATE_CLIPSYS_COMPLEX, false);
147 updateStateBits(&fillRectMask, STATE_CLIP_COMPLEX, false);
150 void setSourcePixmapMask() {
151 updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, true);
152 updateStateBits(&drawPixmapMask, STATE_XFORM_COMPLEX, false);
154 updateStateBits(&drawPixmapMask, STATE_BRUSH_PATTERN, true);
155 updateStateBits(&drawPixmapMask, STATE_BRUSH_ALPHA, false);
157 updateStateBits(&drawPixmapMask, STATE_PEN_ENABLED, true);
159 updateStateBits(&drawPixmapMask, STATE_ANTIALIASING, true);
160 updateStateBits(&drawPixmapMask, STATE_ALPHA, false);
161 updateStateBits(&drawPixmapMask, STATE_BLENDING_COMPLEX, false);
163 updateStateBits(&drawPixmapMask, STATE_CLIPSYS_COMPLEX, false);
164 updateStateBits(&drawPixmapMask, STATE_CLIP_COMPLEX, false);
167 void setSourceOverPixmapMask() {
168 setSourcePixmapMask();
171 void setSourceOverScaledPixmapMask() {
172 setSourceOverPixmapMask();
173 updateStateBits(&drawRectMask, STATE_XFORM_SCALE, true);
176 QBlittable::Capabilities m_capabilities;
180 uint capabillitiesState;
183 class QBlitterPaintEnginePrivate : public QRasterPaintEnginePrivate
185 Q_DECLARE_PUBLIC(QBlitterPaintEngine);
187 QBlitterPaintEnginePrivate(QBlittablePlatformPixmap *p)
188 : QRasterPaintEnginePrivate()
190 , caps(pmData->blittable()->capabilities())
197 void fillRect(const QRectF &rect, const QColor &color);
198 void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr);
201 void updateCompleteState(QPainterState *s);
202 void updatePenState(QPainterState *s);
203 void updateBrushState(QPainterState *s);
204 void updateOpacityState(QPainterState *s);
205 void updateCompositionModeState(QPainterState *s);
206 void updateRenderHintsState(QPainterState *s);
207 void updateTransformState(QPainterState *s);
208 void updateClipState(QPainterState *s);
210 QBlittablePlatformPixmap *pmData;
211 CapabilitiesToStateMask caps;
216 inline void QBlitterPaintEnginePrivate::lock()
218 if (!pmData->blittable()->isLocked())
219 rasterBuffer->prepare(pmData->buffer());
222 inline void QBlitterPaintEnginePrivate::unlock()
224 pmData->blittable()->unlock();
227 // State tracking to make decisions
228 void QBlitterPaintEnginePrivate::updateCompleteState(QPainterState *s)
232 updateOpacityState(s);
233 updateCompositionModeState(s);
234 updateRenderHintsState(s);
235 updateTransformState(s);
239 void QBlitterPaintEnginePrivate::updatePenState(QPainterState *s)
241 caps.updateState(STATE_PEN_ENABLED, qpen_style(s->pen) != Qt::NoPen);
244 void QBlitterPaintEnginePrivate::updateBrushState(QPainterState *s)
246 Qt::BrushStyle style = qbrush_style(s->brush);
248 caps.updateState(STATE_BRUSH_PATTERN, style > Qt::SolidPattern);
249 caps.updateState(STATE_BRUSH_ALPHA,
250 qbrush_color(s->brush).alpha() < 255);
253 void QBlitterPaintEnginePrivate::updateOpacityState(QPainterState *s)
255 bool translucent = s->opacity < 1;
256 caps.updateState(STATE_ALPHA, translucent);
259 void QBlitterPaintEnginePrivate::updateCompositionModeState(QPainterState *s)
261 bool nonTrivial = s->composition_mode != QPainter::CompositionMode_SourceOver
262 && s->composition_mode != QPainter::CompositionMode_Source;
264 caps.updateState(STATE_BLENDING_COMPLEX, nonTrivial);
267 void QBlitterPaintEnginePrivate::updateRenderHintsState(QPainterState *s)
269 bool aa = s->renderHints & QPainter::Antialiasing;
270 caps.updateState(STATE_ANTIALIASING, aa);
273 void QBlitterPaintEnginePrivate::updateTransformState(QPainterState *s)
275 QTransform::TransformationType type = s->matrix.type();
277 caps.updateState(STATE_XFORM_COMPLEX, type > QTransform::TxScale);
278 caps.updateState(STATE_XFORM_SCALE, type > QTransform::TxTranslate);
280 hasXForm = type >= QTransform::TxTranslate;
283 void QBlitterPaintEnginePrivate::updateClipState(QPainterState *)
285 const QClipData *clipData = clip();
286 bool complexClip = clipData && !(clipData->hasRectClip || clipData->hasRegionClip);
287 caps.updateState(STATE_CLIP_COMPLEX, complexClip);
290 void QBlitterPaintEnginePrivate::fillRect(const QRectF &rect, const QColor &color)
292 Q_Q(QBlitterPaintEngine);
293 pmData->unmarkRasterOverlay(rect);
294 QRectF targetRect = rect;
296 targetRect = q->state()->matrix.mapRect(rect);
297 const QClipData *clipData = clip();
299 if (clipData->hasRectClip) {
301 pmData->blittable()->fillRect(targetRect & clipData->clipRect, color);
302 } else if (clipData->hasRegionClip) {
303 QVector<QRect> rects = clipData->clipRegion.rects();
304 for (int i = 0; i < rects.size(); ++i) {
305 QRect intersectRect = rects.at(i).intersected(targetRect.toRect());
306 if (!intersectRect.isEmpty()) {
308 pmData->blittable()->fillRect(intersectRect, color);
313 if (targetRect.x() >= 0 && targetRect.y() >= 0
314 && targetRect.width() <= q->paintDevice()->width()
315 && targetRect.height() <= q->paintDevice()->height()) {
317 pmData->blittable()->fillRect(targetRect, color);
319 QRectF deviceRect(0, 0, q->paintDevice()->width(), q->paintDevice()->height());
321 pmData->blittable()->fillRect(deviceRect & targetRect, color);
326 void QBlitterPaintEnginePrivate::clipAndDrawPixmap(const QRectF &clip,
327 const QRectF &target,
331 QRectF intersectedRect = clip.intersected(target);
332 if (intersectedRect.isEmpty())
335 if (intersectedRect.size() != target.size()) {
336 qreal deltaTop = target.top() - intersectedRect.top();
337 qreal deltaLeft = target.left() - intersectedRect.left();
338 qreal deltaBottom = target.bottom() - intersectedRect.bottom();
339 qreal deltaRight = target.right() - intersectedRect.right();
340 source.adjust(-deltaLeft, -deltaTop, -deltaRight, -deltaBottom);
342 pmData->unmarkRasterOverlay(intersectedRect);
343 pmData->blittable()->drawPixmap(intersectedRect, pm, source);
346 QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePlatformPixmap *p)
347 : QRasterPaintEngine(*(new QBlitterPaintEnginePrivate(p)), p->buffer())
351 void QBlitterPaintEngine::penChanged()
353 Q_D(QBlitterPaintEngine);
355 QRasterPaintEngine::penChanged();
356 d->updatePenState(state());
359 void QBlitterPaintEngine::brushChanged()
361 Q_D(QBlitterPaintEngine);
363 QRasterPaintEngine::brushChanged();
364 d->updateBrushState(state());
367 void QBlitterPaintEngine::opacityChanged()
369 Q_D(QBlitterPaintEngine);
371 QRasterPaintEngine::opacityChanged();
372 d->updateOpacityState(state());
375 void QBlitterPaintEngine::compositionModeChanged()
377 Q_D(QBlitterPaintEngine);
379 QRasterPaintEngine::compositionModeChanged();
380 d->updateCompositionModeState(state());
383 void QBlitterPaintEngine::renderHintsChanged()
385 Q_D(QBlitterPaintEngine);
387 QRasterPaintEngine::renderHintsChanged();
388 d->updateRenderHintsState(state());
391 void QBlitterPaintEngine::transformChanged()
393 Q_D(QBlitterPaintEngine);
395 QRasterPaintEngine::transformChanged();
396 d->updateTransformState(state());
399 void QBlitterPaintEngine::clipEnabledChanged()
401 Q_D(QBlitterPaintEngine);
402 QRasterPaintEngine::clipEnabledChanged();
403 d->updateClipState(state());
406 bool QBlitterPaintEngine::begin(QPaintDevice *pdev)
408 bool ok = QRasterPaintEngine::begin(pdev);
409 #ifdef QT_BLITTER_RASTEROVERLAY
410 Q_D(QBlitterPaintEngine);
411 d->pmData->unmergeOverlay();
416 bool QBlitterPaintEngine::end()
418 #ifdef QT_BLITTER_RASTEROVERLAY
419 Q_D(QBlitterPaintEngine);
420 d->pmData->mergeOverlay();
423 return QRasterPaintEngine::end();
426 void QBlitterPaintEngine::setState(QPainterState *s)
428 Q_D(QBlitterPaintEngine);
430 QRasterPaintEngine::setState(s);
431 d->updateCompleteState(s);
435 void QBlitterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
437 Q_D(QBlitterPaintEngine);
438 if (path.shape() == QVectorPath::RectangleHint) {
439 QRectF rect(((QPointF *) path.points())[0], ((QPointF *) path.points())[2]);
440 fillRect(rect, brush);
443 d->pmData->markRasterOverlay(path);
444 QRasterPaintEngine::fill(path, brush);
448 void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color)
450 Q_D(QBlitterPaintEngine);
451 if (d->caps.canBlitterFillRect() && color.alpha() == 0xff) {
452 d->fillRect(rect, color);
455 d->pmData->markRasterOverlay(rect);
456 QRasterPaintEngine::fillRect(rect, color);
460 void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
462 if (rect.size().isEmpty())
465 Q_D(QBlitterPaintEngine);
467 if (qbrush_style(brush) == Qt::SolidPattern
468 && qbrush_color(brush).alpha() == 0xff
469 && d->caps.canBlitterFillRect()) {
470 d->fillRect(rect, qbrush_color(brush));
471 } else if (brush.style() == Qt::TexturePattern
472 && d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)) {
473 bool rectIsFilled = false;
474 QRectF transformedRect = state()->matrix.mapRect(rect);
475 qreal x = transformedRect.x();
476 qreal y = transformedRect.y();
477 QPixmap pm = brush.texture();
479 int srcX = int(rect.x() - state()->brushOrigin.x()) % pm.width();
481 srcX = pm.width() + srcX;
482 const int startX = srcX;
483 int srcY = int(rect.y() - state()->brushOrigin.y()) % pm.height();
485 srcY = pm.height() + srcY;
486 while (!rectIsFilled) {
487 qreal blitWidth = (pm.width() ) - srcX;
488 qreal blitHeight = (pm.height() ) - srcY;
489 if (x + blitWidth > transformedRect.right())
490 blitWidth = transformedRect.right() -x;
491 if (y + blitHeight > transformedRect.bottom())
492 blitHeight = transformedRect.bottom() - y;
493 const QClipData *clipData = d->clip();
494 if (clipData->hasRectClip) {
495 QRect targetRect = QRect(x, y, blitWidth, blitHeight).intersected(clipData->clipRect);
496 if (targetRect.isValid()) {
497 int tmpSrcX = srcX + (targetRect.x() - x);
498 int tmpSrcY = srcY + (targetRect.y() - y);
499 QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height());
500 d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect);
502 } else if (clipData->hasRegionClip) {
503 QVector<QRect> clipRects = clipData->clipRegion.rects();
504 QRect unclippedTargetRect(x, y, blitWidth, blitHeight);
505 QRegion intersectedRects = clipData->clipRegion.intersected(unclippedTargetRect);
507 for (int i = 0; i < intersectedRects.rects().size(); ++i) {
508 QRect targetRect = intersectedRects.rects().at(i);
509 if (!targetRect.isValid() || targetRect.isEmpty())
511 int tmpSrcX = srcX + (targetRect.x() - x);
512 int tmpSrcY = srcY + (targetRect.y() - y);
513 QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height());
514 d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect);
518 if (x >= transformedRect.right()) {
519 x = transformedRect.x();
523 if (y >= transformedRect.bottom())
530 d->pmData->markRasterOverlay(rect);
531 QRasterPaintEngine::fillRect(rect, brush);
536 void QBlitterPaintEngine::drawRects(const QRect *rects, int rectCount)
538 Q_D(QBlitterPaintEngine);
539 if (d->caps.canBlitterDrawRectMask()) {
540 for (int i=0; i<rectCount; ++i)
541 d->fillRect(rects[i], qbrush_color(state()->brush));
543 d->pmData->markRasterOverlay(rects, rectCount);
544 QRasterPaintEngine::drawRects(rects, rectCount);
548 void QBlitterPaintEngine::drawRects(const QRectF *rects, int rectCount)
550 Q_D(QBlitterPaintEngine);
551 if (d->caps.canBlitterDrawRectMask()) {
552 for (int i = 0; i < rectCount; ++i)
553 d->fillRect(rects[i], qbrush_color(state()->brush));
555 d->pmData->markRasterOverlay(rects, rectCount);
556 QRasterPaintEngine::drawRects(rects, rectCount);
560 void QBlitterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
562 drawPixmap(QRectF(pos, pm.size()), pm, pm.rect());
565 void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
567 Q_D(QBlitterPaintEngine);
568 if (d->caps.canBlitterDrawPixmap(r, pm, sr)) {
571 QRectF targetRect = r;
573 targetRect = state()->matrix.mapRect(r);
574 const QClipData *clipData = d->clip();
576 if (clipData->hasRectClip) {
577 d->clipAndDrawPixmap(clipData->clipRect, targetRect, pm, sr);
578 } else if (clipData->hasRegionClip) {
579 QVector<QRect>rects = clipData->clipRegion.rects();
580 for (int i = 0; i<rects.size(); ++i)
581 d->clipAndDrawPixmap(rects.at(i), targetRect, pm, sr);
584 QRectF deviceRect(0, 0, paintDevice()->width(), paintDevice()->height());
585 d->clipAndDrawPixmap(deviceRect, targetRect, pm, sr);
589 d->pmData->markRasterOverlay(r);
590 QRasterPaintEngine::drawPixmap(r, pm, sr);
594 // Overriden methods to lock the graphics memory
595 void QBlitterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
597 Q_D(QBlitterPaintEngine);
599 d->pmData->markRasterOverlay(points, pointCount);
600 QRasterPaintEngine::drawPolygon(points, pointCount, mode);
603 void QBlitterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
605 Q_D(QBlitterPaintEngine);
607 d->pmData->markRasterOverlay(points, pointCount);
608 QRasterPaintEngine::drawPolygon(points, pointCount, mode);
611 void QBlitterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
613 Q_D(QBlitterPaintEngine);
615 d->pmData->markRasterOverlay(path);
616 QRasterPaintEngine::fillPath(path, fillData);
619 void QBlitterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
621 Q_D(QBlitterPaintEngine);
623 d->pmData->markRasterOverlay(points, pointCount);
624 QRasterPaintEngine::fillPolygon(points, pointCount, mode);
627 void QBlitterPaintEngine::drawEllipse(const QRectF &r)
629 Q_D(QBlitterPaintEngine);
631 d->pmData->markRasterOverlay(r);
632 QRasterPaintEngine::drawEllipse(r);
635 void QBlitterPaintEngine::drawImage(const QPointF &pos, const QImage &image)
637 drawImage(QRectF(pos, image.size()), image, image.rect());
640 void QBlitterPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
641 Qt::ImageConversionFlags flags)
643 Q_D(QBlitterPaintEngine);
645 d->pmData->markRasterOverlay(r);
646 QRasterPaintEngine::drawImage(r, pm, sr, flags);
649 void QBlitterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr)
651 Q_D(QBlitterPaintEngine);
653 d->pmData->markRasterOverlay(r);
654 QRasterPaintEngine::drawTiledPixmap(r, pm, sr);
657 void QBlitterPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
659 Q_D(QBlitterPaintEngine);
661 d->pmData->markRasterOverlay(pos, ti);
662 QRasterPaintEngine::drawTextItem(pos, ti);
665 void QBlitterPaintEngine::drawPoints(const QPointF *points, int pointCount)
667 Q_D(QBlitterPaintEngine);
669 d->pmData->markRasterOverlay(points, pointCount);
670 QRasterPaintEngine::drawPoints(points, pointCount);
673 void QBlitterPaintEngine::drawPoints(const QPoint *points, int pointCount)
675 Q_D(QBlitterPaintEngine);
677 d->pmData->markRasterOverlay(points, pointCount);
678 QRasterPaintEngine::drawPoints(points, pointCount);
681 void QBlitterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
683 Q_D(QBlitterPaintEngine);
685 d->pmData->markRasterOverlay(path);
686 QRasterPaintEngine::stroke(path, pen);
689 void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti)
691 Q_D(QBlitterPaintEngine);
693 QRasterPaintEngine::drawStaticTextItem(sti);
695 #ifdef QT_BLITTER_RASTEROVERLAY
696 //#### d->pmData->markRasterOverlay(sti);
697 qWarning("not implemented: markRasterOverlay for QStaticTextItem");
702 #endif //QT_NO_BLITTABLE