qtextengine.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/text/qtextengine.cpp
Switch to Source codePreprocessed file
LineSourceCount
1-
2-
3-
4-
5-
6static const float smallCapsFraction = 0.7f;-
7-
8namespace {-
9-
10-
11class Itemizer {-
12public:-
13 Itemizer(const QString &string, const QScriptAnalysis *analysis, QScriptItemArray &items)-
14 : m_string(string),-
15 m_analysis(analysis),-
16 m_items(items),-
17 m_splitter(0)-
18 {-
19 }-
20 ~Itemizer()-
21 {-
22 delete m_splitter;-
23 }-
24-
25-
26-
27 void generate(int start, int length, QFont::Capitalization caps)-
28 {-
29 if (caps == QFont::SmallCaps)-
30 generateScriptItemsSmallCaps(reinterpret_cast<const ushort *>(m_string.unicode()), start, length);-
31 else if(caps == QFont::Capitalize)-
32 generateScriptItemsCapitalize(start, length);-
33 else if(caps != QFont::MixedCase) {-
34 generateScriptItemsAndChangeCase(start, length,-
35 caps == QFont::AllLowercase ? QScriptAnalysis::Lowercase : QScriptAnalysis::Uppercase);-
36 }-
37 else-
38 generateScriptItems(start, length);-
39 }-
40-
41private:-
42 enum { MaxItemLength = 4096 };-
43-
44 void generateScriptItemsAndChangeCase(int start, int length, QScriptAnalysis::Flags flags)-
45 {-
46 generateScriptItems(start, length);-
47 if (m_items.isEmpty())-
48 return;-
49 QScriptItemArray::Iterator iter = m_items.end();-
50 do {-
51 iter--;-
52 if (iter->analysis.flags < QScriptAnalysis::LineOrParagraphSeparator)-
53 iter->analysis.flags = flags;-
54 } while (iter->position > start);-
55 }-
56-
57 void generateScriptItems(int start, int length)-
58 {-
59 if (!length)-
60 return;-
61 const int end = start + length;-
62 for (int i = start + 1; i < end; ++i) {-
63 if (m_analysis[i].bidiLevel == m_analysis[start].bidiLevel-
64 && m_analysis[i].flags == m_analysis[start].flags-
65 && (m_analysis[i].script == m_analysis[start].script || m_string[i] == QLatin1Char('.'))-
66 && m_analysis[i].flags < QScriptAnalysis::SpaceTabOrObject-
67 && i - start < MaxItemLength)-
68 continue;-
69 m_items.append(QScriptItem(start, m_analysis[start]));-
70 start = i;-
71 }-
72 m_items.append(QScriptItem(start, m_analysis[start]));-
73 }-
74-
75 void generateScriptItemsCapitalize(int start, int length)-
76 {-
77 if (!length)-
78 return;-
79-
80 if (!m_splitter)-
81 m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word,-
82 m_string.constData(), m_string.length(),-
83 0, 0);-
84-
85 m_splitter->setPosition(start);-
86 QScriptAnalysis itemAnalysis = m_analysis[start];-
87-
88 if (m_splitter->boundaryReasons() & QTextBoundaryFinder::StartOfItem)-
89 itemAnalysis.flags = QScriptAnalysis::Uppercase;-
90-
91 m_splitter->toNextBoundary();-
92-
93 const int end = start + length;-
94 for (int i = start + 1; i < end; ++i) {-
95 bool atWordStart = false;-
96-
97 if (i == m_splitter->position()) {-
98 if (m_splitter->boundaryReasons() & QTextBoundaryFinder::StartOfItem) {-
99 ((!(m_analysis[i].flags < QScriptAnalysis::TabOrObject)) ? qt_assert("m_analysis[i].flags < QScriptAnalysis::TabOrObject",__FILE__,149155) : qt_noop());-
100 atWordStart = true;-
101 }-
102-
103 m_splitter->toNextBoundary();-
104 }-
105-
106 if (m_analysis[i] == itemAnalysis-
107 && m_analysis[i].flags < QScriptAnalysis::TabOrObject-
108 && !atWordStart-
109 && i - start < MaxItemLength)-
110 continue;-
111-
112 m_items.append(QScriptItem(start, itemAnalysis));-
113 start = i;-
114 itemAnalysis = m_analysis[start];-
115-
116 if (atWordStart)-
117 itemAnalysis.flags = QScriptAnalysis::Uppercase;-
118 }-
119 m_items.append(QScriptItem(start, itemAnalysis));-
120 }-
121-
122 void generateScriptItemsSmallCaps(const ushort *uc, int start, int length)-
123 {-
124 if (!length)-
125 return;-
126 bool lower = (QChar::category(uc[start]) == QChar::Letter_Lowercase);-
127 const int end = start + length;-
128-
129 for (int i = start + 1; i < end; ++i) {-
130 bool l = (QChar::category(uc[i]) == QChar::Letter_Lowercase);-
131 if ((m_analysis[i] == m_analysis[start])-
132 && m_analysis[i].flags < QScriptAnalysis::TabOrObject-
133 && l == lower-
134 && i - start < MaxItemLength)-
135 continue;-
136 m_items.append(QScriptItem(start, m_analysis[start]));-
137 if (lower)-
138 m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;-
139-
140 start = i;-
141 lower = l;-
142 }-
143 m_items.append(QScriptItem(start, m_analysis[start]));-
144 if (lower)-
145 m_items.last().analysis.flags = QScriptAnalysis::SmallCaps;-
146 }-
147-
148 const QString &m_string;-
149 const QScriptAnalysis * const m_analysis;-
150 QScriptItemArray &m_items;-
151 QTextBoundaryFinder *m_splitter;-
152};-
153}-
154struct QBidiStatus {-
155 QBidiStatus() {-
156 eor = QChar::DirON;-
157 lastStrong = QChar::DirON;-
158 last = QChar:: DirON;-
159 dir = QChar::DirON;-
160 }-
161 QChar::Direction eor;-
162 QChar::Direction lastStrong;-
163 QChar::Direction last;-
164 QChar::Direction dir;-
165};-
166-
167enum { MaxBidiLevel = 61 };-
168-
169struct QBidiControl {-
170 inline QBidiControl(bool rtl)-
171 : cCtx(0), base(rtl ? 1 : 0), level(rtl ? 1 : 0), override(false) {}-
172-
173 inline void embed(bool rtl, bool o = false) {-
174 unsigned int toAdd = 1;-
175 if((level%2 != 0) == rtl ) {-
176 ++toAdd;-
177 }-
178 if (level + toAdd <= MaxBidiLevel) {-
179 ctx[cCtx].level = level;-
180 ctx[cCtx].override = override;-
181 cCtx++;-
182 override = o;-
183 level += toAdd;-
184 }-
185 }-
186 inline bool canPop() const { return cCtx != 0; }-
187 inline void pdf() {-
188 ((!(cCtx)) ? qt_assert("cCtx",__FILE__,261267) : qt_noop());-
189 --cCtx;-
190 level = ctx[cCtx].level;-
191 override = ctx[cCtx].override;-
192 }-
193-
194 inline QChar::Direction basicDirection() const {-
195 return (base ? QChar::DirR : QChar:: DirL);-
196 }-
197 inline unsigned int baseLevel() const {-
198 return base;-
199 }-
200 inline QChar::Direction direction() const {-
201 return ((level%2) ? QChar::DirR : QChar:: DirL);-
202 }-
203-
204 struct {-
205 unsigned int level;-
206 bool override;-
207 } ctx[MaxBidiLevel];-
208 unsigned int cCtx;-
209 const unsigned int base;-
210 unsigned int level;-
211 bool override;-
212};-
213-
214-
215static void appendItems(QScriptAnalysis *analysis, int &start, int &stop, const QBidiControl &control, QChar::Direction dir)-
216{-
217 if (start > stop)-
218 return;-
219-
220 int level = control.level;-
221-
222 if(dir != QChar::DirON && !control.override) {-
223-
224 if(level % 2) {-
225 if(dir == QChar::DirL || dir == QChar::DirAN || dir == QChar::DirEN)-
226 level++;-
227 } else {-
228 if(dir == QChar::DirR)-
229 level++;-
230 else if(dir == QChar::DirAN || dir == QChar::DirEN)-
231 level += 2;-
232 }-
233 }-
234-
235-
236-
237-
238 QScriptAnalysis *s = analysis + start;-
239 const QScriptAnalysis *e = analysis + stop;-
240 while (s <= e) {-
241 s->bidiLevel = level;-
242 ++s;-
243 }-
244 ++stop;-
245 start = stop;-
246}-
247-
248static QChar::Direction skipBoundryNeutrals(QScriptAnalysis *analysis,-
249 const ushort *unicode, int length,-
250 int &sor, int &eor, QBidiControl &control)-
251{-
252 QChar::Direction dir = control.basicDirection();-
253 int level = sor > 0 ? analysis[sor - 1].bidiLevel : control.level;-
254 while (sor < length) {-
255 dir = QChar::direction(unicode[sor]);-
256-
257 if (dir != QChar::DirBN)-
258 break;-
259 analysis[sor++].bidiLevel = level;-
260 }-
261-
262 eor = sor;-
263 if (eor == length)-
264 dir = control.basicDirection();-
265-
266 return dir;-
267}-
268-
269-
270static bool bidiItemize(QTextEngine *engine, QScriptAnalysis *analysis, QBidiControl &control)-
271{-
272 bool rightToLeft = (control.basicDirection() == 1);-
273 bool hasBidi = rightToLeft;-
274-
275-
276-
277-
278 int sor = 0;-
279 int eor = -1;-
280-
281-
282 int length = engine->layoutData->string.length();-
283-
284 const ushort *unicode = (const ushort *)engine->layoutData->string.unicode();-
285 int current = 0;-
286-
287 QChar::Direction dir = rightToLeft ? QChar::DirR : QChar::DirL;-
288 QBidiStatus status;-
289-
290 QChar::Direction sdir = QChar::direction(*unicode);-
291 if (sdir != QChar::DirL && sdir != QChar::DirR && sdir != QChar::DirEN && sdir != QChar::DirAN)-
292 sdir = QChar::DirON;-
293 else-
294 dir = QChar::DirON;-
295 status.eor = sdir;-
296 status.lastStrong = rightToLeft ? QChar::DirR : QChar::DirL;-
297 status.last = status.lastStrong;-
298 status.dir = sdir;-
299-
300-
301 while (current <= length) {-
302-
303 QChar::Direction dirCurrent;-
304 if (current == (int)length)-
305 dirCurrent = control.basicDirection();-
306 else-
307 dirCurrent = QChar::direction(unicode[current]);-
308 switch(dirCurrent) {-
309-
310-
311 case QChar::DirRLE:-
312 case QChar::DirRLO:-
313 case QChar::DirLRE:-
314 case QChar::DirLRO:-
315 {-
316 bool rtl = (dirCurrent == QChar::DirRLE || dirCurrent == QChar::DirRLO);-
317 hasBidi |= rtl;-
318 bool override = (dirCurrent == QChar::DirLRO || dirCurrent == QChar::DirRLO);-
319-
320 unsigned int level = control.level+1;-
321 if ((level%2 != 0) == rtl) ++level;-
322 if(level < MaxBidiLevel) {-
323 eor = current-1;-
324 appendItems(analysis, sor, eor, control, dir);-
325 eor = current;-
326 control.embed(rtl, override);-
327 QChar::Direction edir = (rtl ? QChar::DirR : QChar::DirL);-
328 dir = status.eor = edir;-
329 status.lastStrong = edir;-
330 }-
331 break;-
332 }-
333 case QChar::DirPDF:-
334 {-
335 if (control.canPop()) {-
336 if (dir != control.direction()) {-
337 eor = current-1;-
338 appendItems(analysis, sor, eor, control, dir);-
339 dir = control.direction();-
340 }-
341 eor = current;-
342 appendItems(analysis, sor, eor, control, dir);-
343 control.pdf();-
344 dir = QChar::DirON; status.eor = QChar::DirON;-
345 status.last = control.direction();-
346 if (control.override)-
347 dir = control.direction();-
348 else-
349 dir = QChar::DirON;-
350 status.lastStrong = control.direction();-
351 }-
352 break;-
353 }-
354-
355-
356 case QChar::DirL:-
357 if(dir == QChar::DirON)-
358 dir = QChar::DirL;-
359 switch(status.last)-
360 {-
361 case QChar::DirL:-
362 eor = current; status.eor = QChar::DirL; break;-
363 case QChar::DirR:-
364 case QChar::DirAL:-
365 case QChar::DirEN:-
366 case QChar::DirAN:-
367 if (eor >= 0) {-
368 appendItems(analysis, sor, eor, control, dir);-
369 status.eor = dir = skipBoundryNeutrals(analysis, unicode, length, sor, eor, control);-
370 } else {-
371 eor = current; status.eor = dir;-
372 }-
373 break;-
374 case QChar::DirES:-
375 case QChar::DirET:-
376 case QChar::DirCS:-
377 case QChar::DirBN:-
378 case QChar::DirB:-
379 case QChar::DirS:-
380 case QChar::DirWS:-
381 case QChar::DirON:-
382 if(dir != QChar::DirL) {-
383-
384 if(control.direction() == QChar::DirR) {-
385 if(status.eor != QChar::DirR) {-
386-
387 appendItems(analysis, sor, eor, control, dir);-
388 status.eor = QChar::DirON;-
389 dir = QChar::DirR;-
390 }-
391 eor = current - 1;-
392 appendItems(analysis, sor, eor, control, dir);-
393 status.eor = dir = skipBoundryNeutrals(analysis, unicode, length, sor, eor, control);-
394 } else {-
395 if(status.eor != QChar::DirL) {-
396 appendItems(analysis, sor, eor, control, dir);-
397 status.eor = QChar::DirON;-
398 dir = QChar::DirL;-
399 } else {-
400 eor = current; status.eor = QChar::DirL; break;-
401 }-
402 }-
403 } else {-
404 eor = current; status.eor = QChar::DirL;-
405 }-
406 default:-
407 break;-
408 }-
409 status.lastStrong = QChar::DirL;-
410 break;-
411 case QChar::DirAL:-
412 case QChar::DirR:-
413 hasBidi = true;-
414 if(dir == QChar::DirON) dir = QChar::DirR;-
415 switch(status.last)-
416 {-
417 case QChar::DirL:-
418 case QChar::DirEN:-
419 case QChar::DirAN:-
420 if (eor >= 0)-
421 appendItems(analysis, sor, eor, control, dir);-
422-
423 case QChar::DirR:-
424 case QChar::DirAL:-
425 dir = QChar::DirR; eor = current; status.eor = QChar::DirR; break;-
426 case QChar::DirES:-
427 case QChar::DirET:-
428 case QChar::DirCS:-
429 case QChar::DirBN:-
430 case QChar::DirB:-
431 case QChar::DirS:-
432 case QChar::DirWS:-
433 case QChar::DirON:-
434 if(status.eor != QChar::DirR && status.eor != QChar::DirAL) {-
435-
436 if(control.direction() == QChar::DirR-
437 || status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) {-
438 appendItems(analysis, sor, eor, control, dir);-
439 dir = QChar::DirR; status.eor = QChar::DirON;-
440 eor = current;-
441 } else {-
442 eor = current - 1;-
443 appendItems(analysis, sor, eor, control, dir);-
444 dir = QChar::DirR; status.eor = QChar::DirON;-
445 }-
446 } else {-
447 eor = current; status.eor = QChar::DirR;-
448 }-
449 default:-
450 break;-
451 }-
452 status.lastStrong = dirCurrent;-
453 break;-
454-
455-
456-
457 case QChar::DirNSM:-
458 if (eor == current-1)-
459 eor = current;-
460 break;-
461 case QChar::DirEN:-
462-
463 if(status.lastStrong != QChar::DirAL) {-
464 if(dir == QChar::DirON) {-
465 if(status.lastStrong == QChar::DirL)-
466 dir = QChar::DirL;-
467 else-
468 dir = QChar::DirEN;-
469 }-
470 switch(status.last)-
471 {-
472 case QChar::DirET:-
473 if (status.lastStrong == QChar::DirR || status.lastStrong == QChar::DirAL) {-
474 appendItems(analysis, sor, eor, control, dir);-
475 status.eor = QChar::DirON;-
476 dir = QChar::DirAN;-
477 }-
478-
479 case QChar::DirEN:-
480 case QChar::DirL:-
481 eor = current;-
482 status.eor = dirCurrent;-
483 break;-
484 case QChar::DirR:-
485 case QChar::DirAL:-
486 case QChar::DirAN:-
487 if (eor >= 0)-
488 appendItems(analysis, sor, eor, control, dir);-
489 else-
490 eor = current;-
491 status.eor = QChar::DirEN;-
492 dir = QChar::DirAN; break;-
493 case QChar::DirES:-
494 case QChar::DirCS:-
495 if(status.eor == QChar::DirEN || dir == QChar::DirAN) {-
496 eor = current; break;-
497 }-
498 case QChar::DirBN:-
499 case QChar::DirB:-
500 case QChar::DirS:-
501 case QChar::DirWS:-
502 case QChar::DirON:-
503 if(status.eor == QChar::DirR) {-
504-
505 eor = current - 1;-
506 appendItems(analysis, sor, eor, control, dir);-
507 dir = QChar::DirON; status.eor = QChar::DirEN;-
508 dir = QChar::DirAN;-
509 }-
510 else if(status.eor == QChar::DirL ||-
511 (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) {-
512 eor = current; status.eor = dirCurrent;-
513 } else {-
514-
515 if(dir != QChar::DirL) {-
516 appendItems(analysis, sor, eor, control, dir);-
517 dir = QChar::DirON; status.eor = QChar::DirON;-
518 eor = current - 1;-
519 dir = QChar::DirR;-
520 appendItems(analysis, sor, eor, control, dir);-
521 dir = QChar::DirON; status.eor = QChar::DirON;-
522 dir = QChar::DirAN;-
523 } else {-
524 eor = current; status.eor = dirCurrent;-
525 }-
526 }-
527 default:-
528 break;-
529 }-
530 break;-
531 }-
532 case QChar::DirAN:-
533 hasBidi = true;-
534 dirCurrent = QChar::DirAN;-
535 if(dir == QChar::DirON) dir = QChar::DirAN;-
536 switch(status.last)-
537 {-
538 case QChar::DirL:-
539 case QChar::DirAN:-
540 eor = current; status.eor = QChar::DirAN; break;-
541 case QChar::DirR:-
542 case QChar::DirAL:-
543 case QChar::DirEN:-
544 if (eor >= 0){-
545 appendItems(analysis, sor, eor, control, dir);-
546 } else {-
547 eor = current;-
548 }-
549 dir = QChar::DirAN; status.eor = QChar::DirAN;-
550 break;-
551 case QChar::DirCS:-
552 if(status.eor == QChar::DirAN) {-
553 eor = current; break;-
554 }-
555 case QChar::DirES:-
556 case QChar::DirET:-
557 case QChar::DirBN:-
558 case QChar::DirB:-
559 case QChar::DirS:-
560 case QChar::DirWS:-
561 case QChar::DirON:-
562 if(status.eor == QChar::DirR) {-
563-
564 eor = current - 1;-
565 appendItems(analysis, sor, eor, control, dir);-
566 status.eor = QChar::DirAN;-
567 dir = QChar::DirAN;-
568 } else if(status.eor == QChar::DirL ||-
569 (status.eor == QChar::DirEN && status.lastStrong == QChar::DirL)) {-
570 eor = current; status.eor = dirCurrent;-
571 } else {-
572-
573 if(dir != QChar::DirL) {-
574 appendItems(analysis, sor, eor, control, dir);-
575 status.eor = QChar::DirON;-
576 eor = current - 1;-
577 dir = QChar::DirR;-
578 appendItems(analysis, sor, eor, control, dir);-
579 status.eor = QChar::DirAN;-
580 dir = QChar::DirAN;-
581 } else {-
582 eor = current; status.eor = dirCurrent;-
583 }-
584 }-
585 default:-
586 break;-
587 }-
588 break;-
589 case QChar::DirES:-
590 case QChar::DirCS:-
591 break;-
592 case QChar::DirET:-
593 if(status.last == QChar::DirEN) {-
594 dirCurrent = QChar::DirEN;-
595 eor = current; status.eor = dirCurrent;-
596 }-
597 break;-
598-
599-
600 case QChar::DirBN:-
601 break;-
602-
603 case QChar::DirB:-
604-
605 break;-
606 case QChar::DirS:-
607-
608 break;-
609 case QChar::DirWS:-
610 case QChar::DirON:-
611 break;-
612 default:-
613 break;-
614 }-
615-
616-
617-
618 if(current >= (int)length) break;-
619-
620-
621 switch(dirCurrent) {-
622 case QChar::DirET:-
623 case QChar::DirES:-
624 case QChar::DirCS:-
625 case QChar::DirS:-
626 case QChar::DirWS:-
627 case QChar::DirON:-
628 switch(status.last)-
629 {-
630 case QChar::DirL:-
631 case QChar::DirR:-
632 case QChar::DirAL:-
633 case QChar::DirEN:-
634 case QChar::DirAN:-
635 status.last = dirCurrent;-
636 break;-
637 default:-
638 status.last = QChar::DirON;-
639 }-
640 break;-
641 case QChar::DirNSM:-
642 case QChar::DirBN:-
643-
644 break;-
645 case QChar::DirLRO:-
646 case QChar::DirLRE:-
647 status.last = QChar::DirL;-
648 break;-
649 case QChar::DirRLO:-
650 case QChar::DirRLE:-
651 status.last = QChar::DirR;-
652 break;-
653 case QChar::DirEN:-
654 if (status.last == QChar::DirL) {-
655 status.last = QChar::DirL;-
656 break;-
657 }-
658-
659 default:-
660 status.last = dirCurrent;-
661 }-
662-
663 ++current;-
664 }-
665-
666-
667-
668-
669 eor = current - 1;-
670-
671 if (sor <= eor)-
672 appendItems(analysis, sor, eor, control, dir);-
673-
674 return hasBidi;-
675}-
676-
677void QTextEngine::bidiReorder(int numItems, const quint8 *levels, int *visualOrder)-
678{-
679-
680-
681 quint8 levelLow = 128;-
682 quint8 levelHigh = 0;-
683 int i = 0;-
684 while (i < numItems
i < numItemsDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
685-
686 if (levels[i] > levelHigh
levels[i] > levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
687 levelHigh = levels[i];
never executed: levelHigh = levels[i];
0
688 if (levels[i] < levelLow
levels[i] < levelLowDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
689 levelLow = levels[i];
never executed: levelLow = levels[i];
0
690 i++;-
691 }
never executed: end of block
0
692-
693-
694-
695-
696-
697-
698 if(!(levelLow%2)
!(levelLow%2)Description
TRUEnever evaluated
FALSEnever evaluated
) levelLow++;
never executed: levelLow++;
0
699-
700-
701-
702-
703-
704 int count = numItems - 1;-
705 for (i = 0; i < numItems
i < numItemsDescription
TRUEnever evaluated
FALSEnever evaluated
; i++)
0
706 visualOrder[i] = i;
never executed: visualOrder[i] = i;
0
707-
708 while(levelHigh >= levelLow
levelHigh >= levelLowDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
709 int i = 0;-
710 while (i < count
i < countDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
711 while(i < count
i < countDescription
TRUEnever evaluated
FALSEnever evaluated
&& levels[i] < levelHigh
levels[i] < levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
) i++;
never executed: i++;
0
712 int start = i;-
713 while(i <= count
i <= countDescription
TRUEnever evaluated
FALSEnever evaluated
&& levels[i] >= levelHigh
levels[i] >= levelHighDescription
TRUEnever evaluated
FALSEnever evaluated
) i++;
never executed: i++;
0
714 int end = i-1;-
715-
716 if(start != end
start != endDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
717-
718 for(int j = 0; j < (end-start+1)/2
j < (end-start+1)/2Description
TRUEnever evaluated
FALSEnever evaluated
; j++) {
0
719 int tmp = visualOrder[start+j];-
720 visualOrder[start+j] = visualOrder[end-j];-
721 visualOrder[end-j] = tmp;-
722 }
never executed: end of block
0
723 }
never executed: end of block
0
724 i++;-
725 }
never executed: end of block
0
726 levelHigh--;-
727 }
never executed: end of block
0
728-
729-
730-
731-
732-
733-
734}
never executed: end of block
0
735-
736-
737enum JustificationClass {-
738 Justification_Prohibited = 0,-
739 Justification_Arabic_Space = 1,-
740 Justification_Character = 2,-
741 Justification_Space = 4,-
742 Justification_Arabic_Normal = 7,-
743 Justification_Arabic_Waw = 8,-
744 Justification_Arabic_BaRa = 9,-
745 Justification_Arabic_Alef = 10,-
746 Justification_Arabic_HahDal = 11,-
747 Justification_Arabic_Seen = 12,-
748 Justification_Arabic_Kashida = 13-
749};-
750-
751-
752-
753-
754-
755-
756-
757static inline void qt_getDefaultJustificationOpportunities(const ushort *string, int length, QGlyphLayout g, ushort *log_clusters, int spaceAs)-
758{-
759 int str_pos = 0;-
760 while (str_pos < length) {-
761 int glyph_pos = log_clusters[str_pos];-
762-
763 ((!(glyph_pos < g.numGlyphs && g.attributes[glyph_pos].clusterStart)) ? qt_assert("glyph_pos < g.numGlyphs && g.attributes[glyph_pos].clusterStart",__FILE__,846852) : qt_noop());-
764-
765 uint ucs4 = string[str_pos];-
766 if (QChar::isHighSurrogate(ucs4) && str_pos + 1 < length) {-
767 ushort low = string[str_pos + 1];-
768 if (QChar::isLowSurrogate(low)) {-
769 ++str_pos;-
770 ucs4 = QChar::surrogateToUcs4(ucs4, low);-
771 }-
772 }-
773-
774-
775 do {-
776 ++str_pos;-
777 } while (str_pos < length && log_clusters[str_pos] == glyph_pos);-
778 do {-
779 ++glyph_pos;-
780 } while (glyph_pos < g.numGlyphs && !g.attributes[glyph_pos].clusterStart);-
781 --glyph_pos;-
782-
783-
784 if (__builtin_expect(!!(QChar::isLetterOrNumber(ucs4)), true))-
785 g.attributes[glyph_pos].justification = Justification_Character;-
786 else if (__builtin_expect(!!(QChar::isSpace(ucs4)), true))-
787 g.attributes[glyph_pos].justification = spaceAs;-
788 }-
789}-
790-
791static inline void qt_getJustificationOpportunities(const ushort *string, int length, const QScriptItem &si, QGlyphLayout g, ushort *log_clusters)-
792{-
793 ((!(length > 0 && g.numGlyphs > 0)) ? qt_assert("length > 0 && g.numGlyphs > 0",__FILE__,876882) : qt_noop());-
794-
795 for (int glyph_pos = 0; glyph_pos < g.numGlyphs; ++glyph_pos)-
796 g.attributes[glyph_pos].justification = Justification_Prohibited;-
797-
798 int spaceAs;-
799-
800 switch (si.analysis.script) {-
801 case QChar::Script_Arabic:-
802 case QChar::Script_Syriac:-
803 case QChar::Script_Nko:-
804 case QChar::Script_Mandaic:-
805 case QChar::Script_Mongolian:-
806 case QChar::Script_PhagsPa:-
807 case QChar::Script_Manichaean:-
808 case QChar::Script_PsalterPahlavi:-
809-
810 spaceAs = Justification_Arabic_Space;-
811 break;-
812-
813 case QChar::Script_Tibetan:-
814 case QChar::Script_Hiragana:-
815 case QChar::Script_Katakana:-
816 case QChar::Script_Bopomofo:-
817 case QChar::Script_Han:-
818-
819 spaceAs = Justification_Character;-
820 break;-
821-
822 default:-
823 spaceAs = Justification_Space;-
824 break;-
825 }-
826-
827 qt_getDefaultJustificationOpportunities(string, length, g, log_clusters, spaceAs);-
828}-
829-
830-
831-
832-
833-
834void QTextEngine::shapeLine(const QScriptLine &line)-
835{-
836 QFixed x;-
837 bool first = true;-
838 int item = findItem(line.from);-
839 if (item == -1)-
840 return;-
841-
842 const int end = findItem(line.from + line.length + line.trailingSpaces - 1, item);-
843 for ( ; item <= end; ++item) {-
844 QScriptItem &si = layoutData->items[item];-
845 if (si.analysis.flags == QScriptAnalysis::Tab) {-
846 ensureSpace(1);-
847 si.width = calculateTabWidth(item, x);-
848 } else {-
849 shape(item);-
850 }-
851 if (first && si.position != line.from) {-
852 QGlyphLayout glyphs = shapedGlyphs(&si);-
853 ((!(line.from > si.position)) ? qt_assert("line.from > si.position",__FILE__,936942) : qt_noop());-
854 for (int i = line.from - si.position - 1; i >= 0; i--) {-
855 x -= glyphs.effectiveAdvance(i);-
856 }-
857 }-
858 first = false;-
859-
860 x += si.width;-
861 }-
862}-
863-
864-
865extern bool qt_useHarfbuzzNG();-
866-
867-
868void QTextEngine::shapeText(int item) const-
869{-
870 ((!(item < layoutData->items.size())) ? qt_assert("item < layoutData->items.size()",__FILE__,953959) : qt_noop());-
871 QScriptItem &si = layoutData->items[item];-
872-
873 if (si.num_glyphs)-
874 return;-
875-
876 si.width = 0;-
877 si.glyph_data_offset = layoutData->used;-
878-
879 const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.constData()) + si.position;-
880 const int itemLength = length(item);-
881-
882 QString casedString;-
883 if (si.analysis.flags && si.analysis.flags <= QScriptAnalysis::SmallCaps) {-
884 casedString.resize(itemLength);-
885 ushort *uc = reinterpret_cast<ushort *>(casedString.data());-
886 for (int i = 0; i < itemLength; ++i) {-
887 uint ucs4 = string[i];-
888 if (QChar::isHighSurrogate(ucs4) && i + 1 < itemLength) {-
889 uint low = string[i + 1];-
890 if (QChar::isLowSurrogate(low)) {-
891 ++i;-
892 ucs4 = QChar::surrogateToUcs4(ucs4, low);-
893 ucs4 = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4)-
894 : QChar::toUpper(ucs4);-
895-
896 uc[i] = QChar::lowSurrogate(ucs4);-
897 }-
898 } else {-
899 uc[i] = si.analysis.flags == QScriptAnalysis::Lowercase ? QChar::toLower(ucs4)-
900 : QChar::toUpper(ucs4);-
901 }-
902 }-
903 string = reinterpret_cast<const ushort *>(casedString.constData());-
904 }-
905-
906 if (__builtin_expect(!!(!ensureSpace(itemLength)), false)) {-
907 do { ((!(false)) ? qt_assert_x("Q_UNREACHABLE()", "Q_UNREACHABLE was reached",__FILE__,990996) : qt_noop()); __builtin_unreachable(); } while (0);-
908 return;-
909 }-
910-
911 QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading);-
912-
913-
914-
915 QVector<uint> itemBoundaries;-
916 itemBoundaries.reserve(24);-
917 if (fontEngine->type() == QFontEngine::Multi) {-
918-
919-
920 QGlyphLayout initialGlyphs = availableGlyphs(&si);-
921-
922 int nGlyphs = initialGlyphs.numGlyphs;-
923 QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);-
924 if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))-
925 do { ((!(false)) ? qt_assert_x("Q_UNREACHABLE()", "Q_UNREACHABLE was reached",__FILE__,10081014) : qt_noop()); __builtin_unreachable(); } while (0);-
926-
927 uint lastEngine = ~0u;-
928 for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {-
929 const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;-
930 if (lastEngine != engineIdx) {-
931 itemBoundaries.append(i);-
932 itemBoundaries.append(glyph_pos);-
933 itemBoundaries.append(engineIdx);-
934-
935 if (engineIdx != 0) {-
936 QFontEngine *actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
937 si.ascent = qMax(actualFontEngine->ascent(), si.ascent);-
938 si.descent = qMax(actualFontEngine->descent(), si.descent);-
939 si.leading = qMax(actualFontEngine->leading(), si.leading);-
940 }-
941-
942 lastEngine = engineIdx;-
943 }-
944-
945 if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))-
946 ++i;-
947 }-
948 } else {-
949 itemBoundaries.append(0);-
950 itemBoundaries.append(0);-
951 itemBoundaries.append(0);-
952 }-
953-
954 bool kerningEnabled;-
955 bool letterSpacingIsAbsolute;-
956 QFixed letterSpacing, wordSpacing;-
957-
958 if (useRawFont) {-
959 QTextCharFormat f = format(&si);-
960 kerningEnabled = f.fontKerning();-
961 wordSpacing = QFixed::fromReal(f.fontWordSpacing());-
962 letterSpacing = QFixed::fromReal(f.fontLetterSpacing());-
963 letterSpacingIsAbsolute = true;-
964 } else-
965-
966 {-
967 QFont font = this->font(si);-
968 kerningEnabled = font.d->kerning;-
969 letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;-
970 letterSpacing = font.d->letterSpacing;-
971 wordSpacing = font.d->wordSpacing;-
972-
973 if (letterSpacingIsAbsolute && letterSpacing.value())-
974 letterSpacing *= font.d->dpi / qt_defaultDpiY();-
975 }-
976-
977-
978 if (__builtin_expect(!!(qt_useHarfbuzzNG()), true))-
979 si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);-
980 else-
981-
982 si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);-
983 if (__builtin_expect(!!(si.num_glyphs == 0), false)) {-
984 do { ((!(false)) ? qt_assert_x("Q_UNREACHABLE()", "Q_UNREACHABLE was reached",__FILE__,10671073) : qt_noop()); __builtin_unreachable(); } while (0);-
985 return;-
986 }-
987-
988-
989 layoutData->used += si.num_glyphs;-
990-
991 QGlyphLayout glyphs = shapedGlyphs(&si);-
992-
993-
994 if (__builtin_expect(!!(qt_useHarfbuzzNG()), true))-
995 qt_getJustificationOpportunities(string, itemLength, si, glyphs, logClusters(&si));-
996-
997-
998 if (letterSpacing != 0) {-
999 for (int i = 1; i < si.num_glyphs; ++i) {-
1000 if (glyphs.attributes[i].clusterStart) {-
1001 if (letterSpacingIsAbsolute)-
1002 glyphs.advances[i - 1] += letterSpacing;-
1003 else {-
1004 QFixed &advance = glyphs.advances[i - 1];-
1005 advance += (letterSpacing - 100) * advance / 100;-
1006 }-
1007 }-
1008 }-
1009 if (letterSpacingIsAbsolute)-
1010 glyphs.advances[si.num_glyphs - 1] += letterSpacing;-
1011 else {-
1012 QFixed &advance = glyphs.advances[si.num_glyphs - 1];-
1013 advance += (letterSpacing - 100) * advance / 100;-
1014 }-
1015 }-
1016 if (wordSpacing != 0) {-
1017 for (int i = 0; i < si.num_glyphs; ++i) {-
1018 if (glyphs.attributes[i].justification == Justification_Space-
1019 || glyphs.attributes[i].justification == Justification_Arabic_Space) {-
1020-
1021 if (i + 1 == si.num_glyphs-
1022 ||(glyphs.attributes[i+1].justification != Justification_Space-
1023 && glyphs.attributes[i+1].justification != Justification_Arabic_Space))-
1024 glyphs.advances[i] += wordSpacing;-
1025 }-
1026 }-
1027 }-
1028-
1029 for (int i = 0; i < si.num_glyphs; ++i)-
1030 si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;-
1031}-
1032-
1033-
1034-
1035-
1036-
1037-
1038-
1039-
1040int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,-
1041 const ushort *string,-
1042 int itemLength,-
1043 QFontEngine *fontEngine,-
1044 const QVector<uint> &itemBoundaries,-
1045 bool kerningEnabled,-
1046 bool hasLetterSpacing) const-
1047{-
1048 uint glyphs_shaped = 0;-
1049-
1050 hb_buffer_t *buffer = hb_buffer_create();-
1051 hb_buffer_set_unicode_funcs(buffer, hb_qt_get_unicode_funcs());-
1052 hb_buffer_pre_allocate(buffer, itemLength);-
1053 if (__builtin_expect(!!(!hb_buffer_allocation_successful(buffer)), false)) {-
1054 hb_buffer_destroy(buffer);-
1055 return 0;-
1056 }-
1057-
1058 hb_segment_properties_t props = {HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, ((hb_language_t) __null), __null, __null};-
1059 props.direction = si.analysis.bidiLevel % 2 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR;-
1060 QChar::Script script = QChar::Script(si.analysis.script);-
1061 props.script = hb_qt_script_to_script(script);-
1062-
1063-
1064 for (int k = 0; k < itemBoundaries.size(); k += 3) {-
1065 const uint item_pos = itemBoundaries[k];-
1066 const uint item_length = (k + 4 < itemBoundaries.size() ? itemBoundaries[k + 3] : itemLength) - item_pos;-
1067 const uint engineIdx = itemBoundaries[k + 2];-
1068-
1069 QFontEngine *actualFontEngine = fontEngine->type() != QFontEngine::Multi ? fontEngine-
1070 : static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
1071-
1072-
1073-
1074 hb_buffer_clear_contents(buffer);-
1075 hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16_t *>(string) + item_pos, item_length, 0, item_length);-
1076-
1077 hb_buffer_set_segment_properties(buffer, &props);-
1078 hb_buffer_guess_segment_properties(buffer);-
1079-
1080 uint buffer_flags = HB_BUFFER_FLAG_DEFAULT;-
1081-
1082-
1083 if (__builtin_expect(!!(actualFontEngine->symbol), false))-
1084 buffer_flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;-
1085 hb_buffer_set_flags(buffer, hb_buffer_flags_t(buffer_flags));-
1086-
1087-
1088-
1089 {-
1090 hb_font_t *hb_font = hb_qt_font_get_for_engine(actualFontEngine);-
1091 ((!(hb_font)) ? qt_assert("hb_font",__FILE__,11751181) : qt_noop());-
1092 hb_qt_font_set_use_design_metrics(hb_font, option.useDesignMetrics() ? uint(QFontEngine::DesignMetrics) : 0);-
1093-
1094-
1095-
1096 bool scriptRequiresOpenType = ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)-
1097 || script == QChar::Script_Khmer || script == QChar::Script_Nko);-
1098-
1099 bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;-
1100 const hb_feature_t features[5] = {-
1101 { ((hb_tag_t)((((uint8_t)('k'))<<24)|(((uint8_t)('e'))<<16)|(((uint8_t)('r'))<<8)|((uint8_t)('n')))), !!kerningEnabled, 0, uint(-1) },-
1102 { ((hb_tag_t)((((uint8_t)('l'))<<24)|(((uint8_t)('i'))<<16)|(((uint8_t)('g'))<<8)|((uint8_t)('a')))), !dontLigate, 0, uint(-1) },-
1103 { ((hb_tag_t)((((uint8_t)('c'))<<24)|(((uint8_t)('l'))<<16)|(((uint8_t)('i'))<<8)|((uint8_t)('g')))), !dontLigate, 0, uint(-1) },-
1104 { ((hb_tag_t)((((uint8_t)('d'))<<24)|(((uint8_t)('l'))<<16)|(((uint8_t)('i'))<<8)|((uint8_t)('g')))), !dontLigate, 0, uint(-1) },-
1105 { ((hb_tag_t)((((uint8_t)('h'))<<24)|(((uint8_t)('l'))<<16)|(((uint8_t)('i'))<<8)|((uint8_t)('g')))), !dontLigate, 0, uint(-1) } };-
1106 const int num_features = dontLigate ? 5 : 1;-
1107-
1108 const char *const *shaper_list = nullptr;-
1109 bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list);-
1110 if (__builtin_expect(!!(!shapedOk), false)) {-
1111 hb_buffer_destroy(buffer);-
1112 return 0;-
1113 }-
1114-
1115 if (__builtin_expect(!!(((((unsigned int) (props.direction)) & ~2U) == 5)), false))-
1116 hb_buffer_reverse(buffer);-
1117 }-
1118-
1119 const uint num_glyphs = hb_buffer_get_length(buffer);-
1120-
1121 if (__builtin_expect(!!(num_glyphs == 0 || !ensureSpace(glyphs_shaped + num_glyphs)), false)) {-
1122 hb_buffer_destroy(buffer);-
1123 return 0;-
1124 }-
1125-
1126-
1127 QGlyphLayout g = availableGlyphs(&si).mid(glyphs_shaped, num_glyphs);-
1128 ushort *log_clusters = logClusters(&si) + item_pos;-
1129-
1130 hb_glyph_info_t *infos = hb_buffer_get_glyph_infos(buffer, 0);-
1131 hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer, 0);-
1132 uint str_pos = 0;-
1133 uint last_cluster = ~0u;-
1134 uint last_glyph_pos = glyphs_shaped;-
1135 for (uint i = 0; i < num_glyphs; ++i, ++infos, ++positions) {-
1136 g.glyphs[i] = infos->codepoint;-
1137-
1138 g.advances[i] = QFixed::fromFixed(positions->x_advance);-
1139 g.offsets[i].x = QFixed::fromFixed(positions->x_offset);-
1140 g.offsets[i].y = QFixed::fromFixed(positions->y_offset);-
1141-
1142 uint cluster = infos->cluster;-
1143 if (__builtin_expect(!!(last_cluster != cluster), true)) {-
1144 g.attributes[i].clusterStart = true;-
1145-
1146-
1147-
1148 while (last_cluster++ < cluster && str_pos < item_length)-
1149 log_clusters[str_pos++] = last_glyph_pos;-
1150 last_glyph_pos = i + glyphs_shaped;-
1151 last_cluster = cluster;-
1152-
1153-
1154 switch (string[item_pos + str_pos]) {-
1155 case QChar::LineFeed:-
1156 case 0x000c:-
1157 case QChar::CarriageReturn:-
1158 case QChar::LineSeparator:-
1159 case QChar::ParagraphSeparator:-
1160 g.attributes[i].dontPrint = true;-
1161 break;-
1162 case QChar::SoftHyphen:-
1163 if (!actualFontEngine->symbol) {-
1164-
1165-
1166-
1167 g.glyphs[i] = actualFontEngine->glyphIndex('-');-
1168 if (__builtin_expect(!!(g.glyphs[i] != 0), true)) {-
1169 QGlyphLayout tmp = g.mid(i, 1);-
1170 actualFontEngine->recalcAdvances(&tmp, 0);-
1171 }-
1172 g.attributes[i].dontPrint = true;-
1173 }-
1174 break;-
1175 default:-
1176 break;-
1177 }-
1178 }-
1179 }-
1180 while (str_pos < item_length)-
1181 log_clusters[str_pos++] = last_glyph_pos;-
1182-
1183 if (__builtin_expect(!!(engineIdx != 0), false)) {-
1184 for (quint32 i = 0; i < num_glyphs; ++i)-
1185 g.glyphs[i] |= (engineIdx << 24);-
1186 }-
1187 if (!actualFontEngine->supportsSubPixelPositions() || (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics)) {-
1188 for (uint i = 0; i < num_glyphs; ++i)-
1189 g.advances[i] = g.advances[i].round();-
1190 }-
1191-
1192 glyphs_shaped += num_glyphs;-
1193 }-
1194-
1195 hb_buffer_destroy(buffer);-
1196-
1197 return glyphs_shaped;-
1198}-
1199-
1200-
1201-
1202-
1203-
1204-
1205-
1206-
1207-
1208static_assert(bool(sizeof(HB_Glyph) == sizeof(glyph_t)), "sizeof(HB_Glyph) == sizeof(glyph_t)");-
1209static_assert(bool(sizeof(HB_Fixed) == sizeof(QFixed)), "sizeof(HB_Fixed) == sizeof(QFixed)");-
1210static_assert(bool(sizeof(HB_FixedPoint) == sizeof(QFixedPoint)), "sizeof(HB_FixedPoint) == sizeof(QFixedPoint)");-
1211-
1212static inline void moveGlyphData(const QGlyphLayout &destination, const QGlyphLayout &source, int num)-
1213{-
1214 if (num > 0 && destination.glyphs != source.glyphs)-
1215 memmove(destination.glyphs, source.glyphs, num * sizeof(glyph_t));-
1216}-
1217-
1218int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const-
1219{-
1220 HB_ShaperItem entire_shaper_item;-
1221 memset(&entire_shaper_item, 0, sizeof(entire_shaper_item));-
1222 entire_shaper_item.string = reinterpret_cast<const HB_UChar16 *>(string);-
1223 entire_shaper_item.stringLength = itemLength;-
1224 entire_shaper_item.item.script = script_to_hbscript(si.analysis.script);-
1225 entire_shaper_item.item.pos = 0;-
1226 entire_shaper_item.item.length = itemLength;-
1227 entire_shaper_item.item.bidiLevel = si.analysis.bidiLevel;-
1228-
1229 entire_shaper_item.shaperFlags = 0;-
1230 if (!kerningEnabled)-
1231 entire_shaper_item.shaperFlags |= HB_ShaperFlag_NoKerning;-
1232 if (option.useDesignMetrics())-
1233 entire_shaper_item.shaperFlags |= HB_ShaperFlag_UseDesignMetrics;-
1234-
1235-
1236 entire_shaper_item.num_glyphs = 0;-
1237 for (int i = 0; i < itemLength; ++i, ++entire_shaper_item.num_glyphs) {-
1238 if (QChar::isHighSurrogate(string[i]) && i + 1 < itemLength && QChar::isLowSurrogate(string[i + 1]))-
1239 ++i;-
1240 }-
1241-
1242-
1243 int remaining_glyphs = entire_shaper_item.num_glyphs;-
1244 int glyph_pos = 0;-
1245-
1246 for (int k = 0; k < itemBoundaries.size(); k += 3) {-
1247 HB_ShaperItem shaper_item = entire_shaper_item;-
1248 shaper_item.item.pos = itemBoundaries[k];-
1249 if (k + 4 < itemBoundaries.size()) {-
1250 shaper_item.item.length = itemBoundaries[k + 3] - shaper_item.item.pos;-
1251 shaper_item.num_glyphs = itemBoundaries[k + 4] - itemBoundaries[k + 1];-
1252 } else {-
1253 shaper_item.item.length -= shaper_item.item.pos - entire_shaper_item.item.pos;-
1254 shaper_item.num_glyphs -= itemBoundaries[k + 1];-
1255 }-
1256 shaper_item.initialGlyphCount = shaper_item.num_glyphs;-
1257 if (shaper_item.num_glyphs < shaper_item.item.length)-
1258 shaper_item.num_glyphs = shaper_item.item.length;-
1259-
1260 uint engineIdx = itemBoundaries[k + 2];-
1261 QFontEngine *actualFontEngine = fontEngine;-
1262 if (fontEngine->type() == QFontEngine::Multi) {-
1263 actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);-
1264-
1265 if ((si.analysis.bidiLevel % 2) == 0)-
1266 shaper_item.glyphIndicesPresent = true;-
1267 }-
1268-
1269 shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();-
1270 shaper_item.face = (HB_Face)actualFontEngine->harfbuzzFace();-
1271-
1272 remaining_glyphs -= shaper_item.initialGlyphCount;-
1273-
1274 QVarLengthArray<HB_GlyphAttributes, 128> hbGlyphAttributes;-
1275 do {-
1276 if (!ensureSpace(glyph_pos + shaper_item.num_glyphs + remaining_glyphs))-
1277 return 0;-
1278 if (hbGlyphAttributes.size() < int(shaper_item.num_glyphs)) {-
1279 hbGlyphAttributes.resize(shaper_item.num_glyphs);-
1280 memset(hbGlyphAttributes.data(), 0, hbGlyphAttributes.size() * sizeof(HB_GlyphAttributes));-
1281 }-
1282-
1283 const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos);-
1284 if (fontEngine->type() == QFontEngine::Multi && shaper_item.num_glyphs > shaper_item.item.length)-
1285 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);-
1286-
1287 shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs);-
1288 shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances);-
1289 shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);-
1290 shaper_item.attributes = hbGlyphAttributes.data();-
1291-
1292 if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {-
1293 for (quint32 i = 0; i < shaper_item.initialGlyphCount; ++i)-
1294 shaper_item.glyphs[i] &= 0x00ffffff;-
1295 }-
1296-
1297 shaper_item.log_clusters = logClusters(&si) + shaper_item.item.pos - entire_shaper_item.item.pos;-
1298 } while (!qShapeItem(&shaper_item));-
1299-
1300 QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos, shaper_item.num_glyphs);-
1301 if (fontEngine->type() == QFontEngine::Multi)-
1302 moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs);-
1303-
1304 for (quint32 i = 0; i < shaper_item.num_glyphs; ++i) {-
1305 HB_GlyphAttributes hbAttrs = hbGlyphAttributes.at(i);-
1306 QGlyphAttributes &attrs = g.attributes[i];-
1307 attrs.clusterStart = hbAttrs.clusterStart;-
1308 attrs.dontPrint = hbAttrs.dontPrint;-
1309 attrs.justification = hbAttrs.justification;-
1310 }-
1311-
1312 for (quint32 i = 0; i < shaper_item.item.length; ++i) {-
1313-
1314 if (shaper_item.log_clusters[i] >= shaper_item.num_glyphs)-
1315 shaper_item.log_clusters[i] = shaper_item.num_glyphs - 1;-
1316 shaper_item.log_clusters[i] += glyph_pos;-
1317 }-
1318-
1319 if (kerningEnabled && !shaper_item.kerning_applied)-
1320 actualFontEngine->doKerning(&g, option.useDesignMetrics() ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0));-
1321-
1322 if (engineIdx != 0) {-
1323 for (quint32 i = 0; i < shaper_item.num_glyphs; ++i)-
1324 g.glyphs[i] |= (engineIdx << 24);-
1325 }-
1326-
1327 glyph_pos += shaper_item.num_glyphs;-
1328 }-
1329-
1330 return glyph_pos;-
1331}-
1332-
1333void QTextEngine::init(QTextEngine *e)-
1334{-
1335 e->ignoreBidi = false;-
1336 e->cacheGlyphs = false;-
1337 e->forceJustification = false;-
1338 e->visualMovement = false;-
1339 e->delayDecorations = false;-
1340-
1341 e->layoutData = 0;-
1342-
1343 e->minWidth = 0;-
1344 e->maxWidth = 0;-
1345-
1346 e->specialData = 0;-
1347 e->stackEngine = false;-
1348-
1349 e->useRawFont = false;-
1350-
1351}-
1352-
1353QTextEngine::QTextEngine()-
1354{-
1355 init(this);-
1356}-
1357-
1358QTextEngine::QTextEngine(const QString &str, const QFont &f)-
1359 : text(str),-
1360 fnt(f)-
1361{-
1362 init(this);-
1363}-
1364-
1365QTextEngine::~QTextEngine()-
1366{-
1367 if (!stackEngine)-
1368 delete layoutData;-
1369 delete specialData;-
1370 resetFontEngineCache();-
1371}-
1372-
1373const QCharAttributes *QTextEngine::attributes() const-
1374{-
1375 if (layoutData && layoutData->haveCharAttributes)-
1376 return (QCharAttributes *) layoutData->memory;-
1377-
1378 itemize();-
1379 if (! ensureSpace(layoutData->string.length()))-
1380 return __null;-
1381-
1382 QVarLengthArray<QUnicodeTools::ScriptItem> scriptItems(layoutData->items.size());-
1383 for (int i = 0; i < layoutData->items.size(); ++i) {-
1384 const QScriptItem &si = layoutData->items[i];-
1385 scriptItems[i].position = si.position;-
1386 scriptItems[i].script = si.analysis.script;-
1387 }-
1388-
1389 QUnicodeTools::initCharAttributes(reinterpret_cast<const ushort *>(layoutData->string.constData()),-
1390 layoutData->string.length(),-
1391 scriptItems.data(), scriptItems.size(),-
1392 (QCharAttributes *)layoutData->memory);-
1393-
1394-
1395 layoutData->haveCharAttributes = true;-
1396 return (QCharAttributes *) layoutData->memory;-
1397}-
1398-
1399void QTextEngine::shape(int item) const-
1400{-
1401 if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) {-
1402 ensureSpace(1);-
1403 if (block.docHandle()) {-
1404 docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)),-
1405 layoutData->items[item].position + block.position(),-
1406 format(&layoutData->items[item]));-
1407 }-
1408 } else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) {-
1409-
1410 fontEngine(layoutData->items[item],-
1411 &layoutData->items[item].ascent,-
1412 &layoutData->items[item].descent,-
1413 &layoutData->items[item].leading);-
1414 } else {-
1415 shapeText(item);-
1416 }-
1417}-
1418-
1419static inline void releaseCachedFontEngine(QFontEngine *fontEngine)-
1420{-
1421 if (fontEngine && !fontEngine->ref.deref())-
1422 delete fontEngine;-
1423}-
1424-
1425void QTextEngine::resetFontEngineCache()-
1426{-
1427 releaseCachedFontEngine(feCache.prevFontEngine);-
1428 releaseCachedFontEngine(feCache.prevScaledFontEngine);-
1429 feCache.reset();-
1430}-
1431-
1432void QTextEngine::invalidate()-
1433{-
1434 freeMemory();-
1435 minWidth = 0;-
1436 maxWidth = 0;-
1437-
1438 resetFontEngineCache();-
1439}-
1440-
1441void QTextEngine::clearLineData()-
1442{-
1443 lines.clear();-
1444}-
1445-
1446void QTextEngine::validate() const-
1447{-
1448 if (layoutData
layoutDataDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
1449 return;
never executed: return;
0
1450 layoutData = new LayoutData();-
1451 if (block.docHandle()
block.docHandle()Description
TRUEnever evaluated
FALSEnever evaluated
) {
0
1452 layoutData->string = block.text();-
1453 const bool nextBlockValid = block.next().isValid();-
1454 if (!nextBlockValid
!nextBlockValidDescription
TRUEnever evaluated
FALSEnever evaluated
&& option.flags() & QTextOption::ShowDocumentTerminator
option.flags()...mentTerminatorDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
1455 layoutData->string += QChar(0xA7);-
1456 }
never executed: end of block
else
if (option.flags() & QTextOption::ShowLineAndParagraphSeparators
option.flags()...raphSeparatorsDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
1457 layoutData->string += QLatin1Char(block.next().isValid()nextBlockValid ? 0xb6 : 0x20);-
1458 }
never executed: end of block
0
1459-
1460 }
never executed: end of block
else {
0
1461 layoutData->string = text;-
1462 }
never executed: end of block
0
1463 if (specialData
specialDataDescription
TRUEnever evaluated
FALSEnever evaluated
&& specialData->preeditPosition != -1
specialData->p...Position != -1Description
TRUEnever evaluated
FALSEnever evaluated
)
0
1464 layoutData->string.insert(specialData->preeditPosition, specialData->preeditText);
never executed: layoutData->string.insert(specialData->preeditPosition, specialData->preeditText);
0
1465}
never executed: end of block
0
1466-
1467void QTextEngine::itemize() const-
1468{-
1469 validate();-
1470 if (layoutData->items.size())-
1471 return;-
1472-
1473 int length = layoutData->string.length();-
1474 if (!length)-
1475 return;-
1476-
1477 const ushort *string = reinterpret_cast<const ushort *>(layoutData->string.unicode());-
1478-
1479 bool ignore = ignoreBidi;-
1480-
1481 bool rtl = isRightToLeft();-
1482-
1483 if (!ignore && !rtl) {-
1484 ignore = true;-
1485 const QChar *start = layoutData->string.unicode();-
1486 const QChar * const end = start + length;-
1487 while (start < end) {-
1488 if (start->unicode() >= 0x590) {-
1489 ignore = false;-
1490 break;-
1491 }-
1492 ++start;-
1493 }-
1494 }-
1495-
1496 QVarLengthArray<QScriptAnalysis, 4096> scriptAnalysis(length);-
1497 QScriptAnalysis *analysis = scriptAnalysis.data();-
1498-
1499 QBidiControl control(rtl);-
1500-
1501 if (ignore) {-
1502 memset(analysis, 0, length*sizeof(QScriptAnalysis));-
1503 if (option.textDirection() == Qt::RightToLeft) {-
1504 for (int i = 0; i < length; ++i)-
1505 analysis[i].bidiLevel = 1;-
1506 layoutData->hasBidi = true;-
1507 }-
1508 } else {-
1509 layoutData->hasBidi = bidiItemize(const_cast<QTextEngine *>(this), analysis, control);-
1510 }-
1511-
1512 {-
1513 QVarLengthArray<uchar> scripts(length);-
1514 QUnicodeTools::initScripts(string, length, scripts.data());-
1515 for (int i = 0; i < length; ++i)-
1516 analysis[i].script = scripts.at(i);-
1517 }-
1518-
1519 const ushort *uc = string;-
1520 const ushort *e = uc + length;-
1521 while (uc < e) {-
1522 switch (*uc) {-
1523 case QChar::ObjectReplacementCharacter:-
1524 analysis->flags = QScriptAnalysis::Object;-
1525 break;-
1526 case QChar::LineSeparator:-
1527 if (analysis->bidiLevel % 2)-
1528 --analysis->bidiLevel;-
1529 analysis->flags = QScriptAnalysis::LineOrParagraphSeparator;-
1530 if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {-
1531 const int offset = uc - string;-
1532 layoutData->string.detach();-
1533 string = reinterpret_cast<const ushort *>(layoutData->string.unicode());-
1534 uc = string + offset;-
1535 e = uc + length;-
1536 *const_cast<ushort*>(uc) = 0x21B5;-
1537 }-
1538 break;-
1539 case QChar::Tabulation:-
1540 analysis->flags = QScriptAnalysis::Tab;-
1541 analysis->bidiLevel = control.baseLevel();-
1542 break;-
1543 case QChar::Space:-
1544 case QChar::Nbsp:-
1545 if (option.flags() & QTextOption::ShowTabsAndSpaces) {-
1546 analysis->flags = QScriptAnalysis::Space;-
1547 analysis->bidiLevel = control.baseLevel();-
1548 break;-
1549 }-
1550-
1551 default:-
1552 analysis->flags = QScriptAnalysis::None;-
1553 break;-
1554 }-
1555-
1556-
1557-
1558 ++uc;-
1559 ++analysis;-
1560 }-
1561 if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) {-
1562 (analysis-1)->flags = QScriptAnalysis::LineOrParagraphSeparator;-
1563 }-
1564-
1565 analysis = scriptAnalysis.data();-
1566 if (qt_useHarfbuzzNG()) {-
1567-
1568 for (int i = 0; i < length; ++i) {-
1569 switch (analysis[i].script) {-
1570 case QChar::Script_Latin:-
1571 case QChar::Script_Hiragana:-
1572 case QChar::Script_Katakana:-
1573 case QChar::Script_Bopomofo:-
1574 case QChar::Script_Han:-
1575 analysis[i].script = QChar::Script_Common;-
1576 break;-
1577 default:-
1578 break;-
1579 }-
1580 }-
1581 } else {-
1582 for (int i = 0; i < length; ++i)-
1583 analysis[i].script = hbscript_to_script(script_to_hbscript(analysis[i].script));-
1584 }-
1585-
1586-
1587 Itemizer itemizer(layoutData->string, scriptAnalysis.data(), layoutData->items);-
1588-
1589 const QTextDocumentPrivate *p = block.docHandle();-
1590 if (p) {-
1591 SpecialData *s = specialData;-
1592-
1593 QTextDocumentPrivate::FragmentIterator it = p->find(block.position());-
1594 QTextDocumentPrivate::FragmentIterator end = p->find(block.position() + block.length() - 1);-
1595 int format = it.value()->format;-
1596-
1597 int prevPosition = 0;-
1598 int position = prevPosition;-
1599 while (1) {-
1600 const QTextFragmentData * const frag = it.value();-
1601 if (it == end || format != frag->format) {-
1602 if (s && position >= s->preeditPosition) {-
1603 position += s->preeditText.length();-
1604 s = 0;-
1605 }-
1606 ((!(position <= length)) ? qt_assert("position <= length",__FILE__,17141725) : qt_noop());-
1607 QFont::Capitalization capitalization =-
1608 formatCollection()->charFormat(format).hasProperty(QTextFormat::FontCapitalization)-
1609 ? formatCollection()->charFormat(format).fontCapitalization()-
1610 : formatCollection()->defaultFont().capitalization();-
1611 itemizer.generate(prevPosition, position - prevPosition, capitalization);-
1612 if (it == end) {-
1613 if (position < length)-
1614 itemizer.generate(position, length - position, capitalization);-
1615 break;-
1616 }-
1617 format = frag->format;-
1618 prevPosition = position;-
1619 }-
1620 position += frag->size_array[0];-
1621 ++it;-
1622 }-
1623 } else {-
1624-
1625 if (useRawFont && specialData) {-
1626 int lastIndex = 0;-
1627 for (int i = 0; i < specialData->formats.size(); ++i) {-
1628 const QTextLayout::FormatRange &range = specialData->formats.at(i);-
1629 const QTextCharFormat &format = range.format;-
1630 if (format.hasProperty(QTextFormat::FontCapitalization)) {-
1631 itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);-
1632 itemizer.generate(range.start, range.length, format.fontCapitalization());-
1633 lastIndex = range.start + range.length;-
1634 }-
1635 }-
1636 itemizer.generate(lastIndex, length - lastIndex, QFont::MixedCase);-
1637 } else-
1638-
1639 itemizer.generate(0, length, static_cast<QFont::Capitalization> (fnt.d->capital));-
1640 }-
1641-
1642 addRequiredBoundaries();-
1643 resolveFormats();-
1644}-
1645-
1646bool QTextEngine::isRightToLeft() const-
1647{-
1648 switch (option.textDirection()) {-
1649 case Qt::LeftToRight:-
1650 return false;-
1651 case Qt::RightToLeft:-
1652 return true;-
1653 default:-
1654 break;-
1655 }-
1656 if (!layoutData)-
1657 itemize();-
1658-
1659 if (layoutData->string.isEmpty())-
1660 return QGuiApplication::inputMethod()->inputDirection() == Qt::RightToLeft;-
1661 return layoutData->string.isRightToLeft();-
1662}-
1663-
1664-
1665int QTextEngine::findItem(int strPos, int firstItem) const-
1666{-
1667 itemize();-
1668 if (strPos < 0 || strPos >= layoutData->string.size() || firstItem < 0)-
1669 return -1;-
1670-
1671 int left = firstItem + 1;-
1672 int right = layoutData->items.size()-1;-
1673 while(left <= right) {-
1674 int middle = ((right-left)/2)+left;-
1675 if (strPos > layoutData->items[middle].position)-
1676 left = middle+1;-
1677 else if(strPos < layoutData->items[middle].position)-
1678 right = middle-1;-
1679 else {-
1680 return middle;-
1681 }-
1682 }-
1683 return right;-
1684}-
1685-
1686QFixed QTextEngine::width(int from, int len) const-
1687{-
1688 itemize();-
1689-
1690 QFixed w = 0;-
1691-
1692-
1693 for (int i = 0; i < layoutData->items.size(); i++) {-
1694 const QScriptItem *si = layoutData->items.constData() + i;-
1695 int pos = si->position;-
1696 int ilen = length(i);-
1697-
1698 if (pos >= from + len)-
1699 break;-
1700 if (pos + ilen > from) {-
1701 if (!si->num_glyphs)-
1702 shape(i);-
1703-
1704 if (si->analysis.flags == QScriptAnalysis::Object) {-
1705 w += si->width;-
1706 continue;-
1707 } else if (si->analysis.flags == QScriptAnalysis::Tab) {-
1708 w += calculateTabWidth(i, w);-
1709 continue;-
1710 }-
1711-
1712-
1713 QGlyphLayout glyphs = shapedGlyphs(si);-
1714 unsigned short *logClusters = this->logClusters(si);-
1715-
1716-
1717-
1718-
1719-
1720-
1721 int charFrom = from - pos;-
1722 if (charFrom < 0)-
1723 charFrom = 0;-
1724 int glyphStart = logClusters[charFrom];-
1725 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)-
1726 while (charFrom < ilen && logClusters[charFrom] == glyphStart)-
1727 charFrom++;-
1728 if (charFrom < ilen) {-
1729 glyphStart = logClusters[charFrom];-
1730 int charEnd = from + len - 1 - pos;-
1731 if (charEnd >= ilen)-
1732 charEnd = ilen-1;-
1733 int glyphEnd = logClusters[charEnd];-
1734 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)-
1735 charEnd++;-
1736 glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd];-
1737-
1738-
1739 for (int i = glyphStart; i < glyphEnd; i++)-
1740 w += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;-
1741 }-
1742 }-
1743 }-
1744-
1745 return w;-
1746}-
1747-
1748glyph_metrics_t QTextEngine::boundingBox(int from, int len) const-
1749{-
1750 itemize();-
1751-
1752 glyph_metrics_t gm;-
1753-
1754 for (int i = 0; i < layoutData->items.size(); i++) {-
1755 const QScriptItem *si = layoutData->items.constData() + i;-
1756-
1757 int pos = si->position;-
1758 int ilen = length(i);-
1759 if (pos > from + len)-
1760 break;-
1761 if (pos + ilen > from) {-
1762 if (!si->num_glyphs)-
1763 shape(i);-
1764-
1765 if (si->analysis.flags == QScriptAnalysis::Object) {-
1766 gm.width += si->width;-
1767 continue;-
1768 } else if (si->analysis.flags == QScriptAnalysis::Tab) {-
1769 gm.width += calculateTabWidth(i, gm.width);-
1770 continue;-
1771 }-
1772-
1773 unsigned short *logClusters = this->logClusters(si);-
1774 QGlyphLayout glyphs = shapedGlyphs(si);-
1775-
1776-
1777 int charFrom = from - pos;-
1778 if (charFrom < 0)-
1779 charFrom = 0;-
1780 int glyphStart = logClusters[charFrom];-
1781 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)-
1782 while (charFrom < ilen && logClusters[charFrom] == glyphStart)-
1783 charFrom++;-
1784 if (charFrom < ilen) {-
1785 QFontEngine *fe = fontEngine(*si);-
1786 glyphStart = logClusters[charFrom];-
1787 int charEnd = from + len - 1 - pos;-
1788 if (charEnd >= ilen)-
1789 charEnd = ilen-1;-
1790 int glyphEnd = logClusters[charEnd];-
1791 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)-
1792 charEnd++;-
1793 glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd];-
1794 if (glyphStart <= glyphEnd ) {-
1795 glyph_metrics_t m = fe->boundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));-
1796 gm.x = qMin(gm.x, m.x + gm.xoff);-
1797 gm.y = qMin(gm.y, m.y + gm.yoff);-
1798 gm.width = qMax(gm.width, m.width+gm.xoff);-
1799 gm.height = qMax(gm.height, m.height+gm.yoff);-
1800 gm.xoff += m.xoff;-
1801 gm.yoff += m.yoff;-
1802 }-
1803 }-
1804 }-
1805 }-
1806 return gm;-
1807}-
1808-
1809glyph_metrics_t QTextEngine::tightBoundingBox(int from, int len) const-
1810{-
1811 itemize();-
1812-
1813 glyph_metrics_t gm;-
1814-
1815 for (int i = 0; i < layoutData->items.size(); i++) {-
1816 const QScriptItem *si = layoutData->items.constData() + i;-
1817 int pos = si->position;-
1818 int ilen = length(i);-
1819 if (pos > from + len)-
1820 break;-
1821 if (pos + len > from) {-
1822 if (!si->num_glyphs)-
1823 shape(i);-
1824 unsigned short *logClusters = this->logClusters(si);-
1825 QGlyphLayout glyphs = shapedGlyphs(si);-
1826-
1827-
1828 int charFrom = from - pos;-
1829 if (charFrom < 0)-
1830 charFrom = 0;-
1831 int glyphStart = logClusters[charFrom];-
1832 if (charFrom > 0 && logClusters[charFrom-1] == glyphStart)-
1833 while (charFrom < ilen && logClusters[charFrom] == glyphStart)-
1834 charFrom++;-
1835 if (charFrom < ilen) {-
1836 glyphStart = logClusters[charFrom];-
1837 int charEnd = from + len - 1 - pos;-
1838 if (charEnd >= ilen)-
1839 charEnd = ilen-1;-
1840 int glyphEnd = logClusters[charEnd];-
1841 while (charEnd < ilen && logClusters[charEnd] == glyphEnd)-
1842 charEnd++;-
1843 glyphEnd = (charEnd == ilen) ? si->num_glyphs : logClusters[charEnd];-
1844 if (glyphStart <= glyphEnd ) {-
1845 QFontEngine *fe = fontEngine(*si);-
1846 glyph_metrics_t m = fe->tightBoundingBox(glyphs.mid(glyphStart, glyphEnd - glyphStart));-
1847 gm.x = qMin(gm.x, m.x + gm.xoff);-
1848 gm.y = qMin(gm.y, m.y + gm.yoff);-
1849 gm.width = qMax(gm.width, m.width+gm.xoff);-
1850 gm.height = qMax(gm.height, m.height+gm.yoff);-
1851 gm.xoff += m.xoff;-
1852 gm.yoff += m.yoff;-
1853 }-
1854 }-
1855 }-
1856 }-
1857 return gm;-
1858}-
1859-
1860QFont QTextEngine::font(const QScriptItem &si) const-
1861{-
1862 QFont font = fnt;-
1863 if (hasFormats()) {-
1864 QTextCharFormat f = format(&si);-
1865 font = f.font();-
1866-
1867 if (block.docHandle() && block.docHandle()->layout()) {-
1868-
1869 QPaintDevice *pdev = block.docHandle()->layout()->paintDevice();-
1870 if (pdev)-
1871 font = QFont(font, pdev);-
1872 } else {-
1873 font = font.resolve(fnt);-
1874 }-
1875 QTextCharFormat::VerticalAlignment valign = f.verticalAlignment();-
1876 if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {-
1877 if (font.pointSize() != -1)-
1878 font.setPointSize((font.pointSize() * 2) / 3);-
1879 else-
1880 font.setPixelSize((font.pixelSize() * 2) / 3);-
1881 }-
1882 }-
1883-
1884 if (si.analysis.flags == QScriptAnalysis::SmallCaps)-
1885 font = font.d->smallCapsFont();-
1886-
1887 return font;-
1888}-
1889-
1890QTextEngine::FontEngineCache::FontEngineCache()-
1891{-
1892 reset();-
1893}-
1894-
1895-
1896-
1897QFontEngine *QTextEngine::fontEngine(const QScriptItem &si, QFixed *ascent, QFixed *descent, QFixed *leading) const-
1898{-
1899 QFontEngine *engine = 0;-
1900 QFontEngine *scaledEngine = 0;-
1901 int script = si.analysis.script;-
1902-
1903 QFont font = fnt;-
1904-
1905 if (useRawFont && rawFont.isValid()) {-
1906 if (feCache.prevFontEngine && feCache.prevFontEngine->type() == QFontEngine::Multi && feCache.prevScript == script) {-
1907 engine = feCache.prevFontEngine;-
1908 } else {-
1909 engine = QFontEngineMulti::createMultiFontEngine(rawFont.d->fontEngine, script);-
1910 feCache.prevFontEngine = engine;-
1911 feCache.prevScript = script;-
1912 engine->ref.ref();-
1913 if (feCache.prevScaledFontEngine) {-
1914 releaseCachedFontEngine(feCache.prevScaledFontEngine);-
1915 feCache.prevScaledFontEngine = 0;-
1916 }-
1917 }-
1918 if (si.analysis.flags == QScriptAnalysis::SmallCaps) {-
1919 if (feCache.prevScaledFontEngine) {-
1920 scaledEngine = feCache.prevScaledFontEngine;-
1921 } else {-
1922 QFontEngine *scEngine = rawFont.d->fontEngine->cloneWithSize(smallCapsFraction * rawFont.pixelSize());-
1923 scEngine->ref.ref();-
1924 scaledEngine = QFontEngineMulti::createMultiFontEngine(scEngine, script);-
1925 scaledEngine->ref.ref();-
1926 feCache.prevScaledFontEngine = scaledEngine;-
1927-
1928 if (!scEngine->ref.deref())-
1929 delete scEngine;-
1930-
1931 }-
1932 }-
1933 } else-
1934-
1935 {-
1936 if (hasFormats()) {-
1937 if (feCache.prevFontEngine && feCache.prevPosition == si.position && feCache.prevLength == length(&si) && feCache.prevScript == script) {-
1938 engine = feCache.prevFontEngine;-
1939 scaledEngine = feCache.prevScaledFontEngine;-
1940 } else {-
1941 QTextCharFormat f = format(&si);-
1942 font = f.font();-
1943-
1944 if (block.docHandle() && block.docHandle()->layout()) {-
1945-
1946 QPaintDevice *pdev = block.docHandle()->layout()->paintDevice();-
1947 if (pdev)-
1948 font = QFont(font, pdev);-
1949 } else {-
1950 font = font.resolve(fnt);-
1951 }-
1952 engine = font.d->engineForScript(script);-
1953 if (engine)-
1954 engine->ref.ref();-
1955-
1956 QTextCharFormat::VerticalAlignment valign = f.verticalAlignment();-
1957 if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {-
1958 if (font.pointSize() != -1)-
1959 font.setPointSize((font.pointSize() * 2) / 3);-
1960 else-
1961 font.setPixelSize((font.pixelSize() * 2) / 3);-
1962 scaledEngine = font.d->engineForScript(script);-
1963 if (scaledEngine)-
1964 scaledEngine->ref.ref();-
1965 }-
1966-
1967 if (feCache.prevFontEngine)-
1968 releaseCachedFontEngine(feCache.prevFontEngine);-
1969 feCache.prevFontEngine = engine;-
1970-
1971 if (feCache.prevScaledFontEngine)-
1972 releaseCachedFontEngine(feCache.prevScaledFontEngine);-
1973 feCache.prevScaledFontEngine = scaledEngine;-
1974-
1975 feCache.prevScript = script;-
1976 feCache.prevPosition = si.position;-
1977 feCache.prevLength = length(&si);-
1978 }-
1979 } else {-
1980 if (feCache.prevFontEngine && feCache.prevScript == script && feCache.prevPosition == -1)-
1981 engine = feCache.prevFontEngine;-
1982 else {-
1983 engine = font.d->engineForScript(script);-
1984-
1985 if (engine)-
1986 engine->ref.ref();-
1987 if (feCache.prevFontEngine)-
1988 releaseCachedFontEngine(feCache.prevFontEngine);-
1989 feCache.prevFontEngine = engine;-
1990-
1991 feCache.prevScript = script;-
1992 feCache.prevPosition = -1;-
1993 feCache.prevLength = -1;-
1994 feCache.prevScaledFontEngine = 0;-
1995 }-
1996 }-
1997-
1998 if (si.analysis.flags == QScriptAnalysis::SmallCaps) {-
1999 QFontPrivate *p = font.d->smallCapsFontPrivate();-
2000 scaledEngine = p->engineForScript(script);-
2001 }-
2002 }-
2003-
2004 if (ascent) {-
2005 *ascent = engine->ascent();-
2006 *descent = engine->descent();-
2007 *leading = engine->leading();-
2008 }-
2009-
2010 if (scaledEngine)-
2011 return scaledEngine;-
2012 return engine;-
2013}-
2014-
2015struct QJustificationPoint {-
2016 int type;-
2017 QFixed kashidaWidth;-
2018 QGlyphLayout glyph;-
2019};-
2020-
2021template<> class QTypeInfo<QJustificationPoint > { public: enum { isComplex = (((Q_PRIMITIVE_TYPE) & Q_PRIMITIVE_TYPE) == 0), isStatic = (((Q_PRIMITIVE_TYPE) & (Q_MOVABLE_TYPE | Q_PRIMITIVE_TYPE)) == 0), isRelocatable = !isStatic || ((Q_PRIMITIVE_TYPE) & Q_RELOCATABLE_TYPE), isLarge = (sizeof(QJustificationPoint)>sizeof(void*)), isPointer = false, isIntegral = QtPrivate::is_integral< QJustificationPoint >::value, isDummy = (((Q_PRIMITIVE_TYPE) & Q_DUMMY_TYPE) != 0), sizeOf = sizeof(QJustificationPoint) }; static inline const char *name() { return "QJustificationPoint"; } };-
2022-
2023static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph, QFontEngine *fe)-
2024{-
2025 point->type = type;-
2026 point->glyph = glyph;-
2027-
2028 if (type >= Justification_Arabic_Normal) {-
2029 QChar ch(0x640);-
2030-
2031 glyph_t kashidaGlyph = fe->glyphIndex(ch.unicode());-
2032 if (kashidaGlyph != 0) {-
2033 QGlyphLayout g;-
2034 g.numGlyphs = 1;-
2035 g.glyphs = &kashidaGlyph;-
2036 g.advances = &point->kashidaWidth;-
2037 fe->recalcAdvances(&g, 0);-
2038-
2039 if (point->kashidaWidth == 0)-
2040 point->type = Justification_Prohibited;-
2041 } else {-
2042 point->type = Justification_Prohibited;-
2043 point->kashidaWidth = 0;-
2044 }-
2045 }-
2046}-
2047-
2048-
2049void QTextEngine::justify(const QScriptLine &line)-
2050{-
2051-
2052 if (line.gridfitted && line.justified)-
2053 return;-
2054-
2055 if (!line.gridfitted) {-
2056-
2057 const_cast<QScriptLine &>(line).gridfitted = true;-
2058 }-
2059-
2060 if ((option.alignment() & Qt::AlignHorizontal_Mask) != Qt::AlignJustify)-
2061 return;-
2062-
2063 itemize();-
2064-
2065 if (!forceJustification) {-
2066 int end = line.from + (int)line.length + line.trailingSpaces;-
2067 if (end == layoutData->string.length())-
2068 return;-
2069 if (end && layoutData->items[findItem(end-1)].analysis.flags == QScriptAnalysis::LineOrParagraphSeparator)-
2070 return;-
2071 }-
2072-
2073-
2074 int maxJustify = 0;-
2075-
2076-
2077 int line_length = line.length;-
2078 const QCharAttributes *a = attributes();-
2079 if (! a)-
2080 return;-
2081 a += line.from;-
2082 while (line_length && a[line_length-1].whiteSpace)-
2083 --line_length;-
2084-
2085 --line_length;-
2086-
2087 if (line_length <= 0)-
2088 return;-
2089-
2090 int firstItem = findItem(line.from);-
2091 int lastItem = findItem(line.from + line_length - 1, firstItem);-
2092 int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;-
2093-
2094 QVarLengthArray<QJustificationPoint> justificationPoints;-
2095 int nPoints = 0;-
2096-
2097 QFixed minKashida = 0x100000;-
2098-
2099-
2100-
2101-
2102 for (int i = 0; i < nItems; ++i) {-
2103 QScriptItem &si = layoutData->items[firstItem + i];-
2104 if (!si.num_glyphs)-
2105 shape(firstItem + i);-
2106 }-
2107-
2108 for (int i = 0; i < nItems; ++i) {-
2109 QScriptItem &si = layoutData->items[firstItem + i];-
2110-
2111 int kashida_type = Justification_Arabic_Normal;-
2112 int kashida_pos = -1;-
2113-
2114 int start = qMax(line.from - si.position, 0);-
2115 int end = qMin(line.from + line_length - (int)si.position, length(firstItem+i));-
2116-
2117 unsigned short *log_clusters = logClusters(&si);-
2118-
2119 int gs = log_clusters[start];-
2120 int ge = (end == length(firstItem+i) ? si.num_glyphs : log_clusters[end]);-
2121-
2122 ((!(ge <= si.num_glyphs)) ? qt_assert("ge <= si.num_glyphs",__FILE__,22302241) : qt_noop());-
2123-
2124 const QGlyphLayout g = shapedGlyphs(&si);-
2125-
2126 for (int i = gs; i < ge; ++i) {-
2127 g.justifications[i].type = QGlyphJustification::JustifyNone;-
2128 g.justifications[i].nKashidas = 0;-
2129 g.justifications[i].space_18d6 = 0;-
2130-
2131 justificationPoints.resize(nPoints+3);-
2132 int justification = g.attributes[i].justification;-
2133-
2134 switch(justification) {-
2135 case Justification_Prohibited:-
2136 break;-
2137 case Justification_Space:-
2138-
2139 case Justification_Arabic_Space:-
2140 if (kashida_pos >= 0) {-
2141-
2142 set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si));-
2143 if (justificationPoints[nPoints].kashidaWidth > 0) {-
2144 minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);-
2145 maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);-
2146 ++nPoints;-
2147 }-
2148 }-
2149 kashida_pos = -1;-
2150 kashida_type = Justification_Arabic_Normal;-
2151-
2152 case Justification_Character:-
2153 set(&justificationPoints[nPoints++], justification, g.mid(i), fontEngine(si));-
2154 maxJustify = qMax(maxJustify, justification);-
2155 break;-
2156 case Justification_Arabic_Normal:-
2157 case Justification_Arabic_Waw:-
2158 case Justification_Arabic_BaRa:-
2159 case Justification_Arabic_Alef:-
2160 case Justification_Arabic_HahDal:-
2161 case Justification_Arabic_Seen:-
2162 case Justification_Arabic_Kashida:-
2163 if (justification >= kashida_type) {-
2164 kashida_pos = i;-
2165 kashida_type = justification;-
2166 }-
2167 }-
2168 }-
2169 if (kashida_pos >= 0) {-
2170 set(&justificationPoints[nPoints], kashida_type, g.mid(kashida_pos), fontEngine(si));-
2171 if (justificationPoints[nPoints].kashidaWidth > 0) {-
2172 minKashida = qMin(minKashida, justificationPoints[nPoints].kashidaWidth);-
2173 maxJustify = qMax(maxJustify, justificationPoints[nPoints].type);-
2174 ++nPoints;-
2175 }-
2176 }-
2177 }-
2178-
2179 QFixed leading = leadingSpaceWidth(line);-
2180 QFixed need = line.width - line.textWidth - leading;-
2181 if (need < 0) {-
2182-
2183 const_cast<QScriptLine &>(line).justified = true;-
2184 return;-
2185 }-
2186-
2187-
2188-
2189-
2190-
2191 if (maxJustify >= Justification_Arabic_Normal) {-
2192 while (need >= minKashida) {-
2193 for (int type = maxJustify; need >= minKashida && type >= Justification_Arabic_Normal; --type) {-
2194 for (int i = 0; need >= minKashida && i < nPoints; ++i) {-
2195 if (justificationPoints[i].type == type && justificationPoints[i].kashidaWidth <= need) {-
2196 justificationPoints[i].glyph.justifications->nKashidas++;-
2197-
2198 justificationPoints[i].glyph.justifications->space_18d6 += justificationPoints[i].kashidaWidth.value();-
2199 need -= justificationPoints[i].kashidaWidth;-
2200-
2201 }-
2202 }-
2203 }-
2204 }-
2205 }-
2206 ((!(need >= 0)) ? qt_assert("need >= 0",__FILE__,23142325) : qt_noop());-
2207 if (!need)-
2208 goto end;-
2209-
2210 maxJustify = qMin(maxJustify, int(Justification_Space));-
2211 for (int type = maxJustify; need != 0 && type > 0; --type) {-
2212 int n = 0;-
2213 for (int i = 0; i < nPoints; ++i) {-
2214 if (justificationPoints[i].type == type)-
2215 ++n;-
2216 }-
2217-
2218-
2219-
2220 if (!n)-
2221 continue;-
2222-
2223 for (int i = 0; i < nPoints; ++i) {-
2224 if (justificationPoints[i].type == type) {-
2225 QFixed add = need/n;-
2226-
2227 justificationPoints[i].glyph.justifications[0].space_18d6 = add.value();-
2228 need -= add;-
2229 --n;-
2230 }-
2231 }-
2232-
2233 ((!(!need)) ? qt_assert("!need",__FILE__,23412352) : qt_noop());-
2234 }-
2235 end:-
2236 const_cast<QScriptLine &>(line).justified = true;-
2237}-
2238-
2239void QScriptLine::setDefaultHeight(QTextEngine *eng)-
2240{-
2241 QFont f;-
2242 QFontEngine *e;-
2243-
2244 if (eng->block.docHandle() && eng->block.docHandle()->layout()) {-
2245 f = eng->block.charFormat().font();-
2246-
2247 QPaintDevice *pdev = eng->block.docHandle()->layout()->paintDevice();-
2248 if (pdev)-
2249 f = QFont(f, pdev);-
2250 e = f.d->engineForScript(QChar::Script_Common);-
2251 } else {-
2252 e = eng->fnt.d->engineForScript(QChar::Script_Common);-
2253 }-
2254-
2255 QFixed other_ascent = e->ascent();-
2256 QFixed other_descent = e->descent();-
2257 QFixed other_leading = e->leading();-
2258 leading = qMax(leading + ascent, other_leading + other_ascent) - qMax(ascent, other_ascent);-
2259 ascent = qMax(ascent, other_ascent);-
2260 descent = qMax(descent, other_descent);-
2261}-
2262-
2263QTextEngine::LayoutData::LayoutData()-
2264{-
2265 memory = 0;-
2266 allocated = 0;-
2267 memory_on_stack = false;-
2268 used = 0;-
2269 hasBidi = false;-
2270 layoutState = LayoutEmpty;-
2271 haveCharAttributes = false;-
2272 logClustersPtr = 0;-
2273 available_glyphs = 0;-
2274}-
2275-
2276QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int _allocated)-
2277 : string(str)-
2278{-
2279 allocated = _allocated;-
2280-
2281 int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;-
2282 int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;-
2283 available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::SpaceNeeded;-
2284-
2285 if (available_glyphs < str.length()) {-
2286-
2287 allocated = 0;-
2288-
2289 memory_on_stack = false;-
2290 memory = 0;-
2291 logClustersPtr = 0;-
2292 } else {-
2293 memory_on_stack = true;-
2294 memory = stack_memory;-
2295 logClustersPtr = (unsigned short *)(memory + space_charAttributes);-
2296-
2297 void *m = memory + space_charAttributes + space_logClusters;-
2298 glyphLayout = QGlyphLayout(reinterpret_cast<char *>(m), str.length());-
2299 glyphLayout.clear();-
2300 memset(memory, 0, space_charAttributes*sizeof(void *));-
2301 }-
2302 used = 0;-
2303 hasBidi = false;-
2304 layoutState = LayoutEmpty;-
2305 haveCharAttributes = false;-
2306}-
2307-
2308QTextEngine::LayoutData::~LayoutData()-
2309{-
2310 if (!memory_on_stack)-
2311 free(memory);-
2312 memory = 0;-
2313}-
2314-
2315bool QTextEngine::LayoutData::reallocate(int totalGlyphs)-
2316{-
2317 ((!(totalGlyphs >= glyphLayout.numGlyphs)) ? qt_assert("totalGlyphs >= glyphLayout.numGlyphs",__FILE__,24252436) : qt_noop());-
2318 if (memory_on_stack && available_glyphs >= totalGlyphs) {-
2319 glyphLayout.grow(glyphLayout.data(), totalGlyphs);-
2320 return true;-
2321 }-
2322-
2323 int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;-
2324 int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;-
2325 int space_glyphs = (totalGlyphs * QGlyphLayout::SpaceNeeded) / sizeof(void *) + 2;-
2326-
2327 int newAllocated = space_charAttributes + space_glyphs + space_logClusters;-
2328-
2329-
2330-
2331 if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {-
2332 layoutState = LayoutFailed;-
2333 return false;-
2334 }-
2335-
2336 void **newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *));-
2337 if (!newMem) {-
2338 layoutState = LayoutFailed;-
2339 return false;-
2340 }-
2341 if (memory_on_stack)-
2342 memcpy(newMem, memory, allocated*sizeof(void *));-
2343 memory = newMem;-
2344 memory_on_stack = false;-
2345-
2346 void **m = memory;-
2347 m += space_charAttributes;-
2348 logClustersPtr = (unsigned short *) m;-
2349 m += space_logClusters;-
2350-
2351 const int space_preGlyphLayout = space_charAttributes + space_logClusters;-
2352 if (allocated < space_preGlyphLayout)-
2353 memset(memory + allocated, 0, (space_preGlyphLayout - allocated)*sizeof(void *));-
2354-
2355 glyphLayout.grow(reinterpret_cast<char *>(m), totalGlyphs);-
2356-
2357 allocated = newAllocated;-
2358 return true;-
2359}-
2360-
2361-
2362void QGlyphLayout::grow(char *address, int totalGlyphs)-
2363{-
2364 QGlyphLayout oldLayout(address, numGlyphs);-
2365 QGlyphLayout newLayout(address, totalGlyphs);-
2366-
2367 if (numGlyphs) {-
2368-
2369 memmove(newLayout.attributes, oldLayout.attributes, numGlyphs * sizeof(QGlyphAttributes));-
2370 memmove(newLayout.justifications, oldLayout.justifications, numGlyphs * sizeof(QGlyphJustification));-
2371 memmove(newLayout.advances, oldLayout.advances, numGlyphs * sizeof(QFixed));-
2372 memmove(newLayout.glyphs, oldLayout.glyphs, numGlyphs * sizeof(glyph_t));-
2373 }-
2374-
2375-
2376 newLayout.clear(numGlyphs);-
2377-
2378 *this = newLayout;-
2379}-
2380-
2381void QTextEngine::freeMemory()-
2382{-
2383 if (!stackEngine) {-
2384 delete layoutData;-
2385 layoutData = 0;-
2386 } else {-
2387 layoutData->used = 0;-
2388 layoutData->hasBidi = false;-
2389 layoutData->layoutState = LayoutEmpty;-
2390 layoutData->haveCharAttributes = false;-
2391 layoutData->items.clear();-
2392 }-
2393 if (specialData)-
2394 specialData->resolvedFormats.clear();-
2395 for (int i = 0; i < lines.size(); ++i) {-
2396 lines[i].justified = 0;-
2397 lines[i].gridfitted = 0;-
2398 }-
2399}-
2400-
2401int QTextEngine::formatIndex(const QScriptItem *si) const-
2402{-
2403 if (specialData && !specialData->resolvedFormats.isEmpty()) {-
2404 QTextFormatCollection *collection = formatCollection();-
2405 ((!(collection)) ? qt_assert("collection",__FILE__,25132524) : qt_noop());-
2406 return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0]));-
2407 }-
2408-
2409 QTextDocumentPrivate *p = block.docHandle();-
2410 if (!p)-
2411 return -1;-
2412 int pos = si->position;-
2413 if (specialData && si->position >= specialData->preeditPosition) {-
2414 if (si->position < specialData->preeditPosition + specialData->preeditText.length())-
2415 pos = qMax(qMin(block.length(), specialData->preeditPosition) - 1, 0);-
2416 else-
2417 pos -= specialData->preeditText.length();-
2418 }-
2419 QTextDocumentPrivate::FragmentIterator it = p->find(block.position() + pos);-
2420 return it.value()->format;-
2421}-
2422-
2423-
2424QTextCharFormat QTextEngine::format(const QScriptItem *si) const-
2425{-
2426 if (const QTextFormatCollection *collection = formatCollection())-
2427 return collection->charFormat(formatIndex(si));-
2428 return QTextCharFormat();-
2429}-
2430-
2431void QTextEngine::addRequiredBoundaries() const-
2432{-
2433 if (specialData) {-
2434 for (int i = 0; i < specialData->formats.size(); ++i) {-
2435 const QTextLayout::FormatRange &r = specialData->formats.at(i);-
2436 setBoundary(r.start);-
2437 setBoundary(r.start + r.length);-
2438-
2439 }-
2440 }-
2441}-
2442-
2443bool QTextEngine::atWordSeparator(int position) const-
2444{-
2445 const QChar c = layoutData->string.at(position);-
2446 switch (c.unicode()) {-
2447 case '.':-
2448 case ',':-
2449 case '?':-
2450 case '!':-
2451 case '@':-
2452 case '#':-
2453 case '$':-
2454 case ':':-
2455 case ';':-
2456 case '-':-
2457 case '<':-
2458 case '>':-
2459 case '[':-
2460 case ']':-
2461 case '(':-
2462 case ')':-
2463 case '{':-
2464 case '}':-
2465 case '=':-
2466 case '/':-
2467 case '+':-
2468 case '%':-
2469 case '&':-
2470 case '^':-
2471 case '*':-
2472 case '\'':-
2473 case '"':-
2474 case '`':-
2475 case '~':-
2476 case '|':-
2477 case '\\':-
2478 return true;-
2479 default:-
2480 break;-
2481 }-
2482 return false;-
2483}-
2484-
2485void QTextEngine::setPreeditArea(int position, const QString &preeditText)-
2486{-
2487 if (preeditText.isEmpty()) {-
2488 if (!specialData)-
2489 return;-
2490 if (specialData->formats.isEmpty()) {-
2491 delete specialData;-
2492 specialData = 0;-
2493 } else {-
2494 specialData->preeditText = QString();-
2495 specialData->preeditPosition = -1;-
2496 }-
2497 } else {-
2498 if (!specialData)-
2499 specialData = new SpecialData;-
2500 specialData->preeditPosition = position;-
2501 specialData->preeditText = preeditText;-
2502 }-
2503 invalidate();-
2504 clearLineData();-
2505}-
2506-
2507void QTextEngine::setFormats(const QVector<QTextLayout::FormatRange> &formats)-
2508{-
2509 if (formats.isEmpty()) {-
2510 if (!specialData)-
2511 return;-
2512 if (specialData->preeditText.isEmpty()) {-
2513 delete specialData;-
2514 specialData = 0;-
2515 } else {-
2516 specialData->formats.clear();-
2517 }-
2518 } else {-
2519 if (!specialData) {-
2520 specialData = new SpecialData;-
2521 specialData->preeditPosition = -1;-
2522 }-
2523 specialData->formats = formats;-
2524 indexFormats();-
2525 }-
2526 invalidate();-
2527 clearLineData();-
2528}-
2529-
2530void QTextEngine::indexFormats()-
2531{-
2532 QTextFormatCollection *collection = formatCollection();-
2533 if (!collection) {-
2534 ((!(!block.docHandle())) ? qt_assert("!block.docHandle()",__FILE__,26422653) : qt_noop());-
2535 specialData->formatCollection.reset(new QTextFormatCollection);-
2536 collection = specialData->formatCollection.data();-
2537 }-
2538-
2539-
2540 for (int i = 0; i < specialData->formats.size(); ++i) {-
2541 QTextCharFormat &format = specialData->formats[i].format;-
2542 format = collection->charFormat(collection->indexForFormat(format));-
2543 }-
2544}-
2545-
2546-
2547-
2548-
2549-
2550static inline bool nextCharJoins(const QString &string, int pos)-
2551{-
2552 while (pos < string.length() && string.at(pos).category() == QChar::Mark_NonSpacing)-
2553 ++pos;-
2554 if (pos == string.length())-
2555 return false;-
2556 QChar::JoiningType joining = string.at(pos).joiningType();-
2557 return joining != QChar::Joining_None && joining != QChar::Joining_Transparent;-
2558}-
2559-
2560static inline bool prevCharJoins(const QString &string, int pos)-
2561{-
2562 while (pos > 0 && string.at(pos - 1).category() == QChar::Mark_NonSpacing)-
2563 --pos;-
2564 if (pos == 0)-
2565 return false;-
2566 QChar::JoiningType joining = string.at(pos - 1).joiningType();-
2567 return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing;-
2568}-
2569-
2570static inline bool isRetainableControlCode(QChar c)-
2571{-
2572 return (c.unicode() >= 0x202a && c.unicode() <= 0x202e)-
2573 || (c.unicode() >= 0x200e && c.unicode() <= 0x200f)-
2574 || (c.unicode() >= 0x2066 && c.unicode() <= 0x2069);-
2575}-
2576-
2577static QString stringMidRetainingBidiCC(const QString &string,-
2578 const QString &ellidePrefix,-
2579 const QString &ellideSuffix,-
2580 int subStringFrom,-
2581 int subStringTo,-
2582 int midStart,-
2583 int midLength)-
2584{-
2585 QString prefix;-
2586 for (int i=subStringFrom; i<midStart; ++i) {-
2587 QChar c = string.at(i);-
2588 if (isRetainableControlCode(c))-
2589 prefix += c;-
2590 }-
2591-
2592 QString suffix;-
2593 for (int i=midStart + midLength; i<subStringTo; ++i) {-
2594 QChar c = string.at(i);-
2595 if (isRetainableControlCode(c))-
2596 suffix += c;-
2597 }-
2598-
2599 return prefix + ellidePrefix + string.mid(midStart, midLength) + ellideSuffix + suffix;-
2600}-
2601-
2602QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int flags, int from, int count) const-
2603{-
2604-
2605-
2606 if (flags & Qt::TextShowMnemonic) {-
2607 itemize();-
2608 QCharAttributes *attributes = const_cast<QCharAttributes *>(this->attributes());-
2609 if (!attributes)-
2610 return QString();-
2611 for (int i = 0; i < layoutData->items.size(); ++i) {-
2612 QScriptItem &si = layoutData->items[i];-
2613 if (!si.num_glyphs)-
2614 shape(i);-
2615-
2616 unsigned short *logClusters = this->logClusters(&si);-
2617 QGlyphLayout glyphs = shapedGlyphs(&si);-
2618-
2619 const int end = si.position + length(&si);-
2620 for (int i = si.position; i < end - 1; ++i) {-
2621 if (layoutData->string.at(i) == QLatin1Char('&')-
2622 && !attributes[i + 1].whiteSpace && attributes[i + 1].graphemeBoundary) {-
2623 const int gp = logClusters[i - si.position];-
2624 glyphs.attributes[gp].dontPrint = true;-
2625-
2626 attributes[i] = attributes[i + 1];-
2627 memset(attributes + i + 1, 0, sizeof(QCharAttributes));-
2628 if (layoutData->string.at(i + 1) == QLatin1Char('&'))-
2629 ++i;-
2630 }-
2631 }-
2632 }-
2633 }-
2634-
2635 validate();-
2636-
2637 const int to = count >= 0 && count <= layoutData->string.length() - from-
2638 ? from + count-
2639 : layoutData->string.length();-
2640-
2641 if (mode == Qt::ElideNone-
2642 || this->width(from, layoutData->string.length()) <= width-
2643 || to - from <= 1)-
2644 return layoutData->string.mid(from, from - to);-
2645-
2646 QFixed ellipsisWidth;-
2647 QString ellipsisText;-
2648 {-
2649 QFontEngine *engine = fnt.d->engineForScript(QChar::Script_Common);-
2650-
2651 QChar ellipsisChar(0x2026);-
2652-
2653 glyph_t glyph = engine->glyphIndex(ellipsisChar.unicode());-
2654-
2655 QGlyphLayout glyphs;-
2656 glyphs.numGlyphs = 1;-
2657 glyphs.glyphs = &glyph;-
2658 glyphs.advances = &ellipsisWidth;-
2659-
2660 if (glyph != 0) {-
2661 engine->recalcAdvances(&glyphs, 0);-
2662-
2663 ellipsisText = ellipsisChar;-
2664 } else {-
2665 glyph = engine->glyphIndex('.');-
2666 if (glyph != 0) {-
2667 engine->recalcAdvances(&glyphs, 0);-
2668-
2669 ellipsisWidth *= 3;-
2670 ellipsisText = ([]() -> QString { enum { Size = sizeof(u"" "...")/2 - 1 }; static const QStaticStringData<Size> qstring_literal = { { { { -1 } }, Size, 0, 0, sizeof(QStringData) }, u"" "..." }; QStringDataPtr holder = { qstring_literal.data_ptr() }; const QString qstring_literal_temp(holder); return qstring_literal_temp; }());-
2671 }-
2672 }-
2673 }-
2674-
2675 const QFixed availableWidth = width - ellipsisWidth;-
2676 if (availableWidth < 0)-
2677 return QString();-
2678-
2679 const QCharAttributes *attributes = this->attributes();-
2680 if (!attributes)-
2681 return QString();-
2682-
2683 if (mode == Qt::ElideRight) {-
2684 QFixed currentWidth;-
2685 int pos;-
2686 int nextBreak = from;-
2687-
2688 do {-
2689 pos = nextBreak;-
2690-
2691 ++nextBreak;-
2692 while (nextBreak < layoutData->string.length() && !attributes[nextBreak].graphemeBoundary)-
2693 ++nextBreak;-
2694-
2695 currentWidth += this->width(pos, nextBreak - pos);-
2696 } while (nextBreak < to-
2697 && currentWidth < availableWidth);-
2698-
2699 if (nextCharJoins(layoutData->string, pos))-
2700 ellipsisText.prepend(QChar(0x200d) );-
2701-
2702 return stringMidRetainingBidiCC(layoutData->string,-
2703 QString(), ellipsisText,-
2704 from, to,-
2705 from, pos - from);-
2706 } else if (mode == Qt::ElideLeft) {-
2707 QFixed currentWidth;-
2708 int pos;-
2709 int nextBreak = to;-
2710-
2711 do {-
2712 pos = nextBreak;-
2713-
2714 --nextBreak;-
2715 while (nextBreak > 0 && !attributes[nextBreak].graphemeBoundary)-
2716 --nextBreak;-
2717-
2718 currentWidth += this->width(nextBreak, pos - nextBreak);-
2719 } while (nextBreak > from-
2720 && currentWidth < availableWidth);-
2721-
2722 if (prevCharJoins(layoutData->string, pos))-
2723 ellipsisText.append(QChar(0x200d) );-
2724-
2725 return stringMidRetainingBidiCC(layoutData->string,-
2726 ellipsisText, QString(),-
2727 from, to,-
2728 pos, to - pos);-
2729 } else if (mode == Qt::ElideMiddle) {-
2730 QFixed leftWidth;-
2731 QFixed rightWidth;-
2732-
2733 int leftPos = from;-
2734 int nextLeftBreak = from;-
2735-
2736 int rightPos = to;-
2737 int nextRightBreak = to;-
2738-
2739 do {-
2740 leftPos = nextLeftBreak;-
2741 rightPos = nextRightBreak;-
2742-
2743 ++nextLeftBreak;-
2744 while (nextLeftBreak < layoutData->string.length() && !attributes[nextLeftBreak].graphemeBoundary)-
2745 ++nextLeftBreak;-
2746-
2747 --nextRightBreak;-
2748 while (nextRightBreak > from && !attributes[nextRightBreak].graphemeBoundary)-
2749 --nextRightBreak;-
2750-
2751 leftWidth += this->width(leftPos, nextLeftBreak - leftPos);-
2752 rightWidth += this->width(nextRightBreak, rightPos - nextRightBreak);-
2753 } while (nextLeftBreak < to-
2754 && nextRightBreak > from-
2755 && leftWidth + rightWidth < availableWidth);-
2756-
2757 if (nextCharJoins(layoutData->string, leftPos))-
2758 ellipsisText.prepend(QChar(0x200d) );-
2759 if (prevCharJoins(layoutData->string, rightPos))-
2760 ellipsisText.append(QChar(0x200d) );-
2761-
2762 return layoutData->string.mid(from, leftPos - from) + ellipsisText + layoutData->string.mid(rightPos, to - rightPos);-
2763 }-
2764-
2765 return layoutData->string.mid(from, to - from);-
2766}-
2767-
2768void QTextEngine::setBoundary(int strPos) const-
2769{-
2770 const int item = findItem(strPos);-
2771 if (item < 0)-
2772 return;-
2773-
2774 QScriptItem newItem = layoutData->items.at(item);-
2775 if (newItem.position != strPos) {-
2776 newItem.position = strPos;-
2777 layoutData->items.insert(item + 1, newItem);-
2778 }-
2779}-
2780-
2781QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const-
2782{-
2783 const QScriptItem &si = layoutData->items[item];-
2784-
2785 QFixed dpiScale = 1;-
2786 if (block.docHandle() && block.docHandle()->layout()) {-
2787 QPaintDevice *pdev = block.docHandle()->layout()->paintDevice();-
2788 if (pdev)-
2789 dpiScale = QFixed::fromReal(pdev->logicalDpiY() / qreal(qt_defaultDpiY()));-
2790 } else {-
2791 dpiScale = QFixed::fromReal(fnt.d->dpi / qreal(qt_defaultDpiY()));-
2792 }-
2793-
2794 QList<QTextOption::Tab> tabArray = option.tabs();-
2795 if (!tabArray.isEmpty()) {-
2796 if (isRightToLeft()) {-
2797 QList<QTextOption::Tab> newTabs;-
2798 newTabs.reserve(tabArray.count());-
2799 QList<QTextOption::Tab>::Iterator iter = tabArray.begin();-
2800 while(iter != tabArray.end()) {-
2801 QTextOption::Tab tab = *iter;-
2802 if (tab.type == QTextOption::LeftTab)-
2803 tab.type = QTextOption::RightTab;-
2804 else if (tab.type == QTextOption::RightTab)-
2805 tab.type = QTextOption::LeftTab;-
2806 newTabs << tab;-
2807 ++iter;-
2808 }-
2809 tabArray = newTabs;-
2810 }-
2811 for (int i = 0; i < tabArray.size(); ++i) {-
2812 QFixed tab = QFixed::fromReal(tabArray[i].position) * dpiScale;-
2813 if (tab > x) {-
2814 QTextOption::Tab tabSpec = tabArray[i];-
2815 int tabSectionEnd = layoutData->string.count();-
2816 if (tabSpec.type == QTextOption::RightTab || tabSpec.type == QTextOption::CenterTab) {-
2817-
2818 tab = QFixed::fromReal(tabSpec.position);-
2819 for (int i=item + 1; i < layoutData->items.count(); i++) {-
2820 const QScriptItem &item = layoutData->items[i];-
2821 if (item.analysis.flags == QScriptAnalysis::TabOrObject) {-
2822 tabSectionEnd = item.position;-
2823 break;-
2824 }-
2825 }-
2826 }-
2827 else if (tabSpec.type == QTextOption::DelimiterTab)-
2828-
2829 tabSectionEnd = qMax(si.position, layoutData->string.indexOf(tabSpec.delimiter, si.position) + 1);-
2830-
2831 if (tabSectionEnd > si.position) {-
2832 QFixed length;-
2833-
2834 for (int i=item; i < layoutData->items.count(); i++) {-
2835 QScriptItem &item = layoutData->items[i];-
2836 if (item.position > tabSectionEnd || item.position <= si.position)-
2837 continue;-
2838 shape(i);-
2839 if (item.analysis.flags == QScriptAnalysis::Object) {-
2840 length += item.width;-
2841 continue;-
2842 }-
2843 QGlyphLayout glyphs = this->shapedGlyphs(&item);-
2844 const int end = qMin(item.position + item.num_glyphs, tabSectionEnd) - item.position;-
2845 for (int i=0; i < end; i++)-
2846 length += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;-
2847 if (end + item.position == tabSectionEnd && tabSpec.type == QTextOption::DelimiterTab)-
2848 length -= glyphs.advances[end] / 2 * !glyphs.attributes[end].dontPrint;-
2849 }-
2850-
2851 switch (tabSpec.type) {-
2852 case QTextOption::CenterTab:-
2853 length /= 2;-
2854-
2855 case QTextOption::DelimiterTab:-
2856-
2857 case QTextOption::RightTab:-
2858 tab = QFixed::fromReal(tabSpec.position) * dpiScale - length;-
2859 if (tab < x)-
2860 return QFixed();-
2861 break;-
2862 case QTextOption::LeftTab:-
2863 break;-
2864 }-
2865 }-
2866 return tab - x;-
2867 }-
2868 }-
2869 }-
2870 QFixed tab = QFixed::fromReal(option.tabStop());-
2871 if (tab <= 0)-
2872 tab = 80;-
2873 tab *= dpiScale;-
2874 QFixed nextTabPos = ((x / tab).truncate() + 1) * tab;-
2875 QFixed tabWidth = nextTabPos - x;-
2876-
2877 return tabWidth;-
2878}-
2879-
2880namespace {-
2881class FormatRangeComparatorByStart {-
2882 const QVector<QTextLayout::FormatRange> &list;-
2883public:-
2884 FormatRangeComparatorByStart(const QVector<QTextLayout::FormatRange> &list) : list(list) { }-
2885 bool operator()(int a, int b) {-
2886 return list.at(a).start < list.at(b).start;-
2887 }-
2888};-
2889class FormatRangeComparatorByEnd {-
2890 const QVector<QTextLayout::FormatRange> &list;-
2891public:-
2892 FormatRangeComparatorByEnd(const QVector<QTextLayout::FormatRange> &list) : list(list) { }-
2893 bool operator()(int a, int b) {-
2894 return list.at(a).start + list.at(a).length < list.at(b).start + list.at(b).length;-
2895 }-
2896};-
2897}-
2898-
2899void QTextEngine::resolveFormats() const-
2900{-
2901 if (!specialData
!specialDataDescription
TRUEnever evaluated
FALSEnever evaluated
|| specialData->formats.isEmpty()
specialData->formats.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
)
0
2902 return;
never executed: return;
0
2903 ((!(specialData->resolvedFormats.isEmpty())) ? qt_assert("specialData->resolvedFormats.isEmpty()",__FILE__,30113022) : qt_noop());-
2904-
2905 QTextFormatCollection *collection = formatCollection();-
2906-
2907 QVector<QTextCharFormat> resolvedFormats(layoutData->items.count());-
2908-
2909 QVarLengthArray<int, 64> formatsSortedByStart;-
2910 formatsSortedByStart.reserve(specialData->formats.size());-
2911 for (int i = 0; i < specialData->formats.size()
i < specialDat...formats.size()Description
TRUEnever evaluated
FALSEnever evaluated
; ++i) {
0
2912 if (specialData->formats.at(i).length >= 0
specialData->f...i).length >= 0Description
TRUEnever evaluated
FALSEnever evaluated
)
0
2913 formatsSortedByStart.append(i);
never executed: formatsSortedByStart.append(i);
0
2914 }
never executed: end of block
0
2915 QVarLengthArray<int, 64> formatsSortedByEnd = formatsSortedByStart;-
2916 std::sort(formatsSortedByStart.begin(), formatsSortedByStart.end(),-
2917 FormatRangeComparatorByStart(specialData->formats));-
2918 std::sort(formatsSortedByEnd.begin(), formatsSortedByEnd.end(),-
2919 FormatRangeComparatorByEnd(specialData->formats));-
2920-
2921 QVarLengthArray<int, 16> currentFormats;-
2922 const int *startIt = formatsSortedByStart.constBegin();-
2923 const int *endIt = formatsSortedByEnd.constBegin();-
2924-
2925 for (int i = 0; i < layoutData->items.count()
i < layoutData->items.count()Description
TRUEnever evaluated
FALSEnever evaluated
; ++i) {
0
2926 const QScriptItem *si = &layoutData->items.at(i);-
2927 int end = si->position + length(si);-
2928-
2929 while (startIt != formatsSortedByStart.constEnd()
startIt != for...art.constEnd()Description
TRUEnever evaluated
FALSEnever evaluated
&&
0
2930 specialData->formats.at(*startIt).start <= si->position
specialData->f...= si->positionDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
2931 currentFormats.insert(std::upper_bound(currentFormats.begin(), currentFormats.end(), *startIt),-
2932 *startIt);-
2933 ++startIt;-
2934 }
never executed: end of block
0
2935 while (endIt != formatsSortedByEnd.constEnd()
endIt != forma...End.constEnd()Description
TRUEnever evaluated
FALSEnever evaluated
&&
0
2936 specialData->formats.at(*endIt).start + specialData->formats.at(*endIt).length < end
specialData->f...).length < endDescription
TRUEnever evaluated
FALSEnever evaluated
) {
0
2937 int *currentFormatIterator = std::lower_bound(currentFormats.begin(), currentFormats.end(), *endIt);-
2938 if (*
*endIt < *curr...FormatIteratorDescription
TRUEnever evaluated
FALSEnever evaluated
endIt < *currentFormatIterator
*endIt < *curr...FormatIteratorDescription
TRUEnever evaluated
FALSEnever evaluated
)
0
2939 currentFormatIterator = currentFormats.end();
never executed: currentFormatIterator = currentFormats.end();
0
2940 currentFormats.remove(currentFormatIterator - currentFormats.begin());-
2941 ++endIt;-
2942 }
never executed: end of block
0
2943-
2944 QTextCharFormat &format = resolvedFormats[i];-
2945 if (block.docHandle()
block.docHandle()Description
TRUEnever evaluated
FALSEnever evaluated
) {
0
2946-
2947-
2948 format = collection->charFormat(formatIndex(si));-
2949 }
never executed: end of block
0
2950 if (!currentFormats.isEmpty()
!currentFormats.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
) {
0
2951 for (QForeachContainer<typename QtPrivate::remove_reference<decltype(currentFormats)>::type> _container_((currentFormats)); _container_.control && _container_.i != _container_.e; ++_container_.i, _container_.control ^= 1) for (int cur = *_container_.i; _container_.control; _container_.control =: 0currentFormats) {-
2952 const QTextLayout::FormatRange &range = specialData->formats.at(cur);-
2953 ((!(range.start <= si->position && range.start + range.length >= end)) ? qt_assert("range.start <= si->position && range.start + range.length >= end",__FILE__,30613072) : qt_noop());-
2954 format.merge(range.format);-
2955 }
never executed: end of block
0
2956 format = collection->charFormat(collection->indexForFormat(format));-
2957 }
never executed: end of block
0
2958 }
never executed: end of block
0
2959-
2960 specialData->resolvedFormats = resolvedFormats;-
2961}
never executed: end of block
0
2962-
2963QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)-
2964{-
2965 if (!line.hasTrailingSpaces-
2966 || (option.flags() & QTextOption::IncludeTrailingSpaces)-
2967 || !isRightToLeft())-
2968 return QFixed();-
2969-
2970 return width(line.from + line.length, line.trailingSpaces);-
2971}-
2972-
2973QFixed QTextEngine::alignLine(const QScriptLine &line)-
2974{-
2975 QFixed x = 0;-
2976 justify(line);-
2977-
2978 if (!line.justified && line.width != (2147483647/256)) {-
2979 int align = option.alignment();-
2980 if (align & Qt::AlignJustify && isRightToLeft())-
2981 align = Qt::AlignRight;-
2982 if (align & Qt::AlignRight)-
2983 x = line.width - (line.textAdvance);-
2984 else if (align & Qt::AlignHCenter)-
2985 x = (line.width - line.textAdvance)/2;-
2986 }-
2987 return x;-
2988}-
2989-
2990QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos)-
2991{-
2992 unsigned short *logClusters = this->logClusters(si);-
2993 const QGlyphLayout &glyphs = shapedGlyphs(si);-
2994-
2995 int offsetInCluster = 0;-
2996 for (int i = pos - 1; i >= 0; i--) {-
2997 if (logClusters[i] == glyph_pos)-
2998 offsetInCluster++;-
2999 else-
3000 break;-
3001 }-
3002-
3003-
3004-
3005 if (offsetInCluster > 0) {-
3006 int clusterLength = 0;-
3007 for (int i = pos - offsetInCluster; i < max; i++) {-
3008 if (logClusters[i] == glyph_pos)-
3009 clusterLength++;-
3010 else-
3011 break;-
3012 }-
3013 if (clusterLength)-
3014 return glyphs.advances[glyph_pos] * offsetInCluster / clusterLength;-
3015 }-
3016-
3017 return 0;-
3018}-
3019-
3020-
3021int QTextEngine::getClusterLength(unsigned short *logClusters,-
3022 const QCharAttributes *attributes,-
3023 int from, int to, int glyph_pos, int *start)-
3024{-
3025 int clusterLength = 0;-
3026 for (int i = from; i < to; i++) {-
3027 if (logClusters[i] == glyph_pos && attributes[i].graphemeBoundary) {-
3028 if (*start < 0)-
3029 *start = i;-
3030 clusterLength++;-
3031 }-
3032 else if (clusterLength)-
3033 break;-
3034 }-
3035 return clusterLength;-
3036}-
3037-
3038int QTextEngine::positionInLigature(const QScriptItem *si, int end,-
3039 QFixed x, QFixed edge, int glyph_pos,-
3040 bool cursorOnCharacter)-
3041{-
3042 unsigned short *logClusters = this->logClusters(si);-
3043 int clusterStart = -1;-
3044 int clusterLength = 0;-
3045-
3046 if (si->analysis.script != QChar::Script_Common &&-
3047 si->analysis.script != QChar::Script_Greek) {-
3048 if (glyph_pos == -1)-
3049 return si->position + end;-
3050 else {-
3051 int i;-
3052 for (i = 0; i < end; i++)-
3053 if (logClusters[i] == glyph_pos)-
3054 break;-
3055 return si->position + i;-
3056 }-
3057 }-
3058-
3059 if (glyph_pos == -1 && end > 0)-
3060 glyph_pos = logClusters[end - 1];-
3061 else {-
3062 if (x <= edge)-
3063 glyph_pos--;-
3064 }-
3065-
3066 const QCharAttributes *attrs = attributes() + si->position;-
3067 logClusters = this->logClusters(si);-
3068 clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart);-
3069-
3070 if (clusterLength) {-
3071 const QGlyphLayout &glyphs = shapedGlyphs(si);-
3072 QFixed glyphWidth = glyphs.effectiveAdvance(glyph_pos);-
3073-
3074 QFixed perItemWidth = glyphWidth / clusterLength;-
3075 if (perItemWidth <= 0)-
3076 return si->position + clusterStart;-
3077 QFixed left = x > edge ? edge : edge - glyphWidth;-
3078 int n = ((x - left) / perItemWidth).floor().toInt();-
3079 QFixed dist = x - left - n * perItemWidth;-
3080 int closestItem = dist > (perItemWidth / 2) ? n + 1 : n;-
3081 if (cursorOnCharacter && closestItem > 0)-
3082 closestItem--;-
3083 int pos = clusterStart + closestItem;-
3084-
3085 while (pos < end && !attrs[pos].graphemeBoundary)-
3086 pos++;-
3087 return si->position + pos;-
3088 }-
3089 return si->position + end;-
3090}-
3091-
3092int QTextEngine::previousLogicalPosition(int oldPos) const-
3093{-
3094 const QCharAttributes *attrs = attributes();-
3095 int len = block.isValid() ? block.length() - 1-
3096 : layoutData->string.length();-
3097 ((!(len <= layoutData->string.length())) ? qt_assert("len <= layoutData->string.length()",__FILE__,32053216) : qt_noop());-
3098 if (!attrs || oldPos <= 0 || oldPos > len)-
3099 return oldPos;-
3100-
3101 oldPos--;-
3102 while (oldPos && !attrs[oldPos].graphemeBoundary)-
3103 oldPos--;-
3104 return oldPos;-
3105}-
3106-
3107int QTextEngine::nextLogicalPosition(int oldPos) const-
3108{-
3109 const QCharAttributes *attrs = attributes();-
3110 int len = block.isValid() ? block.length() - 1-
3111 : layoutData->string.length();-
3112 ((!(len <= layoutData->string.length())) ? qt_assert("len <= layoutData->string.length()",__FILE__,32203231) : qt_noop());-
3113 if (!attrs || oldPos < 0 || oldPos >= len)-
3114 return oldPos;-
3115-
3116 oldPos++;-
3117 while (oldPos < len && !attrs[oldPos].graphemeBoundary)-
3118 oldPos++;-
3119 return oldPos;-
3120}-
3121-
3122int QTextEngine::lineNumberForTextPosition(int pos)-
3123{-
3124 if (!layoutData)-
3125 itemize();-
3126 if (pos == layoutData->string.length() && lines.size())-
3127 return lines.size() - 1;-
3128 for (int i = 0; i < lines.size(); ++i) {-
3129 const QScriptLine& line = lines[i];-
3130 if (line.from + line.length + line.trailingSpaces > pos)-
3131 return i;-
3132 }-
3133 return -1;-
3134}-
3135-
3136void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints)-
3137{-
3138 QTextLineItemIterator iterator(this, lineNum);-
3139-
3140 insertionPoints.reserve(iterator.line.length);-
3141-
3142 bool lastLine = lineNum >= lines.size() - 1;-
3143-
3144 while (!iterator.atEnd()) {-
3145 const QScriptItem &si = iterator.next();-
3146-
3147 int end = iterator.itemEnd;-
3148 if (lastLine && iterator.item == iterator.lastItem)-
3149 ++end;-
3150 if (si.analysis.bidiLevel % 2) {-
3151 for (int i = end - 1; i >= iterator.itemStart; --i)-
3152 insertionPoints.push_back(i);-
3153 } else {-
3154 for (int i = iterator.itemStart; i < end; ++i)-
3155 insertionPoints.push_back(i);-
3156 }-
3157 }-
3158}-
3159-
3160int QTextEngine::endOfLine(int lineNum)-
3161{-
3162 QVector<int> insertionPoints;-
3163 insertionPointsForLine(lineNum, insertionPoints);-
3164-
3165 if (insertionPoints.size() > 0
insertionPoints.size() > 0Description
TRUEnever evaluated
FALSEnever evaluated
)
0
3166 return
never executed: return insertionPoints.constLast();
insertionPoints.lastconstLast();
never executed: return insertionPoints.constLast();
0
3167 return
never executed: return 0;
0;
never executed: return 0;
0
3168}-
3169-
3170int QTextEngine::beginningOfLine(int lineNum)-
3171{-
3172 QVector<int> insertionPoints;-
3173 insertionPointsForLine(lineNum, insertionPoints);-
3174-
3175 if (insertionPoints.size() > 0
insertionPoints.size() > 0Description
TRUEnever evaluated
FALSEnever evaluated
)
0
3176 return
never executed: return insertionPoints.constFirst();
insertionPoints.firstconstFirst();
never executed: return insertionPoints.constFirst();
0
3177 return
never executed: return 0;
0;
never executed: return 0;
0
3178}-
3179-
3180int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op)-
3181{-
3182 itemize();-
3183-
3184 bool moveRight = (op == QTextCursor::Right);-
3185 bool alignRight = isRightToLeft();-
3186 if (!layoutData->hasBidi)-
3187 return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos);-
3188-
3189 int lineNum = lineNumberForTextPosition(pos);-
3190 if (lineNum < 0)-
3191 return pos;-
3192-
3193 QVector<int> insertionPoints;-
3194 insertionPointsForLine(lineNum, insertionPoints);-
3195 int i, max = insertionPoints.size();-
3196 for (i = 0; i < max; i++)-
3197 if (pos == insertionPoints[i]) {-
3198 if (moveRight) {-
3199 if (i + 1 < max)-
3200 return insertionPoints[i + 1];-
3201 } else {-
3202 if (i > 0)-
3203 return insertionPoints[i - 1];-
3204 }-
3205-
3206 if (moveRight ^ alignRight) {-
3207 if (lineNum + 1 < lines.size())-
3208 return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1);-
3209 }-
3210 else {-
3211 if (lineNum > 0)-
3212 return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);-
3213 }-
3214-
3215 break;-
3216 }-
3217-
3218 return pos;-
3219}-
3220-
3221void QTextEngine::addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList)-
3222{-
3223 if (delayDecorations) {-
3224 decorationList->append(ItemDecoration(line.x1(), line.x2(), line.y1(), painter->pen()));-
3225 } else {-
3226 painter->drawLine(line);-
3227 }-
3228}-
3229-
3230void QTextEngine::addUnderline(QPainter *painter, const QLineF &line)-
3231{-
3232-
3233 addItemDecoration(painter, line, &underlineList);-
3234}-
3235-
3236void QTextEngine::addStrikeOut(QPainter *painter, const QLineF &line)-
3237{-
3238 addItemDecoration(painter, line, &strikeOutList);-
3239}-
3240-
3241void QTextEngine::addOverline(QPainter *painter, const QLineF &line)-
3242{-
3243 addItemDecoration(painter, line, &overlineList);-
3244}-
3245-
3246void QTextEngine::drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList)-
3247{-
3248-
3249 if (decorationList.isEmpty()
decorationList.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
)
0
3250 return;
never executed: return;
0
3251-
3252 for (QForeachContainer<typename QtPrivate::remove_reference<decltype(decorationList)>::type> _container_((decorationList)); _container_.control && _container_.i != _container_.e; ++_container_.i, _container_.control ^= 1) for (const ItemDecoration &decoration = *_container_.i; _container_.control; _container_.control =: 0decorationList) {-
3253 painter->setPen(decoration.pen);-
3254 painter->drawLine(QLineF(decoration.x1, decoration.y, decoration.x2, decoration.y));-
3255 }
never executed: end of block
0
3256}
never executed: end of block
0
3257-
3258void QTextEngine::drawDecorations(QPainter *painter)-
3259{-
3260 QPen oldPen = painter->pen();-
3261-
3262 bool wasCompatiblePainting = painter->renderHints()-
3263 & QPainter::Qt4CompatiblePainting;-
3264-
3265 if (wasCompatiblePainting)-
3266 painter->setRenderHint(QPainter::Qt4CompatiblePainting, false);-
3267-
3268 adjustUnderlines();-
3269 drawItemDecorationList(painter, underlineList);-
3270 drawItemDecorationList(painter, strikeOutList);-
3271 drawItemDecorationList(painter, overlineList);-
3272-
3273 clearDecorations();-
3274-
3275 if (wasCompatiblePainting)-
3276 painter->setRenderHint(QPainter::Qt4CompatiblePainting);-
3277-
3278 painter->setPen(oldPen);-
3279}-
3280-
3281void QTextEngine::clearDecorations()-
3282{-
3283 underlineList.clear();-
3284 strikeOutList.clear();-
3285 overlineList.clear();-
3286}-
3287-
3288void QTextEngine::adjustUnderlines()-
3289{-
3290-
3291 if (underlineList.isEmpty())-
3292 return;-
3293-
3294 ItemDecorationList::iterator start = underlineList.begin();-
3295 ItemDecorationList::iterator end = underlineList.end();-
3296 ItemDecorationList::iterator it = start;-
3297 qreal underlinePos = start->y;-
3298 qreal penWidth = start->pen.widthF();-
3299 qreal lastLineEnd = start->x1;-
3300-
3301 while (it != end) {-
3302 if (qFuzzyCompare(lastLineEnd, it->x1)) {-
3303 underlinePos = qMax(underlinePos, it->y);-
3304 penWidth = qMax(penWidth, it->pen.widthF());-
3305 } else {-
3306 adjustUnderlines(start, it, underlinePos, penWidth);-
3307 start = it;-
3308 underlinePos = start->y;-
3309 penWidth = start->pen.widthF();-
3310 }-
3311 lastLineEnd = it->x2;-
3312 ++it;-
3313 }-
3314-
3315 adjustUnderlines(start, end, underlinePos, penWidth);-
3316}-
3317-
3318void QTextEngine::adjustUnderlines(ItemDecorationList::iterator start,-
3319 ItemDecorationList::iterator end,-
3320 qreal underlinePos, qreal penWidth)-
3321{-
3322 for (ItemDecorationList::iterator it = start; it != end; ++it) {-
3323 it->y = underlinePos;-
3324 it->pen.setWidthF(penWidth);-
3325 }-
3326}-
3327-
3328QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)-
3329 : QTextEngine(string, f),-
3330 _layoutData(string, _memory, MemSize)-
3331{-
3332 stackEngine = true;-
3333 layoutData = &_layoutData;-
3334}-
3335-
3336QTextItemInt::QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format)-
3337 : justified(false), underlineStyle(QTextCharFormat::NoUnderline), charFormat(format),-
3338 num_chars(0), chars(0), logClusters(0), f(0), fontEngine(0)-
3339{-
3340 f = font;-
3341 fontEngine = f->d->engineForScript(si.analysis.script);-
3342 ((!(fontEngine)) ? qt_assert("fontEngine",__FILE__,34503461) : qt_noop());-
3343-
3344 initWithScriptItem(si);-
3345}-
3346-
3347QTextItemInt::QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars_, int numChars, QFontEngine *fe, const QTextCharFormat &format)-
3348 : flags(0), justified(false), underlineStyle(QTextCharFormat::NoUnderline), charFormat(format),-
3349 num_chars(numChars), chars(chars_), logClusters(0), f(font), glyphs(g), fontEngine(fe)-
3350{-
3351}-
3352-
3353-
3354void QTextItemInt::initWithScriptItem(const QScriptItem &si)-
3355{-
3356-
3357-
3358 flags = 0;-
3359 if (si.analysis.bidiLevel %2)-
3360 flags |= QTextItem::RightToLeft;-
3361 ascent = si.ascent;-
3362 descent = si.descent;-
3363-
3364 if (charFormat.hasProperty(QTextFormat::TextUnderlineStyle)) {-
3365 underlineStyle = charFormat.underlineStyle();-
3366 } else if (charFormat.boolProperty(QTextFormat::FontUnderline)-
3367 || f->d->underline) {-
3368 underlineStyle = QTextCharFormat::SingleUnderline;-
3369 }-
3370-
3371-
3372 if (underlineStyle == QTextCharFormat::SingleUnderline)-
3373 flags |= QTextItem::Underline;-
3374-
3375 if (f->d->overline || charFormat.fontOverline())-
3376 flags |= QTextItem::Overline;-
3377 if (f->d->strikeOut || charFormat.fontStrikeOut())-
3378 flags |= QTextItem::StrikeOut;-
3379}-
3380-
3381QTextItemInt QTextItemInt::midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const-
3382{-
3383 QTextItemInt ti = *this;-
3384 const int end = firstGlyphIndex + numGlyphs;-
3385 ti.glyphs = glyphs.mid(firstGlyphIndex, numGlyphs);-
3386 ti.fontEngine = fontEngine;-
3387-
3388 if (logClusters && chars) {-
3389 const int logClusterOffset = logClusters[0];-
3390 while (logClusters[ti.chars - chars] - logClusterOffset < firstGlyphIndex)-
3391 ++ti.chars;-
3392-
3393 ti.logClusters += (ti.chars - chars);-
3394-
3395 ti.num_chars = 0;-
3396 int char_start = ti.chars - chars;-
3397 while (char_start + ti.num_chars < num_chars && ti.logClusters[ti.num_chars] - logClusterOffset < end)-
3398 ++ti.num_chars;-
3399 }-
3400 return ti;-
3401}-
3402-
3403-
3404QTransform qt_true_matrix(qreal w, qreal h, QTransform x)-
3405{-
3406 QRectF rect = x.mapRect(QRectF(0, 0, w, h));-
3407 return x * QTransform::fromTranslate(-rect.x(), -rect.y());-
3408}-
3409-
3410-
3411glyph_metrics_t glyph_metrics_t::transformed(const QTransform &matrix) const-
3412{-
3413 if (matrix.type() < QTransform::TxTranslate)-
3414 return *this;-
3415-
3416 glyph_metrics_t m = *this;-
3417-
3418 qreal w = width.toReal();-
3419 qreal h = height.toReal();-
3420 QTransform xform = qt_true_matrix(w, h, matrix);-
3421-
3422 QRectF rect(0, 0, w, h);-
3423 rect = xform.mapRect(rect);-
3424 m.width = QFixed::fromReal(rect.width());-
3425 m.height = QFixed::fromReal(rect.height());-
3426-
3427 QLineF l = xform.map(QLineF(x.toReal(), y.toReal(), xoff.toReal(), yoff.toReal()));-
3428-
3429 m.x = QFixed::fromReal(l.x1());-
3430 m.y = QFixed::fromReal(l.y1());-
3431-
3432-
3433 m.xoff = QFixed::fromReal(l.dx());-
3434 m.yoff = QFixed::fromReal(l.dy());-
3435-
3436 return m;-
3437}-
3438-
3439QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, const QPointF &pos,-
3440 const QTextLayout::FormatRange *_selection)-
3441 : eng(_eng),-
3442 line(eng->lines[_lineNum]),-
3443 si(0),-
3444 lineNum(_lineNum),-
3445 lineEnd(line.from + line.length),-
3446 firstItem(eng->findItem(line.from)),-
3447 lastItem(eng->findItem(lineEnd - 1, firstItem)),-
3448 nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),-
3449 logicalItem(-1),-
3450 item(-1),-
3451 visualOrder(nItems),-
3452 selection(_selection)-
3453{-
3454 x = QFixed::fromReal(pos.x());-
3455-
3456 x += line.x;-
3457-
3458 x += eng->alignLine(line);-
3459-
3460 QVarLengthArray<uchar> levels(nItems);-
3461 for (int i = 0; i < nItems; ++i)-
3462 levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;-
3463 QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());-
3464-
3465 eng->shapeLine(line);-
3466}-
3467-
3468QScriptItem &QTextLineItemIterator::next()-
3469{-
3470 x += itemWidth;-
3471-
3472 ++logicalItem;-
3473 item = visualOrder[logicalItem] + firstItem;-
3474 itemLength = eng->length(item);-
3475 si = &eng->layoutData->items[item];-
3476 if (!si->num_glyphs)-
3477 eng->shape(item);-
3478-
3479 itemStart = qMax(line.from, si->position);-
3480 itemEnd = qMin(lineEnd, si->position + itemLength);-
3481-
3482 if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {-
3483 glyphsStart = 0;-
3484 glyphsEnd = 1;-
3485 itemWidth = si->width;-
3486 return *si;-
3487 }-
3488-
3489 unsigned short *logClusters = eng->logClusters(si);-
3490 QGlyphLayout glyphs = eng->shapedGlyphs(si);-
3491-
3492 glyphsStart = logClusters[itemStart - si->position];-
3493 glyphsEnd = (itemEnd == si->position + itemLength) ? si->num_glyphs : logClusters[itemEnd - si->position];-
3494-
3495-
3496 if (si->position + itemLength >= lineEnd-
3497 && eng->layoutData->string.at(lineEnd - 1).unicode() == QChar::SoftHyphen)-
3498 glyphs.attributes[glyphsEnd - 1].dontPrint = false;-
3499-
3500 itemWidth = 0;-
3501 for (int g = glyphsStart; g < glyphsEnd; ++g)-
3502 itemWidth += glyphs.effectiveAdvance(g);-
3503-
3504 return *si;-
3505}-
3506-
3507bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const-
3508{-
3509 *selectionX = *selectionWidth = 0;-
3510-
3511 if (!selection)-
3512 return false;-
3513-
3514 if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {-
3515 if (si->position >= selection->start + selection->length-
3516 || si->position + itemLength <= selection->start)-
3517 return false;-
3518-
3519 *selectionX = x;-
3520 *selectionWidth = itemWidth;-
3521 } else {-
3522 unsigned short *logClusters = eng->logClusters(si);-
3523 QGlyphLayout glyphs = eng->shapedGlyphs(si);-
3524-
3525 int from = qMax(itemStart, selection->start) - si->position;-
3526 int to = qMin(itemEnd, selection->start + selection->length) - si->position;-
3527 if (from >= to)-
3528 return false;-
3529-
3530 int start_glyph = logClusters[from];-
3531 int end_glyph = (to == itemLength) ? si->num_glyphs : logClusters[to];-
3532 QFixed soff;-
3533 QFixed swidth;-
3534 if (si->analysis.bidiLevel %2) {-
3535 for (int g = glyphsEnd - 1; g >= end_glyph; --g)-
3536 soff += glyphs.effectiveAdvance(g);-
3537 for (int g = end_glyph - 1; g >= start_glyph; --g)-
3538 swidth += glyphs.effectiveAdvance(g);-
3539 } else {-
3540 for (int g = glyphsStart; g < start_glyph; ++g)-
3541 soff += glyphs.effectiveAdvance(g);-
3542 for (int g = start_glyph; g < end_glyph; ++g)-
3543 swidth += glyphs.effectiveAdvance(g);-
3544 }-
3545-
3546-
3547-
3548-
3549-
3550 QFixed leftOffsetInLigature = eng->offsetInLigature(si, from, to, start_glyph);-
3551 *selectionX = x + soff + leftOffsetInLigature;-
3552 *selectionWidth = swidth - leftOffsetInLigature;-
3553-
3554-
3555-
3556 *selectionWidth += eng->offsetInLigature(si, to, itemLength, end_glyph);-
3557 }-
3558 return true;-
3559}-
3560-
3561-
Switch to Source codePreprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9