📄 qpainter.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/// QtCore#include <qdebug.h>#include <qmutex.h>// QtGui#include "qbitmap.h"#include "qimage.h"#include "qpaintdevice.h"#include "qpaintengine.h"#include "qpainter.h"#include "qpainter_p.h"#include "qpainterpath.h"#include "qpicture.h"#include "qpixmapcache.h"#include "qpolygon.h"#include "qtextlayout.h"#include "qwidget.h"#include "qapplication.h"#include "qstyle.h"#include "qthread.h"#include "qvarlengtharray.h"#include <private/qfontengine_p.h>#include <private/qpaintengine_p.h>#include <private/qpainterpath_p.h>#include <private/qtextengine_p.h>#include <private/qwidget_p.h>#include <private/qmath_p.h>#define QGradient_StretchToDevice 0x10000000#define QPaintEngine_OpaqueBackground 0x40000000// #define QT_DEBUG_DRAW#ifdef QT_DEBUG_DRAWbool qt_show_painter_debug_output = true;#endifextern QPixmap qt_pixmapForBrush(int style, bool invert);void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, int tabstops, int* tabarray, int tabarraylen, QPainter *painter);/* Returns true if the gradient requires stretch to device...*/static inline bool check_gradient(const QBrush &brush){ switch (brush.style()) { case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: if (brush.gradient()->coordinateMode() == QGradient::StretchToDeviceMode) return true; default: ; } return false;}static inline bool is_brush_transparent(const QBrush &brush) { Qt::BrushStyle s = brush.style(); return ((s >= Qt::Dense1Pattern && s <= Qt::DiagCrossPattern) || (s == Qt::TexturePattern && brush.texture().isQBitmap()));}static inline bool is_pen_transparent(const QPen &pen) { return pen.style() > Qt::SolidLine || is_brush_transparent(pen.brush());}/* Discards the emulation flags that are not relevant for line drawing and returns the result*/static inline uint line_emulation(uint emulation){ return emulation & (QPaintEngine::PrimitiveTransform | QPaintEngine::AlphaBlend | QPaintEngine::Antialiasing | QPaintEngine::BrushStroke | QPaintEngine::ConstantOpacity | QGradient_StretchToDevice | QPaintEngine_OpaqueBackground);}QTransform QPainterPrivate::viewTransform() const{ QTransform m; if (state->VxF) { qreal scaleW = qreal(state->vw)/qreal(state->ww); qreal scaleH = qreal(state->vh)/qreal(state->wh); m.setMatrix(scaleW, 0, 0, 0, scaleH, 0, state->vx - state->wx*scaleW, state->vy - state->wy*scaleH, 1); } return m;}void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperation op){#ifdef QT_DEBUG_DRAW if (qt_show_painter_debug_output) { printf("QPainter::drawHelper\n"); }#endif if (originalPath.isEmpty()) return; if (state->emulationSpecifier == QGradient_StretchToDevice) { drawStretchToDevice(originalPath, op); return; } else if (state->emulationSpecifier & QPaintEngine_OpaqueBackground) { drawOpaqueBackground(originalPath, op); return; } Q_Q(QPainter); int devMinX = 0, devMaxX = 0, devMinY = 0, devMaxY = 0; qreal strokeOffsetX = 0, strokeOffsetY = 0; QPainterPath path = originalPath * state->matrix; QRectF pathBounds = path.boundingRect(); QRectF strokeBounds; bool doStroke = (op & StrokeDraw) && (state->pen.style() != Qt::NoPen); if (doStroke) { qreal penWidth = state->pen.widthF(); if (penWidth == 0) { strokeOffsetX = 1; strokeOffsetY = 1; } else { // In case of complex xform if (state->txop > QTransform::TxScale) { QPainterPathStroker stroker; stroker.setWidth(penWidth); stroker.setJoinStyle(state->pen.joinStyle()); stroker.setCapStyle(state->pen.capStyle()); QPainterPath stroke = stroker.createStroke(originalPath); strokeBounds = (stroke * state->matrix).boundingRect(); } else { strokeOffsetX = qAbs(penWidth * state->matrix.m11() / 2.0); strokeOffsetY = qAbs(penWidth * state->matrix.m22() / 2.0); } } } const qreal ROUND_UP_TRICK = 0.9999; if (!strokeBounds.isEmpty()) { devMinX = int(strokeBounds.left()); devMaxX = int(strokeBounds.right() + ROUND_UP_TRICK); devMinY = int(strokeBounds.top()); devMaxY = int(strokeBounds.bottom() + ROUND_UP_TRICK); } else { devMinX = int(pathBounds.left() - strokeOffsetX); devMaxX = int(pathBounds.right() + strokeOffsetX + ROUND_UP_TRICK); devMinY = int(pathBounds.top() - strokeOffsetY); devMaxY = int(pathBounds.bottom() + strokeOffsetY + ROUND_UP_TRICK); } QRect absPathRect(devMinX, devMinY, devMaxX - devMinX, devMaxY - devMinY); if (state->clipInfo.size() != 0) { QPainterPath clipPath = q->clipPath() * q->deviceTransform(); QRectF r = clipPath.boundingRect().intersected(absPathRect); absPathRect.setCoords(qFloor(r.left()), qFloor(r.top()), qCeil(r.right()), qCeil(r.bottom())); } absPathRect = absPathRect.intersected(QRect(0, 0, device->width(), device->height()));// qDebug("\nQPainterPrivate::draw_helper(), x=%d, y=%d, w=%d, h=%d",// devMinX, devMinY, device->width(), device->height());// qDebug() << " - matrix" << state->matrix;// qDebug() << " - originalPath.bounds" << originalPath.boundingRect();// qDebug() << " - path.bounds" << path.boundingRect(); if (absPathRect.width() <= 0 || absPathRect.height() <= 0) return; QImage image(absPathRect.width(), absPathRect.height(), QImage::Format_ARGB32_Premultiplied); image.fill(0); QPainter p(&image); p.d_ptr->original_device = original_device; p.setOpacity(state->opacity); p.translate(-absPathRect.x(), -absPathRect.y()); p.setTransform(state->matrix, true); p.setPen(doStroke ? state->pen : QPen(Qt::NoPen)); p.setBrush((op & FillDraw) ? state->brush : QBrush(Qt::NoBrush)); p.setBackground(state->bgBrush); p.setBackgroundMode(state->bgMode); p.setBrushOrigin(state->bgOrigin); p.setRenderHint(QPainter::Antialiasing, state->renderHints & QPainter::Antialiasing); p.setRenderHint(QPainter::SmoothPixmapTransform, state->renderHints & QPainter::SmoothPixmapTransform); p.drawPath(originalPath); p.end(); q->save(); q->resetMatrix(); updateState(state); engine->drawImage(absPathRect, image, QRectF(0, 0, absPathRect.width(), absPathRect.height()), Qt::OrderedDither | Qt::OrderedAlphaDither); q->restore();}void QPainterPrivate::drawOpaqueBackground(const QPainterPath &path, DrawOperation op){ Q_Q(QPainter); q->setBackgroundMode(Qt::TransparentMode); if (op & FillDraw && state->brush.style() != Qt::NoBrush) { q->fillPath(path, state->bgBrush.color()); q->fillPath(path, state->brush); } if (op & StrokeDraw && state->pen.style() != Qt::NoPen) { q->strokePath(path, QPen(state->bgBrush.color(), state->pen.width())); q->strokePath(path, state->pen); } q->setBackgroundMode(Qt::OpaqueMode);}void QPainterPrivate::drawStretchToDevice(const QPainterPath &path, DrawOperation op){ Q_Q(QPainter); double sw = original_device->width(); double sh = original_device->height(); QTransform inv(1.0/sw, 0, 0, 1.0/sh, 0, 0); QPen pen = state->pen; QBrush brush = state->brush; if ((op & FillDraw) && brush.style() == Qt::NoBrush) op = DrawOperation(op - FillDraw); if ((op & StrokeDraw) && pen.style() == Qt::NoPen) op = DrawOperation(op - StrokeDraw); q->scale(sw, sh); q->setPen(Qt::NoPen); updateState(state); // Draw the xformed fill if the brush is a stretch gradient. if ((op & FillDraw) && check_gradient(brush)) { engine->drawPath(path * inv); op = DrawOperation(op - FillDraw); } // Draw the xformed outline if the pen is a stretch gradient. if ((op & StrokeDraw) && check_gradient(pen.brush())) { q->setBrush(pen.brush()); updateState(state); QPainterPathStroker stroker; stroker.setDashPattern(pen.style()); stroker.setWidth(pen.widthF()); stroker.setJoinStyle(pen.joinStyle()); stroker.setCapStyle(pen.capStyle()); stroker.setMiterLimit(pen.miterLimit()); QPainterPath stroke = stroker.createStroke(path); engine->drawPath(stroke * inv); op = DrawOperation(op - StrokeDraw); } q->scale(1/sw, 1/sh); if (op & FillDraw) { updateState(state); engine->drawPath(path); } q->setPen(pen); if (op & StrokeDraw) { q->setBrush(Qt::NoBrush); updateState(state); engine->drawPath(path); q->setBrush(brush); }}void QPainterPrivate::init(){ Q_Q(QPainter); state->painter = q;}void QPainterPrivate::updateMatrix(){ state->matrix = (state->WxF ? state->worldMatrix : QTransform()) * (state->VxF ? viewTransform() : QTransform()); txinv = false; // no inverted matrix state->txop = static_cast<int>(state->matrix.type()); if (!redirection_offset.isNull()) { state->txop |= QTransform::TxTranslate; // We want to translate in dev space so we do the adding of the redirection // offset manually. if (state->matrix.isAffine()) { state->matrix = QTransform(state->matrix.m11(), state->matrix.m12(), state->matrix.m21(), state->matrix.m22(), state->matrix.dx()-redirection_offset.x(), state->matrix.dy()-redirection_offset.y()); } else { QTransform temp; temp.translate(-redirection_offset.x(), -redirection_offset.y()); state->matrix *= temp; } } state->dirtyFlags |= QPaintEngine::DirtyTransform;// printf("VxF=%d, WxF=%d\n", state->VxF, state->WxF);// qDebug() << " --- using matrix" << state->matrix << redirection_offset;}/*! \internal */void QPainterPrivate::updateInvMatrix(){ Q_ASSERT(txinv == false); txinv = true; // creating inverted matrix bool invertible; QTransform m; if (state->VxF) { m.translate(state->vx, state->vy); m.scale(1.0*state->vw/state->ww, 1.0*state->vh/state->wh); m.translate(-state->wx, -state->wy); } if (state->WxF) { if (state->VxF) m = state->worldMatrix * m; else m = state->worldMatrix; } invMatrix = m.inverted(&invertible); // invert matrix}void QPainterPrivate::updateEmulationSpecifier(QPainterState *s){ bool alpha = false; bool linearGradient = false; bool radialGradient = false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -