1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** 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/qapplication_p.h"
48 #include "private/qpixmap_blitter_p.h"
50 #ifndef QT_NO_BLITTABLE
53 #define STATE_XFORM_SCALE 0x00000001
54 #define STATE_XFORM_COMPLEX 0x00000002
56 #define STATE_BRUSH_PATTERN 0x00000010
57 #define STATE_BRUSH_ALPHA 0x00000020
59 #define STATE_PEN_ENABLED 0x00000100
61 #define STATE_ANTIALIASING 0x00001000
62 #define STATE_ALPHA 0x00002000
63 #define STATE_BLENDING_COMPLEX 0x00004000
65 #define STATE_CLIPSYS_COMPLEX 0x00010000
66 #define STATE_CLIP_COMPLEX 0x00020000
69 static inline void updateStateBits(uint *state, uint mask, bool on)
71 *state = on ? (*state | mask) : (*state & ~mask);
74 static inline bool checkStateAgainstMask(uint state, uint mask)
76 return !state || (state & mask && !(state & ~mask));
79 class CapabilitiesToStateMask
82 CapabilitiesToStateMask(QBlittable::Capabilities capabilities)
83 : m_capabilities(capabilities),
89 if (capabilities & QBlittable::SolidRectCapability) {
92 if (capabilities & QBlittable::SourcePixmapCapability) {
93 setSourcePixmapMask();
95 if (capabilities & QBlittable::SourceOverPixmapCapability) {
96 setSourceOverPixmapMask();
98 if (capabilities & QBlittable::SourceOverScaledPixmapCapability) {
99 setSourceOverScaledPixmapMask();
103 inline bool canBlitterFillRect() const
105 return checkStateAgainstMask(capabillitiesState,fillRectMask);
108 inline bool canBlitterDrawRectMask() const
110 return checkStateAgainstMask(capabillitiesState,drawRectMask);
113 bool canBlitterDrawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) const
115 if (pm.pixmapData()->classId() != QPixmapData::BlitterClass)
117 if (checkStateAgainstMask(capabillitiesState,drawPixmapMask)) {
118 if (m_capabilities & (QBlittable::SourceOverPixmapCapability
119 | QBlittable::SourceOverScaledPixmapCapability)) {
120 if (r.size() != sr.size()) {
121 return m_capabilities & QBlittable::SourceOverScaledPixmapCapability;
123 return m_capabilities & QBlittable::SourceOverPixmapCapability;
126 if ((m_capabilities & QBlittable::SourcePixmapCapability) && r.size() == sr.size() && !pm.hasAlphaChannel()) {
127 return m_capabilities & QBlittable::SourcePixmapCapability;
133 inline void updateState(uint mask, bool on) {
134 updateStateBits(&capabillitiesState,mask,on);
139 void setFillRectMask() {
140 updateStateBits(&fillRectMask, STATE_XFORM_SCALE, false);
141 updateStateBits(&fillRectMask, STATE_XFORM_COMPLEX, false);
143 updateStateBits(&fillRectMask, STATE_BRUSH_PATTERN, false);
144 updateStateBits(&fillRectMask, STATE_BRUSH_ALPHA, false);
146 updateStateBits(&fillRectMask, STATE_PEN_ENABLED, true);
148 //Sub-pixel aliasing should not be sent to the blitter
149 updateStateBits(&fillRectMask, STATE_ANTIALIASING, true);
150 updateStateBits(&fillRectMask, STATE_ALPHA, false);
151 updateStateBits(&fillRectMask, STATE_BLENDING_COMPLEX, false);
153 updateStateBits(&fillRectMask, STATE_CLIPSYS_COMPLEX, false);
154 updateStateBits(&fillRectMask, STATE_CLIP_COMPLEX, false);
157 void setSourcePixmapMask() {
158 updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, true);
159 updateStateBits(&drawPixmapMask, STATE_XFORM_COMPLEX, false);
161 updateStateBits(&drawPixmapMask, STATE_BRUSH_PATTERN, true);
162 updateStateBits(&drawPixmapMask, STATE_BRUSH_ALPHA, false);
164 updateStateBits(&drawPixmapMask, STATE_PEN_ENABLED, true);
166 updateStateBits(&drawPixmapMask, STATE_ANTIALIASING, true);
167 updateStateBits(&drawPixmapMask, STATE_ALPHA, false);
168 updateStateBits(&drawPixmapMask, STATE_BLENDING_COMPLEX, false);
170 updateStateBits(&drawPixmapMask, STATE_CLIPSYS_COMPLEX, false);
171 updateStateBits(&drawPixmapMask, STATE_CLIP_COMPLEX, false);
174 void setSourceOverPixmapMask() {
175 setSourcePixmapMask();
178 void setSourceOverScaledPixmapMask() {
179 setSourceOverPixmapMask();
180 updateStateBits(&drawRectMask, STATE_XFORM_SCALE, true);
183 QBlittable::Capabilities m_capabilities;
187 uint capabillitiesState;
190 class QBlitterPaintEnginePrivate : public QPaintEngineExPrivate
192 Q_DECLARE_PUBLIC(QBlitterPaintEngine);
194 QBlitterPaintEnginePrivate(QBlittablePixmapData *p)
195 : QPaintEngineExPrivate(),
197 isBlitterLocked(false),
201 raster = new QRasterPaintEngine(p->buffer());
202 capabillities = new CapabilitiesToStateMask(pmData->blittable()->capabilities());
206 if (!isBlitterLocked) {
207 raster->d_func()->rasterBuffer->prepare(pmData->blittable()->lock());
208 isBlitterLocked = true;
212 inline void unlock() {
213 if (isBlitterLocked) {
214 pmData->blittable()->unlock();
215 isBlitterLocked = false;
219 void fillRect(const QRectF &rect, const QColor &color) {
220 Q_Q(QBlitterPaintEngine);
221 pmData->unmarkRasterOverlay(rect);
222 QRectF targetRect = rect;
224 targetRect = q->state()->matrix.mapRect(rect);
226 const QClipData *clipData = q->clip();
228 if (clipData->hasRectClip) {
230 pmData->blittable()->fillRect(targetRect & clipData->clipRect, color);
231 } else if (clipData->hasRegionClip) {
232 QVector<QRect> rects = clipData->clipRegion.rects();
233 for ( int i = 0; i < rects.size(); i++ ) {
234 QRect intersectRect = rects.at(i).intersected(targetRect.toRect());
235 if (!intersectRect.isEmpty()) {
237 pmData->blittable()->fillRect(intersectRect,color);
242 if (targetRect.x() >= 0 && targetRect.y() >= 0
243 && targetRect.width() <= raster->paintDevice()->width()
244 && targetRect.height() <= raster->paintDevice()->height()) {
246 pmData->blittable()->fillRect(targetRect,color);
248 QRectF deviceRect(0,0,raster->paintDevice()->width(), raster->paintDevice()->height());
250 pmData->blittable()->fillRect(deviceRect&targetRect,color);
255 void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr) {
256 QRectF intersectedRect = clip.intersected(target);
257 if (intersectedRect.isEmpty())
260 if(intersectedRect.size() != target.size()) {
261 qreal deltaTop = target.top() - intersectedRect.top();
262 qreal deltaLeft = target.left() - intersectedRect.left();
263 qreal deltaBottom = target.bottom() - intersectedRect.bottom();
264 qreal deltaRight = target.right() - intersectedRect.right();
265 source.adjust(-deltaLeft,-deltaTop,-deltaRight,-deltaBottom);
267 pmData->unmarkRasterOverlay(intersectedRect);
268 pmData->blittable()->drawPixmap(intersectedRect, pm, source);
272 Q_Q(QBlitterPaintEngine);
273 const QClipData *clip = q->clip();
274 bool complex = clip && !(clip->hasRectClip || clip->hasRegionClip);
275 capabillities->updateState(STATE_CLIP_COMPLEX, complex);
278 void systemStateChanged() {
279 raster->d_func()->systemStateChanged();
282 QRasterPaintEngine *raster;
284 QBlittablePixmapData *pmData;
285 bool isBlitterLocked;
287 CapabilitiesToStateMask *capabillities;
292 QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePixmapData *p)
293 : QPaintEngineEx(*(new QBlitterPaintEnginePrivate(p)))
297 QBlitterPaintEngine::~QBlitterPaintEngine()
301 QPainterState *QBlitterPaintEngine::createState(QPainterState *orig) const
303 Q_D(const QBlitterPaintEngine);
304 return d->raster->createState(orig);
307 bool QBlitterPaintEngine::begin(QPaintDevice *pdev)
309 Q_D(QBlitterPaintEngine);
312 bool ok = d->raster->begin(pdev);
313 #ifdef QT_BLITTER_RASTEROVERLAY
314 d->pmData->unmergeOverlay();
320 bool QBlitterPaintEngine::end()
322 Q_D(QBlitterPaintEngine);
325 #ifdef QT_BLITTER_RASTEROVERLAY
326 d->pmData->mergeOverlay();
328 return d->raster->end();
332 void QBlitterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
334 Q_D(QBlitterPaintEngine);
335 if (path.shape() == QVectorPath::RectangleHint) {
336 QRectF rect(((QPointF *) path.points())[0], ((QPointF *) path.points())[2]);
337 fillRect(rect, brush);
340 d->pmData->markRasterOverlay(path);
341 d->raster->fill(path, brush);
345 void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color)
347 Q_D(QBlitterPaintEngine);
348 if (d->capabillities->canBlitterFillRect() && color.alpha() == 0xff) {
349 d->fillRect(rect, color);
352 d->pmData->markRasterOverlay(rect);
353 d->raster->fillRect(rect, color);
357 void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
359 if(rect.size().isEmpty())
362 Q_D(QBlitterPaintEngine);
364 if (qbrush_style(brush) == Qt::SolidPattern
365 && qbrush_color(brush).alpha() == 0xff
366 && d->capabillities->canBlitterFillRect())
368 d->fillRect(rect, qbrush_color(brush));
369 }else if (brush.style() == Qt::TexturePattern
370 && d->capabillities->canBlitterDrawPixmap(rect,brush.texture(),rect))
372 bool rectIsFilled = false;
373 QRectF transformedRect = state()->matrix.mapRect(rect);
374 qreal x = transformedRect.x();
375 qreal y = transformedRect.y();
376 QPixmap pm = brush.texture();
378 int srcX = int(rect.x() - state()->brushOrigin.x()) % pm.width();
380 srcX = pm.width() + srcX;
381 const int startX = srcX;
382 int srcY = int(rect.y() - state()->brushOrigin.y()) % pm.height();
384 srcY = pm.height() + srcY;
385 while (!rectIsFilled) {
386 qreal blitWidth = (pm.width() ) - srcX;
387 qreal blitHeight = (pm.height() ) - srcY;
388 if (x + blitWidth > transformedRect.right())
389 blitWidth = transformedRect.right() -x;
390 if (y + blitHeight > transformedRect.bottom())
391 blitHeight = transformedRect.bottom() - y;
392 const QClipData *clipData = clip();
393 if (clipData->hasRectClip) {
394 QRect targetRect = QRect(x,y,blitWidth,blitHeight).intersected(clipData->clipRect);
395 if (targetRect.isValid()) {
396 int tmpSrcX = srcX + (targetRect.x() - x);
397 int tmpSrcY = srcY + (targetRect.y() - y);
398 QRect srcRect(tmpSrcX,tmpSrcY,targetRect.width(),targetRect.height());
399 d->pmData->blittable()->drawPixmap(targetRect,pm,srcRect);
401 } else if (clipData->hasRegionClip) {
402 QVector<QRect> clipRects = clipData->clipRegion.rects();
403 QRect unclippedTargetRect(x,y,blitWidth,blitHeight);
404 QRegion intersectedRects = clipData->clipRegion.intersected(unclippedTargetRect);
406 for ( int i = 0; i < intersectedRects.rects().size(); i++ ) {
407 QRect targetRect = intersectedRects.rects().at(i);
408 if (!targetRect.isValid() || targetRect.isEmpty())
410 int tmpSrcX = srcX + (targetRect.x() - x);
411 int tmpSrcY = srcY + (targetRect.y() - y);
412 QRect srcRect(tmpSrcX,tmpSrcY,targetRect.width(),targetRect.height());
413 d->pmData->blittable()->drawPixmap(targetRect,pm,srcRect);
417 if (x>=transformedRect.right()) {
418 x = transformedRect.x();
422 if (y>=transformedRect.bottom())
429 d->pmData->markRasterOverlay(rect);
430 d->raster->fillRect(rect, brush);
435 void QBlitterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
437 Q_D(QBlitterPaintEngine);
439 d->pmData->markRasterOverlay(path);
440 d->raster->stroke(path, pen);
443 void QBlitterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
445 Q_D(QBlitterPaintEngine);
447 d->raster->clip(path, op);
450 void QBlitterPaintEngine::clip(const QRect &rect, Qt::ClipOperation op){
451 Q_D(QBlitterPaintEngine);
453 d->raster->clip(rect,op);
456 void QBlitterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
458 Q_D(QBlitterPaintEngine);
460 d->raster->clip(region,op);
464 void QBlitterPaintEngine::clipEnabledChanged()
466 Q_D(QBlitterPaintEngine);
468 d->raster->clipEnabledChanged();
471 void QBlitterPaintEngine::penChanged()
473 Q_D(QBlitterPaintEngine);
475 d->raster->penChanged();
476 d->capabillities->updateState(STATE_PEN_ENABLED,qpen_style(state()->pen) != Qt::NoPen);
479 void QBlitterPaintEngine::brushChanged()
481 Q_D(QBlitterPaintEngine);
482 d->raster->brushChanged();
484 bool solid = qbrush_style(state()->brush) == Qt::SolidPattern;
486 d->capabillities->updateState(STATE_BRUSH_PATTERN, !solid);
487 d->capabillities->updateState(STATE_BRUSH_ALPHA,
488 qbrush_color(state()->brush).alpha() < 255);
491 void QBlitterPaintEngine::brushOriginChanged()
493 Q_D(QBlitterPaintEngine);
494 d->raster->brushOriginChanged();
497 void QBlitterPaintEngine::opacityChanged()
499 Q_D(QBlitterPaintEngine);
500 d->raster->opacityChanged();
502 bool translucent = state()->opacity < 1;
503 d->capabillities->updateState(STATE_ALPHA,translucent);
506 void QBlitterPaintEngine::compositionModeChanged()
508 Q_D(QBlitterPaintEngine);
509 d->raster->compositionModeChanged();
511 bool nonTrivial = state()->composition_mode != QPainter::CompositionMode_SourceOver
512 && state()->composition_mode != QPainter::CompositionMode_Source;
514 d->capabillities->updateState(STATE_BLENDING_COMPLEX,nonTrivial);
517 void QBlitterPaintEngine::renderHintsChanged()
519 Q_D(QBlitterPaintEngine);
520 d->raster->renderHintsChanged();
522 bool aa = state()->renderHints & QPainter::Antialiasing;
523 d->capabillities->updateState(STATE_ANTIALIASING, aa);
527 void QBlitterPaintEngine::transformChanged()
529 Q_D(QBlitterPaintEngine);
530 d->raster->transformChanged();
532 QTransform::TransformationType type = state()->matrix.type();
534 d->capabillities->updateState(STATE_XFORM_COMPLEX, type > QTransform::TxScale);
535 d->capabillities->updateState(STATE_XFORM_SCALE, type > QTransform::TxTranslate);
537 d->hasXForm = type >= QTransform::TxTranslate;
541 void QBlitterPaintEngine::drawRects(const QRect *rects, int rectCount)
543 Q_D(QBlitterPaintEngine);
544 if (d->capabillities->canBlitterDrawRectMask()) {
545 for (int i=0; i<rectCount; ++i) {
546 d->fillRect(rects[i], qbrush_color(state()->brush));
549 d->pmData->markRasterOverlay(rects,rectCount);
550 QPaintEngineEx::drawRects(rects, rectCount);
554 void QBlitterPaintEngine::drawRects(const QRectF *rects, int rectCount)
556 Q_D(QBlitterPaintEngine);
557 if (d->capabillities->canBlitterDrawRectMask()) {
558 for (int i=0; i<rectCount; ++i) {
559 d->fillRect(rects[i], qbrush_color(state()->brush));
562 d->pmData->markRasterOverlay(rects,rectCount);
563 QPaintEngineEx::drawRects(rects, rectCount);
567 void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
569 Q_D(QBlitterPaintEngine);
570 if (d->capabillities->canBlitterDrawPixmap(r,pm,sr)) {
573 QRectF targetRect = r;
575 targetRect = state()->matrix.mapRect(r);
577 const QClipData *clipData = clip();
579 if (clipData->hasRectClip) {
580 d->clipAndDrawPixmap(clipData->clipRect,targetRect,pm,sr);
581 }else if (clipData->hasRegionClip) {
582 QVector<QRect>rects = clipData->clipRegion.rects();
583 for (int i = 0; i<rects.size(); i++) {
584 d->clipAndDrawPixmap(rects.at(i),targetRect,pm,sr);
588 QRectF deviceRect(0,0,d->raster->paintDevice()->width(), d->raster->paintDevice()->height());
589 d->clipAndDrawPixmap(deviceRect,targetRect,pm,sr);
593 d->pmData->markRasterOverlay(r);
594 d->raster->drawPixmap(r, pm, sr);
598 void QBlitterPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
599 Qt::ImageConversionFlags flags)
601 Q_D(QBlitterPaintEngine);
603 d->pmData->markRasterOverlay(r);
604 d->raster->drawImage(r, pm, sr, flags);
608 void QBlitterPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
610 Q_D(QBlitterPaintEngine);
612 d->raster->drawTextItem(pos, ti);
613 d->pmData->markRasterOverlay(pos,ti);
616 void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti)
618 Q_D(QBlitterPaintEngine);
620 d->raster->drawStaticTextItem(sti);
622 //#### d->pmData->markRasterOverlay(sti);
623 qWarning("not implemented: markRasterOverlay for QStaticTextItem");
628 void QBlitterPaintEngine::drawEllipse(const QRectF &r)
630 Q_D(QBlitterPaintEngine);
632 d->pmData->markRasterOverlay(r);
633 d->raster->drawEllipse(r);
636 void QBlitterPaintEngine::setState(QPainterState *s)
638 Q_D(QBlitterPaintEngine);
640 QPaintEngineEx::setState(s);
641 d->raster->setState(s);
643 clipEnabledChanged();
646 brushOriginChanged();
648 compositionModeChanged();
649 renderHintsChanged();
655 inline QRasterPaintEngine *QBlitterPaintEngine::raster() const
657 Q_D(const QBlitterPaintEngine);
662 #endif //QT_NO_BLITTABLE