summaryrefslogtreecommitdiffstats
path: root/src/gui/painting
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting')
-rw-r--r--src/gui/painting/qbezier.cpp41
-rw-r--r--src/gui/painting/qblendfunctions.cpp4
-rw-r--r--src/gui/painting/qbrush.cpp15
-rw-r--r--src/gui/painting/qdrawhelper.cpp2
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp15
-rw-r--r--src/gui/painting/qdrawhelper_ssse3.cpp75
-rw-r--r--src/gui/painting/qgraphicssystem_runtime.cpp6
-rw-r--r--src/gui/painting/qgraphicssystem_runtime_p.h1
-rw-r--r--src/gui/painting/qgraphicssystemfactory.cpp2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp10
-rw-r--r--src/gui/painting/qpaintengineex.cpp2
-rw-r--r--src/gui/painting/qpainter.cpp4
-rw-r--r--src/gui/painting/qprintengine_ps.cpp1
-rw-r--r--src/gui/painting/qprintengine_win.cpp2
-rw-r--r--src/gui/painting/qregion.cpp4
-rw-r--r--src/gui/painting/qstroker.cpp2
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp129
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h42
18 files changed, 183 insertions, 174 deletions
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index 2a9b31a549..54c81ba3cf 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -293,36 +293,6 @@ static ShiftResult good_offset(const QBezier *b1, const QBezier *b2, qreal offse
return Ok;
}
-static inline QLineF qline_shifted(const QPointF &p1, const QPointF &p2, qreal offset)
-{
- QLineF l(p1, p2);
- QLineF ln = l.normalVector().unitVector();
- l.translate(ln.dx() * offset, ln.dy() * offset);
- return l;
-}
-
-static bool qbezier_is_line(QPointF *points, int pointCount)
-{
- Q_ASSERT(pointCount > 2);
-
- qreal dx13 = points[2].x() - points[0].x();
- qreal dy13 = points[2].y() - points[0].y();
-
- qreal dx12 = points[1].x() - points[0].x();
- qreal dy12 = points[1].y() - points[0].y();
-
- if (pointCount == 3) {
- return qFuzzyCompare(dx12 * dy13, dx13 * dy12);
- } else if (pointCount == 4) {
- qreal dx14 = points[3].x() - points[0].x();
- qreal dy14 = points[3].y() - points[0].y();
-
- return (qFuzzyCompare(dx12 * dy13, dx13 * dy12) && qFuzzyCompare(dx12 * dy14, dx14 * dy12));
- }
-
- return false;
-}
-
static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
{
int map[4];
@@ -353,17 +323,6 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr
if (np == 1)
return Discard;
- // We need to specialcase lines of 3 or 4 points due to numerical
- // instability in intersections below
- if (np > 2 && qbezier_is_line(points, np)) {
- if (points[0] == points[np-1])
- return Discard;
-
- QLineF l = qline_shifted(points[0], points[np-1], offset);
- *shifted = QBezier::fromPoints(l.p1(), l.pointAt(qreal(0.33)), l.pointAt(qreal(0.66)), l.p2());
- return Ok;
- }
-
QRectF b = orig->bounds();
if (np == 4 && b.width() < .1*offset && b.height() < .1*offset) {
qreal l = (orig->x1 - orig->x2)*(orig->x1 - orig->x2) +
diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp
index 0edf256315..e0c2d16d8c 100644
--- a/src/gui/painting/qblendfunctions.cpp
+++ b/src/gui/painting/qblendfunctions.cpp
@@ -309,9 +309,9 @@ template <typename T> void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl,
const uchar *src = srcPixels + y * sbpl;
const uchar *srcEnd = src + srcOffset;
while (src < srcEnd) {
-#if defined(QT_ARCH_ARM) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU))
+#if defined(QT_ARCH_ARMV5) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU))
// non-16-bit aligned memory access is not possible on PowerPC,
- // ARM <v6 (QT_ARCH_ARMV6) & SH & AVR32 & SPARC w/GCC
+ // ARM <v6 (QT_ARCH_ARMV5) & SH & AVR32 & SPARC w/GCC
quint16 spix = (quint16(src[2])<<8) + src[1];
#else
quint16 spix = *(quint16 *) (src + 1);
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index d3061d8a2b..d0788c70dc 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1218,17 +1218,16 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\o QConicalGradient
\endtable
- The colors in a gradient is defined using stop points of the
- QGradientStop type, i.e. a position and a color. Use the
- setColorAt() function to define a single stop
- point. Alternatively, use the setStops() function to define
- several stop points in one go. Note that the latter function \e
- replaces the current set of stop points.
+ The colors in a gradient are defined using stop points of the
+ QGradientStop type; i.e., a position and a color. Use the setColorAt()
+ function to define a single stop point. Alternatively, use the
+ setStops() function to define several stop points in one go. Note that
+ the latter function \e replaces the current set of stop points.
It is the gradient's complete set of stop points (accessible
through the stops() function) that describes how the gradient area
- should be filled. If no stop points have been specified, a
- gradient of black at 0 to white at 1 is used.
+ should be filled. If no stop points have been specified, a gradient
+ of black at 0 to white at 1 is used.
A diagonal linear gradient from black at (100, 100) to white at
(200, 200) could be specified like this:
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index bd5b0bdf09..5f190ba1ce 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -4835,7 +4835,7 @@ void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
if (SRC::hasAlpha()) {
while (length >= 4) {
- const quint32 alpha = BYTE_MUL(uint(alpha_4(src)), uint(coverage));
+ const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
if (alpha)
interpolate_pixel_4(dest, src, alpha);
length -= 4;
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index ba2ba323f9..f97d86540c 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -266,10 +266,10 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, int count)
int n = (count128 + 3) / 4;
switch (count128 & 0x3) {
- case 0: do { _mm_store_si128(dst128++, value128);
- case 3: _mm_store_si128(dst128++, value128);
- case 2: _mm_store_si128(dst128++, value128);
- case 1: _mm_store_si128(dst128++, value128);
+ case 0: do { _mm_stream_si128(dst128++, value128);
+ case 3: _mm_stream_si128(dst128++, value128);
+ case 2: _mm_stream_si128(dst128++, value128);
+ case 1: _mm_stream_si128(dst128++, value128);
} while (--n > 0);
}
@@ -300,11 +300,14 @@ void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, u
const __m128i half = _mm_set1_epi16(0x80);
const __m128i minusAlphaOfColorVector = _mm_set1_epi16(minusAlphaOfColor);
+ ALIGNMENT_PROLOGUE_16BYTES(dst, x, length)
+ destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
+
for (; x < length-3; x += 4) {
- __m128i dstVector = _mm_loadu_si128((__m128i *)&dst[x]);
+ __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]);
BYTE_MUL_SSE2(dstVector, dstVector, minusAlphaOfColorVector, colorMask, half);
dstVector = _mm_add_epi8(colorVector, dstVector);
- _mm_storeu_si128((__m128i *)&dst[x], dstVector);
+ _mm_store_si128((__m128i *)&dst[x], dstVector);
}
for (;x < length; ++x)
destPixels[x] = color + BYTE_MUL(destPixels[x], minusAlphaOfColor);
diff --git a/src/gui/painting/qdrawhelper_ssse3.cpp b/src/gui/painting/qdrawhelper_ssse3.cpp
index 4cb40895ba..fb5602e5c3 100644
--- a/src/gui/painting/qdrawhelper_ssse3.cpp
+++ b/src/gui/painting/qdrawhelper_ssse3.cpp
@@ -79,69 +79,6 @@ inline static void blend_pixel(quint32 &dst, const quint32 src)
}
-#define BLEND_SOURCE_OVER_ARGB32_FIRST_ROW_SSSE3(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
- int x = 0; \
-\
- /* First, get dst aligned. */ \
- const int offsetToAlignOn16Bytes = (4 - ((reinterpret_cast<quintptr>(dst) >> 2) & 0x3)) & 0x3;\
- const int prologLength = qMin(length, offsetToAlignOn16Bytes);\
-\
- for (; x < prologLength; ++x) {\
- blend_pixel(dst[x], src[x]); \
- } \
-\
- const int minusOffsetToAlignSrcOn16Bytes = (reinterpret_cast<quintptr>(&(src[x])) >> 2) & 0x3;\
-\
- if (!minusOffsetToAlignSrcOn16Bytes) {\
- /* src is aligned, usual algorithm but with aligned operations.\
- See the SSE2 version for more documentation on the algorithm itself. */\
- const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
- for (; x < length-3; x += 4) { \
- const __m128i srcVector = _mm_load_si128((__m128i *)&src[x]); \
- const __m128i srcVectorAlpha = _mm_and_si128(srcVector, alphaMask); \
- if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, alphaMask)) == 0xffff) { \
- _mm_store_si128((__m128i *)&dst[x], srcVector); \
- } else if (_mm_movemask_epi8(_mm_cmpeq_epi32(srcVectorAlpha, nullVector)) != 0xffff) { \
- __m128i alphaChannel = _mm_shuffle_epi8(srcVector, alphaShuffleMask); \
- alphaChannel = _mm_sub_epi16(one, alphaChannel); \
- const __m128i dstVector = _mm_load_si128((__m128i *)&dst[x]); \
- __m128i destMultipliedByOneMinusAlpha; \
- BYTE_MUL_SSE2(destMultipliedByOneMinusAlpha, dstVector, alphaChannel, colorMask, half); \
- const __m128i result = _mm_add_epi8(srcVector, destMultipliedByOneMinusAlpha); \
- _mm_store_si128((__m128i *)&dst[x], result); \
- } \
- } /* end for() */\
- } else if ((length - x) >= 8) {\
- /* We are at the first line, so "x - minusOffsetToAlignSrcOn16Bytes" could go before src, and\
- generate an invalid access. */\
-\
- /* We use two vectors to extract the src: prevLoaded for the first pixels, lastLoaded for the current pixels. */\
- __m128i srcVectorPrevLoaded;\
- if (minusOffsetToAlignSrcOn16Bytes > prologLength) {\
- /* We go forward 4 pixels to avoid reading before src. */\
- for (; x < prologLength + 4; ++x)\
- blend_pixel(dst[x], src[x]); \
- }\
- srcVectorPrevLoaded = _mm_load_si128((__m128i *)&src[x - minusOffsetToAlignSrcOn16Bytes]);\
- const int palignrOffset = minusOffsetToAlignSrcOn16Bytes << 2;\
-\
- const __m128i alphaShuffleMask = _mm_set_epi8(0xff,15,0xff,15,0xff,11,0xff,11,0xff,7,0xff,7,0xff,3,0xff,3);\
- switch (palignrOffset) {\
- case 4:\
- BLENDING_LOOP(4, length)\
- break;\
- case 8:\
- BLENDING_LOOP(8, length)\
- break;\
- case 12:\
- BLENDING_LOOP(12, length)\
- break;\
- }\
- }\
- for (; x < length; ++x) \
- blend_pixel(dst[x], src[x]); \
-}
-
// Basically blend src over dst with the const alpha defined as constAlphaVector.
// nullVector, half, one, colorMask are constant accross the whole image/texture, and should be defined as:
//const __m128i nullVector = _mm_set1_epi32(0);
@@ -153,7 +90,7 @@ inline static void blend_pixel(quint32 &dst, const quint32 src)
// The computation being done is:
// result = s + d * (1-alpha)
// with shortcuts if fully opaque or fully transparent.
-#define BLEND_SOURCE_OVER_ARGB32_MAIN_SSSE3(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
+#define BLEND_SOURCE_OVER_ARGB32_SSSE3(dst, src, length, nullVector, half, one, colorMask, alphaMask) { \
int x = 0; \
\
/* First, get dst aligned. */ \
@@ -218,14 +155,8 @@ void qt_blend_argb32_on_argb32_ssse3(uchar *destPixels, int dbpl,
const __m128i one = _mm_set1_epi16(0xff);
const __m128i colorMask = _mm_set1_epi32(0x00ff00ff);
- // We have to unrol the first row in order to deal with the load on unaligned data
- // prior to the src pointer.
- BLEND_SOURCE_OVER_ARGB32_FIRST_ROW_SSSE3(dst, src, w, nullVector, half, one, colorMask, alphaMask);
- dst = (quint32 *)(((uchar *) dst) + dbpl);
- src = (const quint32 *)(((const uchar *) src) + sbpl);
-
- for (int y = 1; y < h; ++y) {
- BLEND_SOURCE_OVER_ARGB32_MAIN_SSSE3(dst, src, w, nullVector, half, one, colorMask, alphaMask);
+ for (int y = 0; y < h; ++y) {
+ BLEND_SOURCE_OVER_ARGB32_SSSE3(dst, src, w, nullVector, half, one, colorMask, alphaMask);
dst = (quint32 *)(((uchar *) dst) + dbpl);
src = (const quint32 *)(((const uchar *) src) + sbpl);
}
diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp
index 2828e9db61..a9fbbeeb2f 100644
--- a/src/gui/painting/qgraphicssystem_runtime.cpp
+++ b/src/gui/painting/qgraphicssystem_runtime.cpp
@@ -94,7 +94,8 @@ QRuntimePixmapData::QRuntimePixmapData(const QRuntimeGraphicsSystem *gs, PixelTy
QRuntimePixmapData::~QRuntimePixmapData()
{
- m_graphicsSystem->removePixmapData(this);
+ if (QApplicationPrivate::graphics_system)
+ m_graphicsSystem->removePixmapData(this);
delete m_data;
}
@@ -258,7 +259,8 @@ QRuntimeWindowSurface::QRuntimeWindowSurface(const QRuntimeGraphicsSystem *gs, Q
QRuntimeWindowSurface::~QRuntimeWindowSurface()
{
- m_graphicsSystem->removeWindowSurface(this);
+ if (QApplicationPrivate::graphics_system)
+ m_graphicsSystem->removeWindowSurface(this);
}
QPaintDevice *QRuntimeWindowSurface::paintDevice()
diff --git a/src/gui/painting/qgraphicssystem_runtime_p.h b/src/gui/painting/qgraphicssystem_runtime_p.h
index 02322418fe..421fbeb941 100644
--- a/src/gui/painting/qgraphicssystem_runtime_p.h
+++ b/src/gui/painting/qgraphicssystem_runtime_p.h
@@ -177,6 +177,7 @@ private:
friend class QRuntimePixmapData;
friend class QRuntimeWindowSurface;
+ friend class QMeeGoGraphicsSystem;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp
index ee6fbd8341..3adeba4dc2 100644
--- a/src/gui/painting/qgraphicssystemfactory.cpp
+++ b/src/gui/painting/qgraphicssystemfactory.cpp
@@ -73,7 +73,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key)
if (system.isEmpty()) {
system = QLatin1String("runtime");
}
-#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN)
+#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11)
if (system.isEmpty()) {
system = QLatin1String("raster");
}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 4792f00021..3d963a734b 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -3100,9 +3100,17 @@ void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
int margin = cache->glyphMargin();
+ bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
+
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
- const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
+
+ QFixed subPixelPosition;
+ if (supportsSubPixelPositions)
+ subPixelPosition = cache->subPixelPositionForX(positions[i].x);
+ QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
+ const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
+
int x = qFloor(positions[i].x) + c.baseLineX - margin;
int y = qFloor(positions[i].y) - c.baseLineY - margin;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 881bd6e145..1e857e4c91 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -768,7 +768,7 @@ void QPaintEngineEx::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yR
x1, y2 - (1 - KAPPA) * yRadius,
x1, y2 - yRadius,
x1, y1 + yRadius, // LineTo
- x1, y1 + KAPPA * yRadius, // CurveTo
+ x1, y1 + (1 - KAPPA) * yRadius, // CurveTo
x1 + (1 - KAPPA) * xRadius, y1,
x1 + xRadius, y1
};
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 004d9cd7e9..35a74c9f16 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -2737,6 +2737,8 @@ QRectF QPainter::clipBoundingRect() const
if (info.clipType == QPainterClipInfo::RectClip)
r = info.rect;
+ else if (info.clipType == QPainterClipInfo::RectFClip)
+ r = info.rectf;
else if (info.clipType == QPainterClipInfo::RegionClip)
r = info.region.boundingRect();
else
@@ -8932,7 +8934,7 @@ QPainterPath QPaintEngineState::clipPath() const
}
/*!
- Returns wether clipping is enabled or not in the current paint
+ Returns whether clipping is enabled or not in the current paint
engine state.
This variable should only be used when the state() returns a
diff --git a/src/gui/painting/qprintengine_ps.cpp b/src/gui/painting/qprintengine_ps.cpp
index 28e9a7a309..ca694ae6a7 100644
--- a/src/gui/painting/qprintengine_ps.cpp
+++ b/src/gui/painting/qprintengine_ps.cpp
@@ -64,7 +64,6 @@
#include "qbitmap.h"
#include "qregion.h"
#include "qimagewriter.h"
-#include <private/qunicodetables_p.h>
#include <private/qpainterpath_p.h>
#include <qdebug.h>
#include <private/qdrawhelper_p.h>
diff --git a/src/gui/painting/qprintengine_win.cpp b/src/gui/painting/qprintengine_win.cpp
index dd4de997b5..afae0a51e5 100644
--- a/src/gui/painting/qprintengine_win.cpp
+++ b/src/gui/painting/qprintengine_win.cpp
@@ -851,7 +851,7 @@ void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QC
HPEN pen = ExtCreatePen(((penWidth == 0) ? PS_COSMETIC : PS_GEOMETRIC)
| PS_SOLID | capStyle | joinStyle,
- penWidth, &brush, 0, 0);
+ (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
HGDIOBJ old_pen = SelectObject(hdc, pen);
StrokePath(hdc);
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index c57db829e4..c5d5dc931c 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -1699,8 +1699,8 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include <limits.h>
QT_END_INCLUDE_NAMESPACE
-/* 1 if two BOXs overlap.
- * 0 if two BOXs do not overlap.
+/* 1 if two BOXes overlap.
+ * 0 if two BOXes do not overlap.
* Remember, x2 and y2 are not in the region
*/
#define EXTENTCHECK(r1, r2) \
diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp
index eabbd8a602..9cff3390be 100644
--- a/src/gui/painting/qstroker.cpp
+++ b/src/gui/painting/qstroker.cpp
@@ -609,7 +609,7 @@ void QStroker::joinPoints(qfixed focal_x, qfixed focal_y, const QLineF &nextLine
}
QLineF miterLine(QPointF(qt_fixed_to_real(focal_x),
qt_fixed_to_real(focal_y)), isect);
- if (miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) {
+ if (type == QLineF::NoIntersection || miterLine.length() > qt_fixed_to_real(m_strokeWidth * m_miterLimit) / 2) {
emitLineTo(qt_real_to_fixed(nextLine.x1()),
qt_real_to_fixed(nextLine.y1()));
} else {
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 376219ba8f..92198765f1 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -47,10 +47,6 @@
#include "private/qnativeimage_p.h"
#include "private/qfontengine_ft_p.h"
-#ifndef QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH
-#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH 256
-#endif
-
QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
@@ -69,8 +65,60 @@ static inline int qt_next_power_of_two(int v)
return v;
}
+int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
+{
+ // Test 12 different subpixel positions since it factors into 3*4 so it gives
+ // the coverage we need.
+
+ QList<QImage> images;
+ for (int i=0; i<12; ++i) {
+ QImage img = textureMapForGlyph(glyph, QFixed::fromReal(i / 12.0));
+
+ if (images.isEmpty()) {
+ QPainterPath path;
+ QFixedPoint point;
+ m_current_fontengine->addGlyphsToPath(&glyph, &point, 1, &path, QTextItem::RenderFlags());
+
+ // Glyph is space, return 0 to indicate that we need to keep trying
+ if (path.isEmpty())
+ break;
+
+ images.append(img);
+ } else {
+ bool found = false;
+ for (int j=0; j<images.size(); ++j) {
+ if (images.at(j) == img) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ images.append(img);
+ }
+ }
+
+ return images.size();
+}
+
+QFixed QTextureGlyphCache::subPixelPositionForX(QFixed x) const
+{
+ if (m_subPixelPositionCount == 0)
+ return QFixed();
+
+ QFixed subPixelPosition;
+ if (x != 0) {
+ subPixelPosition = x - x.floor();
+ QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
+
+ // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
+ // the lower boundary for the selected rasterization by adding 1/64.
+ subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
+ }
+ return subPixelPosition;
+}
+
void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *)
+ const QFixedPoint *positions)
{
#ifdef CACHE_DEBUG
printf("Populating with %d glyphs\n", numGlyphs);
@@ -81,15 +129,33 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
const int margin = glyphMargin();
const int paddingDoubled = glyphPadding() * 2;
- QHash<glyph_t, Coord> listItemCoordinates;
+ bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
+ if (m_subPixelPositionCount == 0) {
+ if (!supportsSubPixelPositions) {
+ m_subPixelPositionCount = 1;
+ } else {
+ int i = 0;
+ while (m_subPixelPositionCount == 0 && i < numGlyphs)
+ m_subPixelPositionCount = calculateSubPixelPositionCount(glyphs[i++]);
+ }
+ }
+
+ QHash<GlyphAndSubPixelPosition, Coord> listItemCoordinates;
int rowHeight = 0;
// check each glyph for its metrics and get the required rowHeight.
for (int i=0; i < numGlyphs; ++i) {
const glyph_t glyph = glyphs[i];
- if (coords.contains(glyph))
+
+ QFixed subPixelPosition;
+ if (supportsSubPixelPositions) {
+ QFixed x = positions != 0 ? positions[i].x : QFixed();
+ subPixelPosition = subPixelPositionForX(x);
+ }
+
+ if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
continue;
- if (listItemCoordinates.contains(glyph))
+ if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
continue;
glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform);
@@ -119,7 +185,7 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
metrics.x.round().truncate(),
-metrics.y.truncate() }; // baseline for horizontal scripts
- listItemCoordinates.insert(glyph, c);
+ listItemCoordinates.insert(GlyphAndSubPixelPosition(glyph, subPixelPosition), c);
rowHeight = qMax(rowHeight, glyph_height);
}
if (listItemCoordinates.isEmpty())
@@ -135,17 +201,25 @@ void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
}
// now actually use the coords and paint the wanted glyps into cache.
- QHash<glyph_t, Coord>::iterator iter = listItemCoordinates.begin();
+ QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = listItemCoordinates.begin();
+ int requiredWidth = m_w;
while (iter != listItemCoordinates.end()) {
Coord c = iter.value();
m_currentRowHeight = qMax(m_currentRowHeight, c.h + margin * 2);
- if (m_cx + c.w > m_w) {
- // no room on the current line, start new glyph strip
- m_cx = 0;
- m_cy += m_currentRowHeight + paddingDoubled;
- m_currentRowHeight = 0; // New row
+ if (m_cx + c.w > requiredWidth) {
+ int new_width = requiredWidth*2;
+ while (new_width < m_cx + c.w)
+ new_width *= 2;
+ if (new_width <= maxTextureWidth()) {
+ requiredWidth = new_width;
+ } else {
+ // no room on the current line, start new glyph strip
+ m_cx = 0;
+ m_cy += m_currentRowHeight + paddingDoubled;
+ m_currentRowHeight = 0; // New row
+ }
}
c.x = m_cx;
@@ -164,27 +238,30 @@ void QTextureGlyphCache::fillInPendingGlyphs()
if (m_pendingGlyphs.isEmpty())
return;
- int requiredHeight = 0;
+ int requiredHeight = m_h;
+ int requiredWidth = m_w; // Use a minimum size to avoid a lot of initial reallocations
{
- QHash<glyph_t, Coord>::iterator iter = m_pendingGlyphs.begin();
+ QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
while (iter != m_pendingGlyphs.end()) {
Coord c = iter.value();
requiredHeight = qMax(requiredHeight, c.y + c.h);
+ requiredWidth = qMax(requiredWidth, c.x + c.w);
++iter;
}
}
- if (requiredHeight > m_h) {
+ if (isNull() || requiredHeight > m_h || requiredWidth > m_w) {
if (isNull())
- createCache(m_w, qt_next_power_of_two(requiredHeight));
+ createCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight));
else
- resizeCache(m_w, qt_next_power_of_two(requiredHeight));
+ resizeCache(qt_next_power_of_two(requiredWidth), qt_next_power_of_two(requiredHeight));
}
{
- QHash<glyph_t, Coord>::iterator iter = m_pendingGlyphs.begin();
+ QHash<GlyphAndSubPixelPosition, Coord>::iterator iter = m_pendingGlyphs.begin();
while (iter != m_pendingGlyphs.end()) {
- fillTexture(iter.value(), iter.key());
+ GlyphAndSubPixelPosition key = iter.key();
+ fillTexture(iter.value(), key.glyph, key.subPixelPosition);
++iter;
}
@@ -193,7 +270,7 @@ void QTextureGlyphCache::fillInPendingGlyphs()
m_pendingGlyphs.clear();
}
-QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
+QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const
{
#if defined(Q_WS_X11)
if (m_transform.type() > QTransform::TxTranslate) {
@@ -226,7 +303,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
} else
#endif
if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
- return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
+ return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, glyphMargin(), m_transform);
else
return m_current_fontengine->alphaMapForGlyph(g, m_transform);
@@ -272,9 +349,9 @@ int QImageTextureGlyphCache::glyphMargin() const
#endif
}
-void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g)
+void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition)
{
- QImage mask = textureMapForGlyph(g);
+ QImage mask = textureMapForGlyph(g, subPixelPosition);
#ifdef CACHE_DEBUG
printf("fillTexture of %dx%d at %d,%d in the cache of %dx%d\n", c.w, c.h, c.x, c.y, m_image.width(), m_image.height());
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index 0770ed41bc..82aaf0de88 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -64,6 +64,10 @@
# undef m_type
#endif
+#ifndef QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH
+#define QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH 256
+#endif
+
struct glyph_metrics_t;
typedef unsigned int glyph_t;
@@ -77,11 +81,24 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache
public:
QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
: QFontEngineGlyphCache(matrix, type), m_current_fontengine(0),
- m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0)
+ m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0), m_subPixelPositionCount(0)
{ }
virtual ~QTextureGlyphCache() { }
+ struct GlyphAndSubPixelPosition
+ {
+ GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
+
+ bool operator==(const GlyphAndSubPixelPosition &other) const
+ {
+ return glyph == other.glyph && subPixelPosition == other.subPixelPosition;
+ }
+
+ glyph_t glyph;
+ QFixed subPixelPosition;
+ };
+
struct Coord {
int x;
int y;
@@ -101,7 +118,7 @@ public:
virtual int glyphMargin() const { return 0; }
virtual int glyphPadding() const { return 0; }
- virtual void fillTexture(const Coord &coord, glyph_t glyph) = 0;
+ virtual void fillTexture(const Coord &coord, glyph_t glyph, QFixed subPixelPosition) = 0;
inline void createCache(int width, int height) {
m_w = width;
@@ -118,22 +135,33 @@ public:
inline bool isNull() const { return m_h == 0; }
- QHash<glyph_t, Coord> coords;
+ QHash<GlyphAndSubPixelPosition, Coord> coords;
+ virtual int maxTextureWidth() const { return QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; }
+ virtual int maxTextureHeight() const { return 32768; }
+
+ QImage textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const;
- QImage textureMapForGlyph(glyph_t g) const;
+ QFixed subPixelPositionForX(QFixed x) const;
protected:
- QFontEngine *m_current_fontengine;
+ int calculateSubPixelPositionCount(glyph_t) const;
- QHash<glyph_t, Coord> m_pendingGlyphs;
+ QFontEngine *m_current_fontengine;
+ QHash<GlyphAndSubPixelPosition, Coord> m_pendingGlyphs;
int m_w; // image width
int m_h; // image height
int m_cx; // current x
int m_cy; // current y
int m_currentRowHeight; // Height of last row
+ int m_subPixelPositionCount; // Number of positions within a single pixel for this cache
};
+inline uint qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g)
+{
+ return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();
+}
+
class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache
{
@@ -143,7 +171,7 @@ public:
virtual int glyphMargin() const;
virtual void createTextureData(int width, int height);
virtual void resizeTextureData(int width, int height);
- virtual void fillTexture(const Coord &c, glyph_t glyph);
+ virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition);
inline const QImage &image() const { return m_image; }