OpenCoverage

qtextengine.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/text/qtextengine.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui 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 The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include "qdebug.h"-
41#include "qtextformat.h"-
42#include "qtextformat_p.h"-
43#include "qtextengine_p.h"-
44#include "qabstracttextdocumentlayout.h"-
45#include "qtextlayout.h"-
46#include "qtextboundaryfinder.h"-
47#include "qvarlengtharray.h"-
48#include "qfont.h"-
49#include "qfont_p.h"-
50#include "qfontengine_p.h"-
51#include "qstring.h"-
52#include "qtextdocument_p.h"-
53#include "qrawfont.h"-
54#include "qrawfont_p.h"-
55#include <qguiapplication.h>-
56#include <qinputmethod.h>-
57#include <algorithm>-
58#include <stdlib.h>-
59-
60QT_BEGIN_NAMESPACE-
61-
62static const float smallCapsFraction = 0.7f;-
63-
64namespace {-
65// Helper class used in QTextEngine::itemize-
66// keep it out here to allow us to keep supporting various compilers.-
67class Itemizer {-
68public:-
69 Itemizer(const QString &string, const QScriptAnalysis *analysis, QScriptItemArray &items)-
70 : m_string(string),-
71 m_analysis(analysis),-
72 m_items(items),-
73 m_splitter(0)-
74 {-
75 }
never executed: end of block
0
76 ~Itemizer()-
77 {-
78 delete m_splitter;-
79 }
never executed: end of block
0
80-
81 /// generate the script items-
82 /// The caps parameter is used to choose the algoritm of splitting text and assiging roles to the textitems-
83 void generate(int start, int length, QFont::Capitalization caps)-
84 {-
85 if (caps == QFont::SmallCaps)
caps == QFont::SmallCapsDescription
TRUEnever evaluated
FALSEnever evaluated
0
86 generateScriptItemsSmallCaps(reinterpret_cast<const ushort *>(m_string.unicode()), start, length);
never executed: generateScriptItemsSmallCaps(reinterpret_cast<const ushort *>(m_string.unicode()), start, length);
0
87 else if(caps == QFont::Capitalize)
caps == QFont::CapitalizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
88 generateScriptItemsCapitalize(start, length);
never executed: generateScriptItemsCapitalize(start, length);
0
89 else if(caps != QFont::MixedCase) {
caps != QFont::MixedCaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
90 generateScriptItemsAndChangeCase(start, length,-
91 caps == QFont::AllLowercase ? QScriptAnalysis::Lowercase : QScriptAnalysis::Uppercase);-
92 }
never executed: end of block
0
93 else-
94 generateScriptItems(start, length);
never executed: generateScriptItems(start, length);
0
95 }-
96-
97private:-
98 enum { MaxItemLength = 4096 };-
99-
100 void generateScriptItemsAndChangeCase(int start, int length, QScriptAnalysis::Flags flags)-
101 {-
102 generateScriptItems(start, length);-
103 if (m_items.isEmpty()) // the next loop won't work in that case
m_items.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
104 return;
never executed: return;
0
105 QScriptItemArray::Iterator iter = m_items.end();-
106 do {-
107 iter--;-
108 if (iter->analysis.flags < QScriptAnalysis::LineOrParagraphSeparator)
iter->analysis...graphSeparatorDescription
TRUEnever evaluated
FALSEnever evaluated
0
109 iter->analysis.flags = flags;
never executed: iter->analysis.flags = flags;
0
110 } while (iter->position > start);
never executed: end of block
iter->position > startDescription
TRUEnever evaluated
FALSEnever evaluated
0
111 }
never executed: end of block
0
112-
113 void generateScriptItems(int start, int length)-
114 {-
115 if (!length)
!lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
116 return;
never executed: return;
0
117 const int end = start + length;-
118 for (int i = start + 1; i < end; ++i) {
i < endDescription
TRUEnever evaluated
FALSEnever evaluated
0
119 if (m_analysis[i].bidiLevel == m_analysis[start].bidiLevel
m_analysis[i]....art].bidiLevelDescription
TRUEnever evaluated
FALSEnever evaluated
0
120 && m_analysis[i].flags == m_analysis[start].flags
m_analysis[i]....s[start].flagsDescription
TRUEnever evaluated
FALSEnever evaluated
0
121 && (m_analysis[i].script == m_analysis[start].script || m_string[i] == QLatin1Char('.'))
m_analysis[i]....[start].scriptDescription
TRUEnever evaluated
FALSEnever evaluated
m_string[i] ==...atin1Char('.')Description
TRUEnever evaluated
FALSEnever evaluated
0
122 && m_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject
m_analysis[i]....aceTabOrObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
123 && i - start < MaxItemLength)
i - start < MaxItemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
124 continue;
never executed: continue;
0
125 m_items.append(QScriptItem(start, m_analysis[start]));-
126 start = i;-
127 }
never executed: end of block
0
128 m_items.append(QScriptItem(start, m_analysis[start]));-
129 }
never executed: end of block
0
130-
131 void generateScriptItemsCapitalize(int start, int length)-
132 {-
133 if (!length)
!lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
134 return;
never executed: return;
0
135-
136 if (!m_splitter)
!m_splitterDescription
TRUEnever evaluated
FALSEnever evaluated
0
137 m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word,
never executed: m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word, m_string.constData(), m_string.length(), 0, 0);
0
138 m_string.constData(), m_string.length(),
never executed: m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word, m_string.constData(), m_string.length(), 0, 0);
0
139 /*buffer*/0, /*buffer size*/0);
never executed: m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word, m_string.constData(), m_string.length(), 0, 0);
0
140-
141 m_splitter->setPosition(start);-
142 QScriptAnalysis itemAnalysis = m_analysis[start];-
143-
144 if (m_splitter->boundaryReasons() & QTextBoundaryFinder::StartOfItem)
m_splitter->bo...r::StartOfItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
145 itemAnalysis.flags = QScriptAnalysis::Uppercase;
never executed: itemAnalysis.flags = QScriptAnalysis::Uppercase;
0
146-
147 m_splitter->toNextBoundary();-
148-
149 const int end = start + length;-
150 for (int i = start + 1; i < end; ++i) {
i < endDescription
TRUEnever evaluated
FALSEnever evaluated
0
151 bool atWordStart = false;-
152-
153 if (i == m_splitter->position()) {
i == m_splitter->position()Description
TRUEnever evaluated
FALSEnever evaluated
0
154 if (m_splitter->boundaryReasons() & QTextBoundaryFinder::StartOfItem) {
m_splitter->bo...r::StartOfItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
155 Q_ASSERT(m_analysis[i].flags < QScriptAnalysis::TabOrObject);-
156 atWordStart = true;-
157 }
never executed: end of block
0
158-
159 m_splitter->toNextBoundary();-
160 }
never executed: end of block
0
161-
162 if (m_analysis[i] == itemAnalysis
m_analysis[i] == itemAnalysisDescription
TRUEnever evaluated
FALSEnever evaluated
0
163 && m_analysis[i].flags < QScriptAnalysis::TabOrObject
m_analysis[i]....s::TabOrObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
164 && !atWordStart
!atWordStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
165 && i - start < MaxItemLength)
i - start < MaxItemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
166 continue;
never executed: continue;
0
167-
168 m_items.append(QScriptItem(start, itemAnalysis));-
169 start = i;-
170 itemAnalysis = m_analysis[start];-
171-
172 if (atWordStart)
atWordStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
173 itemAnalysis.flags = QScriptAnalysis::Uppercase;
never executed: itemAnalysis.flags = QScriptAnalysis::Uppercase;
0
174 }
never executed: end of block
0
175 m_items.append(QScriptItem(start, itemAnalysis));-
176 }
never executed: end of block
0
177-
178 void generateScriptItemsSmallCaps(const ushort *uc, int start, int length)-
179 {-
180 if (!length)
!lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
181 return;
never executed: return;
0
182 bool lower = (QChar::category(uc[start]) == QChar::Letter_Lowercase);-
183 const int end = start + length;-
184 // split text into parts that are already uppercase and parts that are lowercase, and mark the latter to be uppercased later.-
185 for (int i = start + 1; i < end; ++i) {
i < endDescription
TRUEnever evaluated
FALSEnever evaluated
0
186 bool l = (QChar::category(uc[i]) == QChar::Letter_Lowercase);-
187 if ((m_analysis[i] == m_analysis[start])
(m_analysis[i]...alysis[start])Description
TRUEnever evaluated
FALSEnever evaluated
0
188 && m_analysis[i].flags < QScriptAnalysis::TabOrObject
m_analysis[i]....s::TabOrObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
189 && l == lower
l == lowerDescription
TRUEnever evaluated
FALSEnever evaluated
0
190 && i - start < MaxItemLength)
i - start < MaxItemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
191 continue;
never executed: continue;
0
192 m_items.append(QScriptItem(start, m_analysis[start]));-
193 if (lower)
lowerDescription
TRUEnever evaluated
FALSEnever evaluated
0
194 m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;
never executed: m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;
0
195-
196 start = i;-
197 lower = l;-
198 }
never executed: end of block
0
199 m_items.append(QScriptItem(start, m_analysis[start]));-
200 if (lower)
lowerDescription
TRUEnever evaluated
FALSEnever evaluated
0
201 m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;
never executed: m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;
0
202 }
never executed: end of block
0
203-
204 const QString &m_string;-
205 const QScriptAnalysis * const m_analysis;-
206 QScriptItemArray &m_items;-
207 QTextBoundaryFinder *m_splitter;-
208};-
209}-
210-
211-
212// -----------------------------------------------------------------------------
213//-
214// The BiDi algorithm-
215//-
216// -----------------------------------------------------------------------------
217-
218#define BIDI_DEBUG 0-
219#if (BIDI_DEBUG >= 1)-
220QT_BEGIN_INCLUDE_NAMESPACE-
221#include <iostream>-
222QT_END_INCLUDE_NAMESPACE-
223using namespace std;-
224-
225static const char *directions[] = {-
226 "DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON",-
227 "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN",-
228 "DirLRI", "DirRLI", "DirFSI", "DirPDI"-
229};-
230-
231#endif-
232-
233struct QBidiStatus {-
234 QBidiStatus() {-
235 eor = QChar::DirON;-
236 lastStrong = QChar::DirON;-
237 last = QChar:: DirON;-
238 dir = QChar::DirON;-
239 }
never executed: end of block
0
240 QChar::Direction eor;-
241 QChar::Direction lastStrong;-
242 QChar::Direction last;-
243 QChar::Direction dir;-
244};-
245-
246enum { MaxBidiLevel = 61 };-
247-
248struct QBidiControl {-
249 inline QBidiControl(bool rtl)-
250 : cCtx(0), base(rtl ? 1 : 0), level(rtl ? 1 : 0), override(false) {}
never executed: end of block
0
251-
252 inline void embed(bool rtl, bool o = false) {-
253 unsigned int toAdd = 1;-
254 if((level%2 != 0) == rtl ) {
(level%2 != 0) == rtlDescription
TRUEnever evaluated
FALSEnever evaluated
0
255 ++toAdd;-
256 }
never executed: end of block
0
257 if (level + toAdd <= MaxBidiLevel) {
level + toAdd <= MaxBidiLevelDescription
TRUEnever evaluated
FALSEnever evaluated
0
258 ctx[cCtx].level = level;-
259 ctx[cCtx].override = override;-
260 cCtx++;-
261 override = o;-
262 level += toAdd;-
263 }
never executed: end of block
0
264 }
never executed: end of block
0
265 inline bool canPop() const { return cCtx != 0; }
never executed: return cCtx != 0;
0
266 inline void pdf() {-
267 Q_ASSERT(cCtx);-
268 --cCtx;-
269 level = ctx[cCtx].level;-
270 override = ctx[cCtx].override;-
271 }
never executed: end of block
0
272-
273 inline QChar::Direction basicDirection() const {-
274 return (base ? QChar::DirR : QChar:: DirL);
never executed: return (base ? QChar::DirR : QChar:: DirL);
0
275 }-
276 inline unsigned int baseLevel() const {-
277 return base;
never executed: return base;
0
278 }-
279 inline QChar::Direction direction() const {-
280 return ((level%2) ? QChar::DirR : QChar:: DirL);
never executed: return ((level%2) ? QChar::DirR : QChar:: DirL);
0
281 }-
282-
283 struct {-
284 unsigned int level;-
285 bool override;-
286 } ctx[MaxBidiLevel];-
287 unsigned int cCtx;-
288 const unsigned int base;-
289 unsigned int level;-
290 bool override;-
291};-
292-
293-
294static void appendItems(QScriptAnalysis *analysis, int &start, int &stop, const QBidiControl &control, QChar::Direction dir)-
295{-
296 if (start > stop)
start > stopDescription
TRUEnever evaluated
FALSEnever evaluated
0
297 return;
never executed: return;
0
298-
299 int level = control.level;-
300-
301 if(dir != QChar::DirON && !control.override) {
dir != QChar::DirONDescription
TRUEnever evaluated
FALSEnever evaluated
!control.overrideDescription
TRUEnever evaluated
FALSEnever evaluated
0
302 // add level of run (cases I1 & I2)-
303 if(level % 2) {
level % 2Description
TRUEnever evaluated
FALSEnever evaluated
0
304 if(dir == QChar::DirL || dir == QChar::DirAN || dir == QChar::DirEN)
dir == QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
dir == QChar::DirANDescription
TRUEnever evaluated
FALSEnever evaluated
dir == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
0
305 level++;
never executed: level++;
0
306 } else {
never executed: end of block
0
307 if(dir == QChar::DirR)
dir == QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
308 level++;
never executed: level++;
0
309 else if(dir == QChar::DirAN || dir == QChar::DirEN)
dir == QChar::DirANDescription
TRUEnever evaluated
FALSEnever evaluated
dir == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
0
310 level += 2;
never executed: level += 2;
0
311 }
never executed: end of block
0
312 }-
313-
314#if (BIDI_DEBUG >= 1)-
315 qDebug("new run: dir=%s from %d, to %d level = %d override=%d", directions[dir], start, stop, level, control.override);-
316#endif-
317 QScriptAnalysis *s = analysis + start;-
318 const QScriptAnalysis *e = analysis + stop;-
319 while (s <= e) {
s <= eDescription
TRUEnever evaluated
FALSEnever evaluated
0
320 s->bidiLevel = level;-
321 ++s;-
322 }
never executed: end of block
0
323 ++stop;-
324 start = stop;-
325}
never executed: end of block
0
326-
327static QChar::Direction skipBoundryNeutrals(QScriptAnalysis *analysis,-
328 const ushort *unicode, int length,-
329 int &sor, int &eor, QBidiControl &control)-
330{-
331 QChar::Direction dir = control.basicDirection();-
332 int level = sor > 0 ? analysis[sor - 1].bidiLevel : control.level;
sor > 0Description
TRUEnever evaluated
FALSEnever evaluated
0
333 while (sor < length) {
sor < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
334 dir = QChar::direction(unicode[sor]);-
335 // Keep skipping DirBN as if it doesn't exist-
336 if (dir != QChar::DirBN)
dir != QChar::DirBNDescription
TRUEnever evaluated
FALSEnever evaluated
0
337 break;
never executed: break;
0
338 analysis[sor++].bidiLevel = level;-
339 }
never executed: end of block
0
340-
341 eor = sor;-
342 if (eor == length)
eor == lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
343 dir = control.basicDirection();
never executed: dir = control.basicDirection();
0
344-
345 return dir;
never executed: return dir;
0
346}-
347-
348// creates the next QScript items.-
349static bool bidiItemize(QTextEngine *engine, QScriptAnalysis *analysis, QBidiControl &control)-
350{-
351 bool rightToLeft = (control.basicDirection() == 1);-
352 bool hasBidi = rightToLeft;-
353#if BIDI_DEBUG >= 2-
354 qDebug() << "bidiItemize: rightToLeft=" << rightToLeft << engine->layoutData->string;-
355#endif-
356-
357 int sor = 0;-
358 int eor = -1;-
359-
360-
361 int length = engine->layoutData->string.length();-
362-
363 const ushort *unicode = (const ushort *)engine->layoutData->string.unicode();-
364 int current = 0;-
365-
366 QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL;
rightToLeftDescription
TRUEnever evaluated
FALSEnever evaluated
0
367 QBidiStatus status;-
368-
369 QChar::Direction sdir = QChar::direction(*unicode);-
370 if (sdir != QChar::DirL && sdir != QChar::DirR && sdir != QChar::DirEN && sdir != QChar::DirAN)
sdir != QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
sdir != QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
sdir != QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
sdir != QChar::DirANDescription
TRUEnever evaluated
FALSEnever evaluated
0
371 sdir = QChar::DirON;
never executed: sdir = QChar::DirON;
0
372 else-
373 dir = QChar::DirON;
never executed: dir = QChar::DirON;
0
374 status.eor = sdir;-
375 status.lastStrong = rightToLeft ? QChar::DirR : QChar::DirL;
rightToLeftDescription
TRUEnever evaluated
FALSEnever evaluated
0
376 status.last = status.lastStrong;-
377 status.dir = sdir;-
378-
379-
380 while (current <= length) {
current <= lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
381-
382 QChar::Direction dirCurrent;-
383 if (current == (int)length)
current == (int)lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
384 dirCurrent = control.basicDirection();
never executed: dirCurrent = control.basicDirection();
0
385 else-
386 dirCurrent = QChar::direction(unicode[current]);
never executed: dirCurrent = QChar::direction(unicode[current]);
0
387-
388#if (BIDI_DEBUG >= 2)-
389// qDebug() << "pos=" << current << " dir=" << directions[dir]-
390// << " current=" << directions[dirCurrent] << " last=" << directions[status.last]-
391// << " eor=" << eor << '/' << directions[status.eor]-
392// << " sor=" << sor << " lastStrong="-
393// << directions[status.lastStrong]-
394// << " level=" << (int)control.level << " override=" << (bool)control.override;-
395#endif-
396-
397 switch(dirCurrent) {-
398-
399 // embedding and overrides (X1-X9 in the BiDi specs)-
400 case QChar::DirRLE:
never executed: case QChar::DirRLE:
0
401 case QChar::DirRLO:
never executed: case QChar::DirRLO:
0
402 case QChar::DirLRE:
never executed: case QChar::DirLRE:
0
403 case QChar::DirLRO:
never executed: case QChar::DirLRO:
0
404 {-
405 bool rtl = (dirCurrent == QChar::DirRLE || dirCurrent == QChar::DirRLO);
dirCurrent == QChar::DirRLEDescription
TRUEnever evaluated
FALSEnever evaluated
dirCurrent == QChar::DirRLODescription
TRUEnever evaluated
FALSEnever evaluated
0
406 hasBidi |= rtl;-
407 bool override = (dirCurrent == QChar::DirLRO || dirCurrent == QChar::DirRLO);
dirCurrent == QChar::DirLRODescription
TRUEnever evaluated
FALSEnever evaluated
dirCurrent == QChar::DirRLODescription
TRUEnever evaluated
FALSEnever evaluated
0
408-
409 unsigned int level = control.level+1;-
410 if ((level%2 != 0) == rtl) ++level;
never executed: ++level;
(level%2 != 0) == rtlDescription
TRUEnever evaluated
FALSEnever evaluated
0
411 if(level < MaxBidiLevel) {
level < MaxBidiLevelDescription
TRUEnever evaluated
FALSEnever evaluated
0
412 eor = current-1;-
413 appendItems(analysis, sor, eor, control, dir);-
414 eor = current;-
415 control.embed(rtl, override);-
416 QChar::Direction edir = (rtl ? QChar::DirR : QChar::DirL);
rtlDescription
TRUEnever evaluated
FALSEnever evaluated
0
417 dir = status.eor = edir;-
418 status.lastStrong = edir;-
419 }
never executed: end of block
0
420 break;
never executed: break;
0
421 }-
422 case QChar::DirPDF:
never executed: case QChar::DirPDF:
0
423 {-
424 if (control.canPop()) {
control.canPop()Description
TRUEnever evaluated
FALSEnever evaluated
0
425 if (dir != control.direction()) {
dir != control.direction()Description
TRUEnever evaluated
FALSEnever evaluated
0
426 eor = current-1;-
427 appendItems(analysis, sor, eor, control, dir);-
428 dir = control.direction();-
429 }
never executed: end of block
0
430 eor = current;-
431 appendItems(analysis, sor, eor, control, dir);-
432 control.pdf();-
433 dir = QChar::DirON; status.eor = QChar::DirON;-
434 status.last = control.direction();-
435 if (control.override)
control.overrideDescription
TRUEnever evaluated
FALSEnever evaluated
0
436 dir = control.direction();
never executed: dir = control.direction();
0
437 else-
438 dir = QChar::DirON;
never executed: dir = QChar::DirON;
0
439 status.lastStrong = control.direction();-
440 }
never executed: end of block
0
441 break;
never executed: break;
0
442 }-
443-
444 // strong types-
445 case QChar::DirL:
never executed: case QChar::DirL:
0
446 if(dir == QChar::DirON)
dir == QChar::DirONDescription
TRUEnever evaluated
FALSEnever evaluated
0
447 dir = QChar::DirL;
never executed: dir = QChar::DirL;
0
448 switch(status.last)-
449 {-
450 case QChar::DirL:
never executed: case QChar::DirL:
0
451 eor = current; status.eor = QChar::DirL; break;
never executed: break;
0
452 case QChar::DirR:
never executed: case QChar::DirR:
0
453 case QChar::DirAL:
never executed: case QChar::DirAL:
0
454 case QChar::DirEN:
never executed: case QChar::DirEN:
0
455 case QChar::DirAN:
never executed: case QChar::DirAN:
0
456 if (eor >= 0) {
eor >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
457 appendItems(analysis, sor, eor, control, dir);-
458 status.eor = dir = skipBoundryNeutrals(analysis, unicode, length, sor, eor, control);-
459 } else {
never executed: end of block
0
460 eor = current; status.eor = dir;-
461 }
never executed: end of block
0
462 break;
never executed: break;
0
463 case QChar::DirES:
never executed: case QChar::DirES:
0
464 case QChar::DirET:
never executed: case QChar::DirET:
0
465 case QChar::DirCS:
never executed: case QChar::DirCS:
0
466 case QChar::DirBN:
never executed: case QChar::DirBN:
0
467 case QChar::DirB:
never executed: case QChar::DirB:
0
468 case QChar::DirS:
never executed: case QChar::DirS:
0
469 case QChar::DirWS:
never executed: case QChar::DirWS:
0
470 case QChar::DirON:
never executed: case QChar::DirON:
0
471 if(dir != QChar::DirL) {
dir != QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
472 //last stuff takes embedding dir-
473 if(control.direction() == QChar::DirR) {
control.direct...== QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
474 if(status.eor != QChar::DirR) {
status.eor != QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
475 // AN or EN-
476 appendItems(analysis, sor, eor, control, dir);-
477 status.eor = QChar::DirON;-
478 dir = QChar::DirR;-
479 }
never executed: end of block
0
480 eor = current - 1;-
481 appendItems(analysis, sor, eor, control, dir);-
482 status.eor = dir = skipBoundryNeutrals(analysis, unicode, length, sor, eor, control);-
483 } else {
never executed: end of block
0
484 if(status.eor != QChar::DirL) {
status.eor != QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
485 appendItems(analysis, sor, eor, control, dir);-
486 status.eor = QChar::DirON;-
487 dir = QChar::DirL;-
488 } else {
never executed: end of block
0
489 eor = current; status.eor = QChar::DirL; break;
never executed: break;
0
490 }-
491 }-
492 } else {-
493 eor = current; status.eor = QChar::DirL;-
494 }
never executed: end of block
0
495 default:
code before this statement never executed: default:
never executed: default:
0
496 break;
never executed: break;
0
497 }-
498 status.lastStrong = QChar::DirL;-
499 break;
never executed: break;
0
500 case QChar::DirAL:
never executed: case QChar::DirAL:
0
501 case QChar::DirR:
never executed: case QChar::DirR:
0
502 hasBidi = true;-
503 if(dir == QChar::DirON) dir = QChar::DirR;
never executed: dir = QChar::DirR;
dir == QChar::DirONDescription
TRUEnever evaluated
FALSEnever evaluated
0
504 switch(status.last)-
505 {-
506 case QChar::DirL:
never executed: case QChar::DirL:
0
507 case QChar::DirEN:
never executed: case QChar::DirEN:
0
508 case QChar::DirAN:
never executed: case QChar::DirAN:
0
509 if (eor >= 0)
eor >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
510 appendItems(analysis, sor, eor, control, dir);
never executed: appendItems(analysis, sor, eor, control, dir);
0
511 // fall through-
512 case QChar::DirR:
code before this statement never executed: case QChar::DirR:
never executed: case QChar::DirR:
0
513 case QChar::DirAL:
never executed: case QChar::DirAL:
0
514 dir = QChar::DirR; eor = current; status.eor = QChar::DirR; break;
never executed: break;
0
515 case QChar::DirES:
never executed: case QChar::DirES:
0
516 case QChar::DirET:
never executed: case QChar::DirET:
0
517 case QChar::DirCS:
never executed: case QChar::DirCS:
0
518 case QChar::DirBN:
never executed: case QChar::DirBN:
0
519 case QChar::DirB:
never executed: case QChar::DirB:
0
520 case QChar::DirS:
never executed: case QChar::DirS:
0
521 case QChar::DirWS:
never executed: case QChar::DirWS:
0
522 case QChar::DirON:
never executed: case QChar::DirON:
0
523 if(status.eor != QChar::DirR && status.eor != QChar::DirAL) {
status.eor != QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
status.eor != QChar::DirALDescription
TRUEnever evaluated
FALSEnever evaluated
0
524 //last stuff takes embedding dir-
525 if(control.direction() == QChar::DirR
control.direct...== QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
526 || status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) {
status.lastStr...== QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
status.lastStr...= QChar::DirALDescription
TRUEnever evaluated
FALSEnever evaluated
0
527 appendItems(analysis, sor, eor, control, dir);-
528 dir = QChar::DirR; status.eor = QChar::DirON;-
529 eor = current;-
530 } else {
never executed: end of block
0
531 eor = current - 1;-
532 appendItems(analysis, sor, eor, control, dir);-
533 dir = QChar::DirR; status.eor = QChar::DirON;-
534 }
never executed: end of block
0
535 } else {-
536 eor = current; status.eor = QChar::DirR;-
537 }
never executed: end of block
0
538 default:
code before this statement never executed: default:
never executed: default:
0
539 break;
never executed: break;
0
540 }-
541 status.lastStrong = dirCurrent;-
542 break;
never executed: break;
0
543-
544 // weak types:-
545-
546 case QChar::DirNSM:
never executed: case QChar::DirNSM:
0
547 if (eor == current-1)
eor == current-1Description
TRUEnever evaluated
FALSEnever evaluated
0
548 eor = current;
never executed: eor = current;
0
549 break;
never executed: break;
0
550 case QChar::DirEN:
never executed: case QChar::DirEN:
0
551 // if last strong was AL change EN to AN-
552 if(status.lastStrong != QChar::DirAL) {
status.lastStr...= QChar::DirALDescription
TRUEnever evaluated
FALSEnever evaluated
0
553 if(dir == QChar::DirON) {
dir == QChar::DirONDescription
TRUEnever evaluated
FALSEnever evaluated
0
554 if(status.lastStrong == QChar::DirL)
status.lastStr...== QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
555 dir = QChar::DirL;
never executed: dir = QChar::DirL;
0
556 else-
557 dir = QChar::DirEN;
never executed: dir = QChar::DirEN;
0
558 }-
559 switch(status.last)-
560 {-
561 case QChar::DirET:
never executed: case QChar::DirET:
0
562 if (status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) {
status.lastStr...== QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
status.lastStr...= QChar::DirALDescription
TRUEnever evaluated
FALSEnever evaluated
0
563 appendItems(analysis, sor, eor, control, dir);-
564 status.eor = QChar::DirON;-
565 dir = QChar::DirAN;-
566 }
never executed: end of block
0
567 // fall through-
568 case QChar::DirEN:
code before this statement never executed: case QChar::DirEN:
never executed: case QChar::DirEN:
0
569 case QChar::DirL:
never executed: case QChar::DirL:
0
570 eor = current;-
571 status.eor = dirCurrent;-
572 break;
never executed: break;
0
573 case QChar::DirR:
never executed: case QChar::DirR:
0
574 case QChar::DirAL:
never executed: case QChar::DirAL:
0
575 case QChar::DirAN:
never executed: case QChar::DirAN:
0
576 if (eor >= 0)
eor >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
577 appendItems(analysis, sor, eor, control, dir);
never executed: appendItems(analysis, sor, eor, control, dir);
0
578 else-
579 eor = current;
never executed: eor = current;
0
580 status.eor = QChar::DirEN;-
581 dir = QChar::DirAN; break;
never executed: break;
0
582 case QChar::DirES:
never executed: case QChar::DirES:
0
583 case QChar::DirCS:
never executed: case QChar::DirCS:
0
584 if(status.eor == QChar::DirEN || dir == QChar::DirAN) {
status.eor == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
dir == QChar::DirANDescription
TRUEnever evaluated
FALSEnever evaluated
0
585 eor = current; break;
never executed: break;
0
586 }-
587 case QChar::DirBN:
code before this statement never executed: case QChar::DirBN:
never executed: case QChar::DirBN:
0
588 case QChar::DirB:
never executed: case QChar::DirB:
0
589 case QChar::DirS:
never executed: case QChar::DirS:
0
590 case QChar::DirWS:
never executed: case QChar::DirWS:
0
591 case QChar::DirON:
never executed: case QChar::DirON:
0
592 if(status.eor == QChar::DirR) {
status.eor == QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
593 // neutrals go to R-
594 eor = current - 1;-
595 appendItems(analysis, sor, eor, control, dir);-
596 dir = QChar::DirON; status.eor = QChar::DirEN;-
597 dir = QChar::DirAN;-
598 }
never executed: end of block
0
599 else if(status.eor == QChar::DirL ||
status.eor == QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
600 (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) {
status.eor == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
status.lastStr...== QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
601 eor = current; status.eor = dirCurrent;-
602 } else {
never executed: end of block
0
603 // numbers on both sides, neutrals get right to left direction-
604 if(dir != QChar::DirL) {
dir != QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
605 appendItems(analysis, sor, eor, control, dir);-
606 dir = QChar::DirON; status.eor = QChar::DirON;-
607 eor = current - 1;-
608 dir = QChar::DirR;-
609 appendItems(analysis, sor, eor, control, dir);-
610 dir = QChar::DirON; status.eor = QChar::DirON;-
611 dir = QChar::DirAN;-
612 } else {
never executed: end of block
0
613 eor = current; status.eor = dirCurrent;-
614 }
never executed: end of block
0
615 }-
616 default:
code before this statement never executed: default:
never executed: default:
0
617 break;
never executed: break;
0
618 }-
619 break;
never executed: break;
0
620 }-
621 case QChar::DirAN:
code before this statement never executed: case QChar::DirAN:
never executed: case QChar::DirAN:
0
622 hasBidi = true;-
623 dirCurrent = QChar::DirAN;-
624 if(dir == QChar::DirON) dir = QChar::DirAN;
never executed: dir = QChar::DirAN;
dir == QChar::DirONDescription
TRUEnever evaluated
FALSEnever evaluated
0
625 switch(status.last)-
626 {-
627 case QChar::DirL:
never executed: case QChar::DirL:
0
628 case QChar::DirAN:
never executed: case QChar::DirAN:
0
629 eor = current; status.eor = QChar::DirAN; break;
never executed: break;
0
630 case QChar::DirR:
never executed: case QChar::DirR:
0
631 case QChar::DirAL:
never executed: case QChar::DirAL:
0
632 case QChar::DirEN:
never executed: case QChar::DirEN:
0
633 if (eor >= 0){
eor >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
634 appendItems(analysis, sor, eor, control, dir);-
635 } else {
never executed: end of block
0
636 eor = current;-
637 }
never executed: end of block
0
638 dir = QChar::DirAN; status.eor = QChar::DirAN;-
639 break;
never executed: break;
0
640 case QChar::DirCS:
never executed: case QChar::DirCS:
0
641 if(status.eor == QChar::DirAN) {
status.eor == QChar::DirANDescription
TRUEnever evaluated
FALSEnever evaluated
0
642 eor = current; break;
never executed: break;
0
643 }-
644 case QChar::DirES:
code before this statement never executed: case QChar::DirES:
never executed: case QChar::DirES:
0
645 case QChar::DirET:
never executed: case QChar::DirET:
0
646 case QChar::DirBN:
never executed: case QChar::DirBN:
0
647 case QChar::DirB:
never executed: case QChar::DirB:
0
648 case QChar::DirS:
never executed: case QChar::DirS:
0
649 case QChar::DirWS:
never executed: case QChar::DirWS:
0
650 case QChar::DirON:
never executed: case QChar::DirON:
0
651 if(status.eor == QChar::DirR) {
status.eor == QChar::DirRDescription
TRUEnever evaluated
FALSEnever evaluated
0
652 // neutrals go to R-
653 eor = current - 1;-
654 appendItems(analysis, sor, eor, control, dir);-
655 status.eor = QChar::DirAN;-
656 dir = QChar::DirAN;-
657 } else if(status.eor == QChar::DirL ||
never executed: end of block
status.eor == QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
658 (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) {
status.eor == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
status.lastStr...== QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
659 eor = current; status.eor = dirCurrent;-
660 } else {
never executed: end of block
0
661 // numbers on both sides, neutrals get right to left direction-
662 if(dir != QChar::DirL) {
dir != QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
663 appendItems(analysis, sor, eor, control, dir);-
664 status.eor = QChar::DirON;-
665 eor = current - 1;-
666 dir = QChar::DirR;-
667 appendItems(analysis, sor, eor, control, dir);-
668 status.eor = QChar::DirAN;-
669 dir = QChar::DirAN;-
670 } else {
never executed: end of block
0
671 eor = current; status.eor = dirCurrent;-
672 }
never executed: end of block
0
673 }-
674 default:
code before this statement never executed: default:
never executed: default:
0
675 break;
never executed: break;
0
676 }-
677 break;
never executed: break;
0
678 case QChar::DirES:
never executed: case QChar::DirES:
0
679 case QChar::DirCS:
never executed: case QChar::DirCS:
0
680 break;
never executed: break;
0
681 case QChar::DirET:
never executed: case QChar::DirET:
0
682 if(status.last == QChar::DirEN) {
status.last == QChar::DirENDescription
TRUEnever evaluated
FALSEnever evaluated
0
683 dirCurrent = QChar::DirEN;-
684 eor = current; status.eor = dirCurrent;-
685 }
never executed: end of block
0
686 break;
never executed: break;
0
687-
688 // boundary neutrals should be ignored-
689 case QChar::DirBN:
never executed: case QChar::DirBN:
0
690 break;
never executed: break;
0
691 // neutrals-
692 case QChar::DirB:
never executed: case QChar::DirB:
0
693 // ### what do we do with newline and paragraph separators that come to here?-
694 break;
never executed: break;
0
695 case QChar::DirS:
never executed: case QChar::DirS:
0
696 // ### implement rule L1-
697 break;
never executed: break;
0
698 case QChar::DirWS:
never executed: case QChar::DirWS:
0
699 case QChar::DirON:
never executed: case QChar::DirON:
0
700 break;
never executed: break;
0
701 default:
never executed: default:
0
702 break;
never executed: break;
0
703 }-
704-
705 //qDebug() << " after: dir=" << // dir << " current=" << dirCurrent << " last=" << status.last << " eor=" << status.eor << " lastStrong=" << status.lastStrong << " embedding=" << control.direction();-
706-
707 if(current >= (int)length) break;
never executed: break;
current >= (int)lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
708-
709 // set status.last as needed.-
710 switch(dirCurrent) {-
711 case QChar::DirET:
never executed: case QChar::DirET:
0
712 case QChar::DirES:
never executed: case QChar::DirES:
0
713 case QChar::DirCS:
never executed: case QChar::DirCS:
0
714 case QChar::DirS:
never executed: case QChar::DirS:
0
715 case QChar::DirWS:
never executed: case QChar::DirWS:
0
716 case QChar::DirON:
never executed: case QChar::DirON:
0
717 switch(status.last)-
718 {-
719 case QChar::DirL:
never executed: case QChar::DirL:
0
720 case QChar::DirR:
never executed: case QChar::DirR:
0
721 case QChar::DirAL:
never executed: case QChar::DirAL:
0
722 case QChar::DirEN:
never executed: case QChar::DirEN:
0
723 case QChar::DirAN:
never executed: case QChar::DirAN:
0
724 status.last = dirCurrent;-
725 break;
never executed: break;
0
726 default:
never executed: default:
0
727 status.last = QChar::DirON;-
728 }
never executed: end of block
0
729 break;
never executed: break;
0
730 case QChar::DirNSM:
never executed: case QChar::DirNSM:
0
731 case QChar::DirBN:
never executed: case QChar::DirBN:
0
732 // ignore these-
733 break;
never executed: break;
0
734 case QChar::DirLRO:
never executed: case QChar::DirLRO:
0
735 case QChar::DirLRE:
never executed: case QChar::DirLRE:
0
736 status.last = QChar::DirL;-
737 break;
never executed: break;
0
738 case QChar::DirRLO:
never executed: case QChar::DirRLO:
0
739 case QChar::DirRLE:
never executed: case QChar::DirRLE:
0
740 status.last = QChar::DirR;-
741 break;
never executed: break;
0
742 case QChar::DirEN:
never executed: case QChar::DirEN:
0
743 if (status.last == QChar::DirL) {
status.last == QChar::DirLDescription
TRUEnever evaluated
FALSEnever evaluated
0
744 status.last = QChar::DirL;-
745 break;
never executed: break;
0
746 }-
747 // fall through-
748 default:
code before this statement never executed: default:
never executed: default:
0
749 status.last = dirCurrent;-
750 }
never executed: end of block
0
751-
752 ++current;-
753 }
never executed: end of block
0
754-
755#if (BIDI_DEBUG >= 1)-
756 qDebug() << "reached end of line current=" << current << ", eor=" << eor;-
757#endif-
758 eor = current - 1; // remove dummy char-
759-
760 if (sor <= eor)
sor <= eorDescription
TRUEnever evaluated
FALSEnever evaluated
0
761 appendItems(analysis, sor, eor, control, dir);
never executed: appendItems(analysis, sor, eor, control, dir);
0
762-
763 return hasBidi;
never executed: return hasBidi;
0
764}-
765-
766void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrder)-
767{-
768-
769 // first find highest and lowest levels-
770 quint8 levelLow = 128;-
771 quint8 levelHigh = 0;-
772 int i = 0;-
773 while (i < numItems) {
i < numItemsDescription
TRUEnever evaluated
FALSEnever evaluated
0
774 //printf("level = %d\n", r->level);-
775 if (levels[i] > levelHigh)
levels[i] > levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
0
776 levelHigh = levels[i];
never executed: levelHigh = levels[i];
0
777 if (levels[i] < levelLow)
levels[i] < levelLowDescription
TRUEnever evaluated
FALSEnever evaluated
0
778 levelLow = levels[i];
never executed: levelLow = levels[i];
0
779 i++;-
780 }
never executed: end of block
0
781-
782 // implements reordering of the line (L2 according to BiDi spec):-
783 // L2. From the highest level found in the text to the lowest odd level on each line,-
784 // reverse any contiguous sequence of characters that are at that level or higher.-
785-
786 // reversing is only done up to the lowest odd level-
787 if(!(levelLow%2)) levelLow++;
never executed: levelLow++;
!(levelLow%2)Description
TRUEnever evaluated
FALSEnever evaluated
0
788-
789#if (BIDI_DEBUG >= 1)-
790// qDebug() << "reorderLine: lineLow = " << (uint)levelLow << ", lineHigh = " << (uint)levelHigh;-
791#endif-
792-
793 int count = numItems - 1;-
794 for (i = 0; i < numItems; i++)
i < numItemsDescription
TRUEnever evaluated
FALSEnever evaluated
0
795 visualOrder[i] = i;
never executed: visualOrder[i] = i;
0
796-
797 while(levelHigh >= levelLow) {
levelHigh >= levelLowDescription
TRUEnever evaluated
FALSEnever evaluated
0
798 int i = 0;-
799 while (i < count) {
i < countDescription
TRUEnever evaluated
FALSEnever evaluated
0
800 while(i < count && levels[i] < levelHigh) i++;
never executed: i++;
i < countDescription
TRUEnever evaluated
FALSEnever evaluated
levels[i] < levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
0
801 int start = i;-
802 while(i <= count && levels[i] >= levelHigh) i++;
never executed: i++;
i <= countDescription
TRUEnever evaluated
FALSEnever evaluated
levels[i] >= levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
0
803 int end = i-1;-
804-
805 if(start != end) {
start != endDescription
TRUEnever evaluated
FALSEnever evaluated
0
806 //qDebug() << "reversing from " << start << " to " << end;-
807 for(int j = 0; j < (end-start+1)/2; j++) {
j < (end-start+1)/2Description
TRUEnever evaluated
FALSEnever evaluated
0
808 int tmp = visualOrder[start+j];-
809 visualOrder[start+j] = visualOrder[end-j];-
810 visualOrder[end-j] = tmp;-
811 }
never executed: end of block
0
812 }
never executed: end of block
0
813 i++;-
814 }
never executed: end of block
0
815 levelHigh--;-
816 }
never executed: end of block
0
817-
818#if (BIDI_DEBUG >= 1)-
819// qDebug("visual order is:");-
820// for (i = 0; i < numItems; i++)-
821// qDebug() << visualOrder[i];-
822#endif-
823}
never executed: end of block
0
824-
825-
826enum JustificationClass {-
827 Justification_Prohibited = 0, // Justification can not be applied after this glyph-
828 Justification_Arabic_Space = 1, // This glyph represents a space inside arabic text-
829 Justification_Character = 2, // Inter-character justification point follows this glyph-
830 Justification_Space = 4, // This glyph represents a blank outside an Arabic run-
831 Justification_Arabic_Normal = 7, // Normal Middle-Of-Word glyph that connects to the right (begin)-
832 Justification_Arabic_Waw = 8, // Next character is final form of Waw/Ain/Qaf/Feh-
833 Justification_Arabic_BaRa = 9, // Next two characters are Ba + Ra/Ya/AlefMaksura-
834 Justification_Arabic_Alef = 10, // Next character is final form of Alef/Tah/Lam/Kaf/Gaf-
835 Justification_Arabic_HahDal = 11, // Next character is final form of Hah/Dal/Teh Marbuta-
836 Justification_Arabic_Seen = 12, // Initial or medial form of Seen/Sad-
837 Justification_Arabic_Kashida = 13 // User-inserted Kashida(U+0640)-
838};-
839-
840#ifdef QT_ENABLE_HARFBUZZ_NG-
841-
842/*-
843 Adds an inter character justification opportunity after the number or letter-
844 character and a space justification opportunity after the space character.-
845*/-
846static inline void qt_getDefaultJustificationOpportunities(const ushort *string, int length, QGlyphLayout g, ushort *log_clusters, int spaceAs)-
847{-
848 int str_pos = 0;-
849 while (str_pos < length) {
str_pos < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
850 int glyph_pos = log_clusters[str_pos];-
851-
852 Q_ASSERT(glyph_pos < g.numGlyphs && g.attributes[glyph_pos].clusterStart);-
853-
854 uint ucs4 = string[str_pos];-
855 if (QChar::isHighSurrogate(ucs4) && str_pos + 1 < length) {
QChar::isHighSurrogate(ucs4)Description
TRUEnever evaluated
FALSEnever evaluated
str_pos + 1 < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
856 ushort low = string[str_pos + 1];-
857 if (QChar::isLowSurrogate(low)) {
QChar::isLowSurrogate(low)Description
TRUEnever evaluated
FALSEnever evaluated
0
858 ++str_pos;-
859 ucs4 = QChar::surrogateToUcs4(ucs4, low);-
860 }
never executed: end of block
0
861 }
never executed: end of block
0
862-
863 // skip whole cluster-
864 do {-
865 ++str_pos;-
866 } while (str_pos < length && log_clusters[str_pos] == glyph_pos);
never executed: end of block
str_pos < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
log_clusters[s...] == glyph_posDescription
TRUEnever evaluated
FALSEnever evaluated
0
867 do {-
868 ++glyph_pos;-
869 } while (glyph_pos < g.numGlyphs && !g.attributes[glyph_pos].clusterStart);
never executed: end of block
glyph_pos < g.numGlyphsDescription
TRUEnever evaluated
FALSEnever evaluated
!g.attributes[...].clusterStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
870 --glyph_pos;-
871-
872 // justification opportunity at the end of cluster-
873 if (Q_LIKELY(QChar::isLetterOrNumber(ucs4)))
__builtin_expe...(ucs4)), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
874 g.attributes[glyph_pos].justification = Justification_Character;
never executed: g.attributes[glyph_pos].justification = Justification_Character;
0
875 else if (Q_LIKELY(QChar::isSpace(ucs4)))
__builtin_expe...(ucs4)), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
876 g.attributes[glyph_pos].justification = spaceAs;
never executed: g.attributes[glyph_pos].justification = spaceAs;
0
877 }
never executed: end of block
0
878}
never executed: end of block
0
879-
880static inline void qt_getJustificationOpportunities(const ushort *string, int length, const QScriptItem &si, QGlyphLayout g, ushort *log_clusters)-
881{-
882 Q_ASSERT(length > 0 && g.numGlyphs > 0);-
883-
884 for (int glyph_pos = 0; glyph_pos < g.numGlyphs; ++glyph_pos)
glyph_pos < g.numGlyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
885 g.attributes[glyph_pos].justification = Justification_Prohibited;
never executed: g.attributes[glyph_pos].justification = Justification_Prohibited;
0
886-
887 int spaceAs;-
888-
889 switch (si.analysis.script) {-
890 case QChar::Script_Arabic:
never executed: case QChar::Script_Arabic:
0
891 case QChar::Script_Syriac:
never executed: case QChar::Script_Syriac:
0
892 case QChar::Script_Nko:
never executed: case QChar::Script_Nko:
0
893 case QChar::Script_Mandaic:
never executed: case QChar::Script_Mandaic:
0
894 case QChar::Script_Mongolian:
never executed: case QChar::Script_Mongolian:
0
895 case QChar::Script_PhagsPa:
never executed: case QChar::Script_PhagsPa:
0
896 case QChar::Script_Manichaean:
never executed: case QChar::Script_Manichaean:
0
897 case QChar::Script_PsalterPahlavi:
never executed: case QChar::Script_PsalterPahlavi:
0
898 // same as default but inter character justification takes precedence-
899 spaceAs = Justification_Arabic_Space;-
900 break;
never executed: break;
0
901-
902 case QChar::Script_Tibetan:
never executed: case QChar::Script_Tibetan:
0
903 case QChar::Script_Hiragana:
never executed: case QChar::Script_Hiragana:
0
904 case QChar::Script_Katakana:
never executed: case QChar::Script_Katakana:
0
905 case QChar::Script_Bopomofo:
never executed: case QChar::Script_Bopomofo:
0
906 case QChar::Script_Han:
never executed: case QChar::Script_Han:
0
907 // same as default but inter character justification is the only option-
908 spaceAs = Justification_Character;-
909 break;
never executed: break;
0
910-
911 default:
never executed: default:
0
912 spaceAs = Justification_Space;-
913 break;
never executed: break;
0
914 }-
915-
916 qt_getDefaultJustificationOpportunities(string, length, g, log_clusters, spaceAs);-
917}
never executed: end of block
0
918-
919#endif // QT_ENABLE_HARFBUZZ_NG-
920-
921-
922// shape all the items that intersect with the line, taking tab widths into account to find out what text actually fits in the line.-
923void QTextEngine::shapeLine(const QScriptLine &line)-
924{-
925 QFixed x;-
926 bool first = true;-
927 int item = findItem(line.from);-
928 if (item == -1)
item == -1Description
TRUEnever evaluated
FALSEnever evaluated
0
929 return;
never executed: return;
0
930-
931 const int end = findItem(line.from + line.length + line.trailingSpaces - 1, item);-
932 for ( ; item <= end; ++item) {
item <= endDescription
TRUEnever evaluated
FALSEnever evaluated
0
933 QScriptItem &si = layoutData->items[item];-
934 if (si.analysis.flags == QScriptAnalysis::Tab) {
si.analysis.fl...tAnalysis::TabDescription
TRUEnever evaluated
FALSEnever evaluated
0
935 ensureSpace(1);-
936 si.width = calculateTabWidth(item, x);-
937 } else {
never executed: end of block
0
938 shape(item);-
939 }
never executed: end of block
0
940 if (first && si.position != line.from) { // that means our x position has to be offset
firstDescription
TRUEnever evaluated
FALSEnever evaluated
si.position != line.fromDescription
TRUEnever evaluated
FALSEnever evaluated
0
941 QGlyphLayout glyphs = shapedGlyphs(&si);-
942 Q_ASSERT(line.from > si.position);-
943 for (int i = line.from - si.position - 1; i >= 0; i--) {
i >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
944 x -= glyphs.effectiveAdvance(i);-
945 }
never executed: end of block
0
946 }
never executed: end of block
0
947 first = false;-
948-
949 x += si.width;-
950 }
never executed: end of block
0
951}
never executed: end of block
0
952-
953#ifdef QT_ENABLE_HARFBUZZ_NG-
954extern bool qt_useHarfbuzzNG(); // defined in qfontengine.cpp-
955#endif-
956-
957void QTextEngine::shapeText(int item) const-
958{-
959 Q_ASSERT(item < layoutData->items.size());-
960 QScriptItem &si = layoutData->items[item];-
961-
962 if (si.num_glyphs)
si.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
963 return;
never executed: return;
0
964-
965 si.width = 0;-
966 si.glyph_data_offset = layoutData->used;-
967-
968 const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.constData()) + si.position;-
969 const int itemLength = length(item);-
970-
971 QString casedString;-
972 if (si.analysis.flags && si.analysis.flags <= QScriptAnalysis::SmallCaps) {
si.analysis.flagsDescription
TRUEnever evaluated
FALSEnever evaluated
si.analysis.fl...sis::SmallCapsDescription
TRUEnever evaluated
FALSEnever evaluated
0
973 casedString.resize(itemLength);-
974 ushort *uc = reinterpret_cast<ushort *>(casedString.data());-
975 for (int i = 0; i < itemLength; ++i) {
i < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
976 uint ucs4 = string[i];-
977 if (QChar::isHighSurrogate(ucs4) && i + 1 < itemLength) {
QChar::isHighSurrogate(ucs4)Description
TRUEnever evaluated
FALSEnever evaluated
i + 1 < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
978 uint low = string[i + 1];-
979 if (QChar::isLowSurrogate(low)) {
QChar::isLowSurrogate(low)Description
TRUEnever evaluated
FALSEnever evaluated
0
980 ++i;-
981 ucs4 = QChar::surrogateToUcs4(ucs4, low);-
982 ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4)
si.analysis.fl...sis::LowercaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
983 : QChar::toUpper(ucs4);-
984 // high part never changes in simple casing-
985 uc[i] = QChar::lowSurrogate(ucs4);-
986 }
never executed: end of block
0
987 } else {
never executed: end of block
0
988 uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4)
si.analysis.fl...sis::LowercaseDescription
TRUEnever evaluated
FALSEnever evaluated
0
989 : QChar::toUpper(ucs4);-
990 }
never executed: end of block
0
991 }-
992 string = reinterpret_cast<const ushort *>(casedString.constData());-
993 }
never executed: end of block
0
994-
995 if (Q_UNLIKELY(!ensureSpace(itemLength))) {
__builtin_expe...ngth)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
996 Q_UNREACHABLE(); // ### report OOM error somehow-
997 return;
never executed: return;
0
998 }-
999-
1000 QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading);-
1001-
1002 // split up the item into parts that come from different font engines-
1003 // k * 3 entries, array[k] == index in string, array[k + 1] == index in glyphs, array[k + 2] == engine index-
1004 QVector<uint> itemBoundaries;-
1005 itemBoundaries.reserve(24);-
1006 if (fontEngine->type() == QFontEngine::Multi) {
fontEngine->ty...tEngine::MultiDescription
TRUEnever evaluated
FALSEnever evaluated
0
1007 // ask the font engine to find out which glyphs (as an index in the specific font)-
1008 // to use for the text in one item.-
1009 QGlyphLayout initialGlyphs = availableGlyphs(&si);-
1010-
1011 int nGlyphs = initialGlyphs.numGlyphs;-
1012 QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);-
1013 if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
!fontEngine->s..., shaperFlags)Description
TRUEnever evaluated
FALSEnever evaluated
0
1014 Q_UNREACHABLE();
never executed: end of block
0
1015-
1016 uint lastEngine = ~0u;-
1017 for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
i < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1018 const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;-
1019 if (lastEngine != engineIdx) {
lastEngine != engineIdxDescription
TRUEnever evaluated
FALSEnever evaluated
0
1020 itemBoundaries.append(i);-
1021 itemBoundaries.append(glyph_pos);-
1022 itemBoundaries.append(engineIdx);-
1023-
1024 if (engineIdx != 0) {
engineIdx != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1025 QFontEngine *actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
1026 si.ascent = qMax(actualFontEngine->ascent(), si.ascent);-
1027 si.descent = qMax(actualFontEngine->descent(), si.descent);-
1028 si.leading = qMax(actualFontEngine->leading(), si.leading);-
1029 }
never executed: end of block
0
1030-
1031 lastEngine = engineIdx;-
1032 }
never executed: end of block
0
1033-
1034 if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))
QChar::isHighS...ate(string[i])Description
TRUEnever evaluated
FALSEnever evaluated
i + 1 < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
QChar::isLowSu...string[i + 1])Description
TRUEnever evaluated
FALSEnever evaluated
0
1035 ++i;
never executed: ++i;
0
1036 }
never executed: end of block
0
1037 } else {
never executed: end of block
0
1038 itemBoundaries.append(0);-
1039 itemBoundaries.append(0);-
1040 itemBoundaries.append(0);-
1041 }
never executed: end of block
0
1042-
1043 bool kerningEnabled;-
1044 bool letterSpacingIsAbsolute;-
1045 QFixed letterSpacing, wordSpacing;-
1046#ifndef QT_NO_RAWFONT-
1047 if (useRawFont) {
useRawFontDescription
TRUEnever evaluated
FALSEnever evaluated
0
1048 QTextCharFormat f = format(&si);-
1049 kerningEnabled = f.fontKerning();-
1050 wordSpacing = QFixed::fromReal(f.fontWordSpacing());-
1051 letterSpacing = QFixed::fromReal(f.fontLetterSpacing());-
1052 letterSpacingIsAbsolute = true;-
1053 } else
never executed: end of block
0
1054#endif-
1055 {-
1056 QFont font = this->font(si);-
1057 kerningEnabled = font.d->kerning;-
1058 letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;-
1059 letterSpacing = font.d->letterSpacing;-
1060 wordSpacing = font.d->wordSpacing;-
1061-
1062 if (letterSpacingIsAbsolute && letterSpacing.value())
letterSpacingIsAbsoluteDescription
TRUEnever evaluated
FALSEnever evaluated
letterSpacing.value()Description
TRUEnever evaluated
FALSEnever evaluated
0
1063 letterSpacing *= font.d->dpi / qt_defaultDpiY();
never executed: letterSpacing *= font.d->dpi / qt_defaultDpiY();
0
1064 }
never executed: end of block
0
1065-
1066#ifdef QT_ENABLE_HARFBUZZ_NG-
1067 if (Q_LIKELY(qt_useHarfbuzzNG()))
__builtin_expe...zzNG()), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
1068 si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
never executed: si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
0
1069 else-
1070#endif-
1071 si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
never executed: si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
0
1072 if (Q_UNLIKELY(si.num_glyphs == 0)) {
__builtin_expe... == 0), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1073 Q_UNREACHABLE(); // ### report shaping errors somehow-
1074 return;
never executed: return;
0
1075 }-
1076-
1077-
1078 layoutData->used += si.num_glyphs;-
1079-
1080 QGlyphLayout glyphs = shapedGlyphs(&si);-
1081-
1082#ifdef QT_ENABLE_HARFBUZZ_NG-
1083 if (Q_LIKELY(qt_useHarfbuzzNG()))
__builtin_expe...zzNG()), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
1084 qt_getJustificationOpportunities(string, itemLength, si, glyphs, logClusters(&si));
never executed: qt_getJustificationOpportunities(string, itemLength, si, glyphs, logClusters(&si));
0
1085#endif-
1086-
1087 if (letterSpacing != 0) {
letterSpacing != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1088 for (int i = 1; i < si.num_glyphs; ++i) {
i < si.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1089 if (glyphs.attributes[i].clusterStart) {
glyphs.attribu...].clusterStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
1090 if (letterSpacingIsAbsolute)
letterSpacingIsAbsoluteDescription
TRUEnever evaluated
FALSEnever evaluated
0
1091 glyphs.advances[i - 1] += letterSpacing;
never executed: glyphs.advances[i - 1] += letterSpacing;
0
1092 else {-
1093 QFixed &advance = glyphs.advances[i - 1];-
1094 advance += (letterSpacing - 100) * advance / 100;-
1095 }
never executed: end of block
0
1096 }-
1097 }
never executed: end of block
0
1098 if (letterSpacingIsAbsolute)
letterSpacingIsAbsoluteDescription
TRUEnever evaluated
FALSEnever evaluated
0
1099 glyphs.advances[si.num_glyphs - 1] += letterSpacing;
never executed: glyphs.advances[si.num_glyphs - 1] += letterSpacing;
0
1100 else {-
1101 QFixed &advance = glyphs.advances[si.num_glyphs - 1];-
1102 advance += (letterSpacing - 100) * advance / 100;-
1103 }
never executed: end of block
0
1104 }-
1105 if (wordSpacing != 0) {
wordSpacing != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1106 for (int i = 0; i < si.num_glyphs; ++i) {
i < si.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1107 if (glyphs.attributes[i].justification == Justification_Space
glyphs.attribu...fication_SpaceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1108 || glyphs.attributes[i].justification == Justification_Arabic_Space) {
glyphs.attribu...n_Arabic_SpaceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1109 // word spacing only gets added once to a consecutive run of spaces (see CSS spec)-
1110 if (i + 1 == si.num_glyphs
i + 1 == si.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1111 ||(glyphs.attributes[i+1].justification != Justification_Space
glyphs.attribu...fication_SpaceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1112 && glyphs.attributes[i+1].justification != Justification_Arabic_Space))
glyphs.attribu...n_Arabic_SpaceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1113 glyphs.advances[i] += wordSpacing;
never executed: glyphs.advances[i] += wordSpacing;
0
1114 }
never executed: end of block
0
1115 }
never executed: end of block
0
1116 }
never executed: end of block
0
1117-
1118 for (int i = 0; i < si.num_glyphs; ++i)
i < si.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1119 si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
never executed: si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
0
1120}
never executed: end of block
0
1121-
1122#ifdef QT_ENABLE_HARFBUZZ_NG-
1123-
1124QT_BEGIN_INCLUDE_NAMESPACE-
1125-
1126#include "qharfbuzzng_p.h"-
1127-
1128QT_END_INCLUDE_NAMESPACE-
1129-
1130int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,-
1131 const ushort *string,-
1132 int itemLength,-
1133 QFontEngine *fontEngine,-
1134 const QVector<uint> &itemBoundaries,-
1135 bool kerningEnabled,-
1136 bool hasLetterSpacing) const-
1137{-
1138 uint glyphs_shaped = 0;-
1139-
1140 hb_buffer_t *buffer = hb_buffer_create();-
1141 hb_buffer_set_unicode_funcs(buffer, hb_qt_get_unicode_funcs());-
1142 hb_buffer_pre_allocate(buffer, itemLength);-
1143 if (Q_UNLIKELY(!hb_buffer_allocation_successful(buffer))) {
__builtin_expe...ffer)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1144 hb_buffer_destroy(buffer);-
1145 return 0;
never executed: return 0;
0
1146 }-
1147-
1148 hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT;-
1149 props.direction = si.analysis.bidiLevel % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR;
si.analysis.bidiLevel % 2Description
TRUEnever evaluated
FALSEnever evaluated
0
1150 QChar::Script script = QChar::Script(si.analysis.script);-
1151 props.script = hb_qt_script_to_script(script);-
1152 // ### props.language = hb_language_get_default_for_script(props.script);-
1153-
1154 for (int k = 0; k < itemBoundaries.size(); k += 3) {
k < itemBoundaries.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1155 const uint item_pos = itemBoundaries[k];-
1156 const uint item_length = (k + 4 < itemBoundaries.size() ? itemBoundaries[k + 3] : itemLength) - item_pos;
k + 4 < itemBoundaries.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1157 const uint engineIdx = itemBoundaries[k + 2];-
1158-
1159 QFontEngine *actualFontEngine = fontEngine->type() != QFontEngine::Multi ? fontEngine
fontEngine->ty...tEngine::MultiDescription
TRUEnever evaluated
FALSEnever evaluated
0
1160 : static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
1161-
1162-
1163 // prepare buffer-
1164 hb_buffer_clear_contents(buffer);-
1165 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16_t *>(string) + item_pos, item_length, 0, item_length);-
1166-
1167 hb_buffer_set_segment_properties(buffer, &props);-
1168 hb_buffer_guess_segment_properties(buffer);-
1169-
1170 uint buffer_flags = HB_BUFFER_FLAG_DEFAULT;-
1171 // Symbol encoding used to encode various crap in the 32..255 character code range,-
1172 // and thus might override U+00AD [SHY]; avoid hiding default ignorables-
1173 if (Q_UNLIKELY(actualFontEngine->symbol))
__builtin_expe...ymbol), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1174 buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
never executed: buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
0
1175 hb_buffer_set_flags(buffer, hb_buffer_flags_t(buffer_flags));-
1176-
1177-
1178 // shape-
1179 {-
1180 hb_font_t *hb_font = hb_qt_font_get_for_engine(actualFontEngine);-
1181 Q_ASSERT(hb_font);-
1182 hb_qt_font_set_use_design_metrics(hb_font, option.useDesignMetrics() ? uint(QFontEngine::DesignMetrics) : 0); // ###-
1183-
1184 // Ligatures are incompatible with custom letter spacing, so when a letter spacing is set,-
1185 // we disable them for writing systems where they are purely cosmetic.-
1186 bool scriptRequiresOpenType = ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
script >= QChar::Script_SyriacDescription
TRUEnever evaluated
FALSEnever evaluated
script <= QCha...Script_SinhalaDescription
TRUEnever evaluated
FALSEnever evaluated
0
1187 || script == QChar::Script_Khmer || script == QChar::Script_Nko);
script == QChar::Script_KhmerDescription
TRUEnever evaluated
FALSEnever evaluated
script == QChar::Script_NkoDescription
TRUEnever evaluated
FALSEnever evaluated
0
1188-
1189 bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
hasLetterSpacingDescription
TRUEnever evaluated
FALSEnever evaluated
!scriptRequiresOpenTypeDescription
TRUEnever evaluated
FALSEnever evaluated
0
1190 const hb_feature_t features[5] = {-
1191 { HB_TAG('k','e','r','n'), !!kerningEnabled, 0, uint(-1) },-
1192 { HB_TAG('l','i','g','a'), !dontLigate, 0, uint(-1) },-
1193 { HB_TAG('c','l','i','g'), !dontLigate, 0, uint(-1) },-
1194 { HB_TAG('d','l','i','g'), !dontLigate, 0, uint(-1) },-
1195 { HB_TAG('h','l','i','g'), !dontLigate, 0, uint(-1) } };-
1196 const int num_features = dontLigate ? 5 : 1;
dontLigateDescription
TRUEnever evaluated
FALSEnever evaluated
0
1197-
1198 const char *const *shaper_list = Q_NULLPTR;-
1199#if defined(Q_OS_DARWIN)-
1200 // What's behind QFontEngine::FaceData::user_data isn't compatible between different font engines-
1201 // - specifically functions in hb-coretext.cc would run into undefined behavior with data-
1202 // from non-CoreText engine. The other shapers works with that engine just fine.-
1203 if (actualFontEngine->type() != QFontEngine::Mac) {-
1204 static const char *s_shaper_list_without_coretext[] = {-
1205 "graphite2",-
1206 "ot",-
1207 "fallback",-
1208 Q_NULLPTR-
1209 };-
1210 shaper_list = s_shaper_list_without_coretext;-
1211 }-
1212#endif-
1213-
1214 bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list);-
1215 if (Q_UNLIKELY(!shapedOk)) {
__builtin_expe...pedOk), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1216 hb_buffer_destroy(buffer);-
1217 return 0;
never executed: return 0;
0
1218 }-
1219-
1220 if (Q_UNLIKELY(HB_DIRECTION_IS_BACKWARD(props.direction)))
__builtin_expe...== 5)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1221 hb_buffer_reverse(buffer);
never executed: hb_buffer_reverse(buffer);
0
1222 }-
1223-
1224 const uint num_glyphs = hb_buffer_get_length(buffer);-
1225 // ensure we have enough space for shaped glyphs and metrics-
1226 if (Q_UNLIKELY(num_glyphs == 0 || !ensureSpace(glyphs_shaped + num_glyphs))) {
__builtin_expe...yphs)), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1227 hb_buffer_destroy(buffer);-
1228 return 0;
never executed: return 0;
0
1229 }-
1230-
1231 // fetch the shaped glyphs and metrics-
1232 QGlyphLayout g = availableGlyphs(&si).mid(glyphs_shaped, num_glyphs);-
1233 ushort *log_clusters = logClusters(&si) + item_pos;-
1234-
1235 hb_glyph_info_t *infos = hb_buffer_get_glyph_infos(buffer, 0);-
1236 hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer, 0);-
1237 uint str_pos = 0;-
1238 uint last_cluster = ~0u;-
1239 uint last_glyph_pos = glyphs_shaped;-
1240 for (uint i = 0; i < num_glyphs; ++i, ++infos, ++positions) {
i < num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1241 g.glyphs[i] = infos->codepoint;-
1242-
1243 g.advances[i] = QFixed::fromFixed(positions->x_advance);-
1244 g.offsets[i].x = QFixed::fromFixed(positions->x_offset);-
1245 g.offsets[i].y = QFixed::fromFixed(positions->y_offset);-
1246-
1247 uint cluster = infos->cluster;-
1248 if (Q_LIKELY(last_cluster != cluster)) {
__builtin_expe...luster), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
1249 g.attributes[i].clusterStart = true;-
1250-
1251 // fix up clusters so that the cluster indices will be monotonic-
1252 // and thus we never return out-of-order indices-
1253 while (last_cluster++ < cluster && str_pos < item_length)
last_cluster++ < clusterDescription
TRUEnever evaluated
FALSEnever evaluated
str_pos < item_lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1254 log_clusters[str_pos++] = last_glyph_pos;
never executed: log_clusters[str_pos++] = last_glyph_pos;
0
1255 last_glyph_pos = i + glyphs_shaped;-
1256 last_cluster = cluster;-
1257-
1258 // hide characters that should normally be invisible-
1259 switch (string[item_pos + str_pos]) {-
1260 case QChar::LineFeed:
never executed: case QChar::LineFeed:
0
1261 case 0x000c: // FormFeed
never executed: case 0x000c:
0
1262 case QChar::CarriageReturn:
never executed: case QChar::CarriageReturn:
0
1263 case QChar::LineSeparator:
never executed: case QChar::LineSeparator:
0
1264 case QChar::ParagraphSeparator:
never executed: case QChar::ParagraphSeparator:
0
1265 g.attributes[i].dontPrint = true;-
1266 break;
never executed: break;
0
1267 case QChar::SoftHyphen:
never executed: case QChar::SoftHyphen:
0
1268 if (!actualFontEngine->symbol) {
!actualFontEngine->symbolDescription
TRUEnever evaluated
FALSEnever evaluated
0
1269 // U+00AD [SOFT HYPHEN] is a default ignorable codepoint,-
1270 // so we replace its glyph and metrics with ones for-
1271 // U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break-
1272 g.glyphs[i] = actualFontEngine->glyphIndex('-');-
1273 if (Q_LIKELY(g.glyphs[i] != 0)) {
__builtin_expe...] != 0), true)Description
TRUEnever evaluated
FALSEnever evaluated
0
1274 QGlyphLayout tmp = g.mid(i, 1);-
1275 actualFontEngine->recalcAdvances(&tmp, 0);-
1276 }
never executed: end of block
0
1277 g.attributes[i].dontPrint = true;-
1278 }
never executed: end of block
0
1279 break;
never executed: break;
0
1280 default:
never executed: default:
0
1281 break;
never executed: break;
0
1282 }-
1283 }-
1284 }
never executed: end of block
0
1285 while (str_pos < item_length)
str_pos < item_lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1286 log_clusters[str_pos++] = last_glyph_pos;
never executed: log_clusters[str_pos++] = last_glyph_pos;
0
1287-
1288 if (Q_UNLIKELY(engineIdx != 0)) {
__builtin_expe... != 0), false)Description
TRUEnever evaluated
FALSEnever evaluated
0
1289 for (quint32 i = 0; i < num_glyphs; ++i)
i < num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1290 g.glyphs[i] |= (engineIdx << 24);
never executed: g.glyphs[i] |= (engineIdx << 24);
0
1291 }
never executed: end of block
0
1292-
1293#ifdef Q_OS_DARWIN-
1294 if (actualFontEngine->type() == QFontEngine::Mac) {-
1295 // CTRunGetPosition has a bug which applies matrix on 10.6, so we disable-
1296 // scaling the advances for this particular version-
1297 if (QSysInfo::MacintoshVersion != QSysInfo::MV_10_6 && actualFontEngine->fontDef.stretch != 100) {-
1298 QFixed stretch = QFixed(int(actualFontEngine->fontDef.stretch)) / QFixed(100);-
1299 for (uint i = 0; i < num_glyphs; ++i)-
1300 g.advances[i] *= stretch;-
1301 }-
1302 }-
1303#endif-
1304-
1305 if (!actualFontEngine->supportsSubPixelPositions() || (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics)) {
!actualFontEng...xelPositions()Description
TRUEnever evaluated
FALSEnever evaluated
(actualFontEng...ntegerMetrics)Description
TRUEnever evaluated
FALSEnever evaluated
0
1306 for (uint i = 0; i < num_glyphs; ++i)
i < num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1307 g.advances[i] = g.advances[i].round();
never executed: g.advances[i] = g.advances[i].round();
0
1308 }
never executed: end of block
0
1309-
1310 glyphs_shaped += num_glyphs;-
1311 }
never executed: end of block
0
1312-
1313 hb_buffer_destroy(buffer);-
1314-
1315 return glyphs_shaped;
never executed: return glyphs_shaped;
0
1316}-
1317-
1318#endif // QT_ENABLE_HARFBUZZ_NG-
1319-
1320-
1321QT_BEGIN_INCLUDE_NAMESPACE-
1322-
1323#include <private/qharfbuzz_p.h>-
1324-
1325QT_END_INCLUDE_NAMESPACE-
1326-
1327Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));-
1328Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));-
1329Q_STATIC_ASSERT(sizeof(HB_FixedPoint) == sizeof(QFixedPoint));-
1330-
1331static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num)-
1332{-
1333 if (num > 0 && destination.glyphs != source.glyphs)
num > 0Description
TRUEnever evaluated
FALSEnever evaluated
destination.gl... source.glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1334 memmove(destination.glyphs, source.glyphs, num * sizeof(glyph_t));
never executed: memmove(destination.glyphs, source.glyphs, num * sizeof(glyph_t));
0
1335}
never executed: end of block
0
1336-
1337int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const-
1338{-
1339 HB_ShaperItem entire_shaper_item;-
1340 memset(&entire_shaper_item, 0, sizeof(entire_shaper_item));-
1341 entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(string);-
1342 entire_shaper_item.stringLength = itemLength;-
1343 entire_shaper_item.item.script = script_to_hbscript(si.analysis.script);-
1344 entire_shaper_item.item.pos = 0;-
1345 entire_shaper_item.item.length = itemLength;-
1346 entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;-
1347-
1348 entire_shaper_item.shaperFlags = 0;-
1349 if (!kerningEnabled)
!kerningEnabledDescription
TRUEnever evaluated
FALSEnever evaluated
0
1350 entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning;
never executed: entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning;
0
1351 if (option.useDesignMetrics())
option.useDesignMetrics()Description
TRUEnever evaluated
FALSEnever evaluated
0
1352 entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics;
never executed: entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics;
0
1353-
1354 // ensure we are not asserting in HB_HeuristicSetGlyphAttributes()-
1355 entire_shaper_item.num_glyphs = 0;-
1356 for (int i = 0; i < itemLength; ++i, ++entire_shaper_item.num_glyphs) {
i < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1357 if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))
QChar::isHighS...ate(string[i])Description
TRUEnever evaluated
FALSEnever evaluated
i + 1 < itemLengthDescription
TRUEnever evaluated
FALSEnever evaluated
QChar::isLowSu...string[i + 1])Description
TRUEnever evaluated
FALSEnever evaluated
0
1358 ++i;
never executed: ++i;
0
1359 }
never executed: end of block
0
1360-
1361-
1362 int remaining_glyphs = entire_shaper_item.num_glyphs;-
1363 int glyph_pos = 0;-
1364 // for each item shape using harfbuzz and store the results in our layoutData's glyphs array.-
1365 for (int k = 0; k < itemBoundaries.size(); k += 3) {
k < itemBoundaries.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1366 HB_ShaperItem shaper_item = entire_shaper_item;-
1367 shaper_item.item.pos = itemBoundaries[k];-
1368 if (k + 4 < itemBoundaries.size()) {
k + 4 < itemBoundaries.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1369 shaper_item.item.length = itemBoundaries[k + 3] - shaper_item.item.pos;-
1370 shaper_item.num_glyphs = itemBoundaries[k + 4] - itemBoundaries[k + 1];-
1371 } else { // last combo in the list, avoid out of bounds access.
never executed: end of block
0
1372 shaper_item.item.length -= shaper_item.item.pos - entire_shaper_item.item.pos;-
1373 shaper_item.num_glyphs -= itemBoundaries[k + 1];-
1374 }
never executed: end of block
0
1375 shaper_item.initialGlyphCount = shaper_item.num_glyphs;-
1376 if (shaper_item.num_glyphs < shaper_item.item.length)
shaper_item.nu...em.item.lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1377 shaper_item.num_glyphs = shaper_item.item.length;
never executed: shaper_item.num_glyphs = shaper_item.item.length;
0
1378-
1379 uint engineIdx = itemBoundaries[k + 2];-
1380 QFontEngine *actualFontEngine = fontEngine;-
1381 if (fontEngine->type() == QFontEngine::Multi) {
fontEngine->ty...tEngine::MultiDescription
TRUEnever evaluated
FALSEnever evaluated
0
1382 actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
1383-
1384 if ((si.analysis.bidiLevel % 2) == 0)
(si.analysis.b...evel % 2) == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1385 shaper_item.glyphIndicesPresent = true;
never executed: shaper_item.glyphIndicesPresent = true;
0
1386 }
never executed: end of block
0
1387-
1388 shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();-
1389 shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace();-
1390-
1391 remaining_glyphs -= shaper_item.initialGlyphCount;-
1392-
1393 QVarLengthArray<HB_GlyphAttributes, 128> hbGlyphAttributes;-
1394 do {-
1395 if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs))
!ensureSpace(g...aining_glyphs)Description
TRUEnever evaluated
FALSEnever evaluated
0
1396 return 0;
never executed: return 0;
0
1397 if (hbGlyphAttributes.size() < int(shaper_item.num_glyphs)) {
hbGlyphAttribu...em.num_glyphs)Description
TRUEnever evaluated
FALSEnever evaluated
0
1398 hbGlyphAttributes.resize(shaper_item.num_glyphs);-
1399 memset(hbGlyphAttributes.data(), 0, hbGlyphAttributes.size() * sizeof(HB_GlyphAttributes));-
1400 }
never executed: end of block
0
1401-
1402 const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos);-
1403 if (fontEngine->type() == QFontEngine::Multi && shaper_item.num_glyphs > shaper_item.item.length)
fontEngine->ty...tEngine::MultiDescription
TRUEnever evaluated
FALSEnever evaluated
shaper_item.nu...em.item.lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1404 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
never executed: moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
0
1405-
1406 shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs);-
1407 shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances);-
1408 shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);-
1409 shaper_item.attributes = hbGlyphAttributes.data();-
1410-
1411 if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {
engineIdx != 0Description
TRUEnever evaluated
FALSEnever evaluated
shaper_item.gl...IndicesPresentDescription
TRUEnever evaluated
FALSEnever evaluated
0
1412 for (quint32 i = 0; i < shaper_item.initialGlyphCount; ++i)
i < shaper_ite...tialGlyphCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1413 shaper_item.glyphs[i] &= 0x00ffffff;
never executed: shaper_item.glyphs[i] &= 0x00ffffff;
0
1414 }
never executed: end of block
0
1415-
1416 shaper_item.log_clusters = logClusters(&si) + shaper_item.item.pos - entire_shaper_item.item.pos;-
1417 } while (!qShapeItem(&shaper_item)); // this does the actual shaping via harfbuzz.
never executed: end of block
!qShapeItem(&shaper_item)Description
TRUEnever evaluated
FALSEnever evaluated
0
1418-
1419 QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs);-
1420 if (fontEngine->type() == QFontEngine::Multi)
fontEngine->ty...tEngine::MultiDescription
TRUEnever evaluated
FALSEnever evaluated
0
1421 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
never executed: moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);
0
1422-
1423 for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) {
i < shaper_item.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1424 HB_GlyphAttributes hbAttrs = hbGlyphAttributes.at(i);-
1425 QGlyphAttributes &attrs = g.attributes[i];-
1426 attrs.clusterStart = hbAttrs.clusterStart;-
1427 attrs.dontPrint = hbAttrs.dontPrint;-
1428 attrs.justification = hbAttrs.justification;-
1429 }
never executed: end of block
0
1430-
1431 for (quint32 i = 0; i < shaper_item.item.length; ++i) {
i < shaper_item.item.lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1432 // Workaround wrong log_clusters for surrogates (i.e. QTBUG-39875)-
1433 if (shaper_item.log_clusters[i] >= shaper_item.num_glyphs)
shaper_item.lo...tem.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1434 shaper_item.log_clusters[i] = shaper_item.num_glyphs - 1;
never executed: shaper_item.log_clusters[i] = shaper_item.num_glyphs - 1;
0
1435 shaper_item.log_clusters[i] += glyph_pos;-
1436 }
never executed: end of block
0
1437-
1438 if (kerningEnabled && !shaper_item.kerning_applied)
kerningEnabledDescription
TRUEnever evaluated
FALSEnever evaluated
!shaper_item.kerning_appliedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1439 actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0));
never executed: actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0));
0
1440-
1441 if (engineIdx != 0) {
engineIdx != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1442 for (quint32 i = 0; i < shaper_item.num_glyphs; ++i)
i < shaper_item.num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1443 g.glyphs[i] |= (engineIdx << 24);
never executed: g.glyphs[i] |= (engineIdx << 24);
0
1444 }
never executed: end of block
0
1445-
1446 glyph_pos += shaper_item.num_glyphs;-
1447 }
never executed: end of block
0
1448-
1449 return glyph_pos;
never executed: return glyph_pos;
0
1450}-
1451-
1452void QTextEngine::init(QTextEngine *e)-
1453{-
1454 e->ignoreBidi = false;-
1455 e->cacheGlyphs = false;-
1456 e->forceJustification = false;-
1457 e->visualMovement = false;-
1458 e->delayDecorations = false;-
1459-
1460 e->layoutData = 0;-
1461-
1462 e->minWidth = 0;-
1463 e->maxWidth = 0;-
1464-
1465 e->specialData = 0;-
1466 e->stackEngine = false;-
1467#ifndef QT_NO_RAWFONT-
1468 e->useRawFont = false;-
1469#endif-
1470}
never executed: end of block
0
1471-
1472QTextEngine::QTextEngine()-
1473{-
1474 init(this);-
1475}
never executed: end of block
0
1476-
1477QTextEngine::QTextEngine(const QString &str, const QFont &f)-
1478 : text(str),-
1479 fnt(f)-
1480{-
1481 init(this);-
1482}
never executed: end of block
0
1483-
1484QTextEngine::~QTextEngine()-
1485{-
1486 if (!stackEngine)
!stackEngineDescription
TRUEnever evaluated
FALSEnever evaluated
0
1487 delete layoutData;
never executed: delete layoutData;
0
1488 delete specialData;-
1489 resetFontEngineCache();-
1490}
never executed: end of block
0
1491-
1492const QCharAttributes *QTextEngine::attributes() const-
1493{-
1494 if (layoutData && layoutData->haveCharAttributes)
layoutDataDescription
TRUEnever evaluated
FALSEnever evaluated
layoutData->haveCharAttributesDescription
TRUEnever evaluated
FALSEnever evaluated
0
1495 return (QCharAttributes *) layoutData->memory;
never executed: return (QCharAttributes *) layoutData->memory;
0
1496-
1497 itemize();-
1498 if (! ensureSpace(layoutData->string.length()))
! ensureSpace(...ring.length())Description
TRUEnever evaluated
FALSEnever evaluated
0
1499 return NULL;
never executed: return __null;
0
1500-
1501 QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size());-
1502 for (int i = 0; i < layoutData->items.size(); ++i) {
i < layoutData->items.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1503 const QScriptItem &si = layoutData->items[i];-
1504 scriptItems[i].position = si.position;-
1505 scriptItems[i].script = si.analysis.script;-
1506 }
never executed: end of block
0
1507-
1508 QUnicodeTools::initCharAttributes(reinterpret_cast<const ushort *>(layoutData->string.constData()),-
1509 layoutData->string.length(),-
1510 scriptItems.data(), scriptItems.size(),-
1511 (QCharAttributes *)layoutData->memory);-
1512-
1513-
1514 layoutData->haveCharAttributes = true;-
1515 return (QCharAttributes *) layoutData->memory;
never executed: return (QCharAttributes *) layoutData->memory;
0
1516}-
1517-
1518void QTextEngine::shape(int item) const-
1519{-
1520 if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) {
layoutData->it...alysis::ObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
1521 ensureSpace(1);-
1522 if (block.docHandle()) {
block.docHandle()Description
TRUEnever evaluated
FALSEnever evaluated
0
1523 docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)),-
1524 layoutData->items[item].position + block.position(),-
1525 format(&layoutData->items[item]));-
1526 }
never executed: end of block
0
1527 } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) {
never executed: end of block
layoutData->it...tAnalysis::TabDescription
TRUEnever evaluated
FALSEnever evaluated
0
1528 // set up at least the ascent/descent/leading of the script item for the tab-
1529 fontEngine(layoutData->items[item],-
1530 &layoutData->items[item].ascent,-
1531 &layoutData->items[item].descent,-
1532 &layoutData->items[item].leading);-
1533 } else {
never executed: end of block
0
1534 shapeText(item);-
1535 }
never executed: end of block
0
1536}-
1537-
1538static inline void releaseCachedFontEngine(QFontEngine *fontEngine)-
1539{-
1540 if (fontEngine && !fontEngine->ref.deref())
fontEngineDescription
TRUEnever evaluated
FALSEnever evaluated
!fontEngine->ref.deref()Description
TRUEnever evaluated
FALSEnever evaluated
0
1541 delete fontEngine;
never executed: delete fontEngine;
0
1542}
never executed: end of block
0
1543-
1544void QTextEngine::resetFontEngineCache()-
1545{-
1546 releaseCachedFontEngine(feCache.prevFontEngine);-
1547 releaseCachedFontEngine(feCache.prevScaledFontEngine);-
1548 feCache.reset();-
1549}
never executed: end of block
0
1550-
1551void QTextEngine::invalidate()-
1552{-
1553 freeMemory();-
1554 minWidth = 0;-
1555 maxWidth = 0;-
1556-
1557 resetFontEngineCache();-
1558}
never executed: end of block
0
1559-
1560void QTextEngine::clearLineData()-
1561{-
1562 lines.clear();-
1563}
never executed: end of block
0
1564-
1565void QTextEngine::validate() const-
1566{-
1567 if (layoutData)
layoutDataDescription
TRUEnever evaluated
FALSEnever evaluated
0
1568 return;
never executed: return;
0
1569 layoutData = new LayoutData();-
1570 if (block.docHandle()) {
block.docHandle()Description
TRUEnever evaluated
FALSEnever evaluated
0
1571 layoutData->string = block.text();-
1572 const bool nextBlockValid = block.next().isValid();-
1573 if (!nextBlockValid && option.flags() & QTextOption::ShowDocumentTerminator) {
!nextBlockValidDescription
TRUEnever evaluated
FALSEnever evaluated
option.flags()...mentTerminatorDescription
TRUEnever evaluated
FALSEnever evaluated
0
1574 layoutData->string += QChar(0xA7);-
1575 } else if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
never executed: end of block
option.flags()...raphSeparatorsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1576 layoutData->string += QLatin1Char(nextBlockValid ? 0xb6 : 0x20);-
1577 }
never executed: end of block
0
1578-
1579 } else {
never executed: end of block
0
1580 layoutData->string = text;-
1581 }
never executed: end of block
0
1582 if (specialData && specialData->preeditPosition != -1)
specialDataDescription
TRUEnever evaluated
FALSEnever evaluated
specialData->p...Position != -1Description
TRUEnever evaluated
FALSEnever evaluated
0
1583 layoutData->string.insert(specialData->preeditPosition, specialData->preeditText);
never executed: layoutData->string.insert(specialData->preeditPosition, specialData->preeditText);
0
1584}
never executed: end of block
0
1585-
1586void QTextEngine::itemize() const-
1587{-
1588 validate();-
1589 if (layoutData->items.size())
layoutData->items.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1590 return;
never executed: return;
0
1591-
1592 int length = layoutData->string.length();-
1593 if (!length)
!lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1594 return;
never executed: return;
0
1595-
1596 const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.unicode());-
1597-
1598 bool ignore = ignoreBidi;-
1599-
1600 bool rtl = isRightToLeft();-
1601-
1602 if (!ignore && !rtl) {
!ignoreDescription
TRUEnever evaluated
FALSEnever evaluated
!rtlDescription
TRUEnever evaluated
FALSEnever evaluated
0
1603 ignore = true;-
1604 const QChar *start = layoutData->string.unicode();-
1605 const QChar * const end = start + length;-
1606 while (start < end) {
start < endDescription
TRUEnever evaluated
FALSEnever evaluated
0
1607 if (start->unicode() >= 0x590) {
start->unicode() >= 0x590Description
TRUEnever evaluated
FALSEnever evaluated
0
1608 ignore = false;-
1609 break;
never executed: break;
0
1610 }-
1611 ++start;-
1612 }
never executed: end of block
0
1613 }
never executed: end of block
0
1614-
1615 QVarLengthArray<QScriptAnalysis, 4096> scriptAnalysis(length);-
1616 QScriptAnalysis *analysis = scriptAnalysis.data();-
1617-
1618 QBidiControl control(rtl);-
1619-
1620 if (ignore) {
ignoreDescription
TRUEnever evaluated
FALSEnever evaluated
0
1621 memset(analysis, 0, length*sizeof(QScriptAnalysis));-
1622 if (option.textDirection() == Qt::RightToLeft) {
option.textDir...t::RightToLeftDescription
TRUEnever evaluated
FALSEnever evaluated
0
1623 for (int i = 0; i < length; ++i)
i < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1624 analysis[i].bidiLevel = 1;
never executed: analysis[i].bidiLevel = 1;
0
1625 layoutData->hasBidi = true;-
1626 }
never executed: end of block
0
1627 } else {
never executed: end of block
0
1628 layoutData->hasBidi = bidiItemize(const_cast<QTextEngine *>(this), analysis, control);-
1629 }
never executed: end of block
0
1630-
1631 {-
1632 QVarLengthArray<uchar> scripts(length);-
1633 QUnicodeTools::initScripts(string, length, scripts.data());-
1634 for (int i = 0; i < length; ++i)
i < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1635 analysis[i].script = scripts.at(i);
never executed: analysis[i].script = scripts.at(i);
0
1636 }-
1637-
1638 const ushort *uc = string;-
1639 const ushort *e = uc + length;-
1640 while (uc < e) {
uc < eDescription
TRUEnever evaluated
FALSEnever evaluated
0
1641 switch (*uc) {-
1642 case QChar::ObjectReplacementCharacter:
never executed: case QChar::ObjectReplacementCharacter:
0
1643 analysis->flags = QScriptAnalysis::Object;-
1644 break;
never executed: break;
0
1645 case QChar::LineSeparator:
never executed: case QChar::LineSeparator:
0
1646 if (analysis->bidiLevel % 2)
analysis->bidiLevel % 2Description
TRUEnever evaluated
FALSEnever evaluated
0
1647 --analysis->bidiLevel;
never executed: --analysis->bidiLevel;
0
1648 analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;-
1649 if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
option.flags()...raphSeparatorsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1650 const int offset = uc - string;-
1651 layoutData->string.detach();-
1652 string = reinterpret_cast<const ushort *>(layoutData->string.unicode());-
1653 uc = string + offset;-
1654 e = uc + length;-
1655 *const_cast<ushort*>(uc) = 0x21B5; // visual line separator-
1656 }
never executed: end of block
0
1657 break;
never executed: break;
0
1658 case QChar::Tabulation:
never executed: case QChar::Tabulation:
0
1659 analysis->flags = QScriptAnalysis::Tab;-
1660 analysis->bidiLevel = control.baseLevel();-
1661 break;
never executed: break;
0
1662 case QChar::Space:
never executed: case QChar::Space:
0
1663 case QChar::Nbsp:
never executed: case QChar::Nbsp:
0
1664 if (option.flags() & QTextOption::ShowTabsAndSpaces) {
option.flags()...wTabsAndSpacesDescription
TRUEnever evaluated
FALSEnever evaluated
0
1665 analysis->flags = QScriptAnalysis::Space;-
1666 analysis->bidiLevel = control.baseLevel();-
1667 break;
never executed: break;
0
1668 }-
1669 // fall through-
1670 default:
code before this statement never executed: default:
never executed: default:
0
1671 analysis->flags = QScriptAnalysis::None;-
1672 break;
never executed: break;
0
1673 }-
1674#ifndef QT_ENABLE_HARFBUZZ_NG-
1675 analysis->script = hbscript_to_script(script_to_hbscript(analysis->script));-
1676#endif-
1677 ++uc;-
1678 ++analysis;-
1679 }
never executed: end of block
0
1680 if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
option.flags()...raphSeparatorsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1681 (analysis-1)->flags = QScriptAnalysis::LineOrParagraphSeparator; // to exclude it from width-
1682 }
never executed: end of block
0
1683#ifdef QT_ENABLE_HARFBUZZ_NG-
1684 analysis = scriptAnalysis.data();-
1685 if (qt_useHarfbuzzNG()) {
qt_useHarfbuzzNG()Description
TRUEnever evaluated
FALSEnever evaluated
0
1686 // ### pretend HB-old behavior for now-
1687 for (int i = 0; i < length; ++i) {
i < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1688 switch (analysis[i].script) {-
1689 case QChar::Script_Latin:
never executed: case QChar::Script_Latin:
0
1690 case QChar::Script_Hiragana:
never executed: case QChar::Script_Hiragana:
0
1691 case QChar::Script_Katakana:
never executed: case QChar::Script_Katakana:
0
1692 case QChar::Script_Bopomofo:
never executed: case QChar::Script_Bopomofo:
0
1693 case QChar::Script_Han:
never executed: case QChar::Script_Han:
0
1694 analysis[i].script = QChar::Script_Common;-
1695 break;
never executed: break;
0
1696 default:
never executed: default:
0
1697 break;
never executed: break;
0
1698 }-
1699 }-
1700 } else {
never executed: end of block
0
1701 for (int i = 0; i < length; ++i)
i < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1702 analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script));
never executed: analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script));
0
1703 }
never executed: end of block
0
1704#endif-
1705-
1706 Itemizer itemizer(layoutData->string, scriptAnalysis.data(), layoutData->items);-
1707-
1708 const QTextDocumentPrivate *p = block.docHandle();-
1709 if (p) {
pDescription
TRUEnever evaluated
FALSEnever evaluated
0
1710 SpecialData *s = specialData;-
1711-
1712 QTextDocumentPrivate::FragmentIterator it = p->find(block.position());-
1713 QTextDocumentPrivate::FragmentIterator end = p->find(block.position() + block.length() - 1); // -1 to omit the block separator char-
1714 int format = it.value()->format;-
1715-
1716 int prevPosition = 0;-
1717 int position = prevPosition;-
1718 while (1) {-
1719 const QTextFragmentData * const frag = it.value();-
1720 if (it == end || format != frag->format) {
it == endDescription
TRUEnever evaluated
FALSEnever evaluated
format != frag->formatDescription
TRUEnever evaluated
FALSEnever evaluated
0
1721 if (s && position >= s->preeditPosition) {
sDescription
TRUEnever evaluated
FALSEnever evaluated
position >= s->preeditPositionDescription
TRUEnever evaluated
FALSEnever evaluated
0
1722 position += s->preeditText.length();-
1723 s = 0;-
1724 }
never executed: end of block
0
1725 Q_ASSERT(position <= length);-
1726 QFont::Capitalization capitalization =-
1727 formatCollection()->charFormat(format).hasProperty(QTextFormat::FontCapitalization)
formatCollecti...apitalization)Description
TRUEnever evaluated
FALSEnever evaluated
0
1728 ? formatCollection()->charFormat(format).fontCapitalization()-
1729 : formatCollection()->defaultFont().capitalization();-
1730 itemizer.generate(prevPosition, position - prevPosition, capitalization);-
1731 if (it == end) {
it == endDescription
TRUEnever evaluated
FALSEnever evaluated
0
1732 if (position < length)
position < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
1733 itemizer.generate(position, length - position, capitalization);
never executed: itemizer.generate(position, length - position, capitalization);
0
1734 break;
never executed: break;
0
1735 }-
1736 format = frag->format;-
1737 prevPosition = position;-
1738 }
never executed: end of block
0
1739 position += frag->size_array[0];-
1740 ++it;-
1741 }
never executed: end of block
0
1742 } else {
never executed: end of block
0
1743#ifndef QT_NO_RAWFONT-
1744 if (useRawFont && specialData) {
useRawFontDescription
TRUEnever evaluated
FALSEnever evaluated
specialDataDescription
TRUEnever evaluated
FALSEnever evaluated
0
1745 int lastIndex = 0;-
1746 for (int i = 0; i < specialData->formats.size(); ++i) {
i < specialDat...formats.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1747 const QTextLayout::FormatRange &range = specialData->formats.at(i);-
1748 const QTextCharFormat &format = range.format;-
1749 if (format.hasProperty(QTextFormat::FontCapitalization)) {
format.hasProp...apitalization)Description
TRUEnever evaluated
FALSEnever evaluated
0
1750 itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);-
1751 itemizer.generate(range.start, range.length, format.fontCapitalization());-
1752 lastIndex = range.start + range.length;-
1753 }
never executed: end of block
0
1754 }
never executed: end of block
0
1755 itemizer.generate(lastIndex, length - lastIndex, QFont::MixedCase);-
1756 } else
never executed: end of block
0
1757#endif-
1758 itemizer.generate(0, length, static_cast<QFont::Capitalization> (fnt.d->capital));
never executed: itemizer.generate(0, length, static_cast<QFont::Capitalization> (fnt.d->capital));
0
1759 }-
1760-
1761 addRequiredBoundaries();-
1762 resolveFormats();-
1763}
never executed: end of block
0
1764-
1765bool QTextEngine::isRightToLeft() const-
1766{-
1767 switch (option.textDirection()) {-
1768 case Qt::LeftToRight:
never executed: case Qt::LeftToRight:
0
1769 return false;
never executed: return false;
0
1770 case Qt::RightToLeft:
never executed: case Qt::RightToLeft:
0
1771 return true;
never executed: return true;
0
1772 default:
never executed: default:
0
1773 break;
never executed: break;
0
1774 }-
1775 if (!layoutData)
!layoutDataDescription
TRUEnever evaluated
FALSEnever evaluated
0
1776 itemize();
never executed: itemize();
0
1777 // this places the cursor in the right position depending on the keyboard layout-
1778 if (layoutData->string.isEmpty())
layoutData->string.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1779 return QGuiApplication::inputMethod()->inputDirection() == Qt::RightToLeft;
never executed: return QGuiApplication::inputMethod()->inputDirection() == Qt::RightToLeft;
0
1780 return layoutData->string.isRightToLeft();
never executed: return layoutData->string.isRightToLeft();
0
1781}-
1782-
1783-
1784int QTextEngine::findItem(int strPos, int firstItem) const-
1785{-
1786 itemize();-
1787 if (strPos < 0 || strPos >= layoutData->string.size() || firstItem < 0)
strPos < 0Description
TRUEnever evaluated
FALSEnever evaluated
strPos >= layo...>string.size()Description
TRUEnever evaluated
FALSEnever evaluated
firstItem < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1788 return -1;
never executed: return -1;
0
1789-
1790 int left = firstItem + 1;-
1791 int right = layoutData->items.size()-1;-
1792 while(left <= right) {
left <= rightDescription
TRUEnever evaluated
FALSEnever evaluated
0
1793 int middle = ((right-left)/2)+left;-
1794 if (strPos > layoutData->items[middle].position)
strPos > layou...ddle].positionDescription
TRUEnever evaluated
FALSEnever evaluated
0
1795 left = middle+1;
never executed: left = middle+1;
0
1796 else if(strPos < layoutData->items[middle].position)
strPos < layou...ddle].positionDescription
TRUEnever evaluated
FALSEnever evaluated
0
1797 right = middle-1;
never executed: right = middle-1;
0
1798 else {-
1799 return middle;
never executed: return middle;
0
1800 }-
1801 }-
1802 return right;
never executed: return right;
0
1803}-
1804-
1805QFixed QTextEngine::width(int from, int len) const-
1806{-
1807 itemize();-
1808-
1809 QFixed w = 0;-
1810-
1811// qDebug("QTextEngine::width(from = %d, len = %d), numItems=%d, strleng=%d", from, len, items.size(), string.length());-
1812 for (int i = 0; i < layoutData->items.size(); i++) {
i < layoutData->items.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1813 const QScriptItem *si = layoutData->items.constData() + i;-
1814 int pos = si->position;-
1815 int ilen = length(i);-
1816// qDebug("item %d: from %d len %d", i, pos, ilen);-
1817 if (pos >= from + len)
pos >= from + lenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1818 break;
never executed: break;
0
1819 if (pos + ilen > from) {
pos + ilen > fromDescription
TRUEnever evaluated
FALSEnever evaluated
0
1820 if (!si->num_glyphs)
!si->num_glyphsDescription
TRUEnever evaluated
FALSEnever evaluated
0
1821 shape(i);
never executed: shape(i);
0
1822-
1823 if (si->analysis.flags == QScriptAnalysis::Object) {
si->analysis.f...alysis::ObjectDescription
TRUEnever evaluated
FALSEnever evaluated
0
1824 w += si->width;-
1825 continue;
never executed: continue;
0
1826 } else if (si->analysis.flags == QScriptAnalysis::Tab) {
si->analysis.f...tAnalysis::TabDescription
TRUEnever evaluated
FALSEnever evaluated
0
1827 w += calculateTabWidth(i, w);-
1828 continue;
never executed: continue;
0
1829 }-
1830-
1831-
1832 QGlyphLayout glyphs = shapedGlyphs(si);-
1833 unsigned short *logClusters = this->logClusters(si);-
1834-
1835// fprintf(stderr, " logclusters:");-
1836// for (int k = 0; k < ilen; k++)-
1837// fprintf(stderr, " %d", logClusters[k]);-
1838// fprintf(stderr, "\n");-
1839 // do the simple thing for now and give the first glyph in a cluster the full width, all other ones 0.-
1840 int charFrom = from - pos;-
1841 if (charFrom < 0)
charFrom < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1842 charFrom = 0;
never executed: charFrom = 0;
0
1843 int glyphStart = logClusters[charFrom];-
1844 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)
charFrom > 0Description
TRUEnever evaluated
FALSEnever evaluated
logClusters[ch... == glyphStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
1845 while (charFrom < ilen && logClusters[charFrom] == glyphStart)
charFrom < ilenDescription
TRUEnever evaluated
FALSEnever evaluated
logClusters[ch... == glyphStartDescription
TRUEnever evaluated
FALSEnever evaluated
0
1846 charFrom++;
never executed: charFrom++;
0
1847 if (charFrom < ilen) {
charFrom < ilenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1848 glyphStart = logClusters[charFrom];-
1849 int charEnd = from + len - 1 - pos;-
1850 if (charEnd >= ilen)
charEnd >= ilenDescription
TRUEnever evaluated
FALSEnever evaluated
0
1851 charEnd = ilen-1;
never executed: charEnd = ilen-1;
0
1852 int glyphEnd = logClusters[charEnd];-
1853 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)
charEnd < ilenDescription
TRUEnever evaluated
FALSEnever evaluated
logClusters[ch...d] == glyphEndDescription
TRUEnever evaluated
FALSEnever evaluated
0
1854 charEnd++;
never executed: charEnd++;
0
1855 glyphEnd = (charEnd == ilen) ? si->num_glyphs