1
1
/****************************************************************************
3
3
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
** All rights reserved.
4
5
** Contact: Nokia Corporation (qt-info@nokia.com)
6
7
** This file is part of the QtGui module of the Qt Toolkit.
8
9
** $QT_BEGIN_LICENSE:LGPL$
10
** Licensees holding valid Qt Commercial licenses may use this file in
11
** accordance with the Qt Commercial License Agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Nokia.
10
** No Commercial Usage
11
** This file contains pre-release code and may not be distributed.
12
** You may use this file in accordance with the terms and conditions
13
** contained in the Technology Preview License Agreement accompanying
15
16
** GNU Lesser General Public License Usage
16
17
** Alternatively, this file may be used under the terms of the GNU Lesser
20
21
** ensure the GNU Lesser General Public License version 2.1 requirements
21
22
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23
** In addition, as a special exception, Nokia gives you certain
24
** additional rights. These rights are described in the Nokia Qt LGPL
25
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28
** GNU General Public License Usage
29
** Alternatively, this file may be used under the terms of the GNU
30
** General Public License version 3.0 as published by the Free Software
31
** Foundation and appearing in the file LICENSE.GPL included in the
32
** packaging of this file. Please review the following information to
33
** ensure the GNU General Public License version 3.0 requirements will be
34
** met: http://www.gnu.org/copyleft/gpl.html.
36
** If you are unsure which license is appropriate for your use, please
37
** contact the sales department at http://www.qtsoftware.com/contact.
24
** In addition, as a special exception, Nokia gives you certain additional
25
** rights. These rights are described in the Nokia Qt LGPL Exception
26
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28
** If you have questions regarding the use of this file, please contact
29
** Nokia at qt-info@nokia.com.
38
38
** $QT_END_LICENSE$
40
40
****************************************************************************/
348
345
(unsigned char *) malloc(d->rasterPoolSize);
347
Q_CHECK_PTR(d->rasterPoolBase);
351
349
// The antialiasing raster.
352
d->grayRaster = new QT_FT_Raster;
353
qt_ft_grays_raster.raster_new(0, d->grayRaster);
354
qt_ft_grays_raster.raster_reset(*d->grayRaster, d->rasterPoolBase, d->rasterPoolSize);
356
d->rasterizer = new QRasterizer;
357
d->rasterBuffer = new QRasterBuffer();
358
d->outlineMapper = new QOutlineMapper;
350
d->grayRaster.reset(new QT_FT_Raster);
351
Q_CHECK_PTR(d->grayRaster.data());
352
if (qt_ft_grays_raster.raster_new(0, d->grayRaster.data()))
353
QT_THROW(std::bad_alloc()); // an error creating the raster is caused by a bad malloc
356
qt_ft_grays_raster.raster_reset(*d->grayRaster.data(), d->rasterPoolBase, d->rasterPoolSize);
358
d->rasterizer.reset(new QRasterizer);
359
d->rasterBuffer.reset(new QRasterBuffer());
360
d->outlineMapper.reset(new QOutlineMapper);
359
361
d->outlinemapper_xform_dirty = true;
361
363
d->basicStroker.setMoveToHook(qt_ft_outline_move_to);
362
364
d->basicStroker.setLineToHook(qt_ft_outline_line_to);
363
365
d->basicStroker.setCubicToHook(qt_ft_outline_cubic_to);
368
d->image_filler.init(d->rasterBuffer, this);
367
d->baseClip.reset(new QClipData(d->device->height()));
368
d->baseClip->setClipRect(QRect(0, 0, d->device->width(), d->device->height()));
370
d->image_filler.init(d->rasterBuffer.data(), this);
369
371
d->image_filler.type = QSpanData::Texture;
371
d->image_filler_xform.init(d->rasterBuffer, this);
373
d->image_filler_xform.init(d->rasterBuffer.data(), this);
372
374
d->image_filler_xform.type = QSpanData::Texture;
374
d->solid_color_filler.init(d->rasterBuffer, this);
376
d->solid_color_filler.init(d->rasterBuffer.data(), this);
375
377
d->solid_color_filler.type = QSpanData::Solid;
377
379
d->deviceDepth = d->device->depth();
483
479
d->rasterizer->setClipRect(d->deviceRect);
485
s->penData.init(d->rasterBuffer, this);
486
s->penData.setup(s->pen.brush(), s->intOpacity);
481
s->penData.init(d->rasterBuffer.data(), this);
482
s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
487
483
s->stroker = &d->basicStroker;
488
484
d->basicStroker.setClipRect(d->deviceRect);
490
s->brushData.init(d->rasterBuffer, this);
491
s->brushData.setup(s->brush, s->intOpacity);
486
s->brushData.init(d->rasterBuffer.data(), this);
487
s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
493
489
d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
618
612
d->isPlain45DegreeRotation = false;
619
613
if (txop >= QTransform::TxRotate) {
620
614
d->isPlain45DegreeRotation =
621
(qFuzzyCompare(matrix.m11() + 1, qreal(1))
622
&& qFuzzyCompare(matrix.m12(), qreal(1))
623
&& qFuzzyCompare(matrix.m21(), qreal(-1))
624
&& qFuzzyCompare(matrix.m22() + 1, qreal(1))
627
(qFuzzyCompare(matrix.m11(), qreal(-1))
628
&& qFuzzyCompare(matrix.m12() + 1, qreal(1))
629
&& qFuzzyCompare(matrix.m21() + 1, qreal(1))
630
&& qFuzzyCompare(matrix.m22(), qreal(-1))
633
(qFuzzyCompare(matrix.m11() + 1, qreal(1))
634
&& qFuzzyCompare(matrix.m12(), qreal(-1))
635
&& qFuzzyCompare(matrix.m21(), qreal(1))
636
&& qFuzzyCompare(matrix.m22() + 1, qreal(1))
615
(qFuzzyIsNull(matrix.m11())
616
&& qFuzzyIsNull(matrix.m12() - qreal(1))
617
&& qFuzzyIsNull(matrix.m21() + qreal(1))
618
&& qFuzzyIsNull(matrix.m22())
621
(qFuzzyIsNull(matrix.m11() + qreal(1))
622
&& qFuzzyIsNull(matrix.m12())
623
&& qFuzzyIsNull(matrix.m21())
624
&& qFuzzyIsNull(matrix.m22() + qreal(1))
627
(qFuzzyIsNull(matrix.m11())
628
&& qFuzzyIsNull(matrix.m12() + qreal(1))
629
&& qFuzzyIsNull(matrix.m21() - qreal(1))
630
&& qFuzzyIsNull(matrix.m22())
1168
static void qrasterpaintengine_state_setNoClip(QRasterPaintEngineState *s)
1170
if (s->flags.has_clip_ownership)
1173
s->flags.has_clip_ownership = false;
1176
static void qrasterpaintengine_dirty_clip(QRasterPaintEnginePrivate *d, QRasterPaintEngineState *s)
1178
s->fillFlags |= QPaintEngine::DirtyClipPath;
1179
s->strokeFlags |= QPaintEngine::DirtyClipPath;
1180
s->pixmapFlags |= QPaintEngine::DirtyClipPath;
1182
d->solid_color_filler.clip = d->clip();
1183
d->solid_color_filler.adjustSpanMethods();
1185
#ifdef QT_DEBUG_DRAW
1186
dumpClip(d->rasterBuffer->width(), d->rasterBuffer->height(), &*d->clip());
1331
1337
s->clip->setClipRect(base->clipRect & clipRect);
1333
1339
s->clip->setClipRegion(base->clipRegion & clipRect);
1340
s->clip->enabled = true;
1335
1342
QPaintEngineEx::clip(rect, op);
1340
s->brushData.clip = d->clip();
1341
s->penData.clip = d->clip();
1343
s->fillFlags |= DirtyClipPath;
1344
s->strokeFlags |= DirtyClipPath;
1345
s->pixmapFlags |= DirtyClipPath;
1347
d->solid_color_filler.clip = d->clip();
1348
d->solid_color_filler.adjustSpanMethods();
1351
#ifdef QT_CLIPPING_RATIOS
1346
qrasterpaintengine_dirty_clip(d, s);
1359
1353
void QRasterPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
1361
QPaintEngineEx::clip(region, op);
1367
void QRasterPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
1369
QPaintEngineEx::clip(path, op);
1355
#ifdef QT_DEBUG_DRAW
1356
qDebug() << "QRasterPaintEngine::clip(): " << region << op;
1359
Q_D(QRasterPaintEngine);
1361
if (region.numRects() == 1) {
1362
clip(region.boundingRect(), op);
1366
QRasterPaintEngineState *s = state();
1367
const QClipData *clip = d->clip();
1368
const QClipData *baseClip = d->baseClip.data();
1370
if (op == Qt::NoClip) {
1371
qrasterpaintengine_state_setNoClip(s);
1372
} else if (s->matrix.type() > QTransform::TxScale
1373
|| op == Qt::UniteClip
1374
|| (op == Qt::IntersectClip && !clip->hasRectClip && !clip->hasRegionClip)
1375
|| (op == Qt::ReplaceClip && !baseClip->hasRectClip && !baseClip->hasRegionClip)) {
1376
QPaintEngineEx::clip(region, op);
1378
const QClipData *curClip;
1381
if (op == Qt::IntersectClip)
1386
if (s->flags.has_clip_ownership) {
1390
newClip = new QClipData(d->rasterBuffer->height());
1392
s->flags.has_clip_ownership = true;
1395
QRegion r = s->matrix.map(region);
1396
if (curClip->hasRectClip)
1397
newClip->setClipRegion(r & curClip->clipRect);
1398
else if (curClip->hasRegionClip)
1399
newClip->setClipRegion(r & curClip->clipRegion);
1401
qrasterpaintengine_dirty_clip(d, s);
1638
1671
QPaintEngineEx::drawRects(rects, rectCount);
1641
void QRasterPaintEnginePrivate::strokeProjective(const QPainterPath &path)
1643
Q_Q(QRasterPaintEngine);
1644
QRasterPaintEngineState *s = q->state();
1646
const QPen &pen = s->lastPen;
1647
QPainterPathStroker pathStroker;
1648
pathStroker.setWidth(pen.width() == 0 ? qreal(1) : pen.width());
1649
pathStroker.setCapStyle(pen.capStyle());
1650
pathStroker.setJoinStyle(pen.joinStyle());
1651
pathStroker.setMiterLimit(pen.miterLimit());
1652
pathStroker.setDashOffset(pen.dashOffset());
1654
if (qpen_style(pen) == Qt::CustomDashLine)
1655
pathStroker.setDashPattern(pen.dashPattern());
1657
pathStroker.setDashPattern(qpen_style(pen));
1659
outlineMapper->setMatrix(QTransform());
1660
const QPainterPath stroke = pen.isCosmetic()
1661
? pathStroker.createStroke(s->matrix.map(path))
1662
: s->matrix.map(pathStroker.createStroke(path));
1664
rasterize(outlineMapper->convertPath(stroke), s->penData.blend, &s->penData, rasterBuffer);
1665
outlinemapper_xform_dirty = true;
1677
1682
if (!s->penData.blend)
1680
if (s->flags.fast_pen && path.shape() <= QVectorPath::NonCurvedShapeHint && s->lastPen.brush().isOpaque()) {
1681
strokePolygonCosmetic((QPointF *) path.points(), path.elementCount(),
1682
path.hasImplicitClose()
1685
if (s->flags.fast_pen && path.shape() <= QVectorPath::NonCurvedShapeHint
1686
&& s->lastPen.brush().isOpaque()) {
1687
int count = path.elementCount();
1688
QPointF *points = (QPointF *) path.points();
1689
const QPainterPath::ElementType *types = path.elements();
1693
while (first < count) {
1694
while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
1696
while (last < count && types[last] == QPainterPath::LineToElement) ++last;
1697
strokePolygonCosmetic(points + first, last - first,
1698
path.hasImplicitClose() && last == count // only close last one..
1704
strokePolygonCosmetic(points, count,
1705
path.hasImplicitClose()
1686
1710
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
1687
1711
qreal width = s->lastPen.isCosmetic()
1739
1765
static inline QRect toNormalizedFillRect(const QRectF &rect)
1741
const int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1742
const int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1743
const int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1744
const int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1746
return QRect(x1, y1, x2 - x1, y2 - y1).normalized();
1767
int x1 = qRound(rect.x() + aliasedCoordinateDelta);
1768
int y1 = qRound(rect.y() + aliasedCoordinateDelta);
1769
int x2 = qRound(rect.right() + aliasedCoordinateDelta);
1770
int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
1777
return QRect(x1, y1, x2 - x1, y2 - y1);
1903
1931
QRasterPaintEngineState *s = state();
1905
1933
d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color.rgba(), s->intOpacity));
1934
if ((d->solid_color_filler.solid.color & 0xff000000) == 0
1935
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
1906
1938
d->solid_color_filler.clip = d->clip();
1907
1939
d->solid_color_filler.adjustSpanMethods();
1909
1940
fillRect(r, &d->solid_color_filler);
1915
void QRasterPaintEngine::drawPath(const QPainterPath &path)
1917
#ifdef QT_DEBUG_DRAW
1918
QRectF bounds = path.boundingRect();
1919
qDebug(" - QRasterPaintEngine::drawPath(), [%.2f, %.2f, %.2f, %.2f]",
1920
bounds.x(), bounds.y(), bounds.width(), bounds.height());
1927
Q_D(QRasterPaintEngine);
1928
QRasterPaintEngineState *s = state();
1931
if (s->brushData.blend) {
1932
ensureOutlineMapper();
1933
fillPath(path, &s->brushData);
1938
if (!s->penData.blend)
1941
if (s->matrix.type() >= QTransform::TxProject) {
1942
d->strokeProjective(path);
1944
Q_ASSERT(s->stroker);
1945
d->outlineMapper->beginOutline(Qt::WindingFill);
1947
if (s->pen.isCosmetic() || (qt_scaleForTransform(s->matrix, &txscale) && txscale != 1)) {
1948
const qreal strokeWidth = d->basicStroker.strokeWidth();
1949
const QRectF clipRect = d->dashStroker ? d->dashStroker->clipRect() : QRectF();
1951
d->dashStroker->setClipRect(d->deviceRect);
1952
d->basicStroker.setStrokeWidth(strokeWidth * txscale);
1953
d->outlineMapper->setMatrix(QTransform());
1954
s->stroker->strokePath(path, d->outlineMapper, s->matrix);
1955
d->outlinemapper_xform_dirty = true;
1956
d->basicStroker.setStrokeWidth(strokeWidth);
1958
d->dashStroker->setClipRect(clipRect);
1960
ensureOutlineMapper();
1961
s->stroker->strokePath(path, d->outlineMapper, QTransform());
1963
d->outlineMapper->endOutline();
1965
ProcessSpans blend = d->getPenFunc(d->outlineMapper->controlPointRect,
1967
d->rasterize(d->outlineMapper->outline(), blend, &s->penData, d->rasterBuffer);
1973
1943
static inline bool isAbove(const QPointF *a, const QPointF *b)
1975
1945
return a->y() < b->y();
2569
2538
qDebug() << " - QRasterPaintEngine::drawImage(), r=" << r << " sr=" << sr << " image=" << img.size() << "depth=" << img.depth();
2572
2544
Q_D(QRasterPaintEngine);
2573
2545
QRasterPaintEngineState *s = state();
2574
const bool aa = s->flags.antialiased || s->flags.bilinear;
2575
if (!aa && sr.size() == QSize(1, 1)) {
2546
int sr_l = qFloor(sr.left());
2547
int sr_r = qCeil(sr.right()) - 1;
2548
int sr_t = qFloor(sr.top());
2549
int sr_b = qCeil(sr.bottom()) - 1;
2551
if (!s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
2576
2552
// as fillRect will apply the aliased coordinate delta we need to
2577
2553
// subtract it here as we don't use it for image drawing
2578
2554
QTransform old = s->matrix;
2579
2555
s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
2580
fillRect(r, QColor::fromRgba(img.pixel(sr.x(), sr.y())));
2557
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
2558
QRgb color = img.pixel(sr_l, sr_t);
2559
switch (img.format()) {
2560
case QImage::Format_ARGB32_Premultiplied:
2561
case QImage::Format_ARGB8565_Premultiplied:
2562
case QImage::Format_ARGB6666_Premultiplied:
2563
case QImage::Format_ARGB8555_Premultiplied:
2564
case QImage::Format_ARGB4444_Premultiplied:
2565
// Combine premultiplied color with the opacity set on the painter.
2566
d->solid_color_filler.solid.color =
2567
((((color & 0x00ff00ff) * s->intOpacity) >> 8) & 0x00ff00ff)
2568
| ((((color & 0xff00ff00) >> 8) * s->intOpacity) & 0xff00ff00);
2571
d->solid_color_filler.solid.color = PREMUL(ARGB_COMBINE_ALPHA(color, s->intOpacity));
2575
if ((d->solid_color_filler.solid.color & 0xff000000) == 0
2576
&& s->composition_mode == QPainter::CompositionMode_SourceOver) {
2580
d->solid_color_filler.clip = d->clip();
2581
d->solid_color_filler.adjustSpanMethods();
2582
fillRect(r, &d->solid_color_filler);
2581
2584
s->matrix = old;
2589
2592
if (s->matrix.type() > QTransform::TxTranslate || stretch_sr) {
2591
2594
if (s->flags.fast_images) {
2592
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2593
if (func && (!clip || clip->hasRectClip)) {
2594
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2595
img.bits(), img.bytesPerLine(),
2596
qt_mapRect_non_normalizing(r, s->matrix), sr,
2597
!clip ? d->deviceRect : clip->clipRect,
2595
if (s->matrix.type() > QTransform::TxScale) {
2596
SrcOverTransformFunc func = qTransformFunctions[d->rasterBuffer->format][img.format()];
2597
if (func && (!clip || clip->hasRectClip)) {
2598
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(), img.bits(),
2599
img.bytesPerLine(), r, sr, !clip ? d->deviceRect : clip->clipRect,
2600
s->matrix, s->intOpacity);
2604
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
2605
if (func && (!clip || clip->hasRectClip)) {
2606
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
2607
img.bits(), img.bytesPerLine(),
2608
qt_mapRect_non_normalizing(r, s->matrix), sr,
2609
!clip ? d->deviceRect : clip->clipRect,
3059
#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
3060
void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
3062
Q_D(QRasterPaintEngine);
3063
QRasterPaintEngineState *s = state();
3065
QFontEngine *fontEngine = ti.fontEngine;
3066
if (fontEngine->type() != QFontEngine::S60FontEngine) {
3067
QPaintEngineEx::drawTextItem(p, ti);
3071
QFontEngineS60 *fe = static_cast<QFontEngineS60 *>(fontEngine);
3073
QVarLengthArray<QFixedPoint> positions;
3074
QVarLengthArray<glyph_t> glyphs;
3075
QTransform matrix = s->matrix;
3076
matrix.translate(p.x(), p.y());
3077
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
3079
const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
3081
for (int i=0; i<glyphs.size(); ++i) {
3082
TOpenFontCharMetrics tmetrics;
3083
const TUint8 *glyphBitmapBytes;
3084
TSize glyphBitmapSize;
3085
fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
3086
const glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]);
3087
const int x = qFloor(positions[i].x + metrics.x + aliasDelta);
3088
const int y = qFloor(positions[i].y + metrics.y + aliasDelta);
3090
alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
3095
#endif // Q_OS_SYMBIAN && QT_NO_FREETYPE
3057
3098
* Returns true if the rectangle is completly within the current clip
4304
m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4305
m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4310
m_clipLines[y].spans = 0;
4311
m_clipLines[y].count = 0;
4315
const int len = clipRect.width();
4318
QSpan *span = m_spans + count;
4322
span->coverage = 255;
4325
m_clipLines[y].spans = span;
4326
m_clipLines[y].count = 1;
4330
while (y < clipSpanHeight) {
4331
m_clipLines[y].spans = 0;
4332
m_clipLines[y].count = 0;
4335
} else if (hasRegionClip) {
4337
const QVector<QRect> rects = clipRegion.rects();
4338
const int numRects = rects.size();
4341
const int maxSpans = (ymax - ymin) * numRects;
4342
if (maxSpans > allocated) {
4343
m_spans = (QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan));
4344
allocated = maxSpans;
4349
int firstInBand = 0;
4350
while (firstInBand < numRects) {
4351
const int currMinY = rects.at(firstInBand).y();
4352
const int currMaxY = currMinY + rects.at(firstInBand).height();
4354
while (y < currMinY) {
4355
m_clipLines[y].spans = 0;
4356
m_clipLines[y].count = 0;
4360
int lastInBand = firstInBand;
4361
while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4364
while (y < currMaxY) {
4366
m_clipLines[y].spans = m_spans + count;
4367
m_clipLines[y].count = lastInBand - firstInBand + 1;
4369
for (int r = firstInBand; r <= lastInBand; ++r) {
4370
const QRect &currRect = rects.at(r);
4354
m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
4356
Q_CHECK_PTR(m_clipLines);
4358
m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan));
4359
allocated = clipSpanHeight;
4360
Q_CHECK_PTR(m_spans);
4366
m_clipLines[y].spans = 0;
4367
m_clipLines[y].count = 0;
4371
const int len = clipRect.width();
4371
4374
QSpan *span = m_spans + count;
4372
span->x = currRect.x();
4373
span->len = currRect.width();
4375
4378
span->coverage = 255;
4381
m_clipLines[y].spans = span;
4382
m_clipLines[y].count = 1;
4386
while (y < clipSpanHeight) {
4387
m_clipLines[y].spans = 0;
4388
m_clipLines[y].count = 0;
4391
} else if (hasRegionClip) {
4393
const QVector<QRect> rects = clipRegion.rects();
4394
const int numRects = rects.size();
4397
const int maxSpans = (ymax - ymin) * numRects;
4398
if (maxSpans > allocated) {
4399
m_spans = q_check_ptr((QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)));
4400
allocated = maxSpans;
4405
int firstInBand = 0;
4407
while (firstInBand < numRects) {
4408
const int currMinY = rects.at(firstInBand).y();
4409
const int currMaxY = currMinY + rects.at(firstInBand).height();
4411
while (y < currMinY) {
4412
m_clipLines[y].spans = 0;
4413
m_clipLines[y].count = 0;
4417
int lastInBand = firstInBand;
4418
while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y)
4421
while (y < currMaxY) {
4423
m_clipLines[y].spans = m_spans + count;
4424
m_clipLines[y].count = lastInBand - firstInBand + 1;
4426
for (int r = firstInBand; r <= lastInBand; ++r) {
4427
const QRect &currRect = rects.at(r);
4428
QSpan *span = m_spans + count;
4429
span->x = currRect.x();
4430
span->len = currRect.width();
4432
span->coverage = 255;
4438
firstInBand = lastInBand + 1;
4441
Q_ASSERT(count <= allocated);
4443
while (y < clipSpanHeight) {
4444
m_clipLines[y].spans = 0;
4445
m_clipLines[y].count = 0;
4381
firstInBand = lastInBand + 1;
4384
Q_ASSERT(count <= allocated);
4386
while (y < clipSpanHeight) {
4387
m_clipLines[y].spans = 0;
4388
m_clipLines[y].count = 0;
4451
free(m_spans); // have to free m_spans again or someone might think that we were successfully initialized.
4456
free(m_clipLines); // same for clipLines
4407
4474
ymax = m_spans[count-1].y + 1;
4408
4475
xmin = INT_MAX;
4479
int left = m_spans[0].x;
4480
int right = m_spans[0].x + m_spans[0].len;
4410
4482
for (int i = 0; i < count; ++i) {
4411
// qDebug() << " " << spans[i].x << spans[i].y << spans[i].len << spans[i].coverage;
4412
4483
if (m_spans[i].y != y) {
4484
if (m_spans[i].y != y + 1 && y != -1) {
4413
4487
y = m_spans[i].y;
4414
4488
m_clipLines[y].spans = m_spans+i;
4415
4489
m_clipLines[y].count = 0;
4416
4490
// qDebug() << " new line: y=" << y;
4418
4492
++m_clipLines[y].count;
4493
int sl = (int) m_spans[i].x;
4494
int sr = sl + m_spans[i].len;
4419
4496
xmin = qMin(xmin, (int)m_spans[i].x);
4420
4497
xmax = qMax(xmax, (int)m_spans[i].x + m_spans[i].len);
4423
// qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d", xmin, xmax, ymin, ymax);
4499
if (sl != left || sr != right)
4502
// qDebug("xmin=%d,xmax=%d,ymin=%d,ymax=%d %s", xmin, xmax, ymin, ymax, isRect ? "rectangular" : "");
4506
clipRect.setRect(xmin, ymin, xmax - xmin, ymax - ymin);
4608
Clip spans to \a{clip}-region.
4609
Returns number of unclipped spans
4611
static int qt_intersect_spans(QT_FT_Span *spans, int numSpans,
4613
QT_FT_Span *outSpans, int maxOut,
4614
const QRegion &clip)
4616
const QVector<QRect> rects = clip.rects();
4617
const int numRects = rects.size();
4620
short miny, minx, maxx, maxy;
4622
const QRect &rect = rects[0];
4625
maxx = rect.right();
4626
maxy = rect.bottom();
4629
// TODO: better mapping of currY and startRect
4633
int currY = spans[i].y;
4634
while (i < numSpans) {
4636
if (spans[i].y != currY && r != 0) {
4639
const QRect &rect = rects[r];
4642
maxx = rect.right();
4643
maxy = rect.bottom();
4646
if (spans[i].y < miny) {
4651
if (spans[i].y > maxy || spans[i].x > maxx) {
4652
if (++r >= numRects) {
4657
const QRect &rect = rects[r];
4660
maxx = rect.right();
4661
maxy = rect.bottom();
4665
if (spans[i].x + spans[i].len <= minx) {
4670
outSpans[n].y = spans[i].y;
4671
outSpans[n].coverage = spans[i].coverage;
4673
if (spans[i].x < minx) {
4674
const ushort cutaway = minx - spans[i].x;
4675
outSpans[n].len = qMin(spans[i].len - cutaway, maxx - minx + 1);
4676
outSpans[n].x = minx;
4677
if (outSpans[n].len == spans[i].len - cutaway) {
4680
// span wider than current rect
4681
spans[i].len -= outSpans[n].len + cutaway;
4682
spans[i].x = maxx + 1;
4684
} else { // span starts inside current rect
4685
outSpans[n].x = spans[i].x;
4686
outSpans[n].len = qMin(spans[i].len,
4687
ushort(maxx - spans[i].x + 1));
4688
if (outSpans[n].len == spans[i].len) {
4691
// span wider than current rect
4692
spans[i].len -= outSpans[n].len;
4693
spans[i].x = maxx + 1;
4705
4693
static void qt_span_fill_clipRect(int count, const QSpan *spans,
4706
4694
void *userData)
4718
4706
fillData->unclipped_blend(count, spans, fillData);
4721
static void qt_span_fill_clipRegion(int count, const QSpan *spans,
4724
QSpanData *fillData = reinterpret_cast<QSpanData *>(userData);
4725
Q_ASSERT(fillData->blend && fillData->unclipped_blend);
4727
Q_ASSERT(fillData->clip);
4728
Q_ASSERT(!fillData->clip->clipRegion.isEmpty());
4730
const int NSPANS = 256;
4731
QSpan cspans[NSPANS];
4732
int currentClip = 0;
4733
while (currentClip < count) {
4734
const int unclipped = qt_intersect_spans(const_cast<QSpan*>(spans),
4735
count, ¤tClip,
4737
fillData->clip->clipRegion);
4739
fillData->unclipped_blend(unclipped, cspans, fillData);
4744
4709
static void qt_span_clip(int count, const QSpan *spans, void *userData)
4746
4711
ClipData *clipData = reinterpret_cast<ClipData *>(userData);