1
#define QT_FT_BEGIN_HEADER
2
#define QT_FT_END_HEADER
3
#include <private/qrasterdefs_p.h>
4
#include <private/qgrayraster_p.h>
5
#include <private/qblackraster_p.h>
7
#include <qpainterpath.h>
13
#include <private/qmath_p.h>
15
#include <private/qdatabuffer_p.h>
16
#include <private/qpainter_p.h>
17
#include <private/qtextengine_p.h>
18
#include <private/qpixmap_p.h>
19
#include <private/qfontengine_p.h>
21
#include "qpaintengine_raster_p.h"
25
# include <qx11info_x11.h>
26
# include <X11/Xlib.h>
27
# include <X11/Xutil.h>
28
#elif defined(Q_WS_WIN)
29
# include <qt_windows.h>
30
# include <qvarlengtharray.h>
31
# include <private/qfontengine_p.h>
32
#elif defined(Q_WS_MAC)
33
# include <private/qt_mac_p.h>
36
#if defined(Q_WS_WIN64)
41
Used to prevent division by zero in LinearGradientData::init.
42
This number does not have to be the smallest possible positive qreal.
43
The size of the result of QPaintDevice::width() is more interesting, since the error
44
is accumulated for each pixel in the interpolation. Thus, interpolating over a large number of pixels
45
will make the error larger.
47
#define GRADIENT_EPSILON 0.000000001
49
#define qreal_to_fixed_26_6(f) (int(f * 64))
50
#define qt_swap_int(x, y) { int tmp = (x); (x) = (y); (y) = tmp; }
51
#define qt_swap_qreal(x, y) { qreal tmp = (x); (x) = (y); (y) = tmp; }
53
static QT_FT_Raster qt_gray_raster;
54
static QT_FT_Raster qt_black_raster;
56
static void qt_initialize_ft()
58
// printf("qt_initialize_ft()\n");
61
// The antialiasing raster.
62
error = qt_ft_grays_raster.raster_new(0, &qt_gray_raster);
64
qWarning("failed to initlize qt_ft_grays_raster");
68
unsigned long poolSize = 128 * 128;
70
#if defined(Q_WS_WIN64)
71
unsigned char *poolBase = (unsigned char *) _aligned_malloc(poolSize, __alignof(void*));
73
unsigned char *poolBase = (unsigned char *) malloc(poolSize);
76
qt_ft_grays_raster.raster_reset(qt_gray_raster, poolBase, poolSize);
78
// Initialize the standard raster.
79
error = qt_ft_standard_raster.raster_new(0, &qt_black_raster);
81
qWarning("Failed to initialize standard raster: code=%d\n", error);
84
qt_ft_standard_raster.raster_reset(qt_black_raster, poolBase, poolSize);
88
void qt_draw_text_item(const QPointF &point, const QTextItemInt &ti, HDC hdc,
89
QRasterPaintEnginePrivate *d);
92
// #define QT_DEBUG_DRAW
93
// #define QT_DEBUG_CONVERT
95
/********************************************************************************
98
typedef void (*qt_span_func)(int y, int count, QT_FT_Span *spans, void *userData);
100
void qt_span_fill_clipped(int y, int count, QT_FT_Span *spans, void *userData);
101
void qt_span_solidfill(int y, int count, QT_FT_Span *spans, void *userData);
102
void qt_span_texturefill(int y, int count, QT_FT_Span *spans, void *userData);
103
void qt_span_texturefill_xform(int y, int count, QT_FT_Span *spans, void *userData);
104
void qt_span_linear_gradient(int y, int count, QT_FT_Span *spans, void *userData);
105
void qt_span_radial_gradient(int y, int count, QT_FT_Span *spans, void *userData);
106
void qt_span_conical_gradient(int y, int count, QT_FT_Span *spans, void *userData);
107
void qt_span_clip(int y, int count, QT_FT_Span *spans, void *userData);
111
QRasterBuffer *rasterBuffer;
113
BlendColor blendColor;
114
QPainter::CompositionMode compositionMode;
117
struct TextureFillData
119
QRasterBuffer *rasterBuffer;
120
const void *imageData;
123
qreal m11, m12, m21, m22, dx, dy; // inverse xform matrix
126
BlendTransformed blendFunc;
128
QPainter::CompositionMode compositionMode;
130
void init(QRasterBuffer *rasterBuffer, const QImage *image, const QMatrix &matrix,
131
Blend b, BlendTransformed func);
136
QRasterBuffer *rasterBuffer;
137
qt_span_func callback;
143
QRasterBuffer *rasterBuffer;
144
Qt::ClipOperation operation;
148
void qt_scanconvert(QT_FT_Outline *outline, qt_span_func callback, void *userData, QT_FT_BBox *bounds, QRasterPaintEnginePrivate *d);
154
LineDrawIncludeLastPixel
157
static void drawLine_midpoint_f(const QLineF &line, qt_span_func span_func, void *data,
158
LineDrawMode style, const QRect &devRect);
159
// static void drawLine_midpoint_i(const QLine &line, qt_span_func span_func, void *data,
160
// LineDrawMode style, const QRect &devRect);
163
/********************************************************************************
164
* class QFTOutlineMapper
166
* Used to map between QPainterPath and the QT_FT_Outline structure used by the
167
* freetype scanconvertor.
169
* The outline mapper uses a path iterator to get points from the path,
170
* so that it is possible to transform the points as they are converted. The
171
* callback can be a noop, translate or full-fledged xform. (Tests indicated
172
* that using a C callback was low cost).
174
class QFTOutlineMapper
179
Sets up the matrix to be used for conversion. This also
180
sets up the qt_path_iterator function that is used as a callback
183
void setMatrix(const QMatrix &m, uint /* txop */)
193
inline qreal map_x(qreal x, qreal y) { return m_m11*x + m_m21*y + m_dx; }
195
inline qreal map_y(qreal x, qreal y) { return m_m12*x + m_m22*y + m_dy; }
197
void beginOutline(Qt::FillRule fillRule)
199
#ifdef QT_DEBUG_CONVERT
200
printf("QFTOutlineMapper::beginOutline rule=%d\n", fillRule);
206
m_outline.flags = fillRule == Qt::WindingFill
208
: QT_FT_OUTLINE_EVEN_ODD_FILL;
209
m_subpath_start.x = m_subpath_start.y = 0;
216
m_outline.n_contours = m_contours.size();
217
m_outline.n_points = m_points.size();
219
m_outline.points = m_points.data();
220
m_outline.tags = m_tags.data();
221
m_outline.contours = m_contours.data();
224
#ifdef QT_DEBUG_CONVERT
225
printf("QFTOutlineMapper::endOutline\n");
227
printf(" - contours: %d\n", m_outline.n_contours);
228
for (int i=0; i<m_outline.n_contours; ++i) {
229
printf(" - %d\n", m_outline.contours[i]);
232
printf(" - points: %d\n", m_outline.n_points);
233
for (int i=0; i<m_outline.n_points; ++i) {
234
printf(" - %d -- %.2f, %.2f, (%d, %d)\n", i,
235
m_outline.points[i].x / 64.0,
236
m_outline.points[i].y / 64.0,
237
m_outline.points[i], m_outline.points[i]);
242
inline void closeSubpath()
244
#ifdef QT_DEBUG_CONVERT
245
printf("QFTOutlineMapper::closeSubpath()\n");
247
int pointCount = m_points.size();
249
#ifdef QT_DEBUG_CONVERT
250
printf(" - implicitly closed\n");
253
QT_FT_Vector last = m_points.at(pointCount-1);
255
// implicitly close last if not already closed.
256
if (m_subpath_start.x != last.x || m_subpath_start.y != last.y) {
257
m_points.add(m_subpath_start);
258
m_tags.add(QT_FT_CURVE_TAG_ON);
261
// for close only (not first point)
262
m_contours.add(m_points.size() - 1);
267
void moveTo(const QPointF &pt)
269
QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(map_x(pt.x(), pt.y())),
270
qreal_to_fixed_26_6(map_y(pt.x(), pt.y())) };
271
#ifdef QT_DEBUG_CONVERT
272
printf("QFTOutlineMapper::moveTo(%.2f, %.2f): subpath started=(%.2f,%.2f)\n",
273
pt_fixed.x / 64.0, pt_fixed.y / 64.0,
274
m_subpath_start.x / 64.0, m_subpath_start.y / 64.0);
277
m_points.add(pt_fixed);
278
m_tags.add(QT_FT_CURVE_TAG_ON);
279
m_subpath_start = pt_fixed;
283
void lineTo(const QPointF &pt)
285
QT_FT_Vector pt_fixed = { qreal_to_fixed_26_6(map_x(pt.x(), pt.y())),
286
qreal_to_fixed_26_6(map_y(pt.x(), pt.y())) };
287
#ifdef QT_DEBUG_CONVERT
288
printf("QFTOutlineMapper::lineTo(%.2f, %.2f)\n",
289
pt_fixed.x / 64.0, pt_fixed.y / 64.0);
291
m_points.add(pt_fixed);
292
m_tags.add(QT_FT_CURVE_TAG_ON);
296
void curveTo(const QPointF &cp1, const QPointF &cp2, const QPointF &ep)
298
QT_FT_Vector cp1_fixed = { qreal_to_fixed_26_6(map_x(cp1.x(), cp1.y())),
299
qreal_to_fixed_26_6(map_y(cp1.x(), cp1.y())) };
300
QT_FT_Vector cp2_fixed = { qreal_to_fixed_26_6(map_x(cp2.x(), cp2.y())),
301
qreal_to_fixed_26_6(map_y(cp2.x(), cp2.y())) };
302
QT_FT_Vector ep_fixed = { qreal_to_fixed_26_6(map_x(ep.x(), ep.y())),
303
qreal_to_fixed_26_6(map_y(ep.x(), ep.y())) };
305
m_points.add(cp1_fixed);
306
m_points.add(cp2_fixed);
307
m_points.add(ep_fixed);
309
#ifdef QT_DEBUG_CONVERT
310
printf("QFTOutlineMapper::curveTo((%.2f,%.2f) ,(%.2f,%.2f), (%.2f,%.2f))\n",
311
cp1_fixed.x / 64.0, cp1_fixed.y / 64.0,
312
cp2_fixed.x / 64.0, cp2_fixed.y / 64.0,
313
ep_fixed.x / 64.0, ep_fixed.y / 64.0);
316
m_tags.add(QT_FT_CURVE_TAG_CUBIC); // Control point 1
317
m_tags.add(QT_FT_CURVE_TAG_CUBIC); // Control point 2
318
m_tags.add(QT_FT_CURVE_TAG_ON); // End point
323
QT_FT_Outline *convertPath(const QPainterPath &path)
325
Q_ASSERT(!path.isEmpty());
327
int elmCount = path.elementCount();
330
#ifdef QT_DEBUG_CONVERT
331
printf("QFTOutlineMapper::convertPath(), size=%d\n", elmCount);
335
beginOutline(path.fillRule());
337
for (int index=0; index<elmCount; ++index) {
338
const QPainterPath::Element &elm = path.elementAt(index);
342
case QPainterPath::MoveToElement:
343
if (index == elmCount - 1)
348
case QPainterPath::LineToElement:
352
case QPainterPath::CurveToElement:
353
curveTo(elm, path.elementAt(index + 1), path.elementAt(index + 2));
358
break; // This will never hit..
367
QDataBuffer<QT_FT_Vector> m_points;
368
QDataBuffer<char> m_tags;
369
QDataBuffer<short> m_contours;
370
QT_FT_Outline m_outline;
372
QT_FT_Vector m_subpath_start;
384
#if !defined(QT_NO_DEBUG) && 0
385
static void qt_debug_path(const QPainterPath &path)
387
const char *names[] = {
394
printf("\nQPainterPath: elementCount=%d\n", path.elementCount());
395
for (int i=0; i<path.elementCount(); ++i) {
396
const QPainterPath::Element &e = path.elementAt(i);
397
Q_ASSERT(e.type >= 0 && e.type <= QPainterPath::CurveToDataElement);
398
printf(" - %3d:: %s, (%.2f, %.2f)\n", i, names[e.type], e.x, e.y);
403
QHash<int, QImage> qt_raster_image_cache;
405
QRasterPaintEngine::QRasterPaintEngine()
406
: QPaintEngine(*(new QRasterPaintEnginePrivate),
407
QPaintEngine::PaintEngineFeatures(AllFeatures)
410
Q_D(QRasterPaintEngine);
412
d->rasterBuffer = new QRasterBuffer();
413
d->fontRasterBuffer = new QRasterBuffer();
414
d->outlineMapper = new QFTOutlineMapper;
415
if (!qt_gray_raster || !qt_black_raster) {
419
d->fillData = new FillData;
420
d->solidFillData = new SolidFillData;
421
d->textureFillData = new TextureFillData;
422
d->linearGradientData = new LinearGradientData;
423
d->radialGradientData = new RadialGradientData;
424
d->conicalGradientData = new ConicalGradientData;
426
d->flushOnEnd = true;
429
QRasterPaintEngine::~QRasterPaintEngine()
431
Q_D(QRasterPaintEngine);
433
delete d->rasterBuffer;
434
delete d->outlineMapper;
435
delete d->fontRasterBuffer;
438
delete d->solidFillData;
439
delete d->textureFillData;
440
delete d->linearGradientData;
441
delete d->radialGradientData;
442
delete d->conicalGradientData;
446
bool QRasterPaintEngine::begin(QPaintDevice *device)
448
Q_D(QRasterPaintEngine);
450
qInitDrawhelperAsm();
451
d->deviceDepth = device->depth();
452
d->clipEnabled = false;
453
d->antialiased = false;
455
d->opaqueBackground = false;
456
d->bgBrush = Qt::white;
457
d->mono_surface = false;
458
d->compositionMode = QPainter::CompositionMode_SourceOver;
460
d->deviceRect = QRect(0, 0, device->width(), device->height());
462
DrawHelper::Layout layout = DrawHelper::Layout_RGB32;
464
gccaps &= ~PorterDuff;
466
// reset paintevent clip
467
d->baseClip = QPainterPath();
468
if (device->devType() == QInternal::Widget) {
469
QRegion sysClip = systemClip();
470
if (!sysClip.isEmpty()) {
471
d->baseClip.addRegion(sysClip);
472
d->deviceRect = sysClip.boundingRect();
473
// Shift the baseclip to absolute
474
d->baseClip = d->baseClip * QMatrix(1, 0, 0, 1,
479
#if defined(Q_WS_QWS)
480
else if (device->devType() == QInternal::Pixmap) {
481
// Only embedded uses system clipping on pixmaps
482
QRegion sysClip = systemClip();
483
if (!sysClip.isEmpty())
484
d->baseClip.addRegion(sysClip);
488
bool isBitmap = false;
489
#if defined(Q_WS_WIN) || defined(Q_WS_QWS)
490
if (device->devType() == QInternal::Pixmap) {
491
QPixmap *pixmap = static_cast<QPixmap *>(device);
492
if (pixmap->isNull()) {
493
qWarning("Cannot paint on a null pixmap");
496
QPixmapData *data = static_cast<QPixmap *>(device)->data;
497
device = &data->image;
498
isBitmap = pixmap->depth() == 1;
502
if (device->devType() == QInternal::Image) {
503
QImage *image = static_cast<QImage *>(device);
504
int format = image->format();
505
d->flushOnEnd = (format != QImage::Format_ARGB32_Premultiplied
506
&& format != QImage::Format_RGB32
509
d->rasterBuffer->prepare(image);
511
if (format == QImage::Format_MonoLSB && isBitmap) {
512
d->mono_surface = true;
513
layout = DrawHelper::Layout_MonoLSB;
514
} else if (format == QImage::Format_RGB32) {
515
layout = DrawHelper::Layout_RGB32;
516
} else if (format == QImage::Format_ARGB32_Premultiplied) {
517
layout = DrawHelper::Layout_ARGB;
518
gccaps |= PorterDuff;
520
qWarning("QRasterPaintEngine::begin(), unsupported image format (%d)\n"
521
"Supported image formats: Format_RGB32 and Format_ARGB32_Premultiplied",
526
d->rasterBuffer->prepare(d->deviceRect.width(), d->deviceRect.height());
529
d->rasterBuffer->resetClip();
531
d->drawHelper = qDrawHelper + layout;
533
d->matrix = QMatrix();
534
d->txop = QPainterPrivate::TxNone;
535
d->outlineMapper->setMatrix(d->matrix, d->txop);
537
if (device->depth() == 1) {
538
d->pen = QPen(Qt::color1);
539
d->brush = QBrush(Qt::color0);
541
d->pen = QPen(Qt::black);
542
d->brush = QBrush(Qt::NoBrush);
545
updateClipPath(QPainterPath(), Qt::NoClip);
552
bool QRasterPaintEngine::end()
554
Q_D(QRasterPaintEngine);
557
flush(d->pdev, QPoint());
559
d->clipEnabled = false;
567
void QRasterPaintEngine::setFlushOnEnd(bool flushOnEnd)
569
Q_D(QRasterPaintEngine);
571
d->flushOnEnd = flushOnEnd;
576
Force the contents of the buffer out on the underlying device.
578
void QRasterPaintEngine::flush(QPaintDevice *device, const QPoint &offset)
580
Q_D(QRasterPaintEngine);
583
#if defined(Q_WS_WIN)
584
if (device->devType() == QInternal::Widget) {
585
HDC hdc = device->getDC();
588
QRegion sysClip = systemClip();
589
if (sysClip.isEmpty()) {
590
BitBlt(hdc, d->deviceRect.x() + offset.x(), d->deviceRect.y() + offset.y(),
591
d->deviceRect.width(), d->deviceRect.height(),
592
d->rasterBuffer->hdc(), 0, 0, SRCCOPY);
594
QVector<QRect> rects = sysClip.rects();
595
for (int i=0; i<rects.size(); ++i) {
596
QRect r = rects.at(i);
598
r.x() + offset.x(), r.y() + offset.y(), r.width(), r.height(),
599
d->rasterBuffer->hdc(), r.x() - d->deviceRect.x(), r.y() - d->deviceRect.y(),
603
device->releaseDC(hdc);
609
if (device->devType() == QInternal::Pixmap) {
610
target = &static_cast<QPixmap *>(device)->data->image;
611
} else if (device->devType() == QInternal::Image) {
612
target = static_cast<QImage *>(device);
616
Q_ASSERT(target->format() != QImage::Format_RGB32 &&
617
target->format() != QImage::Format_ARGB32_Premultiplied);
619
switch (target->format()) {
621
case QImage::Format_ARGB32:
622
d->rasterBuffer->flushToARGBImage(target);
626
qWarning("QRasterPaintEngine::flush(), unhandled case: %d", target->format());
631
#elif defined(Q_WS_MAC)
632
# ifdef QMAC_NO_COREGRAPHICS
633
# warning "unhandled"
635
extern CGContextRef qt_macCreateCGHandle(const QPaintDevice *); //qpaintdevice_mac.cpp
636
extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
638
if(CGContextRef ctx = qt_mac_cg_context(device)) {
639
CGRect rect = CGRectMake(d->deviceRect.x(), d->deviceRect.y(),
640
d->deviceRect.width(), d->deviceRect.height());
641
HIViewDrawCGImage(ctx, &rect, d->rasterBuffer->m_data); //top left
642
CGContextRelease(ctx);
653
void QRasterPaintEngine::updateState(const QPaintEngineState &state)
655
Q_D(QRasterPaintEngine);
657
QPaintEngine::DirtyFlags flags = state.state();
659
if (flags & DirtyTransform) {
660
d->matrix = state.matrix();
661
if (d->matrix.m12() != 0 || d->matrix.m21() != 0)
662
d->txop = QPainterPrivate::TxRotShear;
663
else if (d->matrix.m11() != 1 || d->matrix.m22() != 1)
664
d->txop = QPainterPrivate::TxScale;
665
else if (d->matrix.dx() != 0 || d->matrix.dy() != 0)
666
d->txop = QPainterPrivate::TxTranslate;
668
d->txop = QPainterPrivate::TxNone;
669
d->outlineMapper->setMatrix(d->matrix, d->txop);
672
if (flags & DirtyPen) {
673
d->pen = state.pen();
676
if ((flags & DirtyBrush) || (flags & DirtyBrushOrigin)) {
677
QBrush brush = state.brush();
678
QPointF offset = state.brushOrigin();
680
d->brushOffset = offset;
683
if (flags & DirtyBackgroundMode) {
684
d->opaqueBackground = (state.backgroundMode() == Qt::OpaqueMode);
687
if (flags & DirtyBackground) {
688
d->bgBrush = state.backgroundBrush();
691
if (flags & DirtyClipPath) {
692
updateClipPath(state.clipPath(), state.clipOperation());
695
if (flags & DirtyClipRegion) {
696
updateClipRegion(state.clipRegion(), state.clipOperation());
699
if (!d->mono_surface) {
700
if (flags & DirtyHints) {
701
d->antialiased = bool(state.renderHints() & QPainter::Antialiasing);
702
d->bilinear = bool(state.renderHints() & QPainter::SmoothPixmapTransform);
705
if (flags & DirtyCompositionMode) {
706
d->compositionMode = state.compositionMode();
712
void QRasterPaintEngine::updateClipRegion(const QRegion &r, Qt::ClipOperation op)
715
qDebug() << " - QRasterPaintEngine::updateClipRegion() op=" << op << r;
719
updateClipPath(p, op);
723
void QRasterPaintEngine::updateClipPath(const QPainterPath &path, Qt::ClipOperation op)
725
Q_D(QRasterPaintEngine);
727
qDebug() << " - QRasterPaintEngine::updateClipPath(), op="
729
<< path.boundingRect();
731
d->updateClip_helper(path, op);
733
// Reset if baseClip if the operation it.
734
if (!d->baseClip.isEmpty()) {
737
case Qt::ReplaceClip:
739
d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
740
d->updateClip_helper(d->baseClip, Qt::IntersectClip);
741
d->outlineMapper->setMatrix(d->matrix, d->txop);
750
QImage qt_map_to_32bit(const QPixmap &pixmap)
752
QImage image = pixmap.toImage();
753
return image.convertToFormat(image.hasAlphaChannel()
754
? QImage::Format_ARGB32_Premultiplied
755
: QImage::Format_RGB32);
758
void QRasterPaintEngine::fillPath(const QPainterPath &path, FillData *fillData)
761
qDebug() << " --- fillPath, bounds=" << path.boundingRect();
764
if (!fillData->callback)
767
Q_D(QRasterPaintEngine);
769
QT_FT_BBox clipBox = { 0, 0, d->deviceRect.width(), d->deviceRect.height() };
771
Q_ASSERT(d->deviceRect.width() <= d->rasterBuffer->width());
772
Q_ASSERT(d->deviceRect.height() <= d->rasterBuffer->height());
774
qt_scanconvert(d->outlineMapper->convertPath(path), fillData->callback, fillData->data, &clipBox, d);
778
void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
781
qDebug(" - QRasterPaintEngine::drawRect(), x=%.2f, y=%.2f, width=%.2f, height=%.2f",
782
r.x(), r.y(), r.width(), r.height());
784
Q_D(QRasterPaintEngine);
786
&& d->txop <= QPainterPrivate::TxTranslate) {
788
bool hasPen = d->pen.style() != Qt::NoPen;
789
qreal offset_x = d->matrix.dx();
790
qreal offset_y = d->matrix.dy();
792
QBrush oldBrush = d->brush;
795
for (int i=0; i<rectCount; ++i) {
796
QRectF rect = rects[i].normalized();
797
rect.translate(offset_x, offset_y);
799
FillData fillData = d->fillForBrush(oldBrush);
800
int x1 = qMax(qRound(rect.x()), 0);
801
int x2 = qMin(qRound(rect.width() + rect.x()), d->rasterBuffer->width());
802
int y1 = qMax(qRound(rect.y()), 0);
803
int y2 = qMin(qRound(rect.height() + rect.y()), d->rasterBuffer->height());;
807
if (fillData.callback && len > 0) {
814
for (int y=y1; y<y2; ++y) {
815
fillData.callback(y, 1, &span, fillData.data);
820
QPaintEngine::drawRects(&rects[i], 1);
825
QPaintEngine::drawRects(rects, rectCount);
829
void QRasterPaintEngine::drawPath(const QPainterPath &path)
832
QRectF bounds = path.boundingRect();
833
printf(" - QRasterPaintEngine::drawPath(), [%.2f, %.2f, %.2f, %.2f]\n",
834
bounds.x(), bounds.y(), bounds.width(), bounds.height());
839
Q_D(QRasterPaintEngine);
841
if (d->brush.style() != Qt::NoBrush) {
842
d->outlineMapper->setMatrix(d->matrix, d->txop);
843
FillData fillData = d->fillForBrush(d->brush);
844
fillPath(path, &fillData);
847
if (d->pen.style() != Qt::NoPen) {
848
QPainterPathStroker stroker;
849
stroker.setDashPattern(d->pen.style());
850
stroker.setCapStyle(d->pen.capStyle());
851
stroker.setJoinStyle(d->pen.joinStyle());
854
qreal width = d->pen.widthF();
857
d->outlineMapper->setMatrix(QMatrix(), QPainterPrivate::TxNone);
858
stroke = stroker.createStroke(path * d->matrix);
859
if (stroke.isEmpty())
862
stroker.setWidth(width);
863
stroker.setCurveThreshold(1 / (10 * d->matrix.m11() * d->matrix.m22()));
864
stroke = stroker.createStroke(path);
865
d->outlineMapper->setMatrix(d->matrix, d->txop);
866
if (stroke.isEmpty())
869
FillData fillData = d->fillForBrush(QBrush(d->pen.brush()));
870
fillPath(stroke, &fillData);
873
d->outlineMapper->setMatrix(d->matrix, d->txop);
877
void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
879
Q_D(QRasterPaintEngine);
880
QBrush oldBrush = d->brush;
881
QPainterPath path(points[0]);
882
for (int i=1; i<pointCount; ++i)
883
path.lineTo(points[i]);
884
if (mode == PolylineMode) {
887
path.setFillRule(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
895
void QRasterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, const QRectF &sr)
898
qDebug() << " - QRasterPaintEngine::drawPixmap(), r=" << r << " sr=" << sr << " pixmap=" << pixmap.size() << "depth=" << pixmap.depth();
901
Q_D(QRasterPaintEngine);
904
if (pixmap.depth() == 1) {
905
if (d->txop <= QPainterPrivate::TxTranslate
906
&& !d->opaqueBackground
907
&& r.size() == sr.size()
908
&& r.size() == pixmap.size()) {
909
FillData fill = d->fillForBrush(QBrush(d->pen.color()));
910
d->drawBitmap(r.topLeft() + QPointF(d->matrix.dx(), d->matrix.dy()), pixmap, &fill);
913
image = d->colorizeBitmap(pixmap.toImage(), d->pen.color());
916
image = qt_map_to_32bit(pixmap);
918
drawImage(r, image, sr);
921
void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
922
Qt::ImageConversionFlags)
925
qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
928
const QImage image = img.format() == QImage::Format_RGB32
930
: img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
932
Q_D(QRasterPaintEngine);
933
TextureFillData textureData = {
935
image.bits(), image.width(), image.height(), image.format() != QImage::Format_RGB32,
936
0., 0., 0., 0., 0., 0.,
937
d->drawHelper->blend,
938
d->bilinear ? d->drawHelper->blendTransformedBilinear : d->drawHelper->blendTransformed,
941
FillData fillData = { d->rasterBuffer, 0, &textureData };
943
bool stretch_sr = r.width() != sr.width() || r.height() != sr.height();
945
if (d->txop > QPainterPrivate::TxTranslate || stretch_sr) {
946
fillData.callback = qt_span_texturefill_xform;
947
QMatrix copy = d->matrix;
948
copy.translate(r.x(), r.y());
950
copy.scale(r.width() / sr.width(), r.height() / sr.height());
951
copy.translate(-sr.x(), -sr.y());
952
QMatrix inv = copy.inverted();
953
textureData.m11 = inv.m11();
954
textureData.m12 = inv.m12();
955
textureData.m21 = inv.m21();
956
textureData.m22 = inv.m22();
957
textureData.dx = inv.dx();
958
textureData.dy = inv.dy();
960
fillData.callback = qt_span_texturefill;
961
textureData.dx = -(r.x() + d->matrix.dx()) + sr.x();
962
textureData.dy = -(r.y() + d->matrix.dy()) + sr.y();
968
FillData clippedFill = d->clipForFill(&fillData);
970
bool wasAntialiased = d->antialiased;
971
d->antialiased = d->bilinear;
973
fillPath(path, &clippedFill);
975
d->antialiased = wasAntialiased;
978
void QRasterPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &sr)
981
qDebug() << " - QRasterPaintEngine::drawTiledPixmap(), r=" << r << "pixmap=" << pixmap.size();
983
Q_D(QRasterPaintEngine);
989
if (pixmap.depth() == 1)
990
image = d->colorizeBitmap(pixmap.toImage(), d->pen.color());
992
image = qt_map_to_32bit(pixmap);
994
TextureFillData textureData = {
996
((const QImage &)(image)).bits(), image.width(), image.height(), image.format() != QImage::Format_RGB32,
997
0., 0., 0., 0., 0., 0.,
998
d->drawHelper->blendTiled,
999
d->bilinear ? d->drawHelper->blendTransformedBilinearTiled : d->drawHelper->blendTransformedTiled,
1002
FillData fillData = { d->rasterBuffer, 0, &textureData };
1004
if (d->txop > QPainterPrivate::TxTranslate) {
1005
fillData.callback = qt_span_texturefill_xform;
1006
QMatrix copy = d->matrix;
1007
copy.translate(r.x(), r.y());
1008
copy.translate(-sr.x(), -sr.y());
1009
QMatrix inv = copy.inverted();
1010
textureData.m11 = inv.m11();
1011
textureData.m12 = inv.m12();
1012
textureData.m21 = inv.m21();
1013
textureData.m22 = inv.m22();
1014
textureData.dx = inv.dx();
1015
textureData.dy = inv.dy();
1017
fillData.callback = qt_span_texturefill;
1018
textureData.dx = -( r.x() + d->matrix.dx()) + sr.x();
1019
textureData.dy = -( r.y() + d->matrix.dy()) + sr.y();
1022
FillData clippedFill = d->clipForFill(&fillData);
1023
fillPath(path, &clippedFill);
1029
static inline uchar monoVal(const uchar* s, int x)
1031
return (s[x>>3] << (x&7)) & 0x80;
1033
void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, bool mono, int rx,int ry,int w,int h)
1035
Q_D(QRasterPaintEngine);
1037
// Decide on which span func to use
1038
FillData fillData = d->fillForBrush(d->pen.brush());
1040
if (!fillData.callback)
1043
int y0 = (ry < 0) ? -ry : 0;
1044
int x0 = (rx < 0) ? -rx : 0;
1046
QRasterBuffer *rb = d->rasterBuffer;
1048
w = qMin(w, rb->width() - rx);
1049
h = qMin(h, rb->height() - ry);
1051
static QDataBuffer<QT_FT_Span> spans;
1053
for (int y=y0; y < h; ++y) {
1054
const uchar *scanline = static_cast<const uchar *>(src) + y*bpl;
1055
// Generate spans for this y coord
1059
for (int x = x0; x < w; ) {
1061
// Skip those with 0 coverage
1062
while (x < w && monoVal(scanline,x) == 0)
1066
int prev = monoVal(scanline,x);
1067
QT_FT_Span span = { x + rx, 0, prev*255 };
1069
// extend span until we find a different one.
1070
while (x < w && monoVal(scanline,x) == prev)
1072
span.len = x +rx - span.x;
1076
// Call span func for current set of spans.
1077
fillData.callback(y + ry, spans.size(), spans.data(), fillData.data);
1080
for (int x = x0; x < w; ) {
1081
// Skip those with 0 coverage
1082
while (x < w && scanline[x] == 0)
1086
int prev = scanline[x];
1087
QT_FT_Span span = { x + rx, 0, scanline[x] };
1089
// extend span until we find a different one.
1090
while (x < w && scanline[x] == prev)
1092
span.len = x +rx - span.x;
1097
// Call span func for current set of spans.
1098
fillData.callback(y + ry, spans.size(), spans.data(), fillData.data);
1102
void QRasterPaintEngine::qwsFillRect(int x, int y, int w, int h, const QBrush &brush)
1104
Q_D(QRasterPaintEngine);
1105
FillData fillData = d->fillForBrush(brush);
1107
int x2 = qMin(x+w, d->rasterBuffer->width());
1108
int y1 = qMax(y, 0);
1109
int y2 = qMin(y+h, d->rasterBuffer->height());;
1113
if (fillData.callback && len > 0) {
1117
span.coverage = 255;
1120
for (int y=y1; y<y2; ++y) {
1121
fillData.callback(y, 1, &span, fillData.data);
1128
void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
1130
QPaintEngine::drawTextItem(p, textItem);
1133
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1135
#ifdef QT_DEBUG_DRAW
1136
printf(" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
1137
p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
1139
Q_D(QRasterPaintEngine);
1141
switch(ti.fontEngine->type()) {
1142
case QFontEngine::Multi:
1143
d->drawMulti(p, ti);
1145
case QFontEngine::XLFD:
1148
case QFontEngine::Box:
1151
#ifndef QT_NO_FONTCONFIG
1152
case QFontEngine::Freetype: {
1153
bool aa = d->antialiased;
1154
d->antialiased = !d->mono_surface;
1155
QPaintEngine::drawTextItem(p, ti);
1156
d->antialiased = aa;
1165
void QRasterPaintEnginePrivate::drawMulti(const QPointF &p, const QTextItem &textItem)
1167
Q_Q(QRasterPaintEngine);
1168
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1169
QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
1170
QGlyphLayout *glyphs = ti.glyphs;
1171
int which = glyphs[0].glyph >> 24;
1178
for (end = 0; end < ti.num_glyphs; ++end) {
1179
const int e = glyphs[end].glyph >> 24;
1183
// set the high byte to zero
1184
for (i = start; i < end; ++i)
1185
glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
1188
QTextItemInt ti2 = ti;
1189
ti2.glyphs = ti.glyphs + start;
1190
ti2.num_glyphs = end - start;
1191
ti2.fontEngine = multi->engine(which);
1193
q->drawTextItem(QPointF(x, y), ti2);
1195
// reset the high byte for all glyphs and advance to the next sub-string
1196
const int hi = which << 24;
1197
for (i = start; i < end; ++i) {
1198
glyphs[i].glyph = hi | glyphs[i].glyph;
1199
x += glyphs[i].advance.x();
1207
// set the high byte to zero
1208
for (i = start; i < end; ++i)
1209
glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
1212
QTextItemInt ti2 = ti;
1213
ti2.glyphs = ti.glyphs + start;
1214
ti2.num_glyphs = end - start;
1215
ti2.fontEngine = multi->engine(which);
1217
q->drawTextItem(QPointF(x,y), ti2);
1219
// reset the high byte for all glyphs
1220
const int hi = which << 24;
1221
for (i = start; i < end; ++i)
1222
glyphs[i].glyph = hi | glyphs[i].glyph;
1225
void QRasterPaintEnginePrivate::drawXLFD(const QPointF &p, const QTextItem &textItem)
1227
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1229
// xlfd: draw into bitmap, convert to image and rasterize that
1231
// Decide on which span func to use
1232
FillData fillData = fillForBrush(pen.brush());
1233
if (!fillData.callback)
1236
QRectF logRect(p.x(), p.y() - ti.ascent, ti.width, ti.ascent + ti.descent);
1237
QRect devRect = matrix.mapRect(logRect).toRect();
1239
if(devRect.width() == 0 || devRect.height() == 0)
1242
int w = qRound(ti.width);
1243
int h = qRound(ti.ascent + ti.descent + 1);
1246
QPainter painter(&bm);
1247
painter.fillRect(0, 0, w, h, Qt::color0);
1248
painter.setPen(Qt::color1);
1252
item.descent = ti.descent;
1253
item.ascent = ti.ascent;
1254
item.width = ti.width;
1257
item.glyphs = ti.glyphs;
1258
item.num_glyphs = ti.num_glyphs;
1259
item.fontEngine = ti.fontEngine;
1262
painter.drawTextItem(QPointF(0, ti.ascent), item);
1265
drawBitmap(devRect.topLeft(), bm, &fillData);
1268
void QRasterPaintEnginePrivate::drawBox(const QPointF &, const QTextItem &)
1275
void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
1277
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1279
#ifdef QT_DEBUG_DRAW
1280
printf(" - QRasterPaintEngine::drawTextItem(), (%.2f,%.2f), string=%s\n",
1281
p.x(), p.y(), QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
1283
Q_D(QRasterPaintEngine);
1284
#if defined(Q_WS_WIN)
1287
if (d->txop >= QPainterPrivate::TxScale) {
1288
bool antialiased = d->antialiased;
1289
d->antialiased = true;
1290
QPaintEngine::drawTextItem(p, textItem);
1291
d->antialiased = antialiased;
1295
int x_buffering = ti.ascent;
1296
QRectF logRect(p.x(), p.y() - ti.ascent, ti.width + x_buffering, ti.ascent + ti.descent);
1297
QRect devRect = d->matrix.mapRect(logRect).toRect();
1299
if(devRect.width() == 0 || devRect.height() == 0)
1302
d->fontRasterBuffer->prepare(devRect.width(), devRect.height());
1303
d->fontRasterBuffer->resetBuffer(255);
1305
// Fill buffer with stuff
1306
qt_draw_text_item(QPoint(0, ti.ascent), ti, d->fontRasterBuffer->hdc(), d);
1308
// Decide on which span func to use
1309
FillData fillData = d->fillForBrush(d->pen.brush());
1311
if (!fillData.callback)
1315
int ymax = qMin(devRect.y() + devRect.height(), d->rasterBuffer->height());
1316
int ymin = qMax(devRect.y(), 0);
1317
int xmax = qMin(devRect.x() + devRect.width(), d->rasterBuffer->width());
1318
int xmin = qMax(devRect.x(), 0);
1320
static QDataBuffer<QT_FT_Span> spans;
1322
if (d->mono_surface) {
1323
for (int y=ymin; y<ymax; ++y) {
1324
QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
1325
// Generate spans for this y coord
1327
for (int x = xmin; x<xmax; ) {
1328
// Skip those with 0 coverage (black on white so inverted)
1329
while (x < xmax && qGray(scanline[x]) > 0x80) ++x;
1330
if (x >= xmax) break;
1332
QT_FT_Span span = { x, 0, 255 };
1334
// extend span until we find a different one.
1335
while (x < xmax && qGray(scanline[x]) < 0x80) ++x;
1336
span.len = x - span.x;
1341
// Call span func for current set of spans.
1342
fillData.callback(y, spans.size(), spans.data(), fillData.data);
1346
for (int y=ymin; y<ymax; ++y) {
1347
QRgb *scanline = (QRgb *) d->fontRasterBuffer->scanLine(y - devRect.y()) - devRect.x();
1348
// Generate spans for this y coord
1350
for (int x = xmin; x<xmax; ) {
1351
// Skip those with 0 coverage (black on white so inverted)
1352
while (x < xmax && qGray(scanline[x]) == 255) ++x;
1353
if (x >= xmax) break;
1355
int prev = qGray(scanline[x]);
1356
QT_FT_Span span = { x, 0, 255 - prev };
1358
// extend span until we find a different one.
1359
while (x < xmax && qGray(scanline[x]) == prev) ++x;
1360
span.len = x - span.x;
1365
// Call span func for current set of spans.
1366
fillData.callback(y, spans.size(), spans.data(), fillData.data);
1372
#elif defined Q_WS_QWS
1373
bool useFontEngine = true;
1374
QMatrix matrix = d->matrix;
1375
bool simple = matrix.m11() == 1 && matrix.m12() == 0 && matrix.m21() == 0 && matrix.m22() == 1;
1377
useFontEngine = false;
1378
QFontEngine *fe = ti.fontEngine;
1379
QFontEngine::FECaps fecaps = fe->capabilites();
1380
useFontEngine = (fecaps == QFontEngine::FullTransformations);
1382
&& matrix.m11() == matrix.m22()
1383
&& matrix.m12() == -matrix.m21())
1384
useFontEngine = (fecaps & QFontEngine::RotScale) == QFontEngine::RotScale;
1386
if (useFontEngine) {
1387
ti.fontEngine->draw(this, qRound(p.x()), qRound(p.y()), ti);
1392
// Fallthrough for embedded and default for mac.
1393
bool aa = d->antialiased;
1394
d->antialiased = true;
1395
QPaintEngine::drawTextItem(p, ti);
1396
d->antialiased = aa;
1402
void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
1404
Q_D(QRasterPaintEngine);
1406
double pw = d->pen.widthF();
1408
if (d->txop > QPainterPrivate::TxTranslate || pw > 1) {
1409
QBrush oldBrush = d->brush;
1410
d->brush = Qt::NoBrush;
1412
const QPointF *end = points + pointCount;
1413
while (points < end) {
1415
path.moveTo(*points);
1416
path.lineTo(points->x() + 0.001, points->y());
1421
d->brush = oldBrush;
1424
FillData fillData = d->fillForBrush(d->pen.brush());
1425
if (!fillData.callback)
1428
QT_FT_Span span = { 0, 1, 255 };
1429
qreal dx = d->matrix.dx();
1430
qreal dy = d->matrix.dy();
1431
const QPointF *end = points + pointCount;
1434
int right = d->deviceRect.width();
1436
int bottom = d->deviceRect.height();
1437
while (points < end) {
1438
x = qRound(points->x() + dx);
1439
y = qRound(points->y() + dy);
1440
if (x >= left && x < right && y >= top && y < bottom) {
1442
fillData.callback(y, 1, &span, fillData.data);
1449
void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
1451
#ifdef QT_DEBUG_DRAW
1452
qDebug() << " - QRasterPaintEngine::drawLine()";
1455
Q_D(QRasterPaintEngine);
1457
&& d->pen.style() == Qt::SolidLine
1458
&& (d->pen.widthF() == 0
1459
|| (d->pen.widthF() <= 1 && d->txop <= QPainterPrivate::TxTranslate))) {
1461
QRect bounds(0, 0, d->deviceRect.width(), d->deviceRect.height());
1463
for (int i=0; i<lineCount; ++i) {
1464
QLineF line = lines[i] * d->matrix;
1465
LineDrawMode mode = LineDrawNormal;
1467
if (d->pen.capStyle() != Qt::FlatCap)
1468
mode = LineDrawIncludeLastPixel;
1470
FillData fillData = d->fillForBrush(QBrush(d->pen.brush()));
1471
drawLine_midpoint_f(line.toLine(), fillData.callback, fillData.data, mode, bounds);
1476
QPaintEngine::drawLines(lines, lineCount);
1479
void QRasterPaintEngine::drawEllipse(const QRectF &rect)
1481
Q_D(QRasterPaintEngine);
1482
if (!d->antialiased && d->pen.style() == Qt::NoPen && d->txop <= QPainterPrivate::TxTranslate) {
1483
QPen oldPen = d->pen;
1484
d->pen = QPen(d->brush, 0);
1485
QPaintEngine::drawEllipse(rect.adjusted(0, 0, -1, -1));
1488
QPaintEngine::drawEllipse(rect);
1493
HDC QRasterPaintEngine::getDC() const
1495
Q_D(const QRasterPaintEngine);
1496
return d->rasterBuffer->hdc();
1499
void QRasterPaintEngine::releaseDC(HDC) const
1505
QPoint QRasterPaintEngine::coordinateOffset() const
1507
Q_D(const QRasterPaintEngine);
1508
return QPoint(d->deviceRect.x(), d->deviceRect.y());
1511
void QRasterPaintEnginePrivate::drawBitmap(const QPointF &pos, const QPixmap &pm, FillData *fg)
1514
Q_ASSERT(fg->callback);
1516
const QImage image = pm.toImage();
1517
Q_ASSERT(image.depth() == 1);
1519
const int spanCount = 256;
1520
QT_FT_Span spans[spanCount];
1525
int h = pm.height();
1526
int ymax = qMin(qRound(pos.y() + h), rasterBuffer->height());
1527
int ymin = qMax(qRound(pos.y()), 0);
1528
int xmax = qMin(qRound(pos.x() + w), rasterBuffer->width());
1529
int xmin = qMax(qRound(pos.x()), 0);
1531
int x_offset = xmin - qRound(pos.x());
1534
QImage::Format format = image.format();
1536
for (int y = ymin; y < ymax; ++y) {
1537
const uchar *src = image.scanLine(y - qRound(pos.y()));
1539
if (format == QImage::Format_MonoLSB) {
1541
for (int x = 0; x < xmax - xmin; ++x) {
1542
int src_x = x + x_offset;
1543
uchar pixel = src[src_x >> 3];
1548
if (pixel & (0x1 << (src_x & 7))) {
1549
QT_FT_Span span = { xmin + x, 1, 255 };
1550
while (src_x < w-1 && src[(src_x+1) >> 3] & (0x1 << ((src_x+1) & 7))) {
1558
if (n == spanCount) {
1559
fg->callback(y, n, spans, fg->data);
1565
for (int x = 0; x < xmax - xmin; ++x) {
1566
bool set = src[x >> 3] & (0x80 >> (x & 7));
1568
QT_FT_Span span = { xmin + x, 1, 255 };
1569
while (x < w-1 && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7))) {
1577
if (n == spanCount) {
1578
fg->callback(y, n, spans, fg->data);
1585
fg->callback(y, n, spans, fg->data);
1591
/* Sets up potential clipping for this FillData object.
1592
* Note that the data object must be valid throughout the lifetime of
1595
FillData QRasterPaintEnginePrivate::clipForFill(FillData *data)
1597
if (clipEnabled && data->callback) {
1598
FillData clipFillData = {
1600
qt_span_fill_clipped,
1603
return clipFillData;
1610
FillData QRasterPaintEnginePrivate::fillForBrush(const QBrush &brush)
1614
fillData->rasterBuffer = rasterBuffer;
1615
fillData->callback = 0;
1618
switch (brush.style()) {
1623
case Qt::SolidPattern:
1624
fillData->callback = qt_span_solidfill;
1625
fillData->data = solidFillData;
1626
solidFillData->color = PREMUL(brush.color().rgba());
1627
solidFillData->rasterBuffer = fillData->rasterBuffer;
1628
solidFillData->blendColor = drawHelper->blendColor;
1629
solidFillData->compositionMode = compositionMode;
1632
case Qt::TexturePattern:
1634
QPixmap texture = brush.texture();
1635
if (texture.depth() == 1) {
1636
tempImage = colorizeBitmap(texture.toImage(), brush.color());
1638
tempImage = qt_map_to_32bit(brush.texture());
1640
fillData->data = textureFillData;
1641
fillData->callback = txop > QPainterPrivate::TxTranslate
1642
? qt_span_texturefill_xform
1643
: qt_span_texturefill;
1644
textureFillData->compositionMode = compositionMode;
1645
textureFillData->init(rasterBuffer, &tempImage, brushMatrix(),
1646
drawHelper->blendTiled,
1648
? drawHelper->blendTransformedBilinearTiled
1649
: drawHelper->blendTransformedTiled);
1653
case Qt::LinearGradientPattern:
1655
linearGradientData->rasterBuffer = fillData->rasterBuffer;
1656
linearGradientData->spread = brush.gradient()->spread();
1657
linearGradientData->stopCount = brush.gradient()->stops().size();
1658
linearGradientData->stopPoints = gradientStopPoints(brush.gradient());
1659
linearGradientData->stopColors = gradientStopColors(brush.gradient());
1660
const QLinearGradient *lg = static_cast<const QLinearGradient *>(brush.gradient());
1661
linearGradientData->origin = lg->start();
1662
linearGradientData->end = lg->finalStop();
1664
linearGradientData->brushMatrix = brushMatrix();
1665
linearGradientData->alphaColor = !brush.isOpaque();
1666
linearGradientData->init();
1667
linearGradientData->initColorTable();
1668
linearGradientData->blendFunc = drawHelper->blendLinearGradient;
1669
linearGradientData->compositionMode = compositionMode;
1670
fillData->callback = qt_span_linear_gradient;
1671
fillData->data = linearGradientData;
1675
case Qt::RadialGradientPattern:
1677
radialGradientData->rasterBuffer = fillData->rasterBuffer;
1678
radialGradientData->spread = brush.gradient()->spread();
1679
radialGradientData->stopCount = brush.gradient()->stops().size();
1680
radialGradientData->stopPoints = gradientStopPoints(brush.gradient());
1681
radialGradientData->stopColors = gradientStopColors(brush.gradient());
1682
radialGradientData->center =
1683
static_cast<const QRadialGradient *>(brush.gradient())->center();
1684
radialGradientData->radius =
1685
static_cast<const QRadialGradient *>(brush.gradient())->radius();
1686
radialGradientData->focal =
1687
static_cast<const QRadialGradient *>(brush.gradient())->focalPoint();
1688
radialGradientData->alphaColor = !brush.isOpaque();
1689
radialGradientData->initColorTable();
1690
radialGradientData->imatrix = brushMatrix().inverted();
1691
radialGradientData->blendFunc = drawHelper->blendRadialGradient;
1692
radialGradientData->compositionMode = compositionMode;
1694
fillData->data = radialGradientData;
1695
fillData->callback = qt_span_radial_gradient;
1699
case Qt::ConicalGradientPattern:
1701
conicalGradientData->rasterBuffer = fillData->rasterBuffer;
1702
conicalGradientData->spread = QGradient::RepeatSpread; // don't support any anyway
1703
conicalGradientData->stopCount = brush.gradient()->stops().size();
1704
conicalGradientData->stopPoints = gradientStopPoints(brush.gradient());
1705
conicalGradientData->stopColors = gradientStopColors(brush.gradient());
1706
conicalGradientData->alphaColor = !brush.isOpaque();
1707
conicalGradientData->compositionMode = compositionMode;
1708
conicalGradientData->blendFunc = drawHelper->blendConicalGradient;
1709
const QConicalGradient *cg = static_cast<const QConicalGradient *>(brush.gradient());
1710
conicalGradientData->init(cg->center(), cg->angle(), brushMatrix());
1711
fillData->data = conicalGradientData;
1712
fillData->callback = qt_span_conical_gradient;
1716
case Qt::Dense1Pattern:
1717
case Qt::Dense2Pattern:
1718
case Qt::Dense3Pattern:
1719
case Qt::Dense4Pattern:
1720
case Qt::Dense5Pattern:
1721
case Qt::Dense6Pattern:
1722
case Qt::Dense7Pattern:
1723
case Qt::HorPattern:
1724
case Qt::VerPattern:
1725
case Qt::CrossPattern:
1726
case Qt::BDiagPattern:
1727
case Qt::FDiagPattern:
1728
case Qt::DiagCrossPattern:
1730
extern QPixmap qt_pixmapForBrush(int brushStyle, bool invert);
1731
QPixmap pixmap = qt_pixmapForBrush(brush.style(), true);
1733
Q_ASSERT(!pixmap.isNull());
1734
Q_ASSERT(pixmap.depth() == 1);
1736
tempImage = colorizeBitmap(pixmap.toImage(), brush.color());
1737
fillData->data = textureFillData;
1738
fillData->callback = txop > QPainterPrivate::TxTranslate
1739
? qt_span_texturefill_xform
1740
: qt_span_texturefill;
1741
textureFillData->compositionMode = compositionMode;
1742
textureFillData->init(rasterBuffer, &tempImage, brushMatrix(),
1743
drawHelper->blendTiled,
1745
? drawHelper->blendTransformedBilinearTiled
1746
: drawHelper->blendTransformedTiled);
1755
return clipForFill(fillData);
1759
void QRasterPaintEnginePrivate::updateClip_helper(const QPainterPath &path, Qt::ClipOperation op)
1761
#ifdef QT_DEBUG_DRAW
1762
QRectF bounds = path.boundingRect();
1763
qDebug() << " --- updateClip_helper(), op=" << op << ", bounds=" << bounds;
1765
if (op == Qt::IntersectClip && !clipEnabled)
1766
op = Qt::ReplaceClip;
1769
ClipData clipData = { rasterBuffer, op, 0 };
1773
rasterBuffer->resetClip();
1774
clipEnabled = false;
1776
case Qt::ReplaceClip:
1777
rasterBuffer->resetClip();
1781
case Qt::IntersectClip:
1783
rasterBuffer->resetClip();
1784
clipData.lastIntersected = -1;
1791
QT_FT_BBox clipBox = { 0, 0, rasterBuffer->width(), rasterBuffer->height() };
1792
qt_scanconvert(outlineMapper->convertPath(path), qt_span_clip, &clipData, &clipBox, this);
1794
// Need to reset the clipspans that where not touched during scan conversion.
1795
if (op == Qt::IntersectClip) {
1796
int start = clipData.lastIntersected + 1;
1797
rasterBuffer->resetClipSpans(start, rasterBuffer->height() - start);
1801
qreal *QRasterPaintEnginePrivate::gradientStopPoints(const QGradient *gradient)
1804
QGradientStops stops = gradient->stops();
1805
for (int i=0; i<stops.size(); ++i) {
1806
Q_ASSERT(stops.at(i).first >= 0 && stops.at(i).first <= 1);
1807
stopPoints.add(stops.at(i).first);
1809
return stopPoints.data();
1812
uint *QRasterPaintEnginePrivate::gradientStopColors(const QGradient *gradient)
1815
QGradientStops stops = gradient->stops();
1816
for (int i=0; i<stops.size(); ++i)
1817
stopColors.add(PREMUL(stops.at(i).second.rgba()));
1818
return stopColors.data();
1822
QImage QRasterPaintEnginePrivate::colorizeBitmap(const QImage &image, const QColor &color)
1824
Q_ASSERT(image.depth() == 1);
1826
QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB);
1827
QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied);
1829
QRgb fg = PREMUL(color.rgba());
1830
QRgb bg = opaqueBackground ? PREMUL(bgBrush.color().rgba()) : 0;
1832
for (int y=0; y<sourceImage.height(); ++y) {
1833
uchar *source = sourceImage.scanLine(y);
1834
QRgb *target = reinterpret_cast<QRgb *>(dest.scanLine(y));
1835
for (int x=0; x < sourceImage.width(); ++x)
1836
target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg;
1841
QRasterBuffer::~QRasterBuffer()
1843
if (m_clipSpanCount || m_clipSpanCapacity || m_clipSpans) {
1844
Q_ASSERT(m_clipSpanCount);
1845
qFree(m_clipSpanCount);
1847
Q_ASSERT(m_clipSpanCapacity);
1848
qFree(m_clipSpanCapacity);
1850
Q_ASSERT(m_clipSpans);
1851
for (int y=0; y<m_height; ++y)
1852
qFree((QT_FT_Span *)m_clipSpans[y]);
1856
#if defined (Q_WS_WIN)
1857
if (m_bitmap || m_hdc) {
1860
DeleteObject(m_hdc);
1861
DeleteObject(m_bitmap);
1866
void QRasterBuffer::init()
1868
m_clipSpanCount = 0;
1869
m_clipSpanCapacity = 0;
1871
m_clipSpanHeight = 0;
1875
void QRasterBuffer::prepare(int w, int h)
1877
if (w<=m_width && h<=m_height)
1880
prepareBuffer(w, h);
1885
bytes_per_line = 4*m_width;
1889
void QRasterBuffer::prepare(QImage *image)
1892
int depth = image->depth();
1894
prepareClip(image->width(), image->height());
1895
m_buffer = (uchar *)image->bits();
1896
} else if (depth == 1) {
1897
prepareClip(image->width(), image->height());
1898
m_buffer = (uchar *)image->bits();
1900
qWarning("QRasterBuffer::prepare() cannot prepare from image of depth=%d", depth);
1902
m_width = image->width();
1903
m_height = image->height();
1904
bytes_per_line = 4*(depth == 32 ? m_width : (m_width + 31)/32);
1907
void QRasterBuffer::prepareClip(int /*width*/, int height)
1909
if (height <= m_clipSpanHeight) {
1910
resetClipSpans(0, height);
1913
m_clipSpanHeight = height;
1915
// clean up.. Should reuse old_height first elements for improved reallocs.
1916
if (m_clipSpanCount || m_clipSpanCapacity || m_clipSpans) {
1917
Q_ASSERT(m_clipSpanCount);
1918
qFree(m_clipSpanCount);
1920
Q_ASSERT(m_clipSpanCapacity);
1921
qFree(m_clipSpanCapacity);
1923
Q_ASSERT(m_clipSpans);
1924
for (int y=0; y<m_height; ++y)
1925
qFree((QT_FT_Span *)m_clipSpans[y]);
1929
m_clipSpanCount = (int *) qMalloc(height * sizeof(int));
1930
m_clipSpanCapacity = (int *) qMalloc(height * sizeof(int));
1931
m_clipSpans = (QSpan **) qMalloc(height * sizeof(QT_FT_Span *));
1932
for (int y=0; y<height; ++y) {
1933
m_clipSpanCapacity[y] = 4;
1934
m_clipSpanCount[y] = 0;
1935
m_clipSpans[y] = (QSpan *) qMalloc(m_clipSpanCapacity[y] * sizeof(QSpan));
1941
void QRasterBuffer::resetBuffer(int val)
1943
memset(m_buffer, val, m_width*m_height*sizeof(uint));
1946
#if defined(Q_WS_WIN)
1947
void QRasterBuffer::prepareBuffer(int width, int height)
1950
memset(&bmi, 0, sizeof(bmi));
1951
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1952
bmi.bmiHeader.biWidth = width;
1953
bmi.bmiHeader.biHeight = -height;
1954
bmi.bmiHeader.biPlanes = 1;
1955
bmi.bmiHeader.biBitCount = 32;
1956
bmi.bmiHeader.biCompression = BI_RGB;
1957
bmi.bmiHeader.biSizeImage = 0;
1959
HDC displayDC = GetDC(0);
1961
// a little bit of cleanup...
1962
if (m_bitmap || m_hdc) {
1965
DeleteObject(m_hdc);
1966
DeleteObject(m_bitmap);
1969
m_hdc = CreateCompatibleDC(displayDC);
1973
m_bitmap = CreateDIBSection(m_hdc, &bmi, DIB_RGB_COLORS, (void**) &m_buffer, 0, 0);
1978
SelectObject(m_hdc, m_bitmap);
1980
ReleaseDC(0, displayDC);
1982
#elif defined(Q_WS_X11)
1983
void QRasterBuffer::prepareBuffer(int width, int height)
1986
m_buffer = new uchar[width*height];
1987
memset(m_buffer, 255, width*height*sizeof(uint));
1989
#elif defined(Q_WS_MAC)
1990
static void qt_mac_raster_data_free(void *memory, const void *, size_t)
1995
void QRasterBuffer::prepareBuffer(int width, int height)
1997
m_buffer = new uchar[width*height*sizeof(uint)];
1998
memset(m_buffer, 255, width*height*sizeof(uint));
2000
#ifdef QMAC_NO_COREGRAPHICS
2001
# warning "Unhandled!!"
2004
CGImageRelease(m_data);
2005
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
2006
CGDataProviderRef provider = CGDataProviderCreateWithData(m_buffer, m_buffer, width*height,
2007
qt_mac_raster_data_free);
2008
m_data = CGImageCreate(width, height, 8, 32, width, colorspace,
2009
kCGImageAlphaFirst, provider, 0, 0, kCGRenderingIntentDefault);
2010
CGColorSpaceRelease(colorspace);
2011
CGDataProviderRelease(provider);
2015
#elif defined(Q_WS_QWS)
2016
void QRasterBuffer::prepareBuffer(int /*width*/, int /*height*/)
2018
qFatal("QRasterBuffer::prepareBuffer not implemented on embedded");
2023
void QRasterBuffer::appendClipSpan(int x, int y, int len, int coverage)
2025
// printf("QRasterBuffer::apendClipSpan(x=%d, y=%d, len=%d, oldSize=%d\n", x, y, len,
2026
// m_clipSpanCount[y]);
2030
int clipSpanCount = m_clipSpanCount[y];
2032
if (clipSpanCount == m_clipSpanCapacity[y])
2033
resizeClipSpan(y, clipSpanCount << 1);
2035
// Uncomment for sanity checking
2036
// for (int i=0; i<m_clipSpanCount[y]; ++i) {
2037
// QSpan *s = m_clipSpans[y] + i;
2038
// if (x < s->x + s->len) {
2039
// printf("bad append clip for: x=%d, y=%d, len=%d, cov=%d\n", x, y, len, coverage);
2044
span = m_clipSpans[y] + clipSpanCount;
2048
span->coverage = coverage;
2049
m_clipSpanCount[y] += 1;
2052
void QRasterBuffer::replaceClipSpans(int y, QSpan *spans, int spanCount)
2054
if (m_clipSpanCapacity[y] < spanCount)
2055
resizeClipSpan(y, spanCount);
2056
memcpy(m_clipSpans[y], spans, spanCount * sizeof(QSpan));
2057
m_clipSpanCount[y] = spanCount;
2060
void QRasterBuffer::resetClipSpans(int y, int count)
2062
memset(m_clipSpanCount + y, 0, count * sizeof(int));
2065
void QRasterBuffer::resetClip()
2067
memset(m_clipSpanCount, 0, m_height * sizeof(int));
2070
void QRasterBuffer::resizeClipSpan(int y, int size)
2072
Q_ASSERT(size > m_clipSpanCount[y]);
2073
m_clipSpans[y] = (QSpan *) qRealloc(m_clipSpans[y], size * sizeof(QSpan));
2074
m_clipSpanCapacity[y] = size;
2077
void qt_span_solidfill(int y, int count, QT_FT_Span *spans, void *userData)
2079
SolidFillData *data = reinterpret_cast<SolidFillData *>(userData);
2080
QRasterBuffer *rb = data->rasterBuffer;
2081
uchar *rasterBuffer = rb->scanLine(y);
2082
// fprintf(stdout, "qt_span_solidfill, y=%d, count=%d rb->width=%d rb->bytes_per_line=%d\n", y, count, rb->width(), rb->bytesPerLine());
2086
Q_ASSERT(y < rb->height());
2089
bd.color = data->color;
2092
for (int span=0; span<count; ++span) {
2093
Q_ASSERT(spans->x >= 0);
2094
Q_ASSERT(spans->len > 0);
2095
Q_ASSERT(spans->x + spans->len <= rb->width());
2096
data->blendColor(rasterBuffer, (const QSpan *)spans, data->compositionMode, &bd);
2102
void qt_span_texturefill(int y, int count, QT_FT_Span *spans, void *userData)
2104
TextureFillData *data = reinterpret_cast<TextureFillData *>(userData);
2105
QRasterBuffer *rb = data->rasterBuffer;
2106
int image_width = data->width;
2107
int image_height = data->height;
2108
int xoff = qRound(data->dx) % image_width;
2109
int yoff = qRound(data->dy) % image_height;
2112
xoff += image_width;
2114
yoff += image_height;
2116
uchar *baseTarget = rb->scanLine(y);
2118
QPainter::CompositionMode mode = data->compositionMode;
2119
if (!data->hasAlpha && mode == QPainter::CompositionMode_SourceOver
2120
&& spans->coverage == 255)
2121
mode = QPainter::CompositionMode_Source;
2122
data->blend(baseTarget, (const QSpan *)spans, (xoff + spans->x)%image_width,
2123
((y + yoff) % image_height), data->imageData, image_width, image_height,
2129
void qt_span_texturefill_xform(int y, int count, QT_FT_Span *spans, void *userData)
2131
TextureFillData *data = reinterpret_cast<TextureFillData *>(userData);
2132
QRasterBuffer *rb = data->rasterBuffer;
2133
int image_width = data->width;
2134
int image_height = data->height;
2135
uchar *baseTarget = rb->scanLine(y);
2137
// Base point for the inversed transform
2138
qreal ix = data->m21 * y + data->dx;
2139
qreal iy = data->m22 * y + data->dy;
2141
// The increment pr x in the scanline
2142
qreal dx = data->m11;
2143
qreal dy = data->m12;
2146
data->blendFunc(baseTarget, (const QSpan *)spans,
2148
data->imageData, image_width, image_height,
2149
data->compositionMode);
2155
uint qt_gradient_pixel(const GradientData *data, double pos)
2157
int ipos = qRound(pos * GRADIENT_STOPTABLE_SIZE - 1);
2159
// calculate the actual offset.
2160
if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
2161
if (data->spread == QGradient::RepeatSpread) {
2162
ipos = ipos % GRADIENT_STOPTABLE_SIZE;
2163
ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
2165
} else if (data->spread == QGradient::ReflectSpread) {
2166
const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
2167
ipos = ipos % limit;
2168
ipos = ipos < 0 ? limit + ipos : ipos;
2169
ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
2172
if (ipos < 0) ipos = 0;
2173
else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
2177
Q_ASSERT(ipos >= 0);
2178
Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
2180
return data->colorTable[ipos];
2184
void qt_span_linear_gradient(int y, int count, QT_FT_Span *spans, void *userData)
2186
LinearGradientData *data = reinterpret_cast<LinearGradientData *>(userData);
2187
uchar *baseTarget = data->rasterBuffer->scanLine(y);
2189
qreal ybase = (y - data->origin.y()) * data->yincr;
2192
data->blendFunc(baseTarget, (const QSpan *)spans, data, ybase, y, data->compositionMode);
2197
void qt_span_radial_gradient(int y, int count, QT_FT_Span *spans, void *userData)
2199
RadialGradientData *data = reinterpret_cast<RadialGradientData *>(userData);
2200
uchar *baseTarget = data->rasterBuffer->scanLine(y);
2203
data->blendFunc(baseTarget, (const QSpan *)spans, data, y, data->compositionMode);
2208
void qt_span_conical_gradient(int y, int count, QT_FT_Span *spans, void *userData)
2210
ConicalGradientData *data = reinterpret_cast<ConicalGradientData *>(userData);
2211
uchar *baseTarget = data->rasterBuffer->scanLine(y);
2214
data->blendFunc(baseTarget, (const QSpan *)spans, data, y, data->compositionMode);
2219
void qt_intersect_spans(QSpan *clipSpans, int clipSpanCount,
2220
QT_FT_Span *spans, int spanCount,
2221
QSpan **outSpans, int *outCount)
2223
static QDataBuffer<QSpan> newSpans;
2227
int clipSpanIndex = 0;
2229
int sx1, sx2, cx1, cx2;
2231
while (spanIndex < spanCount && clipSpanIndex < clipSpanCount) {
2232
sx1 = spans[spanIndex].x;
2233
sx2 = sx1 + spans[spanIndex].len;
2234
cx1 = clipSpans[clipSpanIndex].x;
2235
cx2 = cx1 + clipSpans[clipSpanIndex].len;
2237
if (cx1 < sx1 && cx2 < sx1) {
2239
} else if (sx1 < cx1 && sx2 < cx1) {
2243
newClip.x = qMax(sx1, cx1);
2244
newClip.len = qMin(sx2, cx2) - newClip.x;
2245
newClip.coverage = spans[spanIndex].coverage * clipSpans[clipSpanIndex].coverage / 255;
2247
newSpans.add(newClip);
2256
*outSpans = newSpans.data();
2257
*outCount = newSpans.size();
2260
void qt_unite_spans(QSpan *clipSpans, int clipSpanCount,
2261
QT_FT_Span *spans, int spanCount,
2262
QSpan **outSpans, int *outCount)
2266
static QDataBuffer<QSpan> newSpans;
2270
// ### will leak for now... BTW, this is a horrible algorithm, but then again it works...
2271
const int BUFFER_SIZE = 4096;
2272
static int *buffer = (int*) malloc(BUFFER_SIZE * sizeof(int));
2273
memset(buffer, 0, BUFFER_SIZE * sizeof(int));
2275
// Fill with old spans.
2276
for (int i=0; i<clipSpanCount; ++i) {
2277
QSpan *cs = clipSpans + i;
2278
for (int j=cs->x; j<cs->x + cs->len; ++j)
2279
buffer[j] += cs->coverage;
2282
// Fill with new spans
2283
for (int i=0; i<spanCount; ++i) {
2284
QT_FT_Span *s = spans + i;
2285
for (int j=s->x; j<s->x + s->len; ++j) {
2286
buffer[j] += s->coverage;
2287
if (buffer[j] > 255) buffer[j] = 255;
2292
int maxClip = clipSpanCount > 0
2293
? clipSpans[clipSpanCount-1].x + clipSpans[clipSpanCount-1].len
2295
int maxSpan = spanCount > 0
2296
? spans[spanCount-1].x + spans[spanCount-1].len
2299
int max = qMax(maxClip, maxSpan);
2304
// Skip to next span
2305
while (x < max && buffer[x] == 0) ++x;
2306
if (x >= max) break;
2310
sp.coverage = buffer[x];
2312
// Find length of span
2313
while (x < max && buffer[x] == sp.coverage) ++x;
2319
*outSpans = newSpans.data();
2320
*outCount = newSpans.size();
2324
void qt_span_fill_clipped(int y, int spanCount, QT_FT_Span *spans, void *userData)
2326
FillData *fillData = reinterpret_cast<FillData *>(userData);
2328
Q_ASSERT(fillData->callback);
2330
QRasterBuffer *rb = fillData->rasterBuffer;
2332
QSpan *clippedSpans = 0;
2333
int clippedSpanCount = 0;
2335
qt_intersect_spans(rb->clipSpans(y), rb->clipSpanCount(y),
2337
&clippedSpans, &clippedSpanCount);
2339
fillData->callback(y, clippedSpanCount, (QT_FT_Span *) clippedSpans, fillData->data);
2342
void qt_span_clip(int y, int count, QT_FT_Span *spans, void *userData)
2344
ClipData *clipData = reinterpret_cast<ClipData *>(userData);
2345
QRasterBuffer *rb = clipData->rasterBuffer;
2347
switch (clipData->operation) {
2349
case Qt::IntersectClip:
2352
int newSpanCount = 0;
2353
qt_intersect_spans(rb->clipSpans(y), rb->clipSpanCount(y),
2355
&newSpans, &newSpanCount);
2357
// Clear the spans between last y spanned and this.
2358
for (int i=clipData->lastIntersected+1; i<y; ++i)
2359
rb->replaceClipSpans(i, 0, 0);
2360
clipData->lastIntersected = y;
2363
rb->replaceClipSpans(y, newSpans, newSpanCount);
2370
int newSpanCount = 0;
2371
qt_unite_spans(rb->clipSpans(y), rb->clipSpanCount(y),
2373
&newSpans, &newSpanCount);
2375
rb->replaceClipSpans(y, newSpans, newSpanCount);
2379
case Qt::ReplaceClip:
2380
for (int i=0; i<count; ++i) {
2381
rb->appendClipSpan(spans->x, y, spans->len, spans->coverage);
2390
void qt_scanconvert(QT_FT_Outline *outline, qt_span_func callback, void *userData,
2391
QT_FT_BBox *boundingBox, QRasterPaintEnginePrivate *d)
2393
qt_span_func func = callback;
2394
void *data = userData;
2396
QT_FT_Raster_Params rasterParams;
2397
rasterParams.target = 0;
2398
rasterParams.source = outline;
2399
rasterParams.flags = QT_FT_RASTER_FLAG_CLIP;
2400
rasterParams.gray_spans = 0;
2401
rasterParams.black_spans = 0;
2402
rasterParams.bit_test = 0;
2403
rasterParams.bit_set = 0;
2404
rasterParams.user = data;
2405
rasterParams.clip_box = *boundingBox;
2407
if (d->antialiased) {
2408
rasterParams.flags |= (QT_FT_RASTER_FLAG_AA | QT_FT_RASTER_FLAG_DIRECT);
2409
rasterParams.gray_spans = func;
2410
int error = qt_ft_grays_raster.raster_render(qt_gray_raster, &rasterParams);
2412
printf("qt_scanconvert(), gray raster failed...: %d\n", error);
2415
rasterParams.flags |= QT_FT_RASTER_FLAG_DIRECT;
2416
rasterParams.black_spans = func;
2417
int error = qt_ft_standard_raster.raster_render(qt_black_raster, &rasterParams);
2419
qWarning("black raster failed to render, code=%d", error);
2426
QImage QRasterBuffer::clipImage() const
2428
QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
2429
image.fill(qRgb(0, 0, 0));
2431
for (int y = 0; y < m_height; ++y) {
2432
QSpan *spans = clipSpans(y);
2433
int count = clipSpanCount(y);
2436
for (int x=spans->x; x<spans->x + spans->len; ++x) {
2437
QRgb pixel = image.pixel(x, y);
2438
image.setPixel(x, y, qRgb(spans->coverage, qGreen(pixel) + 10, 0));
2446
QImage QRasterBuffer::bufferImage() const
2448
QImage image(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
2450
for (int y = 0; y < m_height; ++y) {
2451
uint *span = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
2453
for (int x=0; x<m_width; ++x) {
2454
uint argb = span[x];
2455
image.setPixel(x, y, argb);
2463
void QRasterBuffer::flushToARGBImage(QImage *target) const
2465
int w = qMin(m_width, target->width());
2466
int h = qMin(m_height, target->height());
2468
for (int y=0; y<h; ++y) {
2469
uint *sourceLine = (uint *)const_cast<QRasterBuffer *>(this)->scanLine(y);
2470
QRgb *dest = (QRgb *) target->scanLine(y);
2471
for (int x=0; x<w; ++x) {
2472
QRgb pixel = sourceLine[x];
2473
int alpha = qAlpha(pixel);
2477
dest[x] = (alpha << 24)
2478
| ((255*qRed(pixel)/alpha) << 16)
2479
| ((255*qGreen(pixel)/alpha) << 8)
2480
| ((255*qBlue(pixel)/alpha) << 0);
2486
void TextureFillData::init(QRasterBuffer *raster, const QImage *image, const QMatrix &matrix,
2487
Blend b, BlendTransformed func)
2489
rasterBuffer = raster;
2490
imageData = (uint*) image->bits();
2491
width = image->width();
2492
height = image->height();
2493
hasAlpha = image->format() != QImage::Format_RGB32;
2495
QMatrix inv = matrix.inverted();
2507
void GradientData::initColorTable()
2509
Q_ASSERT(stopCount > 0);
2511
// The position where the gradient begins and ends
2512
int begin_pos = int(stopPoints[0] * GRADIENT_STOPTABLE_SIZE);
2513
int end_pos = int(stopPoints[stopCount-1] * GRADIENT_STOPTABLE_SIZE);
2515
int pos = 0; // The position in the color table.
2517
// Up to first point
2518
while (pos<=begin_pos) {
2519
colorTable[pos] = stopColors[0];
2523
qreal incr = 1 / qreal(GRADIENT_STOPTABLE_SIZE); // the double increment.
2524
qreal dpos = incr * pos; // The position in terms of 0-1.
2526
int current_stop = 0; // We always interpolate between current and current + 1.
2529
while (pos < end_pos) {
2531
Q_ASSERT(current_stop < stopCount);
2533
uint current_color = stopColors[current_stop];
2534
uint next_color = stopColors[current_stop+1];
2536
int dist = (int)(256*(dpos - stopPoints[current_stop])
2537
/ (stopPoints[current_stop+1] - stopPoints[current_stop]));
2538
int idist = 256 - dist;
2540
colorTable[pos] = INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist);
2545
if (dpos > stopPoints[current_stop+1]) {
2551
while (pos < GRADIENT_STOPTABLE_SIZE) {
2552
colorTable[pos] = stopColors[stopCount-1];
2558
* Initialzes the xincr and yincr delta values that is used to interpolate the Linear Gradient
2560
* The deltas are found by projecting the gradientline down to a horizontal (xincr) or vertical (yincr)
2561
* line that covers the whole gradient (from 0 to 1.0).
2562
* Given that the gradient line is d, the transformed normal vector is n, we use this formula to
2563
* find the length of the side in the triangle is supposed to interpolate over the gradient:
2565
* d + a*n = [l,0], where d = [dx, dy], n = [ndx, ndy], l is the length of the line.
2566
* since we have a zero in our equation, *a* can be found and is used to find *l*.
2568
* rearranging, we get the length of line like this:
2570
* l = dx - dy*ndx/ndy; => xincr = 1.0/l
2572
* We calculate yincr similarly:
2573
* l = dy - dx*ndy/ndx; => yincr = 1.0/l
2576
* We then find the length of that line, and divides the length of the gradient (1.0) by the length
2577
* of the line (in pixels)
2581
void LinearGradientData::init()
2583
qreal x1 = origin.x();
2584
qreal y1 = origin.y();
2588
#ifdef QT_DEBUG_DRAW
2589
qDebug("LinearGradientData::init(), x1=%f, y1=%f, x2=%f, y2=%f, spread=%d",
2590
x1, y1, x2, y2, spread);
2591
for (int i=0; i<stopCount; ++i) {
2592
qDebug(" - %d, pos=%f, color=%x", i, stopPoints[i], stopColors[i]);
2596
// Calculate the normalvector and transform it.
2597
QLineF n = brushMatrix.map(QLineF(x1, y1, x2, y2).normalVector() );
2599
origin = brushMatrix.map(origin);
2600
end = brushMatrix.map(end);
2610
// qDebug() << "(" << x1 << "," << y1 << ")";
2611
// qDebug() << "(" << x2 << "," << y2 << ")";
2616
// qDebug() << "dx: " << dx << "dy: " << dy << "nx: " << nx << "nx: " << nx;;
2617
// Find the length of the projection
2619
if (qAbs(ndy) > GRADIENT_EPSILON) {
2620
qreal l = dx - dy*ndx/ndy;
2626
if (qAbs(ndx) > GRADIENT_EPSILON) {
2627
qreal l = dy - dx*ndy/ndx;
2633
// qDebug() << "inc: " << xincr << "," << yincr;
2637
void ConicalGradientData::init(const QPointF &pt, qreal a, const QMatrix &matrix)
2640
angle = a * 2 * Q_PI / 360.0;
2641
imatrix = matrix.inverted();
2648
static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
2649
QRasterPaintEnginePrivate *d)
2653
if (d->txop > QPainterPrivate::TxTranslate) {
2655
m.eM11 = d->matrix.m11();
2656
m.eM12 = d->matrix.m12();
2657
m.eM21 = d->matrix.m21();
2658
m.eM22 = d->matrix.m22();
2659
// Don't include the translation since it is done when we write the HDC
2660
// Back to the screen.
2663
if (!SetGraphicsMode(hdc, GM_ADVANCED))
2664
qErrnoWarning("QWin32PaintEngine::setNativeMatrix(), SetGraphicsMode failed");
2665
if (!SetWorldTransform(hdc, &m))
2666
qErrnoWarning("QWin32PaintEngine::setNativeMatrix(), SetWorldTransformation failed");
2669
QFontEngine *fe = ti.fontEngine;
2671
SetTextAlign(hdc, TA_BASELINE);
2672
SetBkMode(hdc, TRANSPARENT);
2673
SetTextColor(hdc, RGB(0, 0, 0));
2677
bool transform = false;
2678
bool has_kerning = ti.f->kerning();
2683
if (d->txop >= QPainterPrivate::TxScale
2684
&& !(QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)) {
2685
// Draw rotated and sheared text on Windows 95, 98
2687
// All versions can draw rotated text natively. Scaling can be done with window/viewport transformations.
2688
// Shearing transformations are done by QPainter.
2690
// rotation + scale + translation
2691
scale = sqrt(d->matrix.m11()*d->matrix.m22()
2692
- d->matrix.m12()*d->matrix.m21());
2693
angle = qRound(1800*acos(d->matrix.m11()/scale)/Q_PI);
2694
if (d->matrix.m12() < 0)
2695
angle = 3600 - angle;
2700
if (ti.flags & (QTextItem::Underline|QTextItem::StrikeOut) || scale != 1. || angle) {
2701
LOGFONT lf = fe->logfont;
2702
lf.lfUnderline = (ti.flags & QTextItem::Underline);
2703
lf.lfStrikeOut = (ti.flags & QTextItem::StrikeOut);
2705
lf.lfOrientation = -angle;
2706
lf.lfEscapement = -angle;
2709
lf.lfHeight = (int) (lf.lfHeight*scale);
2710
lf.lfWidth = (int) (lf.lfWidth*scale);
2712
HFONT hf = QT_WA_INLINE(CreateFontIndirectW(&lf), CreateFontIndirectA((LOGFONTA*)&lf));
2713
SelectObject(hdc, hf);
2715
SelectObject(hdc, fe->hfont);
2718
unsigned int options = fe->ttf ? ETO_GLYPH_INDEX : 0;
2720
QGlyphLayout *glyphs = ti.glyphs;
2724
if (!(ti.flags & QTextItem::RightToLeft)) {
2725
// hack to get symbol fonts working on Win95. See also QFontEngine constructor
2726
if (fe->useTextOutA) {
2727
// can only happen if !ttf
2728
for(int i = 0; i < ti.num_glyphs; i++) {
2729
QString str(QChar(glyphs->glyph));
2730
QByteArray cstr = str.toLocal8Bit();
2731
TextOutA(hdc, qRound(x + glyphs->offset.x()), qRound(y + glyphs->offset.y()),
2732
cstr.data(), cstr.length());
2733
x += qRound(glyphs->advance.x());
2737
bool haveOffsets = false;
2739
for(int i = 0; i < ti.num_glyphs; i++) {
2740
if (glyphs[i].offset.x() != 0 || glyphs[i].offset.y() != 0 || glyphs[i].space_18d6 != 0) {
2744
w += glyphs[i].advance.x();
2747
if (haveOffsets || transform || has_kerning) {
2748
for(int i = 0; i < ti.num_glyphs; i++) {
2749
wchar_t chr = glyphs->glyph;
2750
qreal xp = x + glyphs->offset.x();
2751
qreal yp = y + glyphs->offset.y();
2753
d->matrix.map(xp, yp, &xp, &yp);
2754
ExtTextOutW(hdc, qRound(xp), qRound(yp), options, 0, &chr, 1, 0);
2755
x += glyphs->advance.x() + ((qreal)glyphs->space_18d6) / 64.;
2756
y += glyphs->advance.y();
2761
QVarLengthArray<wchar_t> g(ti.num_glyphs);
2762
for (int i = 0; i < ti.num_glyphs; ++i)
2763
g[i] = glyphs[i].glyph;
2766
qRound(x + glyphs->offset.x()),
2767
qRound(y + glyphs->offset.y()),
2768
options, 0, g.data(), ti.num_glyphs, 0);
2773
int i = ti.num_glyphs;
2775
x += glyphs[i].advance.x() + ((qreal)glyphs[i].space_18d6) / 64.;
2776
y += glyphs[i].advance.y();
2779
while(i < ti.num_glyphs) {
2780
x -= glyphs[i].advance.x();
2781
y -= glyphs[i].advance.y();
2783
int xp = qRound(x+glyphs[i].offset.x());
2784
int yp = qRound(y+glyphs[i].offset.y());
2785
ExtTextOutW(hdc, xp, yp, options, 0, reinterpret_cast<wchar_t *>(&glyphs[i].glyph), 1, 0);
2787
if (glyphs[i].nKashidas) {
2788
QChar ch(0x640); // Kashida character
2791
ti.fontEngine->stringToCMap(&ch, 1, g, &nglyphs, 0);
2792
for (uint k = 0; k < glyphs[i].nKashidas; ++k) {
2793
x -= g[0].advance.x();
2794
y -= g[0].advance.y();
2796
int xp = qRound(x+g[0].offset.x());
2797
int yp = qRound(y+g[0].offset.y());
2798
ExtTextOutW(hdc, xp, yp, options, 0, reinterpret_cast<wchar_t *>(&g[0].glyph), 1, 0);
2801
x -= ((qreal)glyphs[i].space_18d6) / 64;
2807
if (ti.flags & (QTextItem::Underline|QTextItem::StrikeOut) || scale != 1. || angle)
2808
DeleteObject(SelectObject(hdc, fe->hfont));
2810
if (ti.flags & (QTextItem::Overline)) {
2811
int lw = qRound(fe->lineThickness());
2812
int yp = qRound(y - fe->ascent() - 1);
2813
Rectangle(hdc, xo, yp, qRound(x), yp + lw);
2817
if (d->txop > QPainterPrivate::TxTranslate) {
2819
m.eM11 = m.eM22 = 1;
2820
m.eDx = m.eDy = m.eM12 = m.eM21 = 0;
2821
if (!SetWorldTransform(hdc, &m))
2822
qErrnoWarning("SetWorldTransformation failed");
2823
if (!SetGraphicsMode(hdc, GM_COMPATIBLE))
2824
qErrnoWarning("SetGraphicsMode failed");
2828
static void draw_text_item_multi(const QPointF &p, const QTextItemInt &ti, HDC hdc,
2829
QRasterPaintEnginePrivate *d)
2831
QFontEngineMulti *multi = static_cast<QFontEngineMulti *>(ti.fontEngine);
2832
QGlyphLayout *glyphs = ti.glyphs;
2833
int which = glyphs[0].glyph >> 24;
2840
for (end = 0; end < ti.num_glyphs; ++end) {
2841
const int e = glyphs[end].glyph >> 24;
2845
// set the high byte to zero
2846
for (i = start; i < end; ++i)
2847
glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
2850
QTextItemInt ti2 = ti;
2851
ti2.glyphs = ti.glyphs + start;
2852
ti2.num_glyphs = end - start;
2853
ti2.fontEngine = multi->engine(which);
2855
draw_text_item_win(QPointF(x, y), ti2, hdc, d);
2857
// reset the high byte for all glyphs and advance to the next sub-string
2858
const int hi = which << 24;
2859
for (i = start; i < end; ++i) {
2860
glyphs[i].glyph = hi | glyphs[i].glyph;
2861
x += glyphs[i].advance.x();
2869
// set the high byte to zero
2870
for (i = start; i < end; ++i)
2871
glyphs[i].glyph = glyphs[i].glyph & 0xffffff;
2874
QTextItemInt ti2 = ti;
2875
ti2.glyphs = ti.glyphs + start;
2876
ti2.num_glyphs = end - start;
2877
ti2.fontEngine = multi->engine(which);
2879
draw_text_item_win(QPointF(x, y), ti2, hdc, d);
2881
// reset the high byte for all glyphs
2882
const int hi = which << 24;
2883
for (i = start; i < end; ++i)
2884
glyphs[i].glyph = hi | glyphs[i].glyph;
2887
void qt_draw_text_item(const QPointF &pos, const QTextItemInt &ti, HDC hdc,
2888
QRasterPaintEnginePrivate *d)
2893
switch(ti.fontEngine->type()) {
2894
case QFontEngine::Multi:
2895
draw_text_item_multi(pos, ti, hdc, d);
2897
case QFontEngine::Win:
2899
draw_text_item_win(pos, ti, hdc, d);
2909
static void drawLine_midpoint_f(const QLineF &line, qt_span_func span_func, void *data, LineDrawMode style, const QRect &devRect)
2912
qDebug(" - drawLine_midpoint_f, x1=%.2f, y1=%.2f, x2=%.2f, y2=%.2f",
2913
line.x1(), line.y1(), line.x2(), line.y2());
2917
qreal dx, dy, d, incrE, incrNE;
2919
qreal x1 = line.x1();
2920
qreal x2 = line.x2();
2921
qreal y1 = line.y1();
2922
qreal y2 = line.y2();
2924
QT_FT_Span span = { 0, 1, 255 };
2929
// specialcase horizontal lines
2931
if (y1 >= 0 && y1 < devRect.height()) {
2932
int start = qMax(0, qRound(qMin(x1, x2)));
2933
int stop = qRound(qMax(x1, x2)) + 1;
2934
int stop_clipped = qMin(devRect.width(), stop);
2935
int len = stop_clipped - start;
2937
if (style == LineDrawNormal && stop == stop_clipped)
2939
span.x = ushort(start);
2940
span.len = ushort(len);
2941
span_func(ushort(y1), 1, &span, data);
2945
} else if (dx == 0) {
2946
if (x1 >= 0 && x1 < devRect.width()) {
2947
int start = qMax(0, qRound(qMin(y1, y2)));
2948
int stop = qRound(qMax(y1, y2)) + 1;
2949
int stop_clipped = qMin(devRect.height(), stop);
2950
if (style == LineDrawNormal && stop == stop_clipped)
2952
span.x = ushort(x1);
2954
for (int i=start; i<stop_clipped; ++i)
2955
span_func(i, 1, &span, data);
2961
if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */
2963
if (x2 < x1) { /* if coordinates are out of order */
2964
qt_swap_qreal(x1, x2);
2967
qt_swap_qreal(y1, y2);
2971
if (style == LineDrawNormal)
2974
// In the loops below we increment before call the span function so
2975
// we need to stop one pixel before
2976
x2 = qMin(x2, qreal(devRect.width() - 1));
2978
// completly clipped, so abort
2986
if (x>=0 && y>=0 && y < devRect.height()) {
2987
Q_ASSERT(x >= 0 && y >= 0 && x < devRect.width() && y < devRect.height());
2989
span_func(y, 1, &span, data);
2992
if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
2993
y2 = qMin(y2, qreal(devRect.height()) - 1);
2997
incrNE = (dy - dx) * 2;
3016
Q_ASSERT(x<devRect.width());
3017
Q_ASSERT(y<devRect.height());
3019
span_func(y, 1, &span, data);
3021
} else { // 0-45 and 180->225 (unit circle degrees)
3023
y1 = qMin(y1, qreal(devRect.height()) - 1);
3027
incrNE = (dy + dx) * 2;
3043
if (x < 0 || y > y1)
3046
Q_ASSERT(x<devRect.width() && y<devRect.height());
3048
span_func(y, 1, &span, data);
3054
// if y is the major axis:
3056
if (y2 < y1) { /* if coordinates are out of order */
3057
qt_swap_qreal(y1, y2);
3060
qt_swap_qreal(x1, x2);
3064
if (style == LineDrawNormal)
3067
// In the loops below we increment before call the span function so
3068
// we need to stop one pixel before
3069
y2 = qMin(y2, qreal(devRect.height()) - 1);
3071
// completly clipped, so abort
3079
if (x>=0 && y>=0 && x < devRect.width()) {
3080
Q_ASSERT(x >= 0 && y >= 0 && x < devRect.width() && y < devRect.height());
3082
span_func(y, 1, &span, data);
3085
if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
3086
x2 = qMin(x2, qreal(devRect.width() - 1));
3089
incrNE = (dx - dy) * 2;
3106
Q_ASSERT(x<devRect.width() && y<devRect.height());
3108
span_func(y, 1, &span, data);
3110
} else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
3111
x1 = qMin(x1, qreal(devRect.width() - 1));
3114
incrNE = (dx + dy) * 2;
3129
if (y < 0 || x > x1)
3131
Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
3133
span_func(y, 1, &span, data);
3140
static void drawLine_midpoint_i(const QLine &line, qt_span_func span_func, void *data,
3141
LineDrawMode style, const QRect &devRect)
3143
#ifdef QT_DEBUG_DRAW
3144
qDebug(" - drawLine_midpoint_i, x1=%d, y1=%d, x2=%d, y2=%d",
3145
line.x1(), line.y1(), line.x2(), line.y2());
3148
int x, y, dx, dy, d, incrE, incrNE;
3155
// Decide if we need to clip and therefore call the float version...
3157
enum { Left, Right, Top, Bottom };
3159
// clip the lines, after cohen-sutherland, see
3160
// e.g. http://www.nondot.org/~sabre/graphpro/line6.html
3162
int p1 = ((x1 < devRect.left()) << Left)
3163
| ((x1 > devRect.right()) << Right)
3164
| ((y1 < devRect.top()) << Top)
3165
| ((y1 > devRect.bottom()) << Bottom);
3166
int p2 = ((x2 < devRect.left()) << Left)
3167
| ((x2 > devRect.right()) << Right)
3168
| ((y2 < devRect.top()) << Top)
3169
| ((y2 > devRect.bottom()) << Bottom);
3172
// completely outside
3175
} else if (p1 | p2) {
3177
drawLine_midpoint_f(line, span_func, data, style, devRect);
3182
static int use_int=0;
3184
printf("using int version\n");
3188
QT_FT_Span span = { 0, 1, 255 };
3195
if (y1 >= 0 && y1 < devRect.height()) {
3196
int start = qMax(0, qMin(x1, x2));
3197
int stop = qMin(devRect.width(), qMax(x1, x2) + 1);
3198
int len = stop - start;
3200
if (style == LineDrawNormal)
3204
span_func(y1, 1, &span, data);
3208
} else if (dx == 0) {
3210
if (x1 >= 0 && x1 < devRect.width()) {
3211
int start = qMax(0, qMin(y1, y2));
3212
int stop = qMin(devRect.height(), qMax(y1, y2) + 1);
3213
if (style == LineDrawNormal)
3217
for (int i=start; i<stop; ++i)
3218
span_func(i, 1, &span, data);
3224
if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */
3226
if (x2 < x1) { /* if coordinates are out of order */
3227
qt_swap_int(x1, x2);
3230
qt_swap_int(y1, y2);
3234
if (style == LineDrawNormal)
3241
span_func(y, 1, &span, data);
3243
if (y2 > y1) { /* when it is decided to change y, y should be incremented */
3246
incrNE = (dy - dx) << 1;
3256
Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
3258
span_func(y, 1, &span, data);
3261
else { /* when it is decided to change y, y
3262
should be decremented */
3265
incrNE = (dy + dx) << 1;
3274
Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
3276
span_func(y, 1, &span, data);
3280
else { /* if y is the major axis: */
3282
if (y2 < y1) { /* if coordinates are out of order */
3283
qt_swap_int(y1, y2);
3286
qt_swap_int(x1, x2);
3290
if (style == LineDrawNormal)
3297
span_func(y, 1, &span, data);
3299
if (x2 > x1) { /* when it is decided to change x, x
3300
should be incremented */
3303
incrNE = (dx - dy) << 1;
3312
Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
3314
span_func(y, 1, &span, data);
3317
else { /* when it is decided to change x, x
3318
should be decremented */
3321
incrNE = (dx + dy) << 1;
3331
Q_ASSERT(x>=0 && x<devRect.width() && y>=0 && y<devRect.height());
3333
span_func(y, 1, &span, data);