Qt 4.8
qdeclarativetextlayout.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
43 #include <private/qstatictext_p.h>
44 #include <private/qfontengine_p.h>
45 #include <private/qtextengine_p.h>
46 #include <private/qpainter_p.h>
47 #include <private/qpaintengineex_p.h>
48 
50 
52 {
53 public:
55  : cached(false) {}
56 
58 
59  bool cached;
64 };
65 
66 namespace {
67 class DrawTextItemRecorder: public QPaintEngine
68 {
69  public:
70  DrawTextItemRecorder(bool untransformedCoordinates, bool useBackendOptimizations)
71  : m_inertText(0), m_dirtyPen(false), m_useBackendOptimizations(useBackendOptimizations),
72  m_untransformedCoordinates(untransformedCoordinates), m_currentColor(Qt::black)
73  {
74  }
75 
76  virtual void updateState(const QPaintEngineState &newState)
77  {
78  if (newState.state() & QPaintEngine::DirtyPen
79  && newState.pen().color() != m_currentColor) {
80  m_dirtyPen = true;
81  m_currentColor = newState.pen().color();
82  }
83  }
84 
85  virtual void drawTextItem(const QPointF &position, const QTextItem &textItem)
86  {
87  int glyphOffset = m_inertText->glyphs.size(); // Store offset into glyph pool
88  int positionOffset = m_inertText->glyphs.size(); // Offset into position pool
89  int charOffset = m_inertText->chars.size();
90 
91  const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
92 
93  bool needFreshCurrentItem = true;
94  if (!m_inertText->items.isEmpty()) {
95  QStaticTextItem &last = m_inertText->items[m_inertText->items.count() - 1];
96 
97  if (last.fontEngine() == ti.fontEngine && last.font == ti.font() &&
98  (!m_dirtyPen || last.color == state->pen().color())) {
99  needFreshCurrentItem = false;
100 
101  last.numChars += ti.num_chars;
102 
103  }
104  }
105 
106  if (needFreshCurrentItem) {
107  QStaticTextItem currentItem;
108 
109  currentItem.setFontEngine(ti.fontEngine);
110  currentItem.font = ti.font();
111  currentItem.charOffset = charOffset;
112  currentItem.numChars = ti.num_chars;
113  currentItem.numGlyphs = 0;
114  currentItem.glyphOffset = glyphOffset;
115  currentItem.positionOffset = positionOffset;
116  currentItem.useBackendOptimizations = m_useBackendOptimizations;
117  if (m_dirtyPen)
118  currentItem.color = m_currentColor;
119 
120  m_inertText->items.append(currentItem);
121  }
122 
123  QStaticTextItem &currentItem = m_inertText->items.last();
124 
125  QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform();
126  matrix.translate(position.x(), position.y());
127 
130  ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
131 
132  int size = glyphs.size();
133  Q_ASSERT(size == positions.size());
134  currentItem.numGlyphs += size;
135 
136  m_inertText->glyphs.resize(m_inertText->glyphs.size() + size);
137  m_inertText->positions.resize(m_inertText->glyphs.size());
138  m_inertText->chars.resize(m_inertText->chars.size() + ti.num_chars);
139 
140  glyph_t *glyphsDestination = m_inertText->glyphs.data() + glyphOffset;
141  qMemCopy(glyphsDestination, glyphs.constData(), sizeof(glyph_t) * size);
142 
143  QFixedPoint *positionsDestination = m_inertText->positions.data() + positionOffset;
144  qMemCopy(positionsDestination, positions.constData(), sizeof(QFixedPoint) * size);
145 
146  QChar *charsDestination = m_inertText->chars.data() + charOffset;
147  qMemCopy(charsDestination, ti.chars, sizeof(QChar) * ti.num_chars);
148 
149  }
150 
151  virtual void drawPolygon(const QPointF *, int , PolygonDrawMode )
152  {
153  /* intentionally empty */
154  }
155 
156  virtual bool begin(QPaintDevice *) { return true; }
157  virtual bool end() { return true; }
158  virtual void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) {}
159  virtual Type type() const
160  {
161  return User;
162  }
163 
164  void begin(QDeclarativeTextLayoutPrivate *t) {
165  m_inertText = t;
166  m_dirtyPen = false;
167  }
168 
169  private:
170  QDeclarativeTextLayoutPrivate *m_inertText;
171 
172  bool m_dirtyPen;
173  bool m_useBackendOptimizations;
174  bool m_untransformedCoordinates;
175  QColor m_currentColor;
176 };
177 
178 class DrawTextItemDevice: public QPaintDevice
179 {
180  public:
181  DrawTextItemDevice(bool untransformedCoordinates, bool useBackendOptimizations)
182  {
183  m_paintEngine = new DrawTextItemRecorder(untransformedCoordinates,
184  useBackendOptimizations);
185  }
186 
187  ~DrawTextItemDevice()
188  {
189  delete m_paintEngine;
190  }
191 
192  void begin(QDeclarativeTextLayoutPrivate *t) {
193  m_paintEngine->begin(t);
194  }
195 
196  int metric(PaintDeviceMetric m) const
197  {
198  int val;
199  switch (m) {
200  case PdmWidth:
201  case PdmHeight:
202  case PdmWidthMM:
203  case PdmHeightMM:
204  val = 0;
205  break;
206  case PdmDpiX:
207  case PdmPhysicalDpiX:
208  val = qt_defaultDpiX();
209  break;
210  case PdmDpiY:
211  case PdmPhysicalDpiY:
212  val = qt_defaultDpiY();
213  break;
214  case PdmNumColors:
215  val = 16777216;
216  break;
217  case PdmDepth:
218  val = 24;
219  break;
220  default:
221  val = 0;
222  qWarning("DrawTextItemDevice::metric: Invalid metric command");
223  }
224  return val;
225  }
226 
227  virtual QPaintEngine *paintEngine() const
228  {
229  return m_paintEngine;
230  }
231 
232  private:
233  DrawTextItemRecorder *m_paintEngine;
234 };
235 
236 struct InertTextPainter {
237  InertTextPainter()
238  : device(true, true), painter(&device)
239  {
240  painter.setPen(QPen(QColor())); // explicitly invalid color.
241  }
242 
243  DrawTextItemDevice device;
244  QPainter painter;
245 };
246 }
247 
248 Q_GLOBAL_STATIC(InertTextPainter, inertTextPainter);
249 
269 : d(0)
270 {
271 }
272 
274 : QTextLayout(text), d(0)
275 {
276 }
277 
279 {
280  if (d) delete d;
281 }
282 
284 {
285  if (d && d->cached) {
286  d->cached = false;
287  d->items.clear();
288  d->positions.clear();
289  d->glyphs.clear();
290  d->chars.clear();
291  d->position = QPointF();
292  }
294 }
295 
297 {
298  if (d && d->cached) {
299  d->cached = false;
300  d->items.clear();
301  d->positions.clear();
302  d->glyphs.clear();
303  d->chars.clear();
304  d->position = QPointF();
305  }
307 }
308 
310 {
311  if (!d || !d->cached) {
312 
313  if (!d)
315 
316  InertTextPainter *itp = inertTextPainter();
317  itp->device.begin(d);
318  QTextLayout::draw(&itp->painter, QPointF(0, 0));
319 
320  glyph_t *glyphPool = d->glyphs.data();
321  QFixedPoint *positionPool = d->positions.data();
322  QChar *charPool = d->chars.data();
323 
324  int itemCount = d->items.count();
325  for (int ii = 0; ii < itemCount; ++ii) {
326  QStaticTextItem &item = d->items[ii];
327  item.glyphs = glyphPool + item.glyphOffset;
328  item.glyphPositions = positionPool + item.positionOffset;
329  item.chars = charPool + item.charOffset;
330  }
331 
332  d->cached = true;
333  }
334 }
335 
336 // Defined in qpainter.cpp
337 extern Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
338  const QFixedPoint *positions, int glyphCount,
339  QFontEngine *fontEngine, const QFont &font,
340  const QTextCharFormat &charFormat);
341 
343 {
345 
346  bool paintEngineSupportsTransformations = priv->extended &&
347  (priv->extended->type() == QPaintEngine::OpenGL2 ||
348  priv->extended->type() == QPaintEngine::OpenVG ||
349  priv->extended->type() == QPaintEngine::OpenGL);
350 
351  if (!paintEngineSupportsTransformations || !priv->state->matrix.isAffine()) {
352  QTextLayout::draw(painter, p);
353  return;
354  }
355 
356  prepare();
357 
358  int itemCount = d->items.count();
359 
360  if (p != d->position) {
361  QFixed fx = QFixed::fromReal(p.x());
362  QFixed fy = QFixed::fromReal(p.y());
363  QFixed oldX = QFixed::fromReal(d->position.x());
364  QFixed oldY = QFixed::fromReal(d->position.y());
365  for (int item = 0; item < itemCount; ++item) {
366  QStaticTextItem &textItem = d->items[item];
367 
368  for (int ii = 0; ii < textItem.numGlyphs; ++ii) {
369  textItem.glyphPositions[ii].x += fx - oldX;
370  textItem.glyphPositions[ii].y += fy - oldY;
371  }
372  textItem.userDataNeedsUpdate = true;
373  }
374 
375  d->position = p;
376  }
377 
378  QPen oldPen = priv->state->pen;
379  QColor currentColor = oldPen.color();
380  QColor defaultColor = currentColor;
381  for (int ii = 0; ii < itemCount; ++ii) {
382  QStaticTextItem &item = d->items[ii];
383  if (item.color.isValid() && currentColor != item.color) {
384  // up-edge of a <font color="">text</font> tag
385  // we set the painter pen to the text item's specified color.
386  painter->setPen(item.color);
387  currentColor = item.color;
388  } else if (!item.color.isValid() && currentColor != defaultColor) {
389  // down-edge of a <font color="">text</font> tag
390  // we reset the painter pen back to the default color.
391  currentColor = defaultColor;
392  painter->setPen(currentColor);
393  }
394  priv->extended->drawStaticTextItem(&item);
395 
397  item.numGlyphs, item.fontEngine(), painter->font(),
398  QTextCharFormat());
399  }
400  if (currentColor != oldPen.color())
401  painter->setPen(oldPen);
402 }
403 
405 
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
QFontEngine * fontEngine
const T * constData() const
QPaintEngine::DirtyFlags state() const
Returns a combination of flags identifying the set of properties that need to be updated when updatin...
Definition: qpaintengine.h:292
int type
Definition: qmetatype.cpp:239
The QTextCharFormat class provides formatting information for characters in a QTextDocument.
Definition: qtextformat.h:372
QPaintEngineEx * extended
Definition: qpainter_p.h:263
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QFontEngine * fontEngine() const
const QChar * chars
QFixedPoint * glyphPositions
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
Q_GUI_EXPORT int qt_defaultDpiY()
Definition: qfont.cpp:201
QPainterState * state
Definition: qpainter_p.h:204
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
RenderFlags flags
Q_GUI_EXPORT int qt_defaultDpiX()
Definition: qfont.cpp:162
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
QColor color() const
Returns the color of this pen&#39;s brush.
Definition: qpen.cpp:771
QTransform matrix
Definition: qpainter_p.h:161
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
Definition: qtransform.cpp:417
The QString class provides a Unicode character string.
Definition: qstring.h:83
static QFixed fromReal(qreal r)
Definition: qfixed_p.h:70
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
QFont font() const
Returns the current font that is used for the layout, or a default font if none is set...
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
void setFontEngine(QFontEngine *fe)
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
QGlyphLayout glyphs
QString text() const
Returns the layout&#39;s text.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QFixed y
Definition: qfixed_p.h:191
char useBackendOptimizations
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
const QFont & font() const
Returns the currently set font used for drawing text.
Definition: qpainter.cpp:4312
virtual Type type() const =0
Reimplement this function to return the paint engine Type.
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
Q_CORE_EXPORT void qWarning(const char *,...)
Internal QTextItem.
void draw(QPainter *p, const QPointF &pos, const QVector< FormatRange > &selections=QVector< FormatRange >(), const QRectF &clip=QRectF()) const
Draws the whole layout on the painter p at the position specified by pos.
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:90
void * qMemCopy(void *dest, const void *src, size_t n)
Definition: qglobal.cpp:2508
QFixed x
Definition: qfixed_p.h:190
bool isAffine() const
Returns true if the matrix represent an affine transformation, otherwise returns false.
Definition: qtransform.h:200
The QTextLayout class is used to lay out and render text.
Definition: qtextlayout.h:105
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
QVector< QStaticTextItem > items
static QPainterPrivate * get(QPainter *painter)
Definition: qpainter_p.h:249
virtual void drawStaticTextItem(QStaticTextItem *)
Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, const QFixedPoint *positions, int glyphCount, QFontEngine *fontEngine, const QFont &font, const QTextCharFormat &charFormat)
Definition: qpainter.cpp:6820
void setPen(const QColor &color)
Sets the painter&#39;s pen to have style Qt::SolidLine, width 0 and the specified color.
Definition: qpainter.cpp:4047
static const QMetaObjectPrivate * priv(const uint *data)
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
void clearLayout()
Clears the line information in the layout.
The QPaintEngineState class provides information about the active paint engine&#39;s current state...
Definition: qpaintengine.h:289
T * data()
Returns a pointer to the data stored in the vector.
Definition: qvector.h:152
QPen pen() const
Returns the pen in the current paint engine state.
Definition: qpainter.cpp:9259
bool isValid() const
Returns true if the color is valid; otherwise returns false.
Definition: qcolor.h:295
QDeclarativeTextLayoutPrivate * d
The QTextItem class provides all the information required to draw text in a custom paint engine...
Definition: qpaintengine.h:68
Q_GLOBAL_STATIC(InertTextPainter, inertTextPainter)
void draw(QPainter *, const QPointF &=QPointF())
static const KeyPair *const end
QFont font() const
Returns the font that should be used to draw the text.
unsigned int glyph_t
void beginLayout()
Begins the layout process.
int size() const
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
glyph_t * glyphs