summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/embedded/directfb.pri2
-rw-r--r--src/gui/painting/qemulationpaintengine.cpp5
-rw-r--r--src/gui/painting/qemulationpaintengine_p.h1
-rw-r--r--src/gui/painting/qpaintbuffer.cpp26
-rw-r--r--src/gui/painting/qpaintbuffer_p.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp41
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h5
-rw-r--r--src/gui/painting/qpaintengineex_p.h3
-rw-r--r--src/gui/painting/qpainter.cpp109
-rw-r--r--src/gui/painting/qpainter_p.h6
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp17
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h10
-rw-r--r--src/gui/text/qstatictext.cpp551
-rw-r--r--src/gui/text/qstatictext_p.h109
-rw-r--r--src/gui/text/qstatictext_p_p.h141
-rw-r--r--src/gui/text/text.pri7
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp6
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h16
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp227
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h4
-rw-r--r--src/opengl/qglextensions_p.h8
-rw-r--r--src/opengl/qpaintengine_opengl.cpp94
-rw-r--r--src/opengl/qpaintengine_opengl_p.h1
-rw-r--r--src/openvg/qpaintengine_vg.cpp73
-rw-r--r--src/openvg/qpaintengine_vg_p.h4
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp10
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h2
27 files changed, 1349 insertions, 131 deletions
diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri
index bd1d947..d6d77b4 100644
--- a/src/gui/embedded/directfb.pri
+++ b/src/gui/embedded/directfb.pri
@@ -15,7 +15,7 @@
#DEFINES += QT_DIRECTFB_TIMING
#DEFINES += QT_NO_DIRECTFB_OPAQUE_DETECTION
#DEFINES += QT_NO_DIRECTFB_STRETCHBLIT
-#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT
+#DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT|DRAW_STATICTEXT
#DEFINES += \"QT_DIRECTFB_WARN_ON_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\"
#DEFINES += \"QT_DIRECTFB_DISABLE_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\"
diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp
index f2f0c73..4067b97 100644
--- a/src/gui/painting/qemulationpaintengine.cpp
+++ b/src/gui/painting/qemulationpaintengine.cpp
@@ -175,6 +175,11 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text
real_engine->drawTextItem(p, textItem);
}
+void QEmulationPaintEngine::drawStaticTextItem(QStaticTextItem *item)
+{
+ real_engine->drawStaticTextItem(item);
+}
+
void QEmulationPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s)
{
if (state()->bgMode == Qt::OpaqueMode && pixmap.isQBitmap())
diff --git a/src/gui/painting/qemulationpaintengine_p.h b/src/gui/painting/qemulationpaintengine_p.h
index 0ed641b..5835f10 100644
--- a/src/gui/painting/qemulationpaintengine_p.h
+++ b/src/gui/painting/qemulationpaintengine_p.h
@@ -78,6 +78,7 @@ public:
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ virtual void drawStaticTextItem(QStaticTextItem *item);
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags);
diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp
index 2344c04..51eb681 100644
--- a/src/gui/painting/qpaintbuffer.cpp
+++ b/src/gui/painting/qpaintbuffer.cpp
@@ -45,6 +45,8 @@
#include <private/qfontengine_p.h>
#include <private/qemulationpaintengine_p.h>
#include <private/qimage_p.h>
+#include <private/qstatictext_p.h>
+#include <private/qstatictext_p_p.h>
#include <QDebug>
@@ -960,6 +962,18 @@ void QPaintBufferEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
buffer->updateBoundingRect(r);
}
+void QPaintBufferEngine::drawStaticTextItem(QStaticTextItem *staticTextItem)
+{
+ QString text = QString(staticTextItem->chars, staticTextItem->numChars);
+
+ QStaticText staticText(text);
+ staticText.prepare(state()->matrix, staticTextItem->font);
+
+ QVariantList variants;
+ variants << QVariant(staticTextItem->font) << QVariant::fromValue(staticText);
+ buffer->addCommand(QPaintBufferPrivate::Cmd_DrawStaticText, QVariant(variants));
+}
+
void QPaintBufferEngine::drawTextItem(const QPointF &pos, const QTextItem &ti)
{
#ifdef QPAINTBUFFER_DEBUG_DRAW
@@ -1425,6 +1439,18 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd)
#endif
painter->setClipRegion(region, Qt::ClipOperation(cmd.extra));
break; }
+
+ case QPaintBufferPrivate::Cmd_DrawStaticText: {
+
+ QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>());
+
+ QFont font(variants.at(0).value<QFont>());
+ QStaticText text(variants.at(0).value<QStaticText>());
+
+ painter->setFont(font);
+ qt_draw_static_text(painter, QPointF(0, 0), text);
+
+ break; }
case QPaintBufferPrivate::Cmd_DrawText: {
QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h
index 79d7b35..41a26c5 100644
--- a/src/gui/painting/qpaintbuffer_p.h
+++ b/src/gui/painting/qpaintbuffer_p.h
@@ -175,6 +175,7 @@ public:
Cmd_DrawText,
Cmd_DrawTextItem,
+ Cmd_DrawStaticText,
Cmd_DrawImagePos,
Cmd_DrawImageRect,
@@ -394,6 +395,7 @@ public:
virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s);
virtual void drawTextItem(const QPointF &pos, const QTextItem &ti);
+ virtual void drawStaticTextItem(QStaticTextItem *staticTextItem);
virtual void setState(QPainterState *s);
virtual uint flags() const {return QPaintEngineEx::DoNotEmulate;}
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index bc56ed0..a2e14e1 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -67,6 +67,7 @@
// #include <private/qpolygonclipper_p.h>
// #include <private/qrasterizer_p.h>
#include <private/qimage_p.h>
+#include <private/qstatictext_p_p.h>
#include "qpaintengine_raster_p.h"
// #include "qbezier_p.h"
@@ -3006,27 +3007,22 @@ void QRasterPaintEngine::alphaPenBlt(const void* src, int bpl, int depth, int rx
blend(current, spans, &s->penData);
}
-void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
+void QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *positions, QFontEngine *fontEngine)
{
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = s->matrix;
- matrix.translate(p.x(), p.y());
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
- QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType;
+ QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(fontEngine->glyphFormat) : d->glyphCacheType;
QImageTextureGlyphCache *cache =
- (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix);
+ static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphType, s->matrix));
if (!cache) {
cache = new QImageTextureGlyphCache(glyphType, s->matrix);
- ti.fontEngine->setGlyphCache(0, cache);
+ fontEngine->setGlyphCache(0, cache);
}
- cache->populate(ti, glyphs, positions);
+ cache->populate(fontEngine, numGlyphs, glyphs, positions);
const QImage &image = cache->image();
int bpl = image.bytesPerLine();
@@ -3044,7 +3040,7 @@ void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt &
const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
const uchar *bits = image.bits();
- for (int i=0; i<glyphs.size(); ++i) {
+ for (int i=0; i<numGlyphs; ++i) {
const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
int x = qFloor(positions[i].x + offs) + c.baseLineX - margin;
int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
@@ -3221,6 +3217,15 @@ QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
}
+void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
+{
+ ensurePen();
+ ensureState();
+
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
+ textItem->fontEngine);
+}
+
/*!
\reimp
*/
@@ -3269,7 +3274,17 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
drawCached = false;
#endif
if (drawCached) {
- drawCachedGlyphs(p, ti);
+ QRasterPaintEngineState *s = state();
+
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+
+ QTransform matrix = s->matrix;
+ matrix.translate(p.x(), p.y());
+
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ drawCachedGlyphs(glyphs.size(), glyphs.constData(), positions.constData(), ti.fontEngine);
return;
}
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index a1c73cc..55eb82e 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -203,6 +203,8 @@ public:
void clip(const QRect &rect, Qt::ClipOperation op);
void clip(const QRegion &region, Qt::ClipOperation op);
+ void drawStaticTextItem(QStaticTextItem *textItem);
+
enum ClipType {
RectClip,
ComplexClip
@@ -257,7 +259,8 @@ private:
void fillRect(const QRectF &rect, QSpanData *data);
void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill);
- void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
+ void drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions,
+ QFontEngine *fontEngine);
#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
void drawGlyphsS60(const QPointF &p, const QTextItemInt &ti);
diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h
index fccd1dc..90c4f9f 100644
--- a/src/gui/painting/qpaintengineex_p.h
+++ b/src/gui/painting/qpaintengineex_p.h
@@ -70,6 +70,7 @@ QT_MODULE(Gui)
class QPainterState;
class QPaintEngineExPrivate;
+class QStaticTextItem;
struct StrokeHandler;
struct QIntRect {
@@ -200,6 +201,8 @@ public:
virtual void updateState(const QPaintEngineState &state);
+ virtual void drawStaticTextItem(QStaticTextItem *) = 0;
+
virtual void setState(QPainterState *s);
inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); }
inline const QPainterState *state() const { return static_cast<const QPainterState *>(QPaintEngine::state); }
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index bf12c6b..0d47260 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -69,6 +69,8 @@
#include <private/qwidget_p.h>
#include <private/qpaintengine_raster_p.h>
#include <private/qmath_p.h>
+#include <private/qstatictext_p.h>
+#include <private/qstatictext_p_p.h>
QT_BEGIN_NAMESPACE
@@ -5705,6 +5707,113 @@ void QPainter::drawText(const QPointF &p, const QString &str)
drawText(p, str, 0, 0);
}
+QPainterPrivate *QPainterPrivate::get(QPainter *p)
+{
+ return p->d_ptr.data();
+}
+
+void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text)
+{
+ QPainterPrivate *prv = QPainterPrivate::get(p);
+ Q_ASSERT(prv != 0);
+
+ prv->drawStaticText(position, text);
+}
+
+void QPainterPrivate::drawStaticText(const QPointF &position, const QStaticText &staticText)
+{
+ Q_Q(QPainter);
+ if (!engine || staticText.isEmpty() || q->pen().style() == Qt::NoPen)
+ return;
+
+ QStaticTextPrivate *staticText_d =
+ const_cast<QStaticTextPrivate *>(QStaticTextPrivate::get(&staticText));
+
+ // If we don't have an extended paint engine, or if the painter is projected,
+ // we go through standard code path
+ if (extended == 0 || !state->matrix.isAffine()) {
+ if (staticText_d->size.isValid())
+ q->drawText(QRectF(position, staticText_d->size), staticText_d->text);
+ else
+ q->drawText(position, staticText_d->text);
+ return;
+ }
+
+ // Don't recalculate entire layout because of translation, rather add the dx and dy
+ // into the position to move each text item the correct distance.
+ QPointF transformedPosition = position * state->matrix;
+ QTransform matrix = state->matrix;
+
+ // The translation has been applied to transformedPosition. Remove translation
+ // component from matrix.
+ if (state->matrix.isTranslating()) {
+ qreal m11 = state->matrix.m11();
+ qreal m12 = state->matrix.m12();
+ qreal m13 = state->matrix.m13();
+ qreal m21 = state->matrix.m21();
+ qreal m22 = state->matrix.m22();
+ qreal m23 = state->matrix.m23();
+ qreal m33 = state->matrix.m33();
+
+ state->matrix.setMatrix(m11, m12, m13,
+ m21, m22, m23,
+ 0.0, 0.0, m33);
+ }
+
+ // If the transform is not identical to the text transform,
+ // we have to relayout the text (for other transformations than plain translation)
+ bool staticTextNeedsReinit = false;
+ if (staticText_d->matrix != state->matrix) {
+ staticText_d->matrix = state->matrix;
+ staticTextNeedsReinit = true;
+ }
+
+ bool restoreWhenFinished = false;
+ if (staticText_d->needsClipRect) {
+ q->save();
+ q->setClipRect(QRectF(position, staticText_d->size));
+
+ restoreWhenFinished = true;
+ }
+
+ if (q->font() != staticText_d->font) {
+ staticText_d->font = q->font();
+ staticTextNeedsReinit = true;
+ }
+
+ // Recreate the layout of the static text because the matrix or font has changed
+ if (staticTextNeedsReinit)
+ staticText_d->init();
+
+ if (transformedPosition != staticText_d->position) { // Translate to actual position
+ QFixed fx = QFixed::fromReal(transformedPosition.x());
+ QFixed fy = QFixed::fromReal(transformedPosition.y());
+ QFixed oldX = QFixed::fromReal(staticText_d->position.x());
+ QFixed oldY = QFixed::fromReal(staticText_d->position.y());
+ for (int item=0; item<staticText_d->itemCount;++item) {
+ QStaticTextItem *textItem = staticText_d->items + item;
+ for (int i=0; i<textItem->numGlyphs; ++i) {
+ textItem->glyphPositions[i].x += fx - oldX;
+ textItem->glyphPositions[i].y += fy - oldY;
+ }
+ textItem->userDataNeedsUpdate = true;
+ }
+
+ staticText_d->position = transformedPosition;
+ }
+
+ for (int i=0; i<staticText_d->itemCount; ++i) {
+ QStaticTextItem *item = staticText_d->items + i;
+ extended->drawStaticTextItem(item);
+ }
+
+ if (restoreWhenFinished)
+ q->restore();
+
+ if (matrix.isTranslating())
+ state->matrix = matrix;
+}
+
/*!
\internal
*/
diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h
index 02a91aa..2979de6 100644
--- a/src/gui/painting/qpainter_p.h
+++ b/src/gui/painting/qpainter_p.h
@@ -70,6 +70,7 @@ QT_BEGIN_NAMESPACE
class QPaintEngine;
class QEmulationPaintEngine;
class QPaintEngineEx;
+class QStaticText;
struct QTLWExtra;
@@ -229,6 +230,8 @@ public:
void drawStretchedGradient(const QPainterPath &path, DrawOperation operation);
void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation);
+ void drawStaticText(const QPointF &position, const QStaticText &staticText);
+
void updateMatrix();
void updateInvMatrix();
@@ -242,6 +245,8 @@ public:
static bool attachPainterPrivate(QPainter *q, QPaintDevice *pdev);
void detachPainterPrivate(QPainter *q);
+ static QPainterPrivate *get(QPainter *p);
+
QPaintDevice *device;
QPaintDevice *original_device;
QPaintDevice *helper_device;
@@ -252,6 +257,7 @@ public:
};
Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation);
+Q_GUI_EXPORT void qt_draw_static_text(QPainter *p, const QPointF &position, const QStaticText &text);
QString qt_generate_brush_key(const QBrush &brush);
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 7b7f325..7f32d19 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -55,29 +55,28 @@ QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
-void QTextureGlyphCache::populate(const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs,
- const QVarLengthArray<QFixedPoint> &)
+void QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *)
{
#ifdef CACHE_DEBUG
printf("Populating with '%s'\n", QString::fromRawData(ti.chars, ti.num_chars).toLatin1().data());
qDebug() << " -> current transformation: " << m_transform;
#endif
- m_current_textitem = &ti;
+ m_current_fontengine = fontEngine;
const int margin = glyphMargin();
QHash<glyph_t, Coord> listItemCoordinates;
int rowHeight = 0;
// check each glyph for its metrics and get the required rowHeight.
- for (int i=0; i < glyphs.size(); ++i) {
+ for (int i=0; i < numGlyphs; ++i) {
const glyph_t glyph = glyphs[i];
if (coords.contains(glyph))
continue;
if (listItemCoordinates.contains(glyph))
continue;
- glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyph, m_transform);
+ glyph_metrics_t metrics = fontEngine->boundingBox(glyph, m_transform);
#ifdef CACHE_DEBUG
printf("'%c' (%4x): w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f, ti.ascent=%.2f, ti.descent=%.2f\n",
@@ -182,7 +181,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
break;
};
- QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_textitem->fontEngine);
+ QFontEngineFT *ft = static_cast<QFontEngineFT*> (m_current_fontengine);
QFontEngineFT::QGlyphSet *gset = ft->loadTransformedGlyphSet(m_transform);
if (gset && ft->loadGlyphs(gset, &g, 1, format)) {
@@ -194,9 +193,9 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g) const
} else
#endif
if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
- return m_current_textitem->fontEngine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
+ return m_current_fontengine->alphaRGBMapForGlyph(g, glyphMargin(), m_transform);
else
- return m_current_textitem->fontEngine->alphaMapForGlyph(g, m_transform);
+ return m_current_fontengine->alphaMapForGlyph(g, m_transform);
return QImage();
}
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index d347e61..b8717b1 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -76,7 +76,8 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache
{
public:
QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix)
- : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0) { }
+ : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0),
+ m_current_fontengine(0) { }
virtual ~QTextureGlyphCache() { }
@@ -90,9 +91,8 @@ public:
int baseLineY;
};
- void populate(const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs,
- const QVarLengthArray<QFixedPoint> &positions);
+ void populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
+ const QFixedPoint *positions);
virtual void createTextureData(int width, int height) = 0;
virtual void resizeTextureData(int width, int height) = 0;
@@ -113,7 +113,7 @@ public:
QImage textureMapForGlyph(glyph_t g) const;
protected:
- const QTextItemInt *m_current_textitem;
+ QFontEngine *m_current_fontengine;
int m_w; // image width
int m_h; // image height
diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp
new file mode 100644
index 0000000..659324b
--- /dev/null
+++ b/src/gui/text/qstatictext.cpp
@@ -0,0 +1,551 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstatictext_p.h"
+#include "qstatictext_p_p.h"
+#include <private/qtextengine_p.h>
+#include <private/qfontengine_p.h>
+
+#include <QtGui/qapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QStaticText
+ \internal
+ \brief The QStaticText class enables optimized drawing of text when the text and its layout
+ is updated rarely.
+ \since 4.7
+
+ \ingroup multimedia
+ \ingroup text
+ \mainclass
+
+ QStaticText provides a way to cache layout data for a block of text so that it can be drawn
+ more efficiently than by using QPainter::drawText() in which the layout information is
+ recalculated with every call.
+
+ The class primarily provides an optimization for cases where text and the transformations on
+ the painter are static over several paint events. If the text or its layout is changed
+ regularly, QPainter::drawText() is the more efficient alternative. Translating the painter
+ will not cause the layout of the text to be recalculated, but will cause a very small
+ performance impact on drawStaticText(). Altering any other parts of the painter's
+ transformation or the painter's font will cause the layout of the static text to be
+ recalculated. This should be avoided as often as possible to maximize the performance
+ benefit of using QStaticText.
+
+ In addition, only affine transformations are supported by drawStaticText(). Calling
+ drawStaticText() on a projected painter will perform slightly worse than using the regular
+ drawText() call, so this should be avoided.
+
+ \code
+ class MyWidget: public QWidget
+ {
+ public:
+ MyWidget(QWidget *parent = 0) : QWidget(parent), m_staticText("This is static text")
+
+ protected:
+ void paintEvent(QPaintEvent *)
+ {
+ QPainter painter(this);
+ painter.drawStaticText(0, 0, m_staticText);
+ }
+
+ private:
+ QStaticText m_staticText;
+ };
+ \endcode
+
+ The QStaticText class can be used to mimic the behavior of QPainter::drawText() to a specific
+ point with no boundaries, and also when QPainter::drawText() is called with a bounding
+ rectangle.
+
+ If a bounding rectangle is not required, create a QStaticText object without setting a maximum
+ size. The text will then occupy a single line.
+
+ If you set a maximum size on the QStaticText object, this will bound the text. The text will
+ be formatted so that no line exceeds the given width. When the object is painted, it will
+ be clipped at the given size. The position of the text is decided by the argument
+ passed to QPainter::drawStaticText() and can change from call to call with a minimal impact
+ on performance.
+
+ \sa QPainter::drawText(), QPainter::drawStaticText(), QTextLayout, QTextDocument
+*/
+
+/*!
+ Constructs an empty QStaticText
+*/
+QStaticText::QStaticText()
+ : data(new QStaticTextPrivate)
+{
+}
+
+/*!
+ \fn QStaticText::QStaticText(const QString &text, const QFont &font, const QSizeF &maximumSize)
+
+ Constructs a QStaticText object with the given \a text which is to be rendered in the given
+ \a font and bounded by the given \a maximumSize. If an invalid size is passed for \a maximumSize
+ the text will be unbounded.
+*/
+QStaticText::QStaticText(const QString &text, const QSizeF &size)
+ : data(new QStaticTextPrivate)
+{
+ data->text = text;
+ data->size = size;
+ data->init();
+}
+
+/*!
+ Constructs a QStaticText object which is a copy of \a other.
+*/
+QStaticText::QStaticText(const QStaticText &other)
+{
+ data = other.data;
+}
+
+/*!
+ Destroys the QStaticText.
+*/
+QStaticText::~QStaticText()
+{
+ Q_ASSERT(!data || data->ref >= 1);
+}
+
+/*!
+ \internal
+*/
+void QStaticText::detach()
+{
+ if (data->ref != 1)
+ data.detach();
+}
+
+/*!
+ Prepares the QStaticText object for being painted with the given \a matrix and the given
+ \a font to avoid overhead when the actual drawStaticText() call is made.
+
+ When drawStaticText() is called, the layout of the QStaticText will be recalculated if the
+ painter's font or matrix is different from the one used for the currently cached layout. By
+ default, QStaticText will use a default constructed QFont and an identity matrix to create
+ its layout.
+
+ To avoid the overhead of creating the layout the first time you draw the QStaticText with
+ a painter whose matrix or font are different from the defaults, you can use the prepare()
+ function and pass in the matrix and font you expect to use when drawing the text.
+
+ \sa QPainter::setFont(), QPainter::setMatrix()
+*/
+void QStaticText::prepare(const QTransform &matrix, const QFont &font)
+{
+ data->matrix = matrix;
+ data->font = font;
+ data->init();
+}
+
+
+/*!
+ Assigns \a other to this QStaticText.
+*/
+QStaticText &QStaticText::operator=(const QStaticText &other)
+{
+ data = other.data;
+ return *this;
+}
+
+/*!
+ Compares \a other to this QStaticText. Returns true if the texts, fonts and maximum sizes
+ are equal.
+*/
+bool QStaticText::operator==(const QStaticText &other) const
+{
+ return (data == other.data
+ || (data->text == other.data->text
+ && data->font == other.data->font
+ && data->size == other.data->size));
+}
+
+/*!
+ Compares \a other to this QStaticText. Returns true if the texts, fonts or maximum sizes
+ are different.
+*/
+bool QStaticText::operator!=(const QStaticText &other) const
+{
+ return !(*this == other);
+}
+
+/*!
+ Sets the text of the QStaticText to \a text.
+
+ \note This function will cause the layout of the text to be recalculated.
+
+ \sa text()
+*/
+void QStaticText::setText(const QString &text)
+{
+ detach();
+ data->text = text;
+ data->init();
+}
+
+/*!
+ Returns the text of the QStaticText.
+
+ \sa setText()
+*/
+QString QStaticText::text() const
+{
+ return data->text;
+}
+
+/*!
+ Sets whether the QStaticText object should use optimizations specific to the paint engine
+ backend if they are available. If \a on is set to true, backend optimizations will be turned
+ on, otherwise they will be turned off. The default value is false.
+
+ If backend optimizations are on, the paint engine used to draw the static text is allowed to
+ store data in the object which will assist it in future calls to drawStaticText. In particular,
+ when using the opengl graphics system, or when painting on a QGLWidget, turning this flag on will
+ improve performance, but increase the memory footprint of the QStaticText object.
+
+ The default value is false.
+
+ \note This function will cause the layout of the text to be recalculated.
+
+ \sa useBackendOptimizations()
+*/
+void QStaticText::setUseBackendOptimizations(bool on)
+{
+ if ((!on && !data->useBackendOptimizations)
+ || (on && data->useBackendOptimizations))
+ return;
+
+ detach();
+ data->useBackendOptimizations = on;
+ data->init();
+}
+
+/*!
+ Returns whether the QStaticText object should use optimizations specific to the paint engine
+ backend when possible. By default this setting is false.
+
+ \sa setUseBackendOptimizations()
+*/
+bool QStaticText::useBackendOptimizations() const
+{
+ return data->useBackendOptimizations;
+}
+
+/*!
+ Sets the maximum size of the QStaticText to \a maximumSize.
+
+ \note This function will cause the layout of the text to be recalculated.
+
+ \sa maximumSize()
+*/
+void QStaticText::setMaximumSize(const QSizeF &size)
+{
+ detach();
+ data->size = size;
+ data->init();
+}
+
+/*!
+ Returns the maximum size of the QStaticText.
+
+ \sa setMaximumSize()
+*/
+QSizeF QStaticText::maximumSize() const
+{
+ return data->size;
+}
+
+/*!
+ Returns true if the text of the QStaticText is empty, and false if not.
+
+ \sa text()
+*/
+bool QStaticText::isEmpty() const
+{
+ return data->text.isEmpty();
+}
+
+QStaticTextPrivate::QStaticTextPrivate()
+ : items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false),
+ useBackendOptimizations(false)
+{
+ ref = 1;
+}
+
+QStaticTextPrivate::QStaticTextPrivate(const QStaticTextPrivate &other)
+ : text(other.text), font(other.font), size(other.size), matrix(other.matrix),
+ items(0), itemCount(0), glyphPool(0), positionPool(0), needsClipRect(false),
+ useBackendOptimizations(false)
+{
+ ref = 1;
+}
+
+QStaticTextPrivate::~QStaticTextPrivate()
+{
+ delete[] items;
+ delete[] glyphPool;
+ delete[] positionPool;
+}
+
+QStaticTextPrivate *QStaticTextPrivate::get(const QStaticText *q)
+{
+ return q->data.data();
+}
+
+extern int qt_defaultDpiX();
+extern int qt_defaultDpiY();
+
+namespace {
+
+ class DrawTextItemRecorder: public QPaintEngine
+ {
+ public:
+ DrawTextItemRecorder(int expectedItemCount, QStaticTextItem *items,
+ int expectedGlyphCount, QFixedPoint *positionPool, glyph_t *glyphPool)
+ : m_items(items),
+ m_expectedItemCount(expectedItemCount),
+ m_expectedGlyphCount(expectedGlyphCount),
+ m_itemCount(0), m_glyphCount(0),
+ m_positionPool(positionPool),
+ m_glyphPool(glyphPool)
+ {
+ }
+
+ virtual void drawTextItem(const QPointF &position, const QTextItem &textItem)
+ {
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+
+ m_itemCount++;
+ m_glyphCount += ti.glyphs.numGlyphs;
+ if (m_items == 0)
+ return;
+
+ Q_ASSERT(m_itemCount <= m_expectedItemCount);
+ Q_ASSERT(m_glyphCount <= m_expectedGlyphCount);
+
+ QStaticTextItem *currentItem = (m_items + (m_itemCount - 1));
+ currentItem->fontEngine = ti.fontEngine;
+ currentItem->font = ti.font();
+ currentItem->chars = ti.chars;
+ currentItem->numChars = ti.num_chars;
+ currentItem->numGlyphs = ti.glyphs.numGlyphs;
+ currentItem->glyphs = m_glyphPool;
+ currentItem->glyphPositions = m_positionPool;
+
+ QTransform matrix = state->transform();
+ matrix.translate(position.x(), position.y());
+
+ QVarLengthArray<glyph_t> glyphs;
+ QVarLengthArray<QFixedPoint> positions;
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ int size = glyphs.size();
+ Q_ASSERT(size == ti.glyphs.numGlyphs);
+ Q_ASSERT(size == positions.size());
+
+ memmove(currentItem->glyphs, glyphs.constData(), sizeof(glyph_t) * size);
+ memmove(currentItem->glyphPositions, positions.constData(), sizeof(QFixedPoint) * size);
+
+ m_glyphPool += size;
+ m_positionPool += size;
+ }
+
+
+ virtual bool begin(QPaintDevice *) { return true; }
+ virtual bool end() { return true; }
+ virtual void updateState(const QPaintEngineState &) {}
+ virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
+ virtual Type type() const
+ {
+ return User;
+ }
+
+ int itemCount() const
+ {
+ return m_itemCount;
+ }
+
+ int glyphCount() const
+ {
+ return m_glyphCount;
+ }
+
+ private:
+ QStaticTextItem *m_items;
+ int m_itemCount;
+ int m_glyphCount;
+ int m_expectedItemCount;
+ int m_expectedGlyphCount;
+
+ glyph_t *m_glyphPool;
+ QFixedPoint *m_positionPool;
+ };
+
+ class DrawTextItemDevice: public QPaintDevice
+ {
+ public:
+ DrawTextItemDevice(int expectedItemCount = -1, QStaticTextItem *items = 0,
+ int expectedGlyphCount = -1, QFixedPoint *positionPool = 0,
+ glyph_t *glyphPool = 0)
+ {
+ m_paintEngine = new DrawTextItemRecorder(expectedItemCount, items,
+ expectedGlyphCount, positionPool, glyphPool);
+ }
+
+ ~DrawTextItemDevice()
+ {
+ delete m_paintEngine;
+ }
+
+ int metric(PaintDeviceMetric m) const
+ {
+ int val;
+ switch (m) {
+ case PdmWidth:
+ case PdmHeight:
+ case PdmWidthMM:
+ case PdmHeightMM:
+ val = 0;
+ break;
+ case PdmDpiX:
+ case PdmPhysicalDpiX:
+ val = qt_defaultDpiX();
+ break;
+ case PdmDpiY:
+ case PdmPhysicalDpiY:
+ val = qt_defaultDpiY();
+ break;
+ case PdmNumColors:
+ val = 16777216;
+ break;
+ case PdmDepth:
+ val = 24;
+ break;
+ default:
+ val = 0;
+ qWarning("DrawTextItemDevice::metric: Invalid metric command");
+ }
+ return val;
+ }
+
+ virtual QPaintEngine *paintEngine() const
+ {
+ return m_paintEngine;
+ }
+
+ int itemCount() const
+ {
+ return m_paintEngine->itemCount();
+ }
+
+ int glyphCount() const
+ {
+ return m_paintEngine->glyphCount();
+ }
+
+ private:
+ DrawTextItemRecorder *m_paintEngine;
+ };
+
+}
+
+void QStaticTextPrivate::init()
+{
+ delete[] items;
+ delete[] glyphPool;
+ delete[] positionPool;
+
+ position = QPointF(0, 0);
+
+ // Draw once to count number of items and glyphs, so that we can use as little memory
+ // as possible to store the data
+ DrawTextItemDevice counterDevice;
+ {
+ QPainter painter(&counterDevice);
+ painter.setFont(font);
+ painter.setTransform(matrix);
+
+ if (size.isValid())
+ painter.drawText(QRectF(QPointF(0, 0), size), text);
+ else
+ painter.drawText(0, 0, text);
+ }
+
+ itemCount = counterDevice.itemCount();
+ items = new QStaticTextItem[itemCount];
+
+ if (useBackendOptimizations) {
+ for (int i=0; i<itemCount; ++i)
+ items[i].useBackendOptimizations = true;
+ }
+
+
+ int glyphCount = counterDevice.glyphCount();
+ glyphPool = new glyph_t[glyphCount];
+ positionPool = new QFixedPoint[glyphCount];
+
+ // Draw again to actually record the items and glyphs
+ DrawTextItemDevice recorderDevice(itemCount, items, glyphCount, positionPool, glyphPool);
+ {
+ QPainter painter(&recorderDevice);
+ painter.setFont(font);
+ painter.setTransform(matrix);
+
+ if (size.isValid()) {
+ QRectF boundingRect;
+ painter.drawText(QRectF(QPointF(0, 0), size), Qt::TextWordWrap, text, &boundingRect);
+
+ needsClipRect = boundingRect.width() > size.width()
+ || boundingRect.height() > size.height();
+
+ } else {
+ painter.drawText(0, 0, text);
+ needsClipRect = false;
+ }
+ }
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h
new file mode 100644
index 0000000..a19fb6c
--- /dev/null
+++ b/src/gui/text/qstatictext_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATICTEXT_H
+#define QSTATICTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of internal files. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qsize.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qmetatype.h>
+
+#include <QtGui/qtransform.h>
+#include <QtGui/qfont.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QStaticTextPrivate;
+class Q_GUI_EXPORT QStaticText
+{
+public:
+ QStaticText();
+ QStaticText(const QString &text, const QSizeF &maximumSize = QSizeF());
+ QStaticText(const QStaticText &other);
+ ~QStaticText();
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setMaximumSize(const QSizeF &maximumSize);
+ QSizeF maximumSize() const;
+
+ void prepare(const QTransform &matrix, const QFont &font);
+
+ void setUseBackendOptimizations(bool on);
+ bool useBackendOptimizations() const;
+
+ QStaticText &operator=(const QStaticText &);
+ bool operator==(const QStaticText &) const;
+ bool operator!=(const QStaticText &) const;
+
+ bool isEmpty() const;
+
+private:
+ void detach();
+
+ QExplicitlySharedDataPointer<QStaticTextPrivate> data;
+ friend class QStaticTextPrivate;
+};
+
+Q_DECLARE_METATYPE(QStaticText)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSTATICTEXT_H
diff --git a/src/gui/text/qstatictext_p_p.h b/src/gui/text/qstatictext_p_p.h
new file mode 100644
index 0000000..72c8439
--- /dev/null
+++ b/src/gui/text/qstatictext_p_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTATICTEXT_P_H
+#define QSTATICTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of internal files. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtextureglyphcache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QStaticTextUserData
+{
+public:
+ enum Type {
+ NoUserData,
+ OpenGLUserData
+ };
+
+ QStaticTextUserData(Type t) : type(t) {}
+ virtual ~QStaticTextUserData() {}
+
+ Type type;
+};
+
+class Q_GUI_EXPORT QStaticTextItem
+{
+public:
+ QStaticTextItem() : chars(0), numChars(0), fontEngine(0), userData(0),
+ useBackendOptimizations(false), userDataNeedsUpdate(0) {}
+ ~QStaticTextItem() { delete userData; }
+
+ void setUserData(QStaticTextUserData *newUserData)
+ {
+ if (userData == newUserData)
+ return;
+
+ delete userData;
+ userData = newUserData;
+ }
+
+ QFixedPoint *glyphPositions; // 8 bytes per glyph
+ glyph_t *glyphs; // 4 bytes per glyph
+ const QChar *chars; // 2 bytes per glyph
+ // =================
+ // 14 bytes per glyph
+
+ // 12 bytes for pointers
+ int numGlyphs; // 4 bytes per item
+ int numChars; // 4 bytes per item
+ QFontEngine *fontEngine; // 4 bytes per item
+ QFont font; // 8 bytes per item
+ QStaticTextUserData *userData; // 8 bytes per item
+ char useBackendOptimizations : 1; // 1 byte per item
+ char userDataNeedsUpdate : 1; //
+ // ================
+ // 41 bytes per item
+};
+
+class QStaticText;
+class Q_AUTOTEST_EXPORT QStaticTextPrivate
+{
+public:
+ QStaticTextPrivate();
+ QStaticTextPrivate(const QStaticTextPrivate &other);
+ ~QStaticTextPrivate();
+
+ void init();
+
+ QAtomicInt ref; // 4 bytes per text
+
+ QString text; // 4 bytes per text
+ QFont font; // 8 bytes per text
+ QSizeF size; // 16 bytes per text
+ QPointF position; // 16 bytes per text
+
+ QTransform matrix; // 80 bytes per text
+ QStaticTextItem *items; // 4 bytes per text
+ int itemCount; // 4 bytes per text
+ glyph_t *glyphPool; // 4 bytes per text
+ QFixedPoint *positionPool; // 4 bytes per text
+
+ char needsClipRect : 1; // 1 byte per text
+ char useBackendOptimizations : 1;
+ // ================
+ // 145 bytes per text
+
+ static QStaticTextPrivate *get(const QStaticText *q);
+};
+
+QT_END_NAMESPACE
+
+#endif // QSTATICTEXT_P_H
diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri
index b7615a4..2eaa418 100644
--- a/src/gui/text/text.pri
+++ b/src/gui/text/text.pri
@@ -37,7 +37,9 @@ HEADERS += \
text/qtexttable_p.h \
text/qzipreader_p.h \
text/qzipwriter_p.h \
- text/qtextodfwriter_p.h
+ text/qtextodfwriter_p.h \
+ text/qstatictext_p_p.h \
+ text/qstatictext_p.h
SOURCES += \
text/qfont.cpp \
@@ -66,7 +68,8 @@ SOURCES += \
text/qsyntaxhighlighter.cpp \
text/qcssparser.cpp \
text/qzip.cpp \
- text/qtextodfwriter.cpp
+ text/qtextodfwriter.cpp \
+ text/qstatictext.cpp
win32 {
SOURCES += \
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
index 516b847..e454c12 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
@@ -61,12 +61,6 @@ QGLRect QGL2PEXVertexArray::boundingRect() const
return QGLRect(minX, minY, maxX, maxY);
}
-void QGL2PEXVertexArray::addRect(const QRectF &rect)
-{
- vertexArray << rect.topLeft() << rect.topRight() << rect.bottomRight()
- << rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
-}
-
void QGL2PEXVertexArray::addClosingLine(int index)
{
if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last()))
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
index e0497b1..ae73040 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
@@ -102,8 +102,22 @@ public:
QGL2PEXVertexArray() :
maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10),
boundingRectDirty(true) {}
+
+ inline void addRect(const QRectF &rect)
+ {
+ qreal top = rect.top();
+ qreal left = rect.left();
+ qreal bottom = rect.bottom();
+ qreal right = rect.right();
+
+ vertexArray << QGLPoint(left, top)
+ << QGLPoint(right, top)
+ << QGLPoint(right, bottom)
+ << QGLPoint(right, bottom)
+ << QGLPoint(left, bottom)
+ << QGLPoint(left, top);
+ }
- void addRect(const QRectF &rect);
void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
void clear();
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 07f3159..c66472c 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -77,6 +77,7 @@
#include <private/qfontengine_p.h>
#include <private/qpixmapdata_gl_p.h>
#include <private/qdatabuffer_p.h>
+#include <private/qstatictext_p_p.h>
#include "qglgradientcache_p.h"
#include "qglengineshadermanager_p.h"
@@ -1189,6 +1190,20 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
}
+void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
+{
+ Q_D(QGL2PaintEngineEx);
+
+ ensureActive();
+
+ QFontEngineGlyphCache::Type glyphType = textItem->fontEngine->glyphFormat >= 0
+ ? QFontEngineGlyphCache::Type(textItem->fontEngine->glyphFormat)
+ : d->glyphCacheType;
+
+ // ### What about huge fonts? These are not passed through cache in drawTextItem().
+ d->drawCachedGlyphs(glyphType, textItem, true);
+}
+
void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
{
Q_D(QGL2PaintEngineEx);
@@ -1242,33 +1257,95 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
}
if (drawCached) {
- d->drawCachedGlyphs(p, glyphType, ti);
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ {
+ QStaticTextItem staticTextItem;
+ staticTextItem.chars = ti.chars;
+ staticTextItem.fontEngine = ti.fontEngine;
+ staticTextItem.glyphs = glyphs.data();
+ staticTextItem.numChars = ti.num_chars;
+ staticTextItem.numGlyphs = glyphs.size();
+ staticTextItem.glyphPositions = positions.data();
+
+ d->drawCachedGlyphs(glyphType, &staticTextItem, false);
+ }
return;
}
QPaintEngineEx::drawTextItem(p, ti);
}
-void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
- const QTextItemInt &ti)
+#define QSTATICTEXT_USE_INDEXARRAY
+
+class QOpenGLStaticTextUserData: public QObject, public QStaticTextUserData
+{
+ Q_OBJECT
+public:
+ QOpenGLStaticTextUserData(QGLContext *glContext)
+ : QStaticTextUserData(OpenGLUserData),
+ vertexCoordVBOId(0), textureCoordVBOId(0), ctx(glContext)
+ {
+ connect(QGLSignalProxy::instance(),
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
+ }
+
+ ~QOpenGLStaticTextUserData()
+ {
+ if (ctx != 0)
+ cleanupGLContextRefs(ctx);
+ }
+
+ QGLContext *ctx;
+ GLuint vertexCoordVBOId;
+ GLuint textureCoordVBOId;
+
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ QVector<GLuint> indices;
+#endif
+
+public Q_SLOTS:
+ void cleanupGLContextRefs(const QGLContext *context)
+ {
+ if (context == ctx) {
+ if (vertexCoordVBOId != 0)
+ glDeleteBuffers(1, &vertexCoordVBOId);
+
+ if (textureCoordVBOId != 0)
+ glDeleteBuffers(1, &textureCoordVBOId);
+
+ vertexCoordVBOId = 0;
+ textureCoordVBOId = 0;
+ }
+ }
+};
+
+void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType,
+ QStaticTextItem *staticTextItem,
+ bool includeMatrixInCache)
{
Q_Q(QGL2PaintEngineEx);
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ QOpenGL2PaintEngineState *s = q->state();
QGLTextureGlyphCache *cache =
- (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform());
-
+ (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType,
+ includeMatrixInCache
+ ? s->matrix
+ : QTransform());
if (!cache || cache->cacheType() != glyphType) {
- cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
- ti.fontEngine->setGlyphCache(ctx, cache);
+ cache = new QGLTextureGlyphCache(ctx, glyphType,
+ includeMatrixInCache ? s->matrix : QTransform());
+ staticTextItem->fontEngine->setGlyphCache(ctx, cache);
}
cache->setPaintEnginePrivate(this);
- cache->populate(ti, glyphs, positions);
+ cache->populate(staticTextItem->fontEngine, staticTextItem->numGlyphs, staticTextItem->glyphs,
+ staticTextItem->glyphPositions);
if (cache->width() == 0 || cache->height() == 0)
return;
@@ -1280,20 +1357,103 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
GLfloat dx = 1.0 / cache->width();
GLfloat dy = 1.0 / cache->height();
- vertexCoordinateArray.clear();
- textureCoordinateArray.clear();
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ QVector<GLuint> indices;
+#endif
+
+ bool recreateVertexArrays = false;
+ if (staticTextItem->userDataNeedsUpdate)
+ recreateVertexArrays = true;
+ else if (staticTextItem->userData == 0)
+ recreateVertexArrays = true;
+ else if (staticTextItem->userData->type != QStaticTextUserData::OpenGLUserData)
+ recreateVertexArrays = true;
+ else if (static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData)->ctx != ctx)
+ recreateVertexArrays = true;
+
+ if (recreateVertexArrays) {
+ vertexCoordinateArray.clear();
+ textureCoordinateArray.clear();
+
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ QStaticTextUserData *uData = staticTextItem->userData;
+ QOpenGLStaticTextUserData *openGlUserData = uData != 0
+ && uData->type == QStaticTextUserData::OpenGLUserData
+ ? static_cast<QOpenGLStaticTextUserData *>(uData)
+ : 0;
+ bool updateIndices = openGlUserData == 0
+ || openGlUserData->indices.size() < staticTextItem->numGlyphs;
+ int j=0;
+#endif
+
+ for (int i=0; i<staticTextItem->numGlyphs; ++i) {
+ const QTextureGlyphCache::Coord &c = cache->coords.value(staticTextItem->glyphs[i]);
+ int x = staticTextItem->glyphPositions[i].x.toInt() + c.baseLineX - margin;
+ int y = staticTextItem->glyphPositions[i].y.toInt() - c.baseLineY - margin;
+
+ vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
+ textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
+
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ if (updateIndices) {
+ for (int k=0; k<6; ++k)
+ indices.append(j++);
+ }
+#endif
+ }
+
+ if (staticTextItem->useBackendOptimizations) {
+ QOpenGLStaticTextUserData *userData =
+ staticTextItem->userData != 0 && staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData
+ ? static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData)
+ : new QOpenGLStaticTextUserData(ctx);
+
+ int vertexCoordinateArraySize = vertexCoordinateArray.vertexCount() * sizeof(QGLPoint);
+ if (userData->vertexCoordVBOId == 0)
+ glGenBuffers(1, &userData->vertexCoordVBOId);
+
+ int textureCoordinateArraySize = textureCoordinateArray.vertexCount() * sizeof(QGLPoint);
+ if (userData->textureCoordVBOId == 0)
+ glGenBuffers(1, &userData->textureCoordVBOId);
+
+ glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId);
+ glBufferData(GL_ARRAY_BUFFER, vertexCoordinateArraySize,
+ vertexCoordinateArray.data(), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId);
+ glBufferData(GL_ARRAY_BUFFER, textureCoordinateArraySize,
+ textureCoordinateArray.data(), GL_STATIC_DRAW);
- for (int i=0; i<glyphs.size(); ++i) {
- const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
- int x = positions[i].x.toInt() + c.baseLineX - margin;
- int y = positions[i].y.toInt() - c.baseLineY - margin;
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ if (updateIndices)
+ userData->indices = indices;
+#endif
+
+ // If a new user data has been created, make sure we delete the old
+ staticTextItem->setUserData(userData);
+ staticTextItem->userDataNeedsUpdate = false;
- vertexCoordinateArray.addRect(QRectF(x, y, c.w, c.h));
- textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
+ } else {
+ setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
+ setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
+ }
}
+ if (staticTextItem->useBackendOptimizations) {
+ Q_ASSERT(staticTextItem->userData != 0);
+ Q_ASSERT(staticTextItem->userData->type == QStaticTextUserData::OpenGLUserData);
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
+ QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData);
+
+ glBindBuffer(GL_ARRAY_BUFFER, userData->vertexCoordVBOId);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, userData->textureCoordVBOId);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ indices = userData->indices;
+#endif
+ }
if (addOffset) {
addOffset = false;
@@ -1307,6 +1467,12 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
QBrush pensBrush = q->state()->pen.brush();
setBrush(pensBrush);
+ // When painting a QStaticTextItem, the glyph positions are already in device coordinates,
+ // therefore we temporarily set an identity matrix on the painter for the draw call to
+ // avoid transforming the positions twice.
+ QTransform old = s->matrix;
+ if (includeMatrixInCache)
+ s->matrix = QTransform();
if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
// Subpixel antialiasing without gamma correction
@@ -1360,7 +1526,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
- glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
+ glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs);
shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMaskPass2);
@@ -1390,7 +1556,18 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
- glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
+
+#if defined(QSTATICTEXT_USE_INDEXARRAY)
+ glDrawElements(GL_TRIANGLES, 6 * staticTextItem->numGlyphs, GL_UNSIGNED_INT, indices.constData());
+#else
+ glDrawArrays(GL_TRIANGLES, 0, 6 * staticTextItem->numGlyphs);
+#endif
+
+ // Reset bindings
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ if (includeMatrixInCache)
+ s->matrix = old;
}
void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
@@ -2014,3 +2191,5 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
}
QT_END_NAMESPACE
+
+#include "qpaintengineex_opengl2.moc"
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 8fa0eff..70a1621 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -133,6 +133,7 @@ public:
virtual void stroke(const QVectorPath &path, const QPen &pen);
virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
+ virtual void drawStaticTextItem(QStaticTextItem *textItem);
Type type() const { return OpenGL2; }
@@ -194,7 +195,8 @@ public:
void stroke(const QVectorPath &path, const QPen &pen);
void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
- void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti);
+ void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem,
+ bool includeMatrixInCache);
// Calls glVertexAttributePointer if the pointer has changed
inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer);
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index b0cb429..e0fc99c 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -415,6 +415,14 @@ struct QGLExtensionFuncs
// OpenGL constants
+#ifndef GL_ARRAY_BUFFER
+#define GL_ARRAY_BUFFER 0x8892
+#endif
+
+#ifndef GL_STATIC_DRAW
+#define GL_STATIC_DRAW 0x88E4
+#endif
+
/* NV_texture_rectangle */
#ifndef GL_NV_texture_rectangle
#define GL_TEXTURE_RECTANGLE_NV 0x84F5
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index 57918d0..e7a1b7e 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -60,6 +60,7 @@
#include <private/qglpixelbuffer_p.h>
#include <private/qbezier_p.h>
#include <qglframebufferobject.h>
+#include <private/qstatictext_p_p.h>
#include "private/qtessellator_p.h"
@@ -4555,7 +4556,7 @@ public:
QGLGlyphCache() : QObject(0) { current_cache = 0; }
~QGLGlyphCache();
QGLGlyphCoord *lookup(QFontEngine *, glyph_t);
- void cacheGlyphs(QGLContext *, const QTextItemInt &, const QVarLengthArray<glyph_t> &);
+ void cacheGlyphs(QGLContext *, QFontEngine *, glyph_t *glyphs, int numGlyphs);
void cleanCache();
void allocTexture(int width, int height, GLuint texture);
@@ -4707,8 +4708,8 @@ static QImage getCurrentTexture(const QColor &color, QGLFontTexture *font_tex)
}
#endif
-void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs)
+void QGLGlyphCache::cacheGlyphs(QGLContext *context, QFontEngine *fontEngine,
+ glyph_t *glyphs, int numGlyphs)
{
QGLContextHash::const_iterator dev_it = qt_context_cache.constFind(context);
QGLFontGlyphHash *font_cache = 0;
@@ -4744,25 +4745,25 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
}
Q_ASSERT(font_cache != 0);
- QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(ti.fontEngine);
+ QGLFontGlyphHash::const_iterator cache_it = font_cache->constFind(fontEngine);
QGLGlyphHash *cache = 0;
if (cache_it == font_cache->constEnd()) {
cache = new QGLGlyphHash;
- font_cache->insert(ti.fontEngine, cache);
- connect(ti.fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*)));
+ font_cache->insert(fontEngine, cache);
+ connect(fontEngine, SIGNAL(destroyed(QObject*)), SLOT(fontEngineDestroyed(QObject*)));
} else {
cache = cache_it.value();
}
current_cache = cache;
quint64 font_key = (reinterpret_cast<quint64>(context_key ? context_key : context) << 32)
- | reinterpret_cast<quint64>(ti.fontEngine);
+ | reinterpret_cast<quint64>(fontEngine);
QGLFontTexHash::const_iterator it = qt_font_textures.constFind(font_key);
QGLFontTexture *font_tex;
if (it == qt_font_textures.constEnd()) {
GLuint font_texture;
glGenTextures(1, &font_texture);
- GLint tex_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2);
+ GLint tex_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2);
GLint tex_width = qt_next_power_of_two(tex_height*30); // ###
GLint max_tex_size;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size);
@@ -4784,16 +4785,16 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
glBindTexture(GL_TEXTURE_2D, font_tex->texture);
}
- for (int i=0; i< glyphs.size(); ++i) {
+ for (int i=0; i< numGlyphs; ++i) {
QGLGlyphHash::const_iterator it = cache->constFind(glyphs[i]);
if (it == cache->constEnd()) {
// render new glyph and put it in the cache
- glyph_metrics_t metrics = ti.fontEngine->boundingBox(glyphs[i]);
+ glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
int glyph_width = qRound(metrics.width.toReal())+2;
- int glyph_height = qRound(ti.ascent.toReal() + ti.descent.toReal())+2;
+ int glyph_height = qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2;
if (font_tex->x_offset + glyph_width + x_margin > font_tex->width) {
- int strip_height = qt_next_power_of_two(qRound(ti.ascent.toReal() + ti.descent.toReal())+2);
+ int strip_height = qt_next_power_of_two(qRound(fontEngine->ascent().toReal() + fontEngine->descent().toReal())+2);
font_tex->x_offset = x_margin;
font_tex->y_offset += strip_height;
if (font_tex->y_offset >= font_tex->height) {
@@ -4826,7 +4827,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
}
}
- QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i]));
+ QImage glyph_im(fontEngine->alphaMapForGlyph(glyphs[i]));
glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8);
glyph_width = glyph_im.width();
Q_ASSERT(glyph_width >= 0);
@@ -4906,30 +4907,15 @@ void qgl_cleanup_glyph_cache(QGLContext *ctx)
qt_glyph_cache()->cleanupContext(ctx);
}
-void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
+void QOpenGLPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
{
Q_D(QOpenGLPaintEngine);
- const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
-
- // fall back to drawing a polygon if the scale factor is large, or
- // we use a gradient pen
- if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern
- && d->pen_brush_style <= Qt::ConicalGradientPattern)) {
- QPaintEngine::drawTextItem(p, textItem);
- return;
- }
-
d->flushDrawQueue();
- // add the glyphs used to the glyph texture cache
- QVarLengthArray<QFixedPoint> positions;
- QVarLengthArray<glyph_t> glyphs;
- QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y()));
- ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
-
// make sure the glyphs we want to draw are in the cache
- qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs);
+ qt_glyph_cache()->cacheGlyphs(d->device->context(), textItem->fontEngine, textItem->glyphs,
+ textItem->numGlyphs);
d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops
qt_glColor4ubv(d->pen_color);
@@ -4951,13 +4937,13 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- bool antialias = !(ti.fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
- && (d->matrix.type() > QTransform::TxTranslate);
+ bool antialias = !(textItem->fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
+ && (d->matrix.type() > QTransform::TxTranslate);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, antialias ? GL_LINEAR : GL_NEAREST);
- for (int i=0; i< glyphs.size(); ++i) {
- QGLGlyphCoord *g = qt_glyph_cache()->lookup(ti.fontEngine, glyphs[i]);
+ for (int i=0; i< textItem->numGlyphs; ++i) {
+ QGLGlyphCoord *g = qt_glyph_cache()->lookup(textItem->fontEngine, textItem->glyphs[i]);
// we don't cache glyphs with no width/height
if (!g)
@@ -4969,8 +4955,8 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
x2 = x1 + g->width;
y2 = y1 + g->height;
- QPointF logical_pos((positions[i].x - g->x_offset).toReal(),
- (positions[i].y + g->y_offset).toReal());
+ QPointF logical_pos((textItem->glyphPositions[i].x - g->x_offset).toReal(),
+ (textItem->glyphPositions[i].y + g->y_offset).toReal());
qt_add_rect_to_array(QRectF(logical_pos, QSizeF(g->log_width, g->log_height)), vertexArray);
qt_add_texcoords_to_array(x1, y1, x2, y2, texCoordArray);
@@ -4987,6 +4973,40 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
// XXX: This may not be needed as this behavior does seem to be caused by driver bug
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
#endif
+
+}
+
+void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
+{
+ Q_D(QOpenGLPaintEngine);
+
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+
+ // fall back to drawing a polygon if the scale factor is large, or
+ // we use a gradient pen
+ if ((d->matrix.det() > 1) || (d->pen_brush_style >= Qt::LinearGradientPattern
+ && d->pen_brush_style <= Qt::ConicalGradientPattern)) {
+ QPaintEngine::drawTextItem(p, textItem);
+ return;
+ }
+
+ // add the glyphs used to the glyph texture cache
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ QTransform matrix = QTransform::fromTranslate(qRound(p.x()), qRound(p.y()));
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+
+ {
+ QStaticTextItem staticTextItem;
+ staticTextItem.chars = ti.chars;
+ staticTextItem.fontEngine = ti.fontEngine;
+ staticTextItem.glyphs = glyphs.data();
+ staticTextItem.numChars = ti.num_chars;
+ staticTextItem.numGlyphs = glyphs.size();
+ staticTextItem.glyphPositions = positions.data();
+ drawStaticTextItem(&staticTextItem);
+ }
+
}
diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h
index de0086a..55f7792 100644
--- a/src/opengl/qpaintengine_opengl_p.h
+++ b/src/opengl/qpaintengine_opengl_p.h
@@ -133,6 +133,7 @@ public:
void drawImage(const QRectF &r, const QImage &image, const QRectF &sr,
Qt::ImageConversionFlags conversionFlags);
void drawTextItem(const QPointF &p, const QTextItem &ti);
+ void drawStaticTextItem(QStaticTextItem *staticTextItem);
void drawEllipse(const QRectF &rect);
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp
index 6813d2f..c8a60d0 100644
--- a/src/openvg/qpaintengine_vg.cpp
+++ b/src/openvg/qpaintengine_vg.cpp
@@ -50,10 +50,10 @@
#endif
#include <QtCore/qvarlengtharray.h>
#include <QtGui/private/qdrawhelper_p.h>
-#include <QtGui/private/qtextureglyphcache_p.h>
#include <QtGui/private/qtextengine_p.h>
#include <QtGui/private/qfontengine_p.h>
#include <QtGui/private/qpainterpath_p.h>
+#include <QtGui/private/qstatictext_p_p.h>
#include <QDebug>
#include <QSet>
@@ -86,10 +86,9 @@ public:
QVGFontGlyphCache();
~QVGFontGlyphCache();
- void cacheGlyphs(QVGPaintEnginePrivate *d,
- const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs);
- void setScaleFromText(const QTextItemInt &ti);
+ void cacheGlyphs(QVGPaintEnginePrivate *d, QFontEngine *fontEngine, const glyph_t *g, int count);
+
+ void setScaleFromText(const QFont &font, QFontEngine *fontEngine);
VGFont font;
VGfloat scaleX;
@@ -3188,22 +3187,20 @@ QVGFontGlyphCache::~QVGFontGlyphCache()
vgDestroyFont(font);
}
-void QVGFontGlyphCache::setScaleFromText(const QTextItemInt &ti)
+void QVGFontGlyphCache::setScaleFromText(const QFont &font, QFontEngine *fontEngine)
{
- QFontInfo fi(ti.font());
+ QFontInfo fi(font);
qreal pixelSize = fi.pixelSize();
- qreal emSquare = ti.fontEngine->properties().emSquare.toReal();
+ qreal emSquare = fontEngine->properties().emSquare.toReal();
scaleX = scaleY = static_cast<VGfloat>(pixelSize / emSquare);
}
-void QVGFontGlyphCache::cacheGlyphs
- (QVGPaintEnginePrivate *d, const QTextItemInt &ti,
- const QVarLengthArray<glyph_t> &glyphs)
+void QVGFontGlyphCache::cacheGlyphs(QVGPaintEnginePrivate *d,
+ QFontEngine *fontEngine,
+ const glyph_t *g, int count)
{
VGfloat origin[2];
VGfloat escapement[2];
- const glyph_t *g = glyphs.constData();
- int count = glyphs.size();
glyph_metrics_t metrics;
// Some Qt font engines don't set yoff in getUnscaledGlyph().
// Zero the metric structure so that everything has a default value.
@@ -3222,9 +3219,9 @@ void QVGFontGlyphCache::cacheGlyphs
}
#if !defined(QVG_NO_IMAGE_GLYPHS)
Q_UNUSED(d);
- QImage scaledImage = ti.fontEngine->alphaMapForGlyph(glyph);
+ QImage scaledImage = fontEngine->alphaMapForGlyph(glyph);
VGImage vgImage = VG_INVALID_HANDLE;
- metrics = ti.fontEngine->boundingBox(glyph);
+ metrics = fontEngine->boundingBox(glyph);
if (!scaledImage.isNull()) { // Not a space character
if (scaledImage.format() == QImage::Format_Indexed8) {
vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER);
@@ -3248,7 +3245,7 @@ void QVGFontGlyphCache::cacheGlyphs
#else
// Calculate the path for the glyph and cache it.
QPainterPath path;
- ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
+ fontEngine->getUnscaledGlyph(glyph, &path, &metrics);
VGPath vgPath;
if (!path.isEmpty()) {
vgPath = d->painterPathToVGPath(path);
@@ -3289,8 +3286,28 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
ti.fontEngine->getGlyphPositions
(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ if (!drawCachedGlyphs(glyphs.size(), glyphs.data(), ti.font(), ti.fontEngine, p))
+ QPaintEngineEx::drawTextItem(p, textItem);
+#else
+ // OpenGL 1.0 does not have support for VGFont and glyphs,
+ // so fall back to the default Qt path stroking algorithm.
+ QPaintEngineEx::drawTextItem(p, textItem);
+#endif
+}
+
+void QVGPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
+{
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->font, textItem->fontEngine,
+ QPointF(0, 0));
+}
+
+ bool QVGPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font,
+ QFontEngine *fontEngine, const QPointF &p)
+ {
+ Q_D(QVGPaintEngine);
+
// Find the glyph cache for this font.
- QVGFontCache::ConstIterator it = d->fontCache.constFind(ti.fontEngine);
+ QVGFontCache::ConstIterator it = d->fontCache.constFind(fontEngine);
QVGFontGlyphCache *glyphCache;
if (it != d->fontCache.constEnd()) {
glyphCache = it.value();
@@ -3298,15 +3315,14 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
glyphCache = new QVGFontGlyphCache();
if (glyphCache->font == VG_INVALID_HANDLE) {
qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine");
- delete glyphCache;
- QPaintEngineEx::drawTextItem(p, textItem);
- return;
+ delete glyphCache;
+ return false;
}
- glyphCache->setScaleFromText(ti);
- d->fontCache.insert(ti.fontEngine, glyphCache);
+ glyphCache->setScaleFromText(font, fontEngine);
+ d->fontCache.insert(fontEngine, glyphCache);
if (!d->fontEngineCleaner)
d->fontEngineCleaner = new QVGFontEngineCleaner(d);
- QObject::connect(ti.fontEngine, SIGNAL(destroyed()),
+ QObject::connect(fontEngine, SIGNAL(destroyed()),
d->fontEngineCleaner, SLOT(fontEngineDestroyed()));
}
@@ -3319,7 +3335,7 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform);
// Add the glyphs from the text item into the glyph cache.
- glyphCache->cacheGlyphs(d, ti, glyphs);
+ glyphCache->cacheGlyphs(d, fontEngine, glyphs, numGlyphs);
// Set the glyph drawing origin.
VGfloat origin[2];
@@ -3338,13 +3354,10 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
// Draw the glyphs. We need to fill with the brush associated with
// the Qt pen, not the Qt brush.
d->ensureBrush(state()->pen.brush());
- vgDrawGlyphs(glyphCache->font, glyphs.size(), (VGuint*)glyphs.data(),
+ vgDrawGlyphs(glyphCache->font, numGlyphs, (VGuint*)glyphs,
NULL, NULL, VG_FILL_PATH, VG_TRUE);
-#else
- // OpenGL 1.0 does not have support for VGFont and glyphs,
- // so fall back to the default Qt path stroking algorithm.
- QPaintEngineEx::drawTextItem(p, textItem);
-#endif
+
+ return true;
}
void QVGPaintEngine::setState(QPainterState *s)
diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h
index 3f87a72..3f73fed 100644
--- a/src/openvg/qpaintengine_vg_p.h
+++ b/src/openvg/qpaintengine_vg_p.h
@@ -54,6 +54,7 @@
//
#include <QtGui/private/qpaintengineex_p.h>
+#include <QtGui/private/qtextureglyphcache_p.h>
QT_BEGIN_NAMESPACE
@@ -139,6 +140,9 @@ public:
void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QFlags<QDrawPixmaps::DrawingHint> hints);
void drawTextItem(const QPointF &p, const QTextItem &textItem);
+ void drawStaticTextItem(QStaticTextItem *staticTextItem);
+ bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFont &font,
+ QFontEngine *fontEngine, const QPointF &p);
void setState(QPainterState *s);
QVGPainterState *state() { return static_cast<QVGPainterState *>(QPaintEngineEx::state()); }
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
index 2b11058..12f4c6b 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
@@ -176,7 +176,7 @@ enum PaintOperation {
DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100,
DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800,
FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000,
- ALL = 0xffff
+ DRAW_STATICTEXT = 0x8000, ALL = 0xffff
};
#endif
@@ -711,6 +711,14 @@ void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal
QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode);
}
+void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item)
+{
+ RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG());
+ Q_D(QDirectFBPaintEngine);
+ d->lock();
+ QRasterPaintEngine::drawStaticTextItem(item);
+}
+
void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
{
Q_D(QDirectFBPaintEngine);
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h
index 64609d7..19e8b84 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h
@@ -109,6 +109,8 @@ public:
virtual void clip(const QRegion &region, Qt::ClipOperation op);
virtual void clip(const QRect &rect, Qt::ClipOperation op);
+ virtual void drawStaticTextItem(QStaticTextItem *item);
+
static void initImageCache(int size);
};