blob: a50d1dfd73f0a5767812974c63ab12cc297f3693 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "private/qpaintengine_blitter_p.h"
#include "private/qblittable_p.h"
#include "private/qpaintengine_raster_p.h"
#include "private/qpainter_p.h"
#include "private/qpixmap_blitter_p.h"
#ifndef QT_NO_BLITTABLE
QT_BEGIN_NAMESPACE
#define STATE_XFORM_SCALE 0x00000001
#define STATE_XFORM_COMPLEX 0x00000002
#define STATE_BRUSH_PATTERN 0x00000010
#define STATE_BRUSH_ALPHA 0x00000020
#define STATE_PEN_ENABLED 0x00000100
#define STATE_ANTIALIASING 0x00001000
#define STATE_ALPHA 0x00002000
#define STATE_BLENDING_COMPLEX 0x00004000
#define STATE_CLIPSYS_COMPLEX 0x00010000
#define STATE_CLIP_COMPLEX 0x00020000
class CapabilitiesToStateMask
{
public:
CapabilitiesToStateMask(QBlittable::Capabilities capabilities)
: m_capabilities(capabilities)
, fillRectMask(0)
, drawRectMask(0)
, drawPixmapMask(0)
, alphaFillRectMask(0)
, opacityPixmapMask(0)
, capabillitiesState(0)
{
if (capabilities & QBlittable::SolidRectCapability)
setFillRectMask();
if (capabilities & QBlittable::SourcePixmapCapability)
setSourcePixmapMask();
if (capabilities & QBlittable::SourceOverPixmapCapability)
setSourceOverPixmapMask();
if (capabilities & QBlittable::SourceOverScaledPixmapCapability)
setSourceOverScaledPixmapMask();
if (capabilities & QBlittable::AlphaFillRectCapability)
setAlphaFillRectMask();
if (capabilities & QBlittable::OpacityPixmapCapability)
setOpacityPixmapMask();
}
inline bool canBlitterFillRect() const
{
return checkStateAgainstMask(capabillitiesState, fillRectMask);
}
inline bool canBlitterAlphaFillRect() const
{
return checkStateAgainstMask(capabillitiesState, alphaFillRectMask);
}
inline bool canBlitterDrawRectMask() const
{
return checkStateAgainstMask(capabillitiesState, drawRectMask);
}
bool canBlitterDrawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) const
{
if (pm.handle()->classId() != QPlatformPixmap::BlitterClass)
return false;
if (checkStateAgainstMask(capabillitiesState, drawPixmapMask)) {
if (m_capabilities & (QBlittable::SourceOverPixmapCapability
| QBlittable::SourceOverScaledPixmapCapability)) {
if (r.size() != sr.size())
return m_capabilities & QBlittable::SourceOverScaledPixmapCapability;
else
return m_capabilities & QBlittable::SourceOverPixmapCapability;
}
if ((m_capabilities & QBlittable::SourcePixmapCapability) && r.size() == sr.size() && !pm.hasAlphaChannel())
return m_capabilities & QBlittable::SourcePixmapCapability;
}
return false;
}
bool canBlitterDrawPixmapOpacity(const QPixmap &pm) const
{
if (pm.handle()->classId() != QPlatformPixmap::BlitterClass)
return false;
return checkStateAgainstMask(capabillitiesState, opacityPixmapMask);
}
bool canBlitterDrawCachedGlyphs(const QTransform &transform, QFontEngine::GlyphFormat requestedGlyphFormat, bool complexClip) const
{
if (transform.type() > QTransform::TxScale)
return false;
if (!(m_capabilities & QBlittable::DrawScaledCachedGlyphsCapability))
return false;
if (requestedGlyphFormat == QFontEngine::Format_ARGB && !(m_capabilities & QBlittable::SubPixelGlyphsCapability))
return false;
if (complexClip && !(m_capabilities & QBlittable::ComplexClipCapability))
return false;
return true;
}
inline void updateState(uint mask, bool on) {
updateStateBits(&capabillitiesState, mask, on);
}
private:
static inline void updateStateBits(uint *state, uint mask, bool on)
{
*state = on ? (*state | mask) : (*state & ~mask);
}
static inline bool checkStateAgainstMask(uint state, uint mask)
{
return !state || (state & mask && !(state & ~mask));
}
void setFillRectMask() {
updateStateBits(&fillRectMask, STATE_XFORM_SCALE, false);
updateStateBits(&fillRectMask, STATE_XFORM_COMPLEX, false);
updateStateBits(&fillRectMask, STATE_BRUSH_PATTERN, false);
updateStateBits(&fillRectMask, STATE_BRUSH_ALPHA, false);
updateStateBits(&fillRectMask, STATE_PEN_ENABLED, true);
//Sub-pixel aliasing should not be sent to the blitter
updateStateBits(&fillRectMask, STATE_ANTIALIASING, true);
updateStateBits(&fillRectMask, STATE_ALPHA, false);
updateStateBits(&fillRectMask, STATE_BLENDING_COMPLEX, false);
updateStateBits(&fillRectMask, STATE_CLIPSYS_COMPLEX, false);
updateStateBits(&fillRectMask, STATE_CLIP_COMPLEX, false);
}
void setAlphaFillRectMask() {
updateStateBits(&alphaFillRectMask, STATE_XFORM_SCALE, false);
updateStateBits(&alphaFillRectMask, STATE_XFORM_COMPLEX, false);
updateStateBits(&alphaFillRectMask, STATE_BRUSH_PATTERN, false);
updateStateBits(&alphaFillRectMask, STATE_BRUSH_ALPHA, true);
updateStateBits(&alphaFillRectMask, STATE_PEN_ENABLED, true);
//Sub-pixel aliasing should not be sent to the blitter
updateStateBits(&alphaFillRectMask, STATE_ANTIALIASING, true);
updateStateBits(&alphaFillRectMask, STATE_ALPHA, false);
updateStateBits(&alphaFillRectMask, STATE_BLENDING_COMPLEX, false);
updateStateBits(&alphaFillRectMask, STATE_CLIPSYS_COMPLEX, false);
updateStateBits(&alphaFillRectMask, STATE_CLIP_COMPLEX, false);
}
void setSourcePixmapMask() {
updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, false);
updateStateBits(&drawPixmapMask, STATE_XFORM_COMPLEX, false);
updateStateBits(&drawPixmapMask, STATE_BRUSH_PATTERN, true);
updateStateBits(&drawPixmapMask, STATE_BRUSH_ALPHA, false);
updateStateBits(&drawPixmapMask, STATE_PEN_ENABLED, true);
updateStateBits(&drawPixmapMask, STATE_ANTIALIASING, true);
updateStateBits(&drawPixmapMask, STATE_ALPHA, false);
updateStateBits(&drawPixmapMask, STATE_BLENDING_COMPLEX, false);
updateStateBits(&drawPixmapMask, STATE_CLIPSYS_COMPLEX, false);
updateStateBits(&drawPixmapMask, STATE_CLIP_COMPLEX, false);
}
void setSourceOverPixmapMask() {
setSourcePixmapMask();
}
void setSourceOverScaledPixmapMask() {
setSourceOverPixmapMask();
updateStateBits(&drawPixmapMask, STATE_XFORM_SCALE, true);
}
void setOpacityPixmapMask() {
updateStateBits(&opacityPixmapMask, STATE_XFORM_SCALE, true);
updateStateBits(&opacityPixmapMask, STATE_XFORM_COMPLEX, false);
updateStateBits(&opacityPixmapMask, STATE_BRUSH_PATTERN, true);
updateStateBits(&opacityPixmapMask, STATE_BRUSH_ALPHA, true);
updateStateBits(&opacityPixmapMask, STATE_PEN_ENABLED, true);
updateStateBits(&opacityPixmapMask, STATE_ANTIALIASING, true);
updateStateBits(&opacityPixmapMask, STATE_ALPHA, true);
updateStateBits(&opacityPixmapMask, STATE_BLENDING_COMPLEX, false);
updateStateBits(&opacityPixmapMask, STATE_CLIPSYS_COMPLEX, false);
updateStateBits(&opacityPixmapMask, STATE_CLIP_COMPLEX, false);
}
QBlittable::Capabilities m_capabilities;
uint fillRectMask;
uint drawRectMask;
uint drawPixmapMask;
uint alphaFillRectMask;
uint opacityPixmapMask;
uint capabillitiesState;
};
class QBlitterPaintEnginePrivate : public QRasterPaintEnginePrivate
{
Q_DECLARE_PUBLIC(QBlitterPaintEngine)
public:
QBlitterPaintEnginePrivate(QBlittablePlatformPixmap *p)
: QRasterPaintEnginePrivate()
, pmData(p)
, caps(pmData->blittable()->capabilities())
, hasXForm(false)
{}
void lock();
void unlock();
void fillRect(const QRectF &rect, const QColor &color, bool alpha);
void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr, bool opacity);
void updateCompleteState(QPainterState *s);
void updatePenState(QPainterState *s);
void updateBrushState(QPainterState *s);
void updateOpacityState(QPainterState *s);
void updateCompositionModeState(QPainterState *s);
void updateRenderHintsState(QPainterState *s);
void updateTransformState(QPainterState *s);
void updateClipState(QPainterState *s);
QBlittablePlatformPixmap *pmData;
CapabilitiesToStateMask caps;
uint hasXForm;
};
inline void QBlitterPaintEnginePrivate::lock()
{
if (!pmData->blittable()->isLocked())
rasterBuffer->prepare(pmData->buffer());
}
inline void QBlitterPaintEnginePrivate::unlock()
{
pmData->blittable()->unlock();
}
// State tracking to make decisions
void QBlitterPaintEnginePrivate::updateCompleteState(QPainterState *s)
{
updatePenState(s);
updateBrushState(s);
updateOpacityState(s);
updateCompositionModeState(s);
updateRenderHintsState(s);
updateTransformState(s);
updateClipState(s);
}
void QBlitterPaintEnginePrivate::updatePenState(QPainterState *s)
{
caps.updateState(STATE_PEN_ENABLED, qpen_style(s->pen) != Qt::NoPen);
}
void QBlitterPaintEnginePrivate::updateBrushState(QPainterState *s)
{
Qt::BrushStyle style = qbrush_style(s->brush);
caps.updateState(STATE_BRUSH_PATTERN, style != Qt::SolidPattern);
caps.updateState(STATE_BRUSH_ALPHA,
qbrush_color(s->brush).alpha() < 255);
}
void QBlitterPaintEnginePrivate::updateOpacityState(QPainterState *s)
{
bool translucent = s->opacity < 1;
caps.updateState(STATE_ALPHA, translucent);
}
void QBlitterPaintEnginePrivate::updateCompositionModeState(QPainterState *s)
{
bool nonTrivial = s->composition_mode != QPainter::CompositionMode_SourceOver
&& s->composition_mode != QPainter::CompositionMode_Source;
caps.updateState(STATE_BLENDING_COMPLEX, nonTrivial);
}
void QBlitterPaintEnginePrivate::updateRenderHintsState(QPainterState *s)
{
bool aa = s->renderHints & QPainter::Antialiasing;
caps.updateState(STATE_ANTIALIASING, aa);
}
void QBlitterPaintEnginePrivate::updateTransformState(QPainterState *s)
{
QTransform::TransformationType type = s->matrix.type();
// consider scaling operations with a negative factor as "complex" for now.
// as some blitters could handle axisymmetrical operations, we should improve blitter
// paint engine to handle them as a capability
caps.updateState(STATE_XFORM_COMPLEX, (type > QTransform::TxScale) ||
((type == QTransform::TxScale) && ((s->matrix.m11() < 0.0) || (s->matrix.m22() < 0.0))));
caps.updateState(STATE_XFORM_SCALE, type > QTransform::TxTranslate);
hasXForm = type >= QTransform::TxTranslate;
}
void QBlitterPaintEnginePrivate::updateClipState(QPainterState *)
{
const QClipData *clipData = clip();
bool complexClip = clipData && !(clipData->hasRectClip || clipData->hasRegionClip);
caps.updateState(STATE_CLIP_COMPLEX, complexClip);
}
void QBlitterPaintEnginePrivate::fillRect(const QRectF &rect, const QColor &color, bool alpha)
{
Q_Q(QBlitterPaintEngine);
pmData->unmarkRasterOverlay(rect);
QRectF targetRect = rect;
if (hasXForm)
targetRect = q->state()->matrix.mapRect(rect);
const QClipData *clipData = clip();
if (clipData) {
if (clipData->hasRectClip) {
unlock();
if (alpha)
pmData->blittable()->alphaFillRect(targetRect & clipData->clipRect, color, q->state()->compositionMode());
else
pmData->blittable()->fillRect(targetRect & clipData->clipRect, color);
} else if (clipData->hasRegionClip) {
for (const QRect &rect : clipData->clipRegion) {
QRect intersectRect = rect.intersected(targetRect.toRect());
if (!intersectRect.isEmpty()) {
unlock();
if (alpha)
pmData->blittable()->alphaFillRect(intersectRect, color, q->state()->compositionMode());
else
pmData->blittable()->fillRect(intersectRect, color);
}
}
}
} else {
if (targetRect.x() >= 0 && targetRect.y() >= 0
&& targetRect.width() <= q->paintDevice()->width()
&& targetRect.height() <= q->paintDevice()->height()) {
unlock();
if (alpha)
pmData->blittable()->alphaFillRect(targetRect, color, q->state()->compositionMode());
else
pmData->blittable()->fillRect(targetRect, color);
} else {
QRectF deviceRect(0, 0, q->paintDevice()->width(), q->paintDevice()->height());
unlock();
if (alpha)
pmData->blittable()->alphaFillRect(deviceRect & targetRect, color, q->state()->compositionMode());
else
pmData->blittable()->fillRect(deviceRect & targetRect, color);
}
}
}
void QBlitterPaintEnginePrivate::clipAndDrawPixmap(const QRectF &clip,
const QRectF &target,
const QPixmap &pm,
const QRectF &sr,
bool opacity)
{
Q_Q(QBlitterPaintEngine);
QRectF intersectedRect = clip.intersected(target);
if (intersectedRect.isEmpty())
return;
QRectF source = sr;
if (intersectedRect.size() != target.size()) {
if (sr.size() == target.size()) {
// no resize
qreal deltaTop = target.top() - intersectedRect.top();
qreal deltaLeft = target.left() - intersectedRect.left();
qreal deltaBottom = target.bottom() - intersectedRect.bottom();
qreal deltaRight = target.right() - intersectedRect.right();
source.adjust(-deltaLeft, -deltaTop, -deltaRight, -deltaBottom);
} else {
// resize case
qreal hFactor = sr.size().width() / target.size().width();
qreal vFactor = sr.size().height() / target.size().height();
qreal deltaTop = (target.top() - intersectedRect.top()) * vFactor;
qreal deltaLeft = (target.left() - intersectedRect.left()) * hFactor;
qreal deltaBottom = (target.bottom() - intersectedRect.bottom()) * vFactor;
qreal deltaRight = (target.right() - intersectedRect.right()) * hFactor;
source.adjust(-deltaLeft, -deltaTop, -deltaRight, -deltaBottom);
}
}
pmData->unmarkRasterOverlay(intersectedRect);
if (opacity)
pmData->blittable()->drawPixmapOpacity(intersectedRect, pm, source, q->state()->compositionMode(), q->state()->opacity);
else
pmData->blittable()->drawPixmap(intersectedRect, pm, source);
}
QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePlatformPixmap *p)
: QRasterPaintEngine(*(new QBlitterPaintEnginePrivate(p)), p->buffer())
{}
// State tracking
void QBlitterPaintEngine::penChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::penChanged();
d->updatePenState(state());
}
void QBlitterPaintEngine::brushChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::brushChanged();
d->updateBrushState(state());
}
void QBlitterPaintEngine::opacityChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::opacityChanged();
d->updateOpacityState(state());
}
void QBlitterPaintEngine::compositionModeChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::compositionModeChanged();
d->updateCompositionModeState(state());
}
void QBlitterPaintEngine::renderHintsChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::renderHintsChanged();
d->updateRenderHintsState(state());
}
void QBlitterPaintEngine::transformChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::transformChanged();
d->updateTransformState(state());
}
void QBlitterPaintEngine::clipEnabledChanged()
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::clipEnabledChanged();
d->updateClipState(state());
}
bool QBlitterPaintEngine::begin(QPaintDevice *pdev)
{
Q_D(QBlitterPaintEngine);
bool ok = QRasterPaintEngine::begin(pdev);
#ifdef QT_BLITTER_RASTEROVERLAY
d->pmData->unmergeOverlay();
#endif
d->pdev = pdev;
return ok;
}
bool QBlitterPaintEngine::end()
{
#ifdef QT_BLITTER_RASTEROVERLAY
Q_D(QBlitterPaintEngine);
d->pmData->mergeOverlay();
#endif
return QRasterPaintEngine::end();
}
void QBlitterPaintEngine::setState(QPainterState *s)
{
Q_D(QBlitterPaintEngine);
QRasterPaintEngine::setState(s);
d->updateCompleteState(s);
}
// Accelerated paths
void QBlitterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QBlitterPaintEngine);
if (path.shape() == QVectorPath::RectangleHint) {
QRectF rect(((const QPointF *) path.points())[0], ((const QPointF *) path.points())[2]);
fillRect(rect, brush);
} else {
d->lock();
d->pmData->markRasterOverlay(path);
QRasterPaintEngine::fill(path, brush);
}
}
void QBlitterPaintEngine::fillRect(const QRectF &rect, const QColor &color)
{
Q_D(QBlitterPaintEngine);
if (d->caps.canBlitterAlphaFillRect()) {
d->fillRect(rect, color, true);
} else if (d->caps.canBlitterFillRect() && color.alpha() == 0xff) {
d->fillRect(rect, color, false);
} else {
d->lock();
d->pmData->markRasterOverlay(rect);
QRasterPaintEngine::fillRect(rect, color);
}
}
void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
{
if (rect.size().isEmpty())
return;
Q_D(QBlitterPaintEngine);
if (qbrush_style(brush) == Qt::SolidPattern
&& d->caps.canBlitterAlphaFillRect()) {
d->fillRect(rect, qbrush_color(brush), true);
} else if (qbrush_style(brush) == Qt::SolidPattern
&& qbrush_color(brush).alpha() == 0xff
&& d->caps.canBlitterFillRect()) {
d->fillRect(rect, qbrush_color(brush), false);
} else if ((brush.style() == Qt::TexturePattern) &&
(brush.transform().type() <= QTransform::TxTranslate) &&
((d->caps.canBlitterDrawPixmapOpacity(brush.texture())) ||
(d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)))) {
bool rectIsFilled = false;
QRectF transformedRect = state()->matrix.mapRect(rect);
qreal x = transformedRect.x();
qreal y = transformedRect.y();
QPixmap pm = brush.texture();
d->unlock();
int srcX = int(rect.x() - state()->brushOrigin.x() - brush.transform().dx()) % pm.width();
if (srcX < 0)
srcX = pm.width() + srcX;
const int startX = srcX;
int srcY = int(rect.y() - state()->brushOrigin.y() - brush.transform().dy()) % pm.height();
if (srcY < 0)
srcY = pm.height() + srcY;
while (!rectIsFilled) {
qreal blitWidth = (pm.width() ) - srcX;
qreal blitHeight = (pm.height() ) - srcY;
if (x + blitWidth > transformedRect.right())
blitWidth = transformedRect.right() -x;
if (y + blitHeight > transformedRect.bottom())
blitHeight = transformedRect.bottom() - y;
const QClipData *clipData = d->clip();
if (clipData->hasRectClip) {
QRect targetRect = QRect(x, y, blitWidth, blitHeight).intersected(clipData->clipRect);
if (targetRect.isValid()) {
int tmpSrcX = srcX + (targetRect.x() - x);
int tmpSrcY = srcY + (targetRect.y() - y);
QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height());
d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect);
}
} else if (clipData->hasRegionClip) {
QRect unclippedTargetRect(x, y, blitWidth, blitHeight);
const QRegion targetRegion = clipData->clipRegion.intersected(unclippedTargetRect);
for (const QRect &targetRect : targetRegion) {
if (!targetRect.isValid() || targetRect.isEmpty())
continue;
int tmpSrcX = srcX + (targetRect.x() - x);
int tmpSrcY = srcY + (targetRect.y() - y);
QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height());
d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect);
}
}
x+=blitWidth;
if (qFuzzyCompare(x, transformedRect.right())) {
x = transformedRect.x();
srcX = startX;
srcY = 0;
y += blitHeight;
if (qFuzzyCompare(y, transformedRect.bottom()))
rectIsFilled = true;
} else
srcX = 0;
}
} else {
d->lock();
d->pmData->markRasterOverlay(rect);
QRasterPaintEngine::fillRect(rect, brush);
}
}
void QBlitterPaintEngine::drawRects(const QRect *rects, int rectCount)
{
Q_D(QBlitterPaintEngine);
if (d->caps.canBlitterDrawRectMask()) {
for (int i=0; i<rectCount; ++i)
d->fillRect(rects[i], qbrush_color(state()->brush), false);
} else {
d->pmData->markRasterOverlay(rects, rectCount);
QRasterPaintEngine::drawRects(rects, rectCount);
}
}
void QBlitterPaintEngine::drawRects(const QRectF *rects, int rectCount)
{
Q_D(QBlitterPaintEngine);
if (d->caps.canBlitterDrawRectMask()) {
for (int i = 0; i < rectCount; ++i)
d->fillRect(rects[i], qbrush_color(state()->brush), false);
} else {
d->pmData->markRasterOverlay(rects, rectCount);
QRasterPaintEngine::drawRects(rects, rectCount);
}
}
void QBlitterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
{
drawPixmap(QRectF(pos, pm.size()), pm, pm.rect());
}
void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
{
Q_D(QBlitterPaintEngine);
bool canDrawOpacity;
canDrawOpacity = d->caps.canBlitterDrawPixmapOpacity(pm);
if (canDrawOpacity || (d->caps.canBlitterDrawPixmap(r, pm, sr))) {
d->unlock();
QRectF targetRect = r;
if (d->hasXForm)
targetRect = state()->matrix.mapRect(r);
const QClipData *clipData = d->clip();
if (clipData) {
if (clipData->hasRectClip) {
d->clipAndDrawPixmap(clipData->clipRect, targetRect, pm, sr, canDrawOpacity);
} else if (clipData->hasRegionClip) {
for (const QRect &rect : clipData->clipRegion)
d->clipAndDrawPixmap(rect, targetRect, pm, sr, canDrawOpacity);
}
} else {
QRectF deviceRect(0, 0, paintDevice()->width(), paintDevice()->height());
d->clipAndDrawPixmap(deviceRect, targetRect, pm, sr, canDrawOpacity);
}
}else {
d->lock();
d->pmData->markRasterOverlay(r);
QRasterPaintEngine::drawPixmap(r, pm, sr);
}
}
// Overridden methods to lock the graphics memory
void QBlitterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(points, pointCount);
QRasterPaintEngine::drawPolygon(points, pointCount, mode);
}
void QBlitterPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(points, pointCount);
QRasterPaintEngine::drawPolygon(points, pointCount, mode);
}
void QBlitterPaintEngine::fillPath(const QPainterPath &path, QSpanData *fillData)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(path);
QRasterPaintEngine::fillPath(path, fillData);
}
void QBlitterPaintEngine::fillPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(points, pointCount);
QRasterPaintEngine::fillPolygon(points, pointCount, mode);
}
void QBlitterPaintEngine::drawEllipse(const QRectF &r)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(r);
QRasterPaintEngine::drawEllipse(r);
}
void QBlitterPaintEngine::drawImage(const QPointF &pos, const QImage &image)
{
drawImage(QRectF(pos, image.size()), image, image.rect());
}
void QBlitterPaintEngine::drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(r);
QRasterPaintEngine::drawImage(r, pm, sr, flags);
}
void QBlitterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(r);
QRasterPaintEngine::drawTiledPixmap(r, pm, sr);
}
void QBlitterPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(pos, ti);
QRasterPaintEngine::drawTextItem(pos, ti);
}
void QBlitterPaintEngine::drawPoints(const QPointF *points, int pointCount)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(points, pointCount);
QRasterPaintEngine::drawPoints(points, pointCount);
}
void QBlitterPaintEngine::drawPoints(const QPoint *points, int pointCount)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(points, pointCount);
QRasterPaintEngine::drawPoints(points, pointCount);
}
void QBlitterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QBlitterPaintEngine);
d->lock();
d->pmData->markRasterOverlay(path);
QRasterPaintEngine::stroke(path, pen);
}
void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti)
{
Q_D(QBlitterPaintEngine);
d->lock();
QRasterPaintEngine::drawStaticTextItem(sti);
#ifdef QT_BLITTER_RASTEROVERLAY
//#### d->pmData->markRasterOverlay(sti);
qWarning("not implemented: markRasterOverlay for QStaticTextItem");
#endif
}
bool QBlitterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine)
{
Q_D(QBlitterPaintEngine);
QFontEngine::GlyphFormat glyphFormat = d->glyphCacheFormat;
if (fontEngine->glyphFormat != QFontEngine::Format_None)
glyphFormat = fontEngine->glyphFormat;
const QClipData *clipData = d->clip();
const bool complexClip = clipData && !clipData->hasRectClip;
const QPainterState *s = state();
if (d->caps.canBlitterDrawCachedGlyphs(s->transform(), glyphFormat, complexClip)) {
d->unlock();
const bool result = d->pmData->blittable()->drawCachedGlyphs(s, glyphFormat, numGlyphs, glyphs, positions, fontEngine);
// Lock again as the raster paint engine might draw decorations now.
d->lock();
return result;
} else {
return QRasterPaintEngine::drawCachedGlyphs(numGlyphs, glyphs, positions, fontEngine);
}
}
QT_END_NAMESPACE
#endif //QT_NO_BLITTABLE