source: trunk/src/gui/text/qtextengine_p.h@ 234

Last change on this file since 234 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 19.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QTEXTENGINE_P_H
43#define QTEXTENGINE_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists for the convenience
50// of other Qt classes. This header file may change from version to
51// version without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include "QtCore/qglobal.h"
57#include "QtCore/qstring.h"
58#include "QtCore/qvarlengtharray.h"
59#include "QtCore/qnamespace.h"
60#include "QtGui/qtextlayout.h"
61#include "private/qtextformat_p.h"
62#include "private/qfont_p.h"
63#include "QtCore/qvector.h"
64#include "QtGui/qpaintengine.h"
65#include "QtGui/qtextobject.h"
66#include "QtGui/qtextoption.h"
67#include "QtCore/qset.h"
68#include "QtCore/qdebug.h"
69#ifndef QT_BUILD_COMPAT_LIB
70#include "private/qtextdocument_p.h"
71#endif
72#include "private/qharfbuzz_p.h"
73#include "private/qfixed_p.h"
74
75#include <stdlib.h>
76
77QT_BEGIN_NAMESPACE
78
79class QFontPrivate;
80class QFontEngine;
81
82class QString;
83class QPainter;
84
85class QAbstractTextDocumentLayout;
86
87
88// this uses the same coordinate system as Qt, but a different one to freetype.
89// * y is usually negative, and is equal to the ascent.
90// * negative yoff means the following stuff is drawn higher up.
91// the characters bounding rect is given by QRect(x,y,width,height), its advance by
92// xoo and yoff
93struct glyph_metrics_t
94{
95 inline glyph_metrics_t()
96 : x(100000), y(100000) {}
97 inline glyph_metrics_t(QFixed _x, QFixed _y, QFixed _width, QFixed _height, QFixed _xoff, QFixed _yoff)
98 : x(_x),
99 y(_y),
100 width(_width),
101 height(_height),
102 xoff(_xoff),
103 yoff(_yoff)
104 {}
105 QFixed x;
106 QFixed y;
107 QFixed width;
108 QFixed height;
109 QFixed xoff;
110 QFixed yoff;
111
112 glyph_metrics_t transformed(const QTransform &xform) const;
113};
114Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
115
116struct Q_AUTOTEST_EXPORT QScriptAnalysis
117{
118 enum Flags {
119 None = 0,
120 Lowercase = 1,
121 Uppercase = 2,
122 SmallCaps = 3,
123 LineOrParagraphSeparator = 4,
124 Space = 5,
125 SpaceTabOrObject = Space,
126 Tab = 6,
127 TabOrObject = Tab,
128 Object = 7
129 };
130 unsigned short script : 8;
131 unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61)
132 unsigned short flags : 3;
133 inline bool operator == (const QScriptAnalysis &other) const {
134 return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
135 }
136};
137Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
138
139struct QGlyphJustification
140{
141 inline QGlyphJustification()
142 : type(0), nKashidas(0), space_18d6(0)
143 {}
144
145 enum JustificationType {
146 JustifyNone,
147 JustifySpace,
148 JustifyKashida
149 };
150
151 uint type :2;
152 uint nKashidas : 6; // more do not make sense...
153 uint space_18d6 : 24;
154};
155Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
156
157struct QGlyphLayoutInstance
158{
159 QFixedPoint offset;
160 QFixedPoint advance;
161 HB_Glyph glyph;
162 QGlyphJustification justification;
163 HB_GlyphAttributes attributes;
164};
165
166struct QGlyphLayout
167{
168 // init to 0 not needed, done when shaping
169 QFixedPoint *offsets; // 8 bytes per element
170 HB_Glyph *glyphs; // 4 bytes per element
171 QFixed *advances_x; // 4 bytes per element
172 QFixed *advances_y; // 4 bytes per element
173 QGlyphJustification *justifications; // 4 bytes per element
174 HB_GlyphAttributes *attributes; // 2 bytes per element
175
176 int numGlyphs;
177
178 inline QGlyphLayout() : numGlyphs(0) {}
179
180 inline explicit QGlyphLayout(char *address, int totalGlyphs)
181 {
182 offsets = reinterpret_cast<QFixedPoint *>(address);
183 int offset = totalGlyphs * sizeof(HB_FixedPoint);
184 glyphs = reinterpret_cast<HB_Glyph *>(address + offset);
185 offset += totalGlyphs * sizeof(HB_Glyph);
186 advances_x = reinterpret_cast<QFixed *>(address + offset);
187 offset += totalGlyphs * sizeof(QFixed);
188 advances_y = reinterpret_cast<QFixed *>(address + offset);
189 offset += totalGlyphs * sizeof(QFixed);
190 justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
191 offset += totalGlyphs * sizeof(QGlyphJustification);
192 attributes = reinterpret_cast<HB_GlyphAttributes *>(address + offset);
193 numGlyphs = totalGlyphs;
194 }
195
196 inline QGlyphLayout mid(int position, int n = -1) const {
197 QGlyphLayout copy = *this;
198 copy.glyphs += position;
199 copy.advances_x += position;
200 copy.advances_y += position;
201 copy.offsets += position;
202 copy.justifications += position;
203 copy.attributes += position;
204 if (n == -1)
205 copy.numGlyphs -= position;
206 else
207 copy.numGlyphs = n;
208 return copy;
209 }
210
211 static inline int spaceNeededForGlyphLayout(int totalGlyphs) {
212 return totalGlyphs * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
213 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
214 + sizeof(QGlyphJustification));
215 }
216
217 inline QFixed effectiveAdvance(int item) const
218 { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
219
220 inline QGlyphLayoutInstance instance(int position) const {
221 QGlyphLayoutInstance g;
222 g.offset.x = offsets[position].x;
223 g.offset.y = offsets[position].y;
224 g.glyph = glyphs[position];
225 g.advance.x = advances_x[position];
226 g.advance.y = advances_y[position];
227 g.justification = justifications[position];
228 g.attributes = attributes[position];
229 return g;
230 }
231
232 inline void setInstance(int position, const QGlyphLayoutInstance &g) {
233 offsets[position].x = g.offset.x;
234 offsets[position].y = g.offset.y;
235 glyphs[position] = g.glyph;
236 advances_x[position] = g.advance.x;
237 advances_y[position] = g.advance.y;
238 justifications[position] = g.justification;
239 attributes[position] = g.attributes;
240 }
241
242 inline void clear(int first = 0, int last = -1) {
243 if (last == -1)
244 last = numGlyphs;
245 if (first == 0 && last == numGlyphs
246 && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
247 memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs));
248 } else {
249 const int num = last - first;
250 memset(offsets + first, 0, num * sizeof(QFixedPoint));
251 memset(glyphs + first, 0, num * sizeof(HB_Glyph));
252 memset(advances_x + first, 0, num * sizeof(QFixed));
253 memset(advances_y + first, 0, num * sizeof(QFixed));
254 memset(justifications + first, 0, num * sizeof(QGlyphJustification));
255 memset(attributes + first, 0, num * sizeof(HB_GlyphAttributes));
256 }
257 }
258
259 inline char *data() {
260 return reinterpret_cast<char *>(offsets);
261 }
262
263 void grow(char *address, int totalGlyphs);
264};
265
266class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
267{
268private:
269 typedef QVarLengthArray<void *> Array;
270public:
271 QVarLengthGlyphLayoutArray(int totalGlyphs)
272 : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1)
273 , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
274 {
275 memset(Array::data(), 0, Array::size() * sizeof(void *));
276 }
277
278 void resize(int totalGlyphs)
279 {
280 Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1);
281
282 *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
283 memset(Array::data(), 0, Array::size() * sizeof(void *));
284 }
285};
286
287template <int N> struct QGlyphLayoutArray : public QGlyphLayout
288{
289public:
290 QGlyphLayoutArray()
291 : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
292 {
293 memset(buffer, 0, sizeof(buffer));
294 }
295
296private:
297 void *buffer[(N * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
298 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
299 + sizeof(QGlyphJustification)))
300 / sizeof(void *) + 1];
301};
302
303struct QScriptItem;
304/// Internal QTextItem
305class QTextItemInt : public QTextItem
306{
307public:
308 inline QTextItemInt()
309 : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0),
310 logClusters(0), f(0), fontEngine(0)
311 {}
312 QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
313
314 /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
315 /// the width of the returned QTextItemInt is not adjusted, for speed reasons
316 QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
317
318 QFixed descent;
319 QFixed ascent;
320 QFixed width;
321
322 RenderFlags flags;
323 bool justified;
324 QTextCharFormat::UnderlineStyle underlineStyle;
325 const QTextCharFormat charFormat;
326 int num_chars;
327 const QChar *chars;
328 const unsigned short *logClusters;
329 const QFont *f;
330
331 QGlyphLayout glyphs;
332 QFontEngine *fontEngine;
333};
334
335inline bool qIsControlChar(ushort uc)
336{
337 return uc >= 0x200b && uc <= 0x206f
338 && (uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */
339 || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */)
340 || uc >= 0x206a /* ISS, ASS, IAFS, AFS, NADS, NODS */);
341}
342
343struct Q_AUTOTEST_EXPORT QScriptItem
344{
345 inline QScriptItem()
346 : position(0),
347 num_glyphs(0), descent(-1), ascent(-1), width(-1),
348 glyph_data_offset(0) {}
349 inline QScriptItem(int p, const QScriptAnalysis &a)
350 : position(p), analysis(a),
351 num_glyphs(0), descent(-1), ascent(-1), width(-1),
352 glyph_data_offset(0) {}
353
354 int position;
355 QScriptAnalysis analysis;
356 unsigned short num_glyphs;
357 QFixed descent;
358 QFixed ascent;
359 QFixed width;
360 int glyph_data_offset;
361 QFixed height() const { return ascent + descent + 1; }
362};
363
364
365Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
366
367typedef QVector<QScriptItem> QScriptItemArray;
368
369struct Q_AUTOTEST_EXPORT QScriptLine
370{
371 // created and filled in QTextLine::layout_helper
372 QScriptLine()
373 : from(0), length(0),
374 justified(0), gridfitted(0),
375 hasTrailingSpaces(0) {}
376 QFixed descent;
377 QFixed ascent;
378 QFixed x;
379 QFixed y;
380 QFixed width;
381 QFixed textWidth;
382 int from;
383 signed int length : 29;
384 mutable uint justified : 1;
385 mutable uint gridfitted : 1;
386 uint hasTrailingSpaces : 1;
387 QFixed height() const { return ascent + descent + 1; }
388 void setDefaultHeight(QTextEngine *eng);
389 void operator+=(const QScriptLine &other);
390};
391Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
392
393
394inline void QScriptLine::operator+=(const QScriptLine &other)
395{
396 descent = qMax(descent, other.descent);
397 ascent = qMax(ascent, other.ascent);
398 textWidth += other.textWidth;
399 length += other.length;
400}
401
402typedef QVector<QScriptLine> QScriptLineArray;
403
404class QFontPrivate;
405class QTextFormatCollection;
406
407class Q_GUI_EXPORT QTextEngine {
408public:
409 struct LayoutData {
410 LayoutData(const QString &str, void **stack_memory, int mem_size);
411 LayoutData();
412 ~LayoutData();
413 mutable QScriptItemArray items;
414 int allocated;
415 int available_glyphs;
416 void **memory;
417 unsigned short *logClustersPtr;
418 QGlyphLayout glyphLayout;
419 mutable int used;
420 uint hasBidi : 1;
421 uint inLayout : 1;
422 uint memory_on_stack : 1;
423 bool haveCharAttributes;
424 QString string;
425 void reallocate(int totalGlyphs);
426 };
427
428 QTextEngine(LayoutData *data);
429 QTextEngine();
430 QTextEngine(const QString &str, const QFont &f);
431 ~QTextEngine();
432
433 enum Mode {
434 WidthOnly = 0x07
435 };
436
437 // keep in sync with QAbstractFontEngine::TextShapingFlag!!
438 enum ShaperFlag {
439 RightToLeft = 0x0001,
440 DesignMetrics = 0x0002,
441 GlyphIndicesOnly = 0x0004
442 };
443 Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
444
445 void invalidate();
446 void clearLineData();
447
448 void validate() const;
449 void itemize() const;
450
451 static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
452
453 const HB_CharAttributes *attributes() const;
454
455 void shape(int item) const;
456
457 void justify(const QScriptLine &si);
458
459 QFixed width(int charFrom, int numChars) const;
460 glyph_metrics_t boundingBox(int from, int len) const;
461 glyph_metrics_t tightBoundingBox(int from, int len) const;
462
463 int length(int item) const {
464 const QScriptItem &si = layoutData->items[item];
465 int from = si.position;
466 item++;
467 return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
468 }
469 int length(const QScriptItem *si) const {
470 int end;
471 if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
472 end = (si+1)->position;
473 else
474 end = layoutData->string.length();
475 return end - si->position;
476 }
477
478 QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0) const;
479 QFont font(const QScriptItem &si) const;
480 inline QFont font() const { return fnt; }
481
482 /**
483 * Returns a pointer to an array of log clusters, offset at the script item.
484 * Each item in the array is a unsigned short. For each character in the original string there is an entry in the table
485 * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
486 * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
487 * that one glyph is used for more than one character.
488 * \sa glyphs()
489 */
490 inline unsigned short *logClusters(const QScriptItem *si) const
491 { return layoutData->logClustersPtr+si->position; }
492 /**
493 * Returns an array of QGlyphLayout items, offset at the script item.
494 * Each item in the array matches one glyph in the text, storing the advance, position etc.
495 * The returned item's length equals to the number of available glyphs. This may be more
496 * than what was actually shaped.
497 * \sa logClusters()
498 */
499 inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
500 return layoutData->glyphLayout.mid(si->glyph_data_offset);
501 }
502 /**
503 * Returns an array of QGlyphLayout items, offset at the script item.
504 * Each item in the array matches one glyph in the text, storing the advance, position etc.
505 * The returned item's length equals to the number of shaped glyphs.
506 * \sa logClusters()
507 */
508 inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
509 return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
510 }
511
512 inline void ensureSpace(int nGlyphs) const {
513 if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
514 layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
515 }
516
517 void freeMemory();
518
519 int findItem(int strPos) const;
520 inline QTextFormatCollection *formats() const {
521#ifdef QT_BUILD_COMPAT_LIB
522 return 0; // Compat should never reference this symbol
523#else
524 return block.docHandle()->formatCollection();
525#endif
526 }
527 QTextCharFormat format(const QScriptItem *si) const;
528 inline QAbstractTextDocumentLayout *docLayout() const {
529#ifdef QT_BUILD_COMPAT_LIB
530 return 0; // Compat should never reference this symbol
531#else
532 return block.docHandle()->document()->documentLayout();
533#endif
534 }
535 int formatIndex(const QScriptItem *si) const;
536
537 /// returns the width of tab at index (in the tabs array) with the tab-start at position x
538 QFixed calculateTabWidth(int index, QFixed x) const;
539
540 mutable QScriptLineArray lines;
541
542 QString text;
543 QFont fnt;
544 QTextBlock block;
545
546 QTextOption option;
547
548 QFixed minWidth;
549 QFixed maxWidth;
550 QPointF position;
551 uint ignoreBidi : 1;
552 uint cacheGlyphs : 1;
553 uint stackEngine : 1;
554 uint forceJustification : 1;
555
556 int *underlinePositions;
557
558 mutable LayoutData *layoutData;
559
560 inline bool hasFormats() const { return (block.docHandle() || specialData); }
561
562 struct SpecialData {
563 int preeditPosition;
564 QString preeditText;
565 QList<QTextLayout::FormatRange> addFormats;
566 QVector<int> addFormatIndices;
567 QVector<int> resolvedFormatIndices;
568 };
569 SpecialData *specialData;
570
571 bool atWordSeparator(int position) const;
572 bool atSpace(int position) const;
573 void indexAdditionalFormats();
574
575 QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
576
577 void shapeLine(const QScriptLine &line);
578
579private:
580 void setBoundary(int strPos) const;
581 void addRequiredBoundaries() const;
582 void shapeText(int item) const;
583 void shapeTextWithHarfbuzz(int item) const;
584#if defined(Q_OS_WINCE)
585 void shapeTextWithCE(int item) const;
586#endif
587#if defined(Q_WS_MAC)
588 void shapeTextMac(int item) const;
589#endif
590 void splitItem(int item, int pos) const;
591
592 void resolveAdditionalFormats() const;
593};
594
595class QStackTextEngine : public QTextEngine {
596public:
597 enum { MemSize = 256*40/sizeof(void *) };
598 QStackTextEngine(const QString &string, const QFont &f);
599 LayoutData _layoutData;
600 void *_memory[MemSize];
601};
602
603
604Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
605
606QT_END_NAMESPACE
607
608#endif // QTEXTENGINE_P_H
Note: See TracBrowser for help on using the repository browser.