Absolute File Name: | /home/qt/qt5_coco/qt5/qtbase/src/gui/text/qtextlayout.cpp |
Switch to Source code | Preprocessed file |
Line | Source | Count |
---|---|---|
1 | - | |
2 | - | |
3 | - | |
4 | - | |
5 | - | |
6 | - | |
7 | - | |
8 | QRectF QTextInlineObject::rect() const | - |
9 | { | - |
10 | QScriptItem& si = eng->layoutData->items[itm]; | - |
11 | return QRectF(0, -si.ascent.toReal(), si.width.toReal(), si.height().toReal()); | - |
12 | } | - |
13 | - | |
14 | - | |
15 | - | |
16 | - | |
17 | - | |
18 | - | |
19 | qreal QTextInlineObject::width() const | - |
20 | { | - |
21 | return eng->layoutData->items[itm].width.toReal(); | - |
22 | } | - |
23 | - | |
24 | - | |
25 | - | |
26 | - | |
27 | - | |
28 | - | |
29 | qreal QTextInlineObject::ascent() const | - |
30 | { | - |
31 | return eng->layoutData->items[itm].ascent.toReal(); | - |
32 | } | - |
33 | - | |
34 | - | |
35 | - | |
36 | - | |
37 | - | |
38 | - | |
39 | qreal QTextInlineObject::descent() const | - |
40 | { | - |
41 | return eng->layoutData->items[itm].descent.toReal(); | - |
42 | } | - |
43 | - | |
44 | - | |
45 | - | |
46 | - | |
47 | - | |
48 | - | |
49 | - | |
50 | qreal QTextInlineObject::height() const | - |
51 | { | - |
52 | return eng->layoutData->items[itm].height().toReal(); | - |
53 | } | - |
54 | - | |
55 | - | |
56 | - | |
57 | - | |
58 | - | |
59 | - | |
60 | void QTextInlineObject::setWidth(qreal w) | - |
61 | { | - |
62 | eng->layoutData->items[itm].width = QFixed::fromReal(w); | - |
63 | } | - |
64 | - | |
65 | - | |
66 | - | |
67 | - | |
68 | - | |
69 | - | |
70 | void QTextInlineObject::setAscent(qreal a) | - |
71 | { | - |
72 | eng->layoutData->items[itm].ascent = QFixed::fromReal(a); | - |
73 | } | - |
74 | - | |
75 | - | |
76 | - | |
77 | - | |
78 | - | |
79 | - | |
80 | void QTextInlineObject::setDescent(qreal d) | - |
81 | { | - |
82 | eng->layoutData->items[itm].descent = QFixed::fromReal(d); | - |
83 | } | - |
84 | - | |
85 | - | |
86 | - | |
87 | - | |
88 | int QTextInlineObject::textPosition() const | - |
89 | { | - |
90 | return eng->layoutData->items[itm].position; | - |
91 | } | - |
92 | - | |
93 | - | |
94 | - | |
95 | - | |
96 | - | |
97 | int QTextInlineObject::formatIndex() const | - |
98 | { | - |
99 | return eng->formatIndex(&eng->layoutData->items[itm]); | - |
100 | } | - |
101 | - | |
102 | - | |
103 | - | |
104 | - | |
105 | QTextFormat QTextInlineObject::format() const | - |
106 | { | - |
107 | return eng->format(&eng->layoutData->items[itm]); | - |
108 | } | - |
109 | - | |
110 | - | |
111 | - | |
112 | - | |
113 | Qt::LayoutDirection QTextInlineObject::textDirection() const | - |
114 | { | - |
115 | return (eng->layoutData->items[itm].analysis.bidiLevel % 2 ? Qt::RightToLeft : Qt::LeftToRight); | - |
116 | } | - |
117 | QTextLayout::QTextLayout() | - |
118 | { d = new QTextEngine(); } | - |
119 | - | |
120 | - | |
121 | - | |
122 | - | |
123 | QTextLayout::QTextLayout(const QString& text) | - |
124 | { | - |
125 | d = new QTextEngine(); | - |
126 | d->text = text; | - |
127 | } | - |
128 | QTextLayout::QTextLayout(const QString& text, const QFont &font, QPaintDevice *paintdevice) | - |
129 | { | - |
130 | QFont f(font); | - |
131 | if (paintdevice) | - |
132 | f = QFont(font, paintdevice); | - |
133 | d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f); | - |
134 | } | - |
135 | - | |
136 | - | |
137 | - | |
138 | - | |
139 | - | |
140 | QTextLayout::QTextLayout(const QTextBlock &block) | - |
141 | { | - |
142 | d = new QTextEngine(); | - |
143 | d->block = block; | - |
144 | } | - |
145 | - | |
146 | - | |
147 | - | |
148 | - | |
149 | QTextLayout::~QTextLayout() | - |
150 | { | - |
151 | if (!d->stackEngine) | - |
152 | delete d; | - |
153 | } | - |
154 | void QTextLayout::setRawFont(const QRawFont &rawFont) | - |
155 | { | - |
156 | d->rawFont = rawFont; | - |
157 | d->useRawFont = true; | - |
158 | d->resetFontEngineCache(); | - |
159 | } | - |
160 | void QTextLayout::setFont(const QFont &font) | - |
161 | { | - |
162 | d->fnt = font; | - |
163 | - | |
164 | d->useRawFont = false; | - |
165 | - | |
166 | d->resetFontEngineCache(); | - |
167 | } | - |
168 | - | |
169 | - | |
170 | - | |
171 | - | |
172 | - | |
173 | - | |
174 | - | |
175 | QFont QTextLayout::font() const | - |
176 | { | - |
177 | return d->font(); | - |
178 | } | - |
179 | void QTextLayout::setText(const QString& string) | - |
180 | { | - |
181 | d->invalidate(); | - |
182 | d->clearLineData(); | - |
183 | d->text = string; | - |
184 | } | - |
185 | - | |
186 | - | |
187 | - | |
188 | - | |
189 | - | |
190 | - | |
191 | QString QTextLayout::text() const | - |
192 | { | - |
193 | return d->text; | - |
194 | } | - |
195 | - | |
196 | - | |
197 | - | |
198 | - | |
199 | - | |
200 | - | |
201 | - | |
202 | void QTextLayout::setTextOption(const QTextOption &option) | - |
203 | { | - |
204 | d->option = option; | - |
205 | } | - |
206 | - | |
207 | - | |
208 | - | |
209 | - | |
210 | - | |
211 | - | |
212 | const QTextOption &QTextLayout::textOption() const | - |
213 | { | - |
214 | return d->option; | - |
215 | } | - |
216 | void QTextLayout::setPreeditArea(int position, const QString &text) | - |
217 | { | - |
218 | if (d->preeditAreaPosition() == position && d->preeditAreaText() == text) | - |
219 | return; | - |
220 | d->setPreeditArea(position, text); | - |
221 | - | |
222 | if (d->block.docHandle()) | - |
223 | d->block.docHandle()->documentChange(d->block.position(), d->block.length()); | - |
224 | } | - |
225 | - | |
226 | - | |
227 | - | |
228 | - | |
229 | - | |
230 | - | |
231 | - | |
232 | int QTextLayout::preeditAreaPosition() const | - |
233 | { | - |
234 | return d->preeditAreaPosition(); | - |
235 | } | - |
236 | - | |
237 | - | |
238 | - | |
239 | - | |
240 | - | |
241 | - | |
242 | QString QTextLayout::preeditAreaText() const | - |
243 | { | - |
244 | return d->preeditAreaText(); | - |
245 | } | - |
246 | - | |
247 | - | |
248 | - | |
249 | - | |
250 | - | |
251 | void QTextLayout::setAdditionalFormats(const QList<FormatRange> &formatList) | - |
252 | { | - |
253 | setFormats(formatList.toVector()); | - |
254 | } | - |
255 | void QTextLayout::setFormats(const QVector<FormatRange> &formats) | - |
256 | { | - |
257 | d->setFormats(formats); | - |
258 | - | |
259 | if (d->block.docHandle()) | - |
260 | d->block.docHandle()->documentChange(d->block.position(), d->block.length()); | - |
261 | } | - |
262 | - | |
263 | - | |
264 | - | |
265 | - | |
266 | - | |
267 | - | |
268 | - | |
269 | QList<QTextLayout::FormatRange> QTextLayout::additionalFormats() const | - |
270 | { | - |
271 | return formats().toList(); | - |
272 | } | - |
273 | QVector<QTextLayout::FormatRange> QTextLayout::formats() const | - |
274 | { | - |
275 | return d->formats(); | - |
276 | } | - |
277 | - | |
278 | - | |
279 | - | |
280 | - | |
281 | - | |
282 | void QTextLayout::clearAdditionalFormats() | - |
283 | { | - |
284 | clearFormats(); | - |
285 | } | - |
286 | void QTextLayout::clearFormats() | - |
287 | { | - |
288 | setFormats(QVector<FormatRange>()); | - |
289 | } | - |
290 | void QTextLayout::setCacheEnabled(bool enable) | - |
291 | { | - |
292 | d->cacheGlyphs = enable; | - |
293 | } | - |
294 | - | |
295 | - | |
296 | - | |
297 | - | |
298 | - | |
299 | - | |
300 | - | |
301 | bool QTextLayout::cacheEnabled() const | - |
302 | { | - |
303 | return d->cacheGlyphs; | - |
304 | } | - |
305 | void QTextLayout::setCursorMoveStyle(Qt::CursorMoveStyle style) | - |
306 | { | - |
307 | d->visualMovement = style == Qt::VisualMoveStyle; | - |
308 | } | - |
309 | - | |
310 | - | |
311 | - | |
312 | - | |
313 | - | |
314 | - | |
315 | - | |
316 | Qt::CursorMoveStyle QTextLayout::cursorMoveStyle() const | - |
317 | { | - |
318 | return d->visualMovement ? Qt::VisualMoveStyle : Qt::LogicalMoveStyle; | - |
319 | } | - |
320 | - | |
321 | - | |
322 | - | |
323 | - | |
324 | - | |
325 | - | |
326 | void QTextLayout::beginLayout() | - |
327 | { | - |
328 | - | |
329 | if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) { | - |
330 | QMessageLogger(__FILE__, 633639, __PRETTY_FUNCTION__).warning("QTextLayout::beginLayout: Called while already doing layout"); | - |
331 | return; | - |
332 | } | - |
333 | - | |
334 | d->invalidate(); | - |
335 | d->clearLineData(); | - |
336 | d->itemize(); | - |
337 | d->layoutData->layoutState = QTextEngine::InLayout; | - |
338 | } | - |
339 | - | |
340 | - | |
341 | - | |
342 | - | |
343 | - | |
344 | - | |
345 | void QTextLayout::endLayout() | - |
346 | { | - |
347 | - | |
348 | if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) { | - |
349 | QMessageLogger(__FILE__, 652658, __PRETTY_FUNCTION__).warning("QTextLayout::endLayout: Called without beginLayout()"); | - |
350 | return; | - |
351 | } | - |
352 | - | |
353 | int l = d->lines.size(); | - |
354 | if (l && d->lines.at(l-1).length < 0) { | - |
355 | QTextLine(l-1, d).setNumColumns(2147483647); | - |
356 | } | - |
357 | d->layoutData->layoutState = QTextEngine::LayoutEmpty; | - |
358 | if (!d->cacheGlyphs) | - |
359 | d->freeMemory(); | - |
360 | } | - |
361 | - | |
362 | - | |
363 | - | |
364 | - | |
365 | - | |
366 | - | |
367 | - | |
368 | void QTextLayout::clearLayout() | - |
369 | { | - |
370 | d->clearLineData(); | - |
371 | } | - |
372 | int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const | - |
373 | { | - |
374 | const QCharAttributes *attributes = d->attributes(); | - |
375 | int len = d->block.isValid() ? d->block.length() - 1 | - |
376 | : d->layoutData->string.length(); | - |
377 | ((!(len <= d->layoutData->string.length())) ? qt_assert("len <= d->layoutData->string.length()",__FILE__,688694) : qt_noop()); | - |
378 | if (!attributes || oldPos < 0 || oldPos >= len) | - |
379 | return oldPos; | - |
380 | - | |
381 | if (mode == SkipCharacters) { | - |
382 | oldPos++; | - |
383 | while (oldPos < len && !attributes[oldPos].graphemeBoundary) | - |
384 | oldPos++; | - |
385 | } else { | - |
386 | if (oldPos < len && d->atWordSeparator(oldPos)) { | - |
387 | oldPos++; | - |
388 | while (oldPos < len && d->atWordSeparator(oldPos)) | - |
389 | oldPos++; | - |
390 | } else { | - |
391 | while (oldPos < len && !attributes[oldPos].whiteSpace && !d->atWordSeparator(oldPos)) | - |
392 | oldPos++; | - |
393 | } | - |
394 | while (oldPos < len && attributes[oldPos].whiteSpace) | - |
395 | oldPos++; | - |
396 | } | - |
397 | - | |
398 | return oldPos; | - |
399 | } | - |
400 | int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const | - |
401 | { | - |
402 | const QCharAttributes *attributes = d->attributes(); | - |
403 | int len = d->block.isValid() ? d->block.length() - 1 | - |
404 | : d->layoutData->string.length(); | - |
405 | ((!(len <= d->layoutData->string.length())) ? qt_assert("len <= d->layoutData->string.length()",__FILE__,724730) : qt_noop()); | - |
406 | if (!attributes || oldPos <= 0 || oldPos > len) | - |
407 | return oldPos; | - |
408 | - | |
409 | if (mode == SkipCharacters) { | - |
410 | oldPos--; | - |
411 | while (oldPos && !attributes[oldPos].graphemeBoundary) | - |
412 | oldPos--; | - |
413 | } else { | - |
414 | while (oldPos > 0 && attributes[oldPos - 1].whiteSpace) | - |
415 | oldPos--; | - |
416 | - | |
417 | if (oldPos && d->atWordSeparator(oldPos-1)) { | - |
418 | oldPos--; | - |
419 | while (oldPos && d->atWordSeparator(oldPos-1)) | - |
420 | oldPos--; | - |
421 | } else { | - |
422 | while (oldPos > 0 && !attributes[oldPos - 1].whiteSpace && !d->atWordSeparator(oldPos-1)) | - |
423 | oldPos--; | - |
424 | } | - |
425 | } | - |
426 | - | |
427 | return oldPos; | - |
428 | } | - |
429 | int QTextLayout::rightCursorPosition(int oldPos) const | - |
430 | { | - |
431 | int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right); | - |
432 | - | |
433 | return newPos; | - |
434 | } | - |
435 | int QTextLayout::leftCursorPosition(int oldPos) const | - |
436 | { | - |
437 | int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left); | - |
438 | - | |
439 | return newPos; | - |
440 | } | - |
441 | bool QTextLayout::isValidCursorPosition(int pos) const | - |
442 | { | - |
443 | const QCharAttributes *attributes = d->attributes(); | - |
444 | if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length()) | - |
445 | return false; | - |
446 | return attributes[pos].graphemeBoundary; | - |
447 | } | - |
448 | QTextLine QTextLayout::createLine() | - |
449 | { | - |
450 | - | |
451 | if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) { | - |
452 | QMessageLogger(__FILE__, 820826, __PRETTY_FUNCTION__).warning("QTextLayout::createLine: Called without layouting"); | - |
453 | return QTextLine(); | - |
454 | } | - |
455 | - | |
456 | if (d->layoutData->layoutState == QTextEngine::LayoutFailed) | - |
457 | return QTextLine(); | - |
458 | - | |
459 | int l = d->lines.size(); | - |
460 | if (l && d->lines.at(l-1).length < 0) { | - |
461 | QTextLine(l-1, d).setNumColumns(2147483647); | - |
462 | } | - |
463 | int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0; | - |
464 | int strlen = d->layoutData->string.length(); | - |
465 | if (l && from >= strlen) { | - |
466 | if (!d->lines.at(l-1).length || d->layoutData->string.at(strlen - 1) != QChar::LineSeparator) | - |
467 | return QTextLine(); | - |
468 | } | - |
469 | - | |
470 | QScriptLine line; | - |
471 | line.from = from; | - |
472 | line.length = -1; | - |
473 | line.justified = false; | - |
474 | line.gridfitted = false; | - |
475 | - | |
476 | d->lines.append(line); | - |
477 | return QTextLine(l, d); | - |
478 | } | - |
479 | - | |
480 | - | |
481 | - | |
482 | - | |
483 | - | |
484 | - | |
485 | int QTextLayout::lineCount() const | - |
486 | { | - |
487 | return d->lines.size(); | - |
488 | } | - |
489 | - | |
490 | - | |
491 | - | |
492 | - | |
493 | - | |
494 | - | |
495 | QTextLine QTextLayout::lineAt(int i) const | - |
496 | { | - |
497 | return i < lineCount() ? QTextLine(i, d) : QTextLine(); | - |
498 | } | - |
499 | - | |
500 | - | |
501 | - | |
502 | - | |
503 | - | |
504 | - | |
505 | QTextLine QTextLayout::lineForTextPosition(int pos) const | - |
506 | { | - |
507 | int lineNum = d->lineNumberForTextPosition(pos); | - |
508 | return lineNum >= 0 ? lineAt(lineNum) : QTextLine(); | - |
509 | } | - |
510 | QPointF QTextLayout::position() const | - |
511 | { | - |
512 | return d->position; | - |
513 | } | - |
514 | - | |
515 | - | |
516 | - | |
517 | - | |
518 | - | |
519 | - | |
520 | void QTextLayout::setPosition(const QPointF &p) | - |
521 | { | - |
522 | d->position = p; | - |
523 | } | - |
524 | - | |
525 | - | |
526 | - | |
527 | - | |
528 | QRectF QTextLayout::boundingRect() const | - |
529 | { | - |
530 | if (d->lines.isEmpty()) | - |
531 | return QRectF(); | - |
532 | - | |
533 | QFixed xmax, ymax; | - |
534 | QFixed xmin = d->lines.at(0).x; | - |
535 | QFixed ymin = d->lines.at(0).y; | - |
536 | - | |
537 | for (int i = 0; i < d->lines.size(); ++i) { | - |
538 | const QScriptLine &si = d->lines[i]; | - |
539 | xmin = qMin(xmin, si.x); | - |
540 | ymin = qMin(ymin, si.y); | - |
541 | QFixed lineWidth = si.width < (2147483647/256) ? qMax(si.width, si.textWidth) : si.textWidth; | - |
542 | xmax = qMax(xmax, si.x+lineWidth); | - |
543 | - | |
544 | ymax = qMax(ymax, si.y+si.height().ceil()); | - |
545 | } | - |
546 | return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal()); | - |
547 | } | - |
548 | qreal QTextLayout::minimumWidth() const | - |
549 | { | - |
550 | return d->minWidth.toReal(); | - |
551 | } | - |
552 | qreal QTextLayout::maximumWidth() const | - |
553 | { | - |
554 | return d->maxWidth.toReal(); | - |
555 | } | - |
556 | - | |
557 | - | |
558 | - | |
559 | - | |
560 | - | |
561 | void QTextLayout::setFlags(int flags) | - |
562 | { | - |
563 | if (flags & Qt::TextJustificationForced) { | - |
564 | d->option.setAlignment(Qt::AlignJustify); | - |
565 | d->forceJustification = true; | - |
566 | } | - |
567 | - | |
568 | if (flags & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) { | - |
569 | d->ignoreBidi = true; | - |
570 | d->option.setTextDirection((flags & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft); | - |
571 | } | - |
572 | } | - |
573 | - | |
574 | static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection, | - |
575 | QPainterPath *region, QRectF boundingRect) | - |
576 | { | - |
577 | const QScriptLine &line = eng->lines[lineNumber]; | - |
578 | - | |
579 | QTextLineItemIterator iterator(eng, lineNumber, pos, selection); | - |
580 | - | |
581 | - | |
582 | - | |
583 | const qreal selectionY = pos.y() + line.y.toReal(); | - |
584 | const qreal lineHeight = line.height().toReal(); | - |
585 | - | |
586 | QFixed lastSelectionX = iterator.x; | - |
587 | QFixed lastSelectionWidth; | - |
588 | - | |
589 | while (!iterator.atEnd()) { | - |
590 | iterator.next(); | - |
591 | - | |
592 | QFixed selectionX, selectionWidth; | - |
593 | if (iterator.getSelectionBounds(&selectionX, &selectionWidth)) { | - |
594 | if (selectionX == lastSelectionX + lastSelectionWidth) { | - |
595 | lastSelectionWidth += selectionWidth; | - |
596 | continue; | - |
597 | } | - |
598 | - | |
599 | if (lastSelectionWidth > 0) { | - |
600 | QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); | - |
601 | rect.moveLeft(qFloor(rect.left())); | - |
602 | rect.moveTop(qFloor(rect.top())); | - |
603 | region->addRect(rect); | - |
604 | } | - |
605 | - | |
606 | lastSelectionX = selectionX; | - |
607 | lastSelectionWidth = selectionWidth; | - |
608 | } | - |
609 | } | - |
610 | if (lastSelectionWidth > 0) { | - |
611 | QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight); | - |
612 | rect.moveLeft(qFloor(rect.left())); | - |
613 | rect.moveTop(qFloor(rect.top())); | - |
614 | region->addRect(rect); | - |
615 | } | - |
616 | } | - |
617 | - | |
618 | static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip) | - |
619 | { | - |
620 | return clip.isValid() ? (rect & clip) : rect; | - |
621 | } | - |
622 | QList<QGlyphRun> QTextLayout::glyphRuns(int from, int length) const | - |
623 | { | - |
624 | if (from < 0) | - |
625 | from = 0; | - |
626 | if (length < 0) | - |
627 | length = text().length(); | - |
628 | - | |
629 | QHash<QPair<QFontEngine *, int>, QGlyphRun> glyphRunHash; | - |
630 | for (int i=0; i<d->lines.size(); ++i) { | - |
631 | if (d->lines[i].from > from + length) | - |
632 | break; | - |
633 | else if (d->lines[i].from + d->lines[i].length >= from) { | - |
634 | QList<QGlyphRun> glyphRuns = QTextLine(i, d).glyphRuns(from, length); | - |
635 | - | |
636 | for (int j = 0; j < glyphRuns.size(); j++) { | - |
637 | const QGlyphRun &glyphRun = glyphRuns.at(j); | - |
638 | QRawFont rawFont = glyphRun.rawFont(); | - |
639 | - | |
640 | QFontEngine *fontEngine = rawFont.d->fontEngine; | - |
641 | QGlyphRun::GlyphRunFlags flags = glyphRun.flags(); | - |
642 | QPair<QFontEngine *, int> key(fontEngine, int(flags)); | - |
643 | - | |
644 | if (glyphRunHash.contains(key)) { | - |
645 | QGlyphRun &oldGlyphRun = glyphRunHash[key]; | - |
646 | - | |
647 | QVector<quint32> indexes = oldGlyphRun.glyphIndexes(); | - |
648 | QVector<QPointF> positions = oldGlyphRun.positions(); | - |
649 | QRectF boundingRect = oldGlyphRun.boundingRect(); | - |
650 | - | |
651 | indexes += glyphRun.glyphIndexes(); | - |
652 | positions += glyphRun.positions(); | - |
653 | boundingRect = boundingRect.united(glyphRun.boundingRect()); | - |
654 | - | |
655 | oldGlyphRun.setGlyphIndexes(indexes); | - |
656 | oldGlyphRun.setPositions(positions); | - |
657 | oldGlyphRun.setBoundingRect(boundingRect); | - |
658 | } else { | - |
659 | glyphRunHash[key] = glyphRun; | - |
660 | } | - |
661 | } | - |
662 | } | - |
663 | } | - |
664 | - | |
665 | return glyphRunHash.values(); | - |
666 | } | - |
667 | - | |
668 | - | |
669 | - | |
670 | - | |
671 | - | |
672 | - | |
673 | - | |
674 | void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections, const QRectF &clip) const | - |
675 | { | - |
676 | if (d->lines.isEmpty()) | - |
677 | return; | - |
678 | - | |
679 | if (!d->layoutData) | - |
680 | d->itemize(); | - |
681 | - | |
682 | QPointF position = pos + d->position; | - |
683 | - | |
684 | QFixed clipy = ((-2147483647 - 1)/256); | - |
685 | QFixed clipe = (2147483647/256); | - |
686 | if (clip.isValid()) { | - |
687 | clipy = QFixed::fromReal(clip.y() - position.y()); | - |
688 | clipe = clipy + QFixed::fromReal(clip.height()); | - |
689 | } | - |
690 | - | |
691 | int firstLine = 0; | - |
692 | int lastLine = d->lines.size(); | - |
693 | for (int i = 0; i < d->lines.size(); ++i) { | - |
694 | QTextLine l(i, d); | - |
695 | const QScriptLine &sl = d->lines[i]; | - |
696 | - | |
697 | if (sl.y > clipe) { | - |
698 | lastLine = i; | - |
699 | break; | - |
700 | } | - |
701 | if ((sl.y + sl.height()) < clipy) { | - |
702 | firstLine = i; | - |
703 | continue; | - |
704 | } | - |
705 | } | - |
706 | - | |
707 | QPainterPath excludedRegion; | - |
708 | QPainterPath textDoneRegion; | - |
709 | for (int i = 0; i < selections.size(); ++i) { | - |
710 | FormatRange selection = selections.at(i); | - |
711 | const QBrush bg = selection.format.background(); | - |
712 | - | |
713 | QPainterPath region; | - |
714 | region.setFillRule(Qt::WindingFill); | - |
715 | - | |
716 | for (int line = firstLine; line < lastLine; ++line) { | - |
717 | const QScriptLine &sl = d->lines[line]; | - |
718 | QTextLine tl(line, d); | - |
719 | - | |
720 | QRectF lineRect(tl.naturalTextRect()); | - |
721 | lineRect.translate(position); | - |
722 | lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0); | - |
723 | - | |
724 | bool isLastLineInBlock = (line == d->lines.size()-1); | - |
725 | int sl_length = sl.length + (isLastLineInBlock? 1 : 0); | - |
726 | - | |
727 | - | |
728 | if (sl.from > selection.start + selection.length || sl.from + sl_length <= selection.start) | - |
729 | continue; | - |
730 | - | |
731 | const bool selectionStartInLine = sl.from <= selection.start; | - |
732 | const bool selectionEndInLine = selection.start + selection.length < sl.from + sl_length; | - |
733 | - | |
734 | if (sl.length && (selectionStartInLine || selectionEndInLine)) { | - |
735 | addSelectedRegionsToPath(d, line, position, &selection, ®ion, clipIfValid(lineRect, clip)); | - |
736 | } else { | - |
737 | region.addRect(clipIfValid(lineRect, clip)); | - |
738 | } | - |
739 | - | |
740 | if (selection.format.boolProperty(QTextFormat::FullWidthSelection)) { | - |
741 | QRectF fullLineRect(tl.rect()); | - |
742 | fullLineRect.translate(position); | - |
743 | fullLineRect.setRight((2147483647/256)); | - |
744 | if (!selectionEndInLine) | - |
745 | region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip)); | - |
746 | if (!selectionStartInLine) | - |
747 | region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip)); | - |
748 | } else if (!selectionEndInLine | - |
749 | && isLastLineInBlock | - |
750 | &&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) { | - |
751 | region.addRect(clipIfValid(QRectF(lineRect.right(), lineRect.top(), | - |
752 | lineRect.height()/4, lineRect.height()), clip)); | - |
753 | } | - |
754 | - | |
755 | } | - |
756 | { | - |
757 | const QPen oldPen = p->pen(); | - |
758 | const QBrush oldBrush = p->brush(); | - |
759 | - | |
760 | p->setPen(selection.format.penProperty(QTextFormat::OutlinePen)); | - |
761 | p->setBrush(selection.format.brushProperty(QTextFormat::BackgroundBrush)); | - |
762 | p->drawPath(region); | - |
763 | - | |
764 | p->setPen(oldPen); | - |
765 | p->setBrush(oldBrush); | - |
766 | } | - |
767 | - | |
768 | - | |
769 | - | |
770 | bool hasText = (selection.format.foreground().style() != Qt::NoBrush); | - |
771 | bool hasBackground= (selection.format.background().style() != Qt::NoBrush); | - |
772 | - | |
773 | if (hasBackground) { | - |
774 | selection.format.setProperty((QTextFormat::ForegroundBrush + 1), selection.format.property(QTextFormat::BackgroundBrush)); | - |
775 | - | |
776 | - | |
777 | selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush()); | - |
778 | selection.format.clearProperty(QTextFormat::OutlinePen); | - |
779 | } | - |
780 | - | |
781 | selection.format.setProperty(0x5012, !hasText); | - |
782 | - | |
783 | if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty()) | - |
784 | continue; | - |
785 | - | |
786 | p->save(); | - |
787 | p->setClipPath(region, Qt::IntersectClip); | - |
788 | - | |
789 | for (int line = firstLine; line < lastLine; ++line) { | - |
790 | QTextLine l(line, d); | - |
791 | l.draw(p, position, &selection); | - |
792 | } | - |
793 | p->restore(); | - |
794 | - | |
795 | if (hasText) { | - |
796 | textDoneRegion += region; | - |
797 | } else { | - |
798 | if (hasBackground) | - |
799 | textDoneRegion -= region; | - |
800 | } | - |
801 | - | |
802 | excludedRegion += region; | - |
803 | } | - |
804 | - | |
805 | QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion; | - |
806 | if (!needsTextButNoBackground.isEmpty()){ | - |
807 | p->save(); | - |
808 | p->setClipPath(needsTextButNoBackground, Qt::IntersectClip); | - |
809 | FormatRange selection; | - |
810 | selection.start = 0; | - |
811 | selection.length = 2147483647; | - |
812 | selection.format.setProperty(0x513, true); | - |
813 | for (int line = firstLine; line < lastLine; ++line) { | - |
814 | QTextLine l(line, d); | - |
815 | l.draw(p, position, &selection); | - |
816 | } | - |
817 | p->restore(); | - |
818 | } | - |
819 | - | |
820 | if (!excludedRegion.isEmpty()) { | - |
821 | p->save(); | - |
822 | QPainterPath path; | - |
823 | QRectF br = boundingRect().translated(position); | - |
824 | br.setRight((2147483647/256)); | - |
825 | if (!clip.isNull()) | - |
826 | br = br.intersected(clip); | - |
827 | path.addRect(br); | - |
828 | path -= excludedRegion; | - |
829 | p->setClipPath(path, Qt::IntersectClip); | - |
830 | } | - |
831 | - | |
832 | for (int i = firstLine; i < lastLine; ++i) { | - |
833 | QTextLine l(i, d); | - |
834 | l.draw(p, position); | - |
835 | } | - |
836 | if (!excludedRegion.isEmpty()) | - |
837 | p->restore(); | - |
838 | - | |
839 | - | |
840 | if (!d->cacheGlyphs) | - |
841 | d->freeMemory(); | - |
842 | } | - |
843 | void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const | - |
844 | { | - |
845 | drawCursor(p, pos, cursorPosition, 1); | - |
846 | } | - |
847 | void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const | - |
848 | { | - |
849 | if (d->lines.isEmpty()) | - |
850 | return; | - |
851 | - | |
852 | if (!d->layoutData) | - |
853 | d->itemize(); | - |
854 | - | |
855 | QPointF position = pos + d->position; | - |
856 | - | |
857 | cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length()); | - |
858 | int line = d->lineNumberForTextPosition(cursorPosition); | - |
859 | if (line < 0) | - |
860 | line = 0; | - |
861 | if (line >= d->lines.size()) | - |
862 | return; | - |
863 | - | |
864 | QTextLine l(line, d); | - |
865 | const QScriptLine &sl = d->lines[line]; | - |
866 | - | |
867 | qreal x = position.x() + l.cursorToX(cursorPosition); | - |
868 | - | |
869 | int itm; | - |
870 | - | |
871 | if (d->visualCursorMovement()) { | - |
872 | if (cursorPosition == sl.from + sl.length) | - |
873 | cursorPosition--; | - |
874 | itm = d->findItem(cursorPosition); | - |
875 | } else | - |
876 | itm = d->findItem(cursorPosition - 1); | - |
877 | - | |
878 | QFixed base = sl.base(); | - |
879 | QFixed descent = sl.descent; | - |
880 | bool rightToLeft = d->isRightToLeft(); | - |
881 | if (itm >= 0) { | - |
882 | const QScriptItem &si = d->layoutData->items.at(itm); | - |
883 | if (si.ascent > 0) | - |
884 | base = si.ascent; | - |
885 | if (si.descent > 0) | - |
886 | descent = si.descent; | - |
887 | rightToLeft = si.analysis.bidiLevel % 2; | - |
888 | } | - |
889 | qreal y = position.y() + (sl.y + sl.base() - base).toReal(); | - |
890 | bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing) | - |
891 | && (p->transform().type() > QTransform::TxTranslate); | - |
892 | if (toggleAntialiasing) | - |
893 | p->setRenderHint(QPainter::Antialiasing); | - |
894 | p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush()); | - |
895 | if (toggleAntialiasing) | - |
896 | p->setRenderHint(QPainter::Antialiasing, false); | - |
897 | if (d->layoutData->hasBidi) { | - |
898 | const int arrow_extent = 4; | - |
899 | int sign = rightToLeft ? -1 : 1; | - |
900 | p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2)); | - |
901 | p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2)); | - |
902 | } | - |
903 | return; | - |
904 | } | - |
905 | QRectF QTextLine::rect() const | - |
906 | { | - |
907 | const QScriptLine& sl = eng->lines[index]; | - |
908 | return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal()); | - |
909 | } | - |
910 | - | |
911 | - | |
912 | - | |
913 | - | |
914 | QRectF QTextLine::naturalTextRect() const | - |
915 | { | - |
916 | const QScriptLine& sl = eng->lines[index]; | - |
917 | QFixed x = sl.x + eng->alignLine(sl); | - |
918 | - | |
919 | QFixed width = sl.textWidth; | - |
920 | if (sl.justified) | - |
921 | width = sl.width; | - |
922 | - | |
923 | return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal()); | - |
924 | } | - |
925 | - | |
926 | - | |
927 | - | |
928 | - | |
929 | - | |
930 | - | |
931 | qreal QTextLine::x() const | - |
932 | { | - |
933 | return eng->lines[index].x.toReal(); | - |
934 | } | - |
935 | - | |
936 | - | |
937 | - | |
938 | - | |
939 | - | |
940 | - | |
941 | qreal QTextLine::y() const | - |
942 | { | - |
943 | return eng->lines[index].y.toReal(); | - |
944 | } | - |
945 | - | |
946 | - | |
947 | - | |
948 | - | |
949 | - | |
950 | - | |
951 | qreal QTextLine::width() const | - |
952 | { | - |
953 | return eng->lines[index].width.toReal(); | - |
954 | } | - |
955 | - | |
956 | - | |
957 | - | |
958 | - | |
959 | - | |
960 | - | |
961 | - | |
962 | qreal QTextLine::ascent() const | - |
963 | { | - |
964 | return eng->lines[index].ascent.toReal(); | - |
965 | } | - |
966 | - | |
967 | - | |
968 | - | |
969 | - | |
970 | - | |
971 | - | |
972 | qreal QTextLine::descent() const | - |
973 | { | - |
974 | return eng->lines[index].descent.toReal(); | - |
975 | } | - |
976 | qreal QTextLine::height() const | - |
977 | { | - |
978 | return eng->lines[index].height().ceil().toReal(); | - |
979 | } | - |
980 | qreal QTextLine::leading() const | - |
981 | { | - |
982 | return eng->lines[index].leading.toReal(); | - |
983 | } | - |
984 | void QTextLine::setLeadingIncluded(bool included) | - |
985 | { | - |
986 | eng->lines[index].leadingIncluded= included; | - |
987 | - | |
988 | } | - |
989 | bool QTextLine::leadingIncluded() const | - |
990 | { | - |
991 | return eng->lines[index].leadingIncluded; | - |
992 | } | - |
993 | - | |
994 | - | |
995 | - | |
996 | - | |
997 | - | |
998 | - | |
999 | qreal QTextLine::naturalTextWidth() const | - |
1000 | { | - |
1001 | return eng->lines[index].textWidth.toReal(); | - |
1002 | } | - |
1003 | qreal QTextLine::horizontalAdvance() const | - |
1004 | { | - |
1005 | return eng->lines[index].textAdvance.toReal(); | - |
1006 | } | - |
1007 | void QTextLine::setLineWidth(qreal width) | - |
1008 | { | - |
1009 | QScriptLine &line = eng->lines[index]; | - |
1010 | if (!eng->layoutData) { | - |
1011 | QMessageLogger(__FILE__, 15681574, __PRETTY_FUNCTION__).warning("QTextLine: Can't set a line width while not layouting."); | - |
1012 | return; | - |
1013 | } | - |
1014 | - | |
1015 | if (width > (2147483647/256)) | - |
1016 | width = (2147483647/256); | - |
1017 | - | |
1018 | line.width = QFixed::fromReal(width); | - |
1019 | if (line.length | - |
1020 | && line.textWidth <= line.width | - |
1021 | && line.from + line.length == eng->layoutData->string.length()) | - |
1022 | - | |
1023 | - | |
1024 | return; | - |
1025 | line.length = 0; | - |
1026 | line.textWidth = 0; | - |
1027 | - | |
1028 | layout_helper(2147483647); | - |
1029 | } | - |
1030 | void QTextLine::setNumColumns(int numColumns) | - |
1031 | { | - |
1032 | QScriptLine &line = eng->lines[index]; | - |
1033 | line.width = (2147483647/256); | - |
1034 | line.length = 0; | - |
1035 | line.textWidth = 0; | - |
1036 | layout_helper(numColumns); | - |
1037 | } | - |
1038 | void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth) | - |
1039 | { | - |
1040 | QScriptLine &line = eng->lines[index]; | - |
1041 | line.width = QFixed::fromReal(alignmentWidth); | - |
1042 | line.length = 0; | - |
1043 | line.textWidth = 0; | - |
1044 | layout_helper(numColumns); | - |
1045 | } | - |
1046 | - | |
1047 | - | |
1048 | - | |
1049 | - | |
1050 | - | |
1051 | - | |
1052 | - | |
1053 | namespace { | - |
1054 | - | |
1055 | struct LineBreakHelper | - |
1056 | { | - |
1057 | LineBreakHelper() | - |
1058 | : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0), | - |
1059 | manualWrap(false), whiteSpaceOrObject(true) | - |
1060 | { | - |
1061 | } | - |
1062 | - | |
1063 | - | |
1064 | QScriptLine tmpData; | - |
1065 | QScriptLine spaceData; | - |
1066 | - | |
1067 | QGlyphLayout glyphs; | - |
1068 | - | |
1069 | int glyphCount; | - |
1070 | int maxGlyphs; | - |
1071 | int currentPosition; | - |
1072 | glyph_t previousGlyph; | - |
1073 | - | |
1074 | QFixed minw; | - |
1075 | QFixed softHyphenWidth; | - |
1076 | QFixed rightBearing; | - |
1077 | QFixed minimumRightBearing; | - |
1078 | - | |
1079 | QFontEngine *fontEngine; | - |
1080 | const unsigned short *logClusters; | - |
1081 | - | |
1082 | bool manualWrap; | - |
1083 | bool whiteSpaceOrObject; | - |
1084 | - | |
1085 | bool checkFullOtherwiseExtend(QScriptLine &line); | - |
1086 | - | |
1087 | QFixed calculateNewWidth(const QScriptLine &line) const { | - |
1088 | return line.textWidth + tmpData.textWidth + spaceData.textWidth | - |
1089 | + softHyphenWidth + negativeRightBearing(); | - |
1090 | } | - |
1091 | - | |
1092 | inline glyph_t currentGlyph() const | - |
1093 | { | - |
1094 | ((!(currentPosition > 0)) ? qt_assert("currentPosition > 0",__FILE__,16681674) : qt_noop()); | - |
1095 | ((!(logClusters[currentPosition - 1] < glyphs.numGlyphs)) ? qt_assert("logClusters[currentPosition - 1] < glyphs.numGlyphs",__FILE__,16691675) : qt_noop()); | - |
1096 | - | |
1097 | return glyphs.glyphs[logClusters[currentPosition - 1]]; | - |
1098 | } | - |
1099 | - | |
1100 | inline void saveCurrentGlyph() | - |
1101 | { | - |
1102 | previousGlyph = 0; | - |
1103 | if (currentPosition > 0 && | - |
1104 | logClusters[currentPosition - 1] < glyphs.numGlyphs) { | - |
1105 | previousGlyph = currentGlyph(); | - |
1106 | } | - |
1107 | } | - |
1108 | - | |
1109 | inline void calculateRightBearing(glyph_t glyph) | - |
1110 | { | - |
1111 | qreal rb; | - |
1112 | fontEngine->getGlyphBearings(glyph, 0, &rb); | - |
1113 | - | |
1114 | - | |
1115 | - | |
1116 | - | |
1117 | - | |
1118 | rightBearing = qMin(QFixed::fromReal(rb), QFixed(0)); | - |
1119 | } | - |
1120 | - | |
1121 | inline void calculateRightBearing() | - |
1122 | { | - |
1123 | if (currentPosition <= 0) | - |
1124 | return; | - |
1125 | calculateRightBearing(currentGlyph()); | - |
1126 | } | - |
1127 | - | |
1128 | inline void calculateRightBearingForPreviousGlyph() | - |
1129 | { | - |
1130 | if (previousGlyph > 0) | - |
1131 | calculateRightBearing(previousGlyph); | - |
1132 | } | - |
1133 | - | |
1134 | static const QFixed RightBearingNotCalculated; | - |
1135 | - | |
1136 | inline void resetRightBearing() | - |
1137 | { | - |
1138 | rightBearing = RightBearingNotCalculated; | - |
1139 | } | - |
1140 | - | |
1141 | - | |
1142 | - | |
1143 | inline QFixed negativeRightBearing() const | - |
1144 | { | - |
1145 | if (rightBearing == RightBearingNotCalculated) | - |
1146 | return QFixed(0); | - |
1147 | - | |
1148 | return qAbs(rightBearing); | - |
1149 | } | - |
1150 | }; | - |
1151 | - | |
1152 | const QFixed LineBreakHelper::RightBearingNotCalculated = QFixed(1); | - |
1153 | - | |
1154 | inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) | - |
1155 | { | - |
1156 | if (0) QMessageLogger(__FILE__, 17301736, __PRETTY_FUNCTION__).debug("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); dead code: QMessageLogger(__FILE__, 1736, __PRETTY_FUNCTION__).debug("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal()); | - |
1157 | - | |
1158 | QFixed newWidth = calculateNewWidth(line); | - |
1159 | if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs)) | - |
1160 | return true; | - |
1161 | - | |
1162 | minw = qMax(minw, tmpData.textWidth); | - |
1163 | line += tmpData; | - |
1164 | line.textWidth += spaceData.textWidth; | - |
1165 | - | |
1166 | line.length += spaceData.length; | - |
1167 | tmpData.textWidth = 0; | - |
1168 | tmpData.length = 0; | - |
1169 | spaceData.textWidth = 0; | - |
1170 | spaceData.length = 0; | - |
1171 | - | |
1172 | return false; | - |
1173 | } | - |
1174 | - | |
1175 | } | - |
1176 | - | |
1177 | - | |
1178 | static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount, | - |
1179 | const QScriptItem ¤t, const unsigned short *logClusters, | - |
1180 | const QGlyphLayout &glyphs) | - |
1181 | { | - |
1182 | int glyphPosition = logClusters[pos]; | - |
1183 | do { | - |
1184 | ++pos; | - |
1185 | ++line.length; | - |
1186 | } while (pos < end && logClusters[pos] == glyphPosition); | - |
1187 | do { | - |
1188 | if (!glyphs.attributes[glyphPosition].dontPrint) | - |
1189 | line.textWidth += glyphs.advances[glyphPosition]; | - |
1190 | ++glyphPosition; | - |
1191 | } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart); | - |
1192 | - | |
1193 | ((!((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition)) ? qt_assert("(pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition",__FILE__,17671773) : qt_noop()); | - |
1194 | - | |
1195 | ++glyphCount; | - |
1196 | } | - |
1197 | - | |
1198 | - | |
1199 | - | |
1200 | void QTextLine::layout_helper(int maxGlyphs) | - |
1201 | { | - |
1202 | QScriptLine &line = eng->lines[index]; | - |
1203 | line.length = 0; | - |
1204 | line.trailingSpaces = 0; | - |
1205 | line.textWidth = 0; | - |
1206 | line.hasTrailingSpaces = false; | - |
1207 | - | |
1208 | if (!eng->layoutData->items.size() || line.from >= eng->layoutData->string.length()) { | - |
1209 | line.setDefaultHeight(eng); | - |
1210 | return; | - |
1211 | } | - |
1212 | - | |
1213 | ((!(line.from < eng->layoutData->string.length())) ? qt_assert("line.from < eng->layoutData->string.length()",__FILE__,17871793) : qt_noop()); | - |
1214 | - | |
1215 | LineBreakHelper lbh; | - |
1216 | - | |
1217 | lbh.maxGlyphs = maxGlyphs; | - |
1218 | - | |
1219 | QTextOption::WrapMode wrapMode = eng->option.wrapMode(); | - |
1220 | bool breakany = (wrapMode == QTextOption::WrapAnywhere); | - |
1221 | lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); | - |
1222 | - | |
1223 | int item = -1; | - |
1224 | int newItem = eng->findItem(line.from); | - |
1225 | ((!(newItem >= 0)) ? qt_assert("newItem >= 0",__FILE__,17991805) : qt_noop()); | - |
1226 | - | |
1227 | if (0) QMessageLogger(__FILE__, 18011807, __PRETTY_FUNCTION__).debug("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); dead code: QMessageLogger(__FILE__, 1807, __PRETTY_FUNCTION__).debug("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); | - |
1228 | - | |
1229 | Qt::Alignment alignment = eng->option.alignment(); | - |
1230 | - | |
1231 | const QCharAttributes *attributes = eng->attributes(); | - |
1232 | if (!attributes) | - |
1233 | return; | - |
1234 | lbh.currentPosition = line.from; | - |
1235 | int end = 0; | - |
1236 | lbh.logClusters = eng->layoutData->logClustersPtr; | - |
1237 | lbh.previousGlyph = 0; | - |
1238 | - | |
1239 | while (newItem < eng->layoutData->items.size()) { | - |
1240 | lbh.resetRightBearing(); | - |
1241 | lbh.softHyphenWidth = 0; | - |
1242 | if (newItem != item) { | - |
1243 | item = newItem; | - |
1244 | const QScriptItem ¤t = eng->layoutData->items[item]; | - |
1245 | if (!current.num_glyphs) { | - |
1246 | eng->shape(item); | - |
1247 | attributes = eng->attributes(); | - |
1248 | if (!attributes) | - |
1249 | return; | - |
1250 | lbh.logClusters = eng->layoutData->logClustersPtr; | - |
1251 | } | - |
1252 | lbh.currentPosition = qMax(line.from, current.position); | - |
1253 | end = current.position + eng->length(item); | - |
1254 | lbh.glyphs = eng->shapedGlyphs(¤t); | - |
1255 | QFontEngine *fontEngine = eng->fontEngine(current); | - |
1256 | if (lbh.fontEngine != fontEngine) { | - |
1257 | lbh.fontEngine = fontEngine; | - |
1258 | lbh.minimumRightBearing = qMin(QFixed(), | - |
1259 | QFixed::fromReal(fontEngine->minRightBearing())); | - |
1260 | } | - |
1261 | } | - |
1262 | const QScriptItem ¤t = eng->layoutData->items[item]; | - |
1263 | - | |
1264 | lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent, | - |
1265 | current.leading + current.ascent) - qMax(lbh.tmpData.ascent, | - |
1266 | current.ascent); | - |
1267 | lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent); | - |
1268 | lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent); | - |
1269 | - | |
1270 | if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) { | - |
1271 | lbh.whiteSpaceOrObject = true; | - |
1272 | if (lbh.checkFullOtherwiseExtend(line)) | - |
1273 | goto found; | - |
1274 | - | |
1275 | QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth; | - |
1276 | QFixed tabWidth = eng->calculateTabWidth(item, x); | - |
1277 | attributes = eng->attributes(); | - |
1278 | if (!attributes) | - |
1279 | return; | - |
1280 | lbh.logClusters = eng->layoutData->logClustersPtr; | - |
1281 | lbh.glyphs = eng->shapedGlyphs(¤t); | - |
1282 | - | |
1283 | lbh.spaceData.textWidth += tabWidth; | - |
1284 | lbh.spaceData.length++; | - |
1285 | newItem = item + 1; | - |
1286 | - | |
1287 | QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth(); | - |
1288 | lbh.glyphCount += qRound(tabWidth / averageCharWidth); | - |
1289 | - | |
1290 | if (lbh.checkFullOtherwiseExtend(line)) | - |
1291 | goto found; | - |
1292 | } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) { | - |
1293 | lbh.whiteSpaceOrObject = true; | - |
1294 | - | |
1295 | - | |
1296 | if (!line.length && !lbh.tmpData.length) | - |
1297 | line.setDefaultHeight(eng); | - |
1298 | if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) { | - |
1299 | if (lbh.checkFullOtherwiseExtend(line)) | - |
1300 | goto found; | - |
1301 | - | |
1302 | addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, | - |
1303 | current, lbh.logClusters, lbh.glyphs); | - |
1304 | } else { | - |
1305 | lbh.tmpData.length++; | - |
1306 | lbh.calculateRightBearingForPreviousGlyph(); | - |
1307 | } | - |
1308 | line += lbh.tmpData; | - |
1309 | goto found; | - |
1310 | } else if (current.analysis.flags == QScriptAnalysis::Object) { | - |
1311 | lbh.whiteSpaceOrObject = true; | - |
1312 | lbh.tmpData.length++; | - |
1313 | - | |
1314 | if (eng->block.docHandle()) { | - |
1315 | QTextInlineObject inlineObject(item, eng); | - |
1316 | eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format()); | - |
1317 | } | - |
1318 | - | |
1319 | lbh.tmpData.textWidth += current.width; | - |
1320 | - | |
1321 | newItem = item + 1; | - |
1322 | ++lbh.glyphCount; | - |
1323 | if (lbh.checkFullOtherwiseExtend(line)) | - |
1324 | goto found; | - |
1325 | } else if (attributes[lbh.currentPosition].whiteSpace | - |
1326 | && eng->layoutData->string.at(lbh.currentPosition).decompositionTag() != QChar::NoBreak) { | - |
1327 | lbh.whiteSpaceOrObject = true; | - |
1328 | while (lbh.currentPosition < end | - |
1329 | && attributes[lbh.currentPosition].whiteSpace | - |
1330 | && eng->layoutData->string.at(lbh.currentPosition).decompositionTag() != QChar::NoBreak) { | - |
1331 | addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount, | - |
1332 | current, lbh.logClusters, lbh.glyphs); | - |
1333 | } | - |
1334 | - | |
1335 | if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) { | - |
1336 | lbh.spaceData.textWidth = line.width; | - |
1337 | goto found; | - |
1338 | } | - |
1339 | } else { | - |
1340 | lbh.whiteSpaceOrObject = false; | - |
1341 | bool sb_or_ws = false; | - |
1342 | lbh.saveCurrentGlyph(); | - |
1343 | do { | - |
1344 | addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, | - |
1345 | current, lbh.logClusters, lbh.glyphs); | - |
1346 | - | |
1347 | - | |
1348 | - | |
1349 | - | |
1350 | - | |
1351 | - | |
1352 | bool isBreakableSpace = lbh.currentPosition < eng->layoutData->string.length() | - |
1353 | && attributes[lbh.currentPosition].whiteSpace | - |
1354 | && eng->layoutData->string.at(lbh.currentPosition).decompositionTag() != QChar::NoBreak; | - |
1355 | - | |
1356 | if (lbh.currentPosition >= eng->layoutData->string.length() | - |
1357 | || isBreakableSpace | - |
1358 | || attributes[lbh.currentPosition].lineBreak) { | - |
1359 | sb_or_ws = true; | - |
1360 | break; | - |
1361 | } else if (breakany && attributes[lbh.currentPosition].graphemeBoundary) { | - |
1362 | break; | - |
1363 | } | - |
1364 | } while (lbh.currentPosition < end); | - |
1365 | lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); | - |
1366 | - | |
1367 | if (lbh.currentPosition > 0 && lbh.currentPosition < end | - |
1368 | && attributes[lbh.currentPosition].lineBreak | - |
1369 | && eng->layoutData->string.at(lbh.currentPosition - 1).unicode() == QChar::SoftHyphen) { | - |
1370 | if (line.length) | - |
1371 | lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; | - |
1372 | else if (breakany) | - |
1373 | lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; | - |
1374 | } | - |
1375 | - | |
1376 | if (sb_or_ws|breakany) { | - |
1377 | - | |
1378 | - | |
1379 | - | |
1380 | - | |
1381 | - | |
1382 | - | |
1383 | - | |
1384 | QFixed previousRightBearing = lbh.rightBearing; | - |
1385 | if ((lbh.calculateNewWidth(line) + qAbs(lbh.minimumRightBearing)) > line.width) | - |
1386 | lbh.calculateRightBearing(); | - |
1387 | - | |
1388 | if (lbh.checkFullOtherwiseExtend(line)) { | - |
1389 | - | |
1390 | - | |
1391 | - | |
1392 | if (previousRightBearing != LineBreakHelper::RightBearingNotCalculated) | - |
1393 | lbh.rightBearing = previousRightBearing; | - |
1394 | else | - |
1395 | lbh.calculateRightBearingForPreviousGlyph(); | - |
1396 | - | |
1397 | if (!breakany) { | - |
1398 | line.textWidth += lbh.softHyphenWidth; | - |
1399 | } | - |
1400 | - | |
1401 | goto found; | - |
1402 | } | - |
1403 | } | - |
1404 | lbh.saveCurrentGlyph(); | - |
1405 | } | - |
1406 | if (lbh.currentPosition == end) | - |
1407 | newItem = item + 1; | - |
1408 | } | - |
1409 | if (0) QMessageLogger(__FILE__, 20092015, __PRETTY_FUNCTION__).debug("reached end of line"); dead code: QMessageLogger(__FILE__, 2015, __PRETTY_FUNCTION__).debug("reached end of line"); | - |
1410 | lbh.checkFullOtherwiseExtend(line); | - |
1411 | found: | - |
1412 | line.textAdvance = line.textWidth; | - |
1413 | - | |
1414 | - | |
1415 | if (lbh.rightBearing == LineBreakHelper::RightBearingNotCalculated && !lbh.whiteSpaceOrObject) | - |
1416 | lbh.calculateRightBearing(); | - |
1417 | - | |
1418 | - | |
1419 | line.textWidth += lbh.negativeRightBearing(); | - |
1420 | - | |
1421 | if (line.length == 0) { | - |
1422 | if (0) QMessageLogger(__FILE__, 20222028, __PRETTY_FUNCTION__).debug("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", dead code: QMessageLogger(__FILE__, 2028, __PRETTY_FUNCTION__).debug("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); | - |
1423 | lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), dead code: QMessageLogger(__FILE__, 2028, __PRETTY_FUNCTION__).debug("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); | - |
1424 | lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); dead code: QMessageLogger(__FILE__, 2028, __PRETTY_FUNCTION__).debug("no break available in line, adding temp: length %d, width %f, space: length %d, width %f", lbh.tmpData.length, lbh.tmpData.textWidth.toReal(), lbh.spaceData.length, lbh.spaceData.textWidth.toReal()); | - |
1425 | line += lbh.tmpData; | - |
1426 | } | - |
1427 | - | |
1428 | if (0) QMessageLogger(__FILE__, 20282034, __PRETTY_FUNCTION__).debug("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), dead code: QMessageLogger(__FILE__, 2034, __PRETTY_FUNCTION__).debug("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal()); | - |
1429 | line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal()); dead code: QMessageLogger(__FILE__, 2034, __PRETTY_FUNCTION__).debug("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(), line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal()); | - |
1430 | if (0) QMessageLogger(__FILE__, 20302036, __PRETTY_FUNCTION__).debug(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data()); dead code: QMessageLogger(__FILE__, 2036, __PRETTY_FUNCTION__).debug(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data()); | - |
1431 | - | |
1432 | if (lbh.manualWrap) { | - |
1433 | eng->minWidth = qMax(eng->minWidth, line.textWidth); | - |
1434 | eng->maxWidth = qMax(eng->maxWidth, line.textWidth); | - |
1435 | } else { | - |
1436 | eng->minWidth = qMax(eng->minWidth, lbh.minw); | - |
1437 | eng->maxWidth += line.textWidth; | - |
1438 | } | - |
1439 | - | |
1440 | if (line.textWidth > 0 && item < eng->layoutData->items.size()) | - |
1441 | eng->maxWidth += lbh.spaceData.textWidth; | - |
1442 | if (eng->option.flags() & QTextOption::IncludeTrailingSpaces) | - |
1443 | line.textWidth += lbh.spaceData.textWidth; | - |
1444 | if (lbh.spaceData.length) { | - |
1445 | line.trailingSpaces = lbh.spaceData.length; | - |
1446 | line.hasTrailingSpaces = true; | - |
1447 | } | - |
1448 | - | |
1449 | line.justified = false; | - |
1450 | line.gridfitted = false; | - |
1451 | - | |
1452 | if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) { | - |
1453 | if ((lbh.maxGlyphs != 2147483647 && lbh.glyphCount > lbh.maxGlyphs) | - |
1454 | || (lbh.maxGlyphs == 2147483647 && line.textWidth > line.width)) { | - |
1455 | - | |
1456 | eng->option.setWrapMode(QTextOption::WrapAnywhere); | - |
1457 | line.length = 0; | - |
1458 | line.textWidth = 0; | - |
1459 | layout_helper(lbh.maxGlyphs); | - |
1460 | eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); | - |
1461 | } | - |
1462 | } | - |
1463 | } | - |
1464 | - | |
1465 | - | |
1466 | - | |
1467 | - | |
1468 | void QTextLine::setPosition(const QPointF &pos) | - |
1469 | { | - |
1470 | eng->lines[index].x = QFixed::fromReal(pos.x()); | - |
1471 | eng->lines[index].y = QFixed::fromReal(pos.y()); | - |
1472 | } | - |
1473 | - | |
1474 | - | |
1475 | - | |
1476 | - | |
1477 | QPointF QTextLine::position() const | - |
1478 | { | - |
1479 | return QPointF(eng->lines[index].x.toReal(), eng->lines[index].y.toReal()); | - |
1480 | } | - |
1481 | int QTextLine::textStart() const | - |
1482 | { | - |
1483 | return eng->lines[index].from; | - |
1484 | } | - |
1485 | - | |
1486 | - | |
1487 | - | |
1488 | - | |
1489 | - | |
1490 | - | |
1491 | int QTextLine::textLength() const | - |
1492 | { | - |
1493 | if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators | - |
1494 | && eng->block.isValid() && index == eng->lines.count()-1) { | - |
1495 | return eng->lines[index].length - 1; | - |
1496 | } | - |
1497 | return eng->lines[index].length + eng->lines[index].trailingSpaces; | - |
1498 | } | - |
1499 | - | |
1500 | static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r) | - |
1501 | { | - |
1502 | QBrush c = chf.foreground(); | - |
1503 | if (c.style() == Qt::NoBrush) { | - |
1504 | p->setPen(defaultPen); | - |
1505 | } | - |
1506 | - | |
1507 | QBrush bg = chf.background(); | - |
1508 | if (bg.style() != Qt::NoBrush && !chf.property(0x513).toBool()) | - |
1509 | p->fillRect(QRectF(qFloor(r.x()), qFloor(r.y()), r.width(), r.height()), bg); | - |
1510 | if (c.style() != Qt::NoBrush) { | - |
1511 | p->setPen(QPen(c, 0)); | - |
1512 | } | - |
1513 | - | |
1514 | } | - |
1515 | - | |
1516 | - | |
1517 | static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, | - |
1518 | const QGlyphLayout &glyphLayout, | - |
1519 | const QPointF &pos, | - |
1520 | const QGlyphRun::GlyphRunFlags &flags, | - |
1521 | const QFixed &selectionX, | - |
1522 | const QFixed &selectionWidth, | - |
1523 | int glyphsStart, | - |
1524 | int glyphsEnd, | - |
1525 | unsigned short *logClusters, | - |
1526 | int textPosition, | - |
1527 | int textLength) | - |
1528 | { | - |
1529 | ((!(logClusters != 0)) ? qt_assert("logClusters != 0",__FILE__,21412147) : qt_noop()); | - |
1530 | - | |
1531 | QGlyphRun glyphRun; | - |
1532 | - | |
1533 | QGlyphRunPrivate *d = QGlyphRunPrivate::get(glyphRun); | - |
1534 | - | |
1535 | int rangeStart = textPosition; | - |
1536 | while (*logClusters != glyphsStart && rangeStart < textPosition + textLength) { | - |
1537 | ++logClusters; | - |
1538 | ++rangeStart; | - |
1539 | } | - |
1540 | - | |
1541 | int rangeEnd = rangeStart; | - |
1542 | while (*logClusters != glyphsEnd && rangeEnd < textPosition + textLength) { | - |
1543 | ++logClusters; | - |
1544 | ++rangeEnd; | - |
1545 | } | - |
1546 | - | |
1547 | d->textRangeStart = rangeStart; | - |
1548 | d->textRangeEnd = rangeEnd; | - |
1549 | - | |
1550 | - | |
1551 | QRawFont font; | - |
1552 | QRawFontPrivate *fontD = QRawFontPrivate::get(font); | - |
1553 | fontD->setFontEngine(fontEngine); | - |
1554 | - | |
1555 | QVarLengthArray<glyph_t> glyphsArray; | - |
1556 | QVarLengthArray<QFixedPoint> positionsArray; | - |
1557 | - | |
1558 | QTextItem::RenderFlags renderFlags; | - |
1559 | if (flags.testFlag(QGlyphRun::Overline)) | - |
1560 | renderFlags |= QTextItem::Overline; | - |
1561 | if (flags.testFlag(QGlyphRun::Underline)) | - |
1562 | renderFlags |= QTextItem::Underline; | - |
1563 | if (flags.testFlag(QGlyphRun::StrikeOut)) | - |
1564 | renderFlags |= QTextItem::StrikeOut; | - |
1565 | if (flags.testFlag(QGlyphRun::RightToLeft)) | - |
1566 | renderFlags |= QTextItem::RightToLeft; | - |
1567 | - | |
1568 | fontEngine->getGlyphPositions(glyphLayout, QTransform(), renderFlags, glyphsArray, | - |
1569 | positionsArray); | - |
1570 | ((!(glyphsArray.size() == positionsArray.size())) ? qt_assert("glyphsArray.size() == positionsArray.size()",__FILE__,21822188) : qt_noop()); | - |
1571 | - | |
1572 | qreal fontHeight = font.ascent() + font.descent(); | - |
1573 | qreal minY = 0; | - |
1574 | qreal maxY = 0; | - |
1575 | QVector<quint32> glyphs; | - |
1576 | glyphs.reserve(glyphsArray.size()); | - |
1577 | QVector<QPointF> positions; | - |
1578 | positions.reserve(glyphsArray.size()); | - |
1579 | for (int i=0; i<glyphsArray.size(); ++i) { | - |
1580 | glyphs.append(glyphsArray.at(i) & 0xffffff); | - |
1581 | - | |
1582 | QPointF position = positionsArray.at(i).toPointF() + pos; | - |
1583 | positions.append(position); | - |
1584 | - | |
1585 | if (i == 0) { | - |
1586 | maxY = minY = position.y(); | - |
1587 | } else { | - |
1588 | minY = qMin(minY, position.y()); | - |
1589 | maxY = qMax(maxY, position.y()); | - |
1590 | } | - |
1591 | } | - |
1592 | - | |
1593 | qreal height = maxY + fontHeight - minY; | - |
1594 | - | |
1595 | glyphRun.setGlyphIndexes(glyphs); | - |
1596 | glyphRun.setPositions(positions); | - |
1597 | glyphRun.setFlags(flags); | - |
1598 | glyphRun.setRawFont(font); | - |
1599 | - | |
1600 | glyphRun.setBoundingRect(QRectF(selectionX.toReal(), minY - font.ascent(), | - |
1601 | selectionWidth.toReal(), height)); | - |
1602 | - | |
1603 | return glyphRun; | - |
1604 | } | - |
1605 | QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const | - |
1606 | { | - |
1607 | const QScriptLine &line = eng->lines[index]; | - |
1608 | - | |
1609 | if (line.length == 0) | - |
1610 | return QList<QGlyphRun>(); | - |
1611 | - | |
1612 | if (from < 0) | - |
1613 | from = textStart(); | - |
1614 | - | |
1615 | if (length < 0) | - |
1616 | length = textLength(); | - |
1617 | - | |
1618 | if (length == 0) | - |
1619 | return QList<QGlyphRun>(); | - |
1620 | - | |
1621 | QTextLayout::FormatRange selection; | - |
1622 | selection.start = from; | - |
1623 | selection.length = length; | - |
1624 | - | |
1625 | QTextLineItemIterator iterator(eng, index, QPointF(), &selection); | - |
1626 | qreal y = line.y.toReal() + line.base().toReal(); | - |
1627 | QList<QGlyphRun> glyphRuns; | - |
1628 | while (!iterator.atEnd()) { | - |
1629 | QScriptItem &si = iterator.next(); | - |
1630 | if (si.analysis.flags >= QScriptAnalysis::TabOrObject) | - |
1631 | continue; | - |
1632 | - | |
1633 | if (from >= 0 && length >= 0 && (from >= iterator.itemEnd || from + length <= iterator.itemStart)) | - |
1634 | continue; | - |
1635 | - | |
1636 | QPointF pos(iterator.x.toReal(), y); | - |
1637 | - | |
1638 | QFont font; | - |
1639 | QGlyphRun::GlyphRunFlags flags; | - |
1640 | if (!eng->useRawFont) { | - |
1641 | font = eng->font(si); | - |
1642 | if (font.overline()) | - |
1643 | flags |= QGlyphRun::Overline; | - |
1644 | if (font.underline()) | - |
1645 | flags |= QGlyphRun::Underline; | - |
1646 | if (font.strikeOut()) | - |
1647 | flags |= QGlyphRun::StrikeOut; | - |
1648 | } | - |
1649 | - | |
1650 | bool rtl = false; | - |
1651 | if (si.analysis.bidiLevel % 2) { | - |
1652 | flags |= QGlyphRun::RightToLeft; | - |
1653 | rtl = true; | - |
1654 | } | - |
1655 | - | |
1656 | int relativeFrom = qMax(iterator.itemStart, from) - si.position; | - |
1657 | int relativeTo = qMin(iterator.itemEnd, from + length) - 1 - si.position; | - |
1658 | - | |
1659 | unsigned short *logClusters = eng->logClusters(&si); | - |
1660 | int glyphsStart = logClusters[relativeFrom]; | - |
1661 | int glyphsEnd = (relativeTo == iterator.itemLength) ? si.num_glyphs - 1 : logClusters[relativeTo]; | - |
1662 | - | |
1663 | int nextGlyphIndex = (relativeTo < iterator.itemLength - 1) ? logClusters[relativeTo + 1] : si.num_glyphs; | - |
1664 | if (nextGlyphIndex - 1 > glyphsEnd) | - |
1665 | glyphsEnd = nextGlyphIndex - 1; | - |
1666 | bool startsInsideLigature = relativeFrom > 0 && logClusters[relativeFrom - 1] == glyphsStart; | - |
1667 | bool endsInsideLigature = nextGlyphIndex == glyphsEnd; | - |
1668 | - | |
1669 | int itemGlyphsStart = logClusters[iterator.itemStart - si.position]; | - |
1670 | int itemGlyphsEnd = logClusters[iterator.itemEnd - 1 - si.position]; | - |
1671 | - | |
1672 | QGlyphLayout glyphLayout = eng->shapedGlyphs(&si); | - |
1673 | - | |
1674 | - | |
1675 | - | |
1676 | - | |
1677 | if (relativeFrom != (iterator.itemStart - si.position) && !rtl) { | - |
1678 | for (int i=itemGlyphsStart; i<glyphsStart; ++i) { | - |
1679 | QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); | - |
1680 | pos.rx() += (glyphLayout.advances[i] + justification).toReal(); | - |
1681 | } | - |
1682 | } else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) { | - |
1683 | for (int i=itemGlyphsEnd; i>glyphsEnd; --i) { | - |
1684 | QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); | - |
1685 | pos.rx() += (glyphLayout.advances[i] + justification).toReal(); | - |
1686 | } | - |
1687 | } | - |
1688 | - | |
1689 | glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1); | - |
1690 | - | |
1691 | QFixed x; | - |
1692 | QFixed width; | - |
1693 | iterator.getSelectionBounds(&x, &width); | - |
1694 | - | |
1695 | if (glyphLayout.numGlyphs > 0) { | - |
1696 | QFontEngine *mainFontEngine; | - |
1697 | - | |
1698 | if (eng->useRawFont && eng->rawFont.isValid()) | - |
1699 | mainFontEngine= eng->fontEngine(si); | - |
1700 | else | - |
1701 | - | |
1702 | mainFontEngine = font.d->engineForScript(si.analysis.script); | - |
1703 | - | |
1704 | if (mainFontEngine->type() == QFontEngine::Multi) { | - |
1705 | QFontEngineMulti *multiFontEngine = static_cast<QFontEngineMulti *>(mainFontEngine); | - |
1706 | int start = rtl ? glyphLayout.numGlyphs : 0; | - |
1707 | int end = start - 1; | - |
1708 | int which = glyphLayout.glyphs[rtl ? start - 1 : end + 1] >> 24; | - |
1709 | for (; (rtl && start > 0) || (!rtl && end < glyphLayout.numGlyphs - 1); | - |
1710 | rtl ? --start : ++end) { | - |
1711 | const int e = glyphLayout.glyphs[rtl ? start - 1 : end + 1] >> 24; | - |
1712 | if (e == which) | - |
1713 | continue; | - |
1714 | - | |
1715 | QGlyphLayout subLayout = glyphLayout.mid(start, end - start + 1); | - |
1716 | multiFontEngine->ensureEngineAt(which); | - |
1717 | - | |
1718 | QGlyphRun::GlyphRunFlags subFlags = flags; | - |
1719 | if (start == 0 && startsInsideLigature) | - |
1720 | subFlags |= QGlyphRun::SplitLigature; | - |
1721 | - | |
1722 | glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which), | - |
1723 | subLayout, | - |
1724 | pos, | - |
1725 | subFlags, | - |
1726 | x, | - |
1727 | width, | - |
1728 | glyphsStart + start, | - |
1729 | glyphsStart + end, | - |
1730 | logClusters + relativeFrom, | - |
1731 | relativeFrom + si.position, | - |
1732 | relativeTo - relativeFrom + 1)); | - |
1733 | for (int i = 0; i < subLayout.numGlyphs; ++i) { | - |
1734 | QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6); | - |
1735 | pos.rx() += (subLayout.advances[i] + justification).toReal(); | - |
1736 | } | - |
1737 | - | |
1738 | if (rtl) | - |
1739 | end = start - 1; | - |
1740 | else | - |
1741 | start = end + 1; | - |
1742 | which = e; | - |
1743 | } | - |
1744 | - | |
1745 | QGlyphLayout subLayout = glyphLayout.mid(start, end - start + 1); | - |
1746 | multiFontEngine->ensureEngineAt(which); | - |
1747 | - | |
1748 | QGlyphRun::GlyphRunFlags subFlags = flags; | - |
1749 | if ((start == 0 && startsInsideLigature) || endsInsideLigature) | - |
1750 | subFlags |= QGlyphRun::SplitLigature; | - |
1751 | - | |
1752 | QGlyphRun glyphRun = glyphRunWithInfo(multiFontEngine->engine(which), | - |
1753 | subLayout, | - |
1754 | pos, | - |
1755 | subFlags, | - |
1756 | x, | - |
1757 | width, | - |
1758 | glyphsStart + start, | - |
1759 | glyphsStart + end, | - |
1760 | logClusters + relativeFrom, | - |
1761 | relativeFrom + si.position, | - |
1762 | relativeTo - relativeFrom + 1); | - |
1763 | if (!glyphRun.isEmpty()) | - |
1764 | glyphRuns.append(glyphRun); | - |
1765 | } else { | - |
1766 | if (startsInsideLigature || endsInsideLigature) | - |
1767 | flags |= QGlyphRun::SplitLigature; | - |
1768 | QGlyphRun glyphRun = glyphRunWithInfo(mainFontEngine, | - |
1769 | glyphLayout, | - |
1770 | pos, | - |
1771 | flags, | - |
1772 | x, | - |
1773 | width, | - |
1774 | glyphsStart, | - |
1775 | glyphsEnd, | - |
1776 | logClusters + relativeFrom, | - |
1777 | relativeFrom + si.position, | - |
1778 | relativeTo - relativeFrom + 1); | - |
1779 | if (!glyphRun.isEmpty()) | - |
1780 | glyphRuns.append(glyphRun); | - |
1781 | } | - |
1782 | } | - |
1783 | } | - |
1784 | - | |
1785 | return glyphRuns; | - |
1786 | } | - |
1787 | void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const | - |
1788 | { | - |
1789 | - | |
1790 | - | |
1791 | ((!(!eng->useRawFont)) ? qt_assert("!eng->useRawFont",__FILE__,24252431) : qt_noop()); | - |
1792 | - | |
1793 | const QScriptLine &line = eng->lines[index]; | - |
1794 | QPen pen = p->pen(); | - |
1795 | - | |
1796 | bool noText = (selection && selection->format.property(0x5012).toBool()); | - |
1797 | - | |
1798 | if (!line.length) { | - |
1799 | if (selection | - |
1800 | && selection->start <= line.from | - |
1801 | && selection->start + selection->length > line.from) { | - |
1802 | - | |
1803 | const qreal lineHeight = line.height().toReal(); | - |
1804 | QRectF r(pos.x() + line.x.toReal(), pos.y() + line.y.toReal(), | - |
1805 | lineHeight / 2, QFontMetrics(eng->font()).width(QLatin1Char(' '))); | - |
1806 | setPenAndDrawBackground(p, QPen(), selection->format, r); | - |
1807 | p->setPen(pen); | - |
1808 | } | - |
1809 | return; | - |
1810 | } | - |
1811 | - | |
1812 | - | |
1813 | QTextLineItemIterator iterator(eng, index, pos, selection); | - |
1814 | QFixed lineBase = line.base(); | - |
1815 | eng->clearDecorations(); | - |
1816 | eng->enableDelayDecorations(); | - |
1817 | - | |
1818 | const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase; | - |
1819 | - | |
1820 | bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors); | - |
1821 | while (!iterator.atEnd()) { | - |
1822 | QScriptItem &si = iterator.next(); | - |
1823 | - | |
1824 | if (selection && selection->start >= 0 && iterator.isOutsideSelection()) | - |
1825 | continue; | - |
1826 | - | |
1827 | if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator | - |
1828 | && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) | - |
1829 | continue; | - |
1830 | - | |
1831 | QFixed itemBaseLine = y; | - |
1832 | QFont f = eng->font(si); | - |
1833 | QTextCharFormat format; | - |
1834 | - | |
1835 | if (eng->hasFormats() || selection) { | - |
1836 | format = eng->format(&si); | - |
1837 | if (suppressColors) { | - |
1838 | format.clearForeground(); | - |
1839 | format.clearBackground(); | - |
1840 | format.clearProperty(QTextFormat::TextUnderlineColor); | - |
1841 | } | - |
1842 | if (selection) | - |
1843 | format.merge(selection->format); | - |
1844 | - | |
1845 | setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(), | - |
1846 | iterator.itemWidth.toReal(), line.height().toReal())); | - |
1847 | - | |
1848 | QTextCharFormat::VerticalAlignment valign = format.verticalAlignment(); | - |
1849 | if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) { | - |
1850 | QFontEngine *fe = f.d->engineForScript(si.analysis.script); | - |
1851 | QFixed height = fe->ascent() + fe->descent(); | - |
1852 | if (valign == QTextCharFormat::AlignSubScript) | - |
1853 | itemBaseLine += height / 6; | - |
1854 | else if (valign == QTextCharFormat::AlignSuperScript) | - |
1855 | itemBaseLine -= height / 2; | - |
1856 | } | - |
1857 | } | - |
1858 | - | |
1859 | if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { | - |
1860 | - | |
1861 | if (eng->hasFormats()) { | - |
1862 | p->save(); | - |
1863 | if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) { | - |
1864 | QFixed itemY = y - si.ascent; | - |
1865 | if (format.verticalAlignment() == QTextCharFormat::AlignTop) { | - |
1866 | itemY = y - lineBase; | - |
1867 | } | - |
1868 | - | |
1869 | QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal()); | - |
1870 | - | |
1871 | eng->docLayout()->drawInlineObject(p, itemRect, | - |
1872 | QTextInlineObject(iterator.item, eng), | - |
1873 | si.position + eng->block.position(), | - |
1874 | format); | - |
1875 | if (selection) { | - |
1876 | QBrush bg = format.brushProperty((QTextFormat::ForegroundBrush + 1)); | - |
1877 | if (bg.style() != Qt::NoBrush) { | - |
1878 | QColor c = bg.color(); | - |
1879 | c.setAlpha(128); | - |
1880 | p->fillRect(itemRect, c); | - |
1881 | } | - |
1882 | } | - |
1883 | } else { | - |
1884 | QFont f = eng->font(si); | - |
1885 | QTextItemInt gf(si, &f, format); | - |
1886 | gf.chars = 0; | - |
1887 | gf.num_chars = 0; | - |
1888 | gf.width = iterator.itemWidth; | - |
1889 | QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng); | - |
1890 | if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) { | - |
1891 | QChar visualTab(0x2192); | - |
1892 | int w = QFontMetrics(f).width(visualTab); | - |
1893 | qreal x = iterator.itemWidth.toReal() - w; | - |
1894 | if (x < 0) | - |
1895 | p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(), | - |
1896 | iterator.itemWidth.toReal(), line.height().toReal()), | - |
1897 | Qt::IntersectClip); | - |
1898 | else | - |
1899 | x /= 2; | - |
1900 | p->drawText(QPointF(iterator.x.toReal() + x, | - |
1901 | y.toReal()), visualTab); | - |
1902 | } | - |
1903 | - | |
1904 | } | - |
1905 | p->restore(); | - |
1906 | } | - |
1907 | - | |
1908 | continue; | - |
1909 | } | - |
1910 | - | |
1911 | unsigned short *logClusters = eng->logClusters(&si); | - |
1912 | QGlyphLayout glyphs = eng->shapedGlyphs(&si); | - |
1913 | - | |
1914 | QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart), | - |
1915 | &f, eng->layoutData->string.unicode() + iterator.itemStart, | - |
1916 | iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format); | - |
1917 | gf.logClusters = logClusters + iterator.itemStart - si.position; | - |
1918 | gf.width = iterator.itemWidth; | - |
1919 | gf.justified = line.justified; | - |
1920 | gf.initWithScriptItem(si); | - |
1921 | - | |
1922 | ((!(gf.fontEngine)) ? qt_assert("gf.fontEngine",__FILE__,25562562) : qt_noop()); | - |
1923 | - | |
1924 | QPointF pos(iterator.x.toReal(), itemBaseLine.toReal()); | - |
1925 | if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) { | - |
1926 | QPainterPath path; | - |
1927 | path.setFillRule(Qt::WindingFill); | - |
1928 | - | |
1929 | if (gf.glyphs.numGlyphs) | - |
1930 | gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags); | - |
1931 | if (gf.flags) { | - |
1932 | const QFontEngine *fe = gf.fontEngine; | - |
1933 | const qreal lw = fe->lineThickness().toReal(); | - |
1934 | if (gf.flags & QTextItem::Underline) { | - |
1935 | qreal offs = fe->underlinePosition().toReal(); | - |
1936 | path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw); | - |
1937 | } | - |
1938 | if (gf.flags & QTextItem::Overline) { | - |
1939 | qreal offs = fe->ascent().toReal() + 1; | - |
1940 | path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw); | - |
1941 | } | - |
1942 | if (gf.flags & QTextItem::StrikeOut) { | - |
1943 | qreal offs = fe->ascent().toReal() / 3; | - |
1944 | path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw); | - |
1945 | } | - |
1946 | } | - |
1947 | - | |
1948 | p->save(); | - |
1949 | p->setRenderHint(QPainter::Antialiasing); | - |
1950 | - | |
1951 | - | |
1952 | if (p->pen().style() == Qt::NoPen) | - |
1953 | p->setBrush(Qt::NoBrush); | - |
1954 | else | - |
1955 | p->setBrush(p->pen().brush()); | - |
1956 | - | |
1957 | p->setPen(format.textOutline()); | - |
1958 | p->drawPath(path); | - |
1959 | p->restore(); | - |
1960 | } else { | - |
1961 | if (noText) | - |
1962 | gf.glyphs.numGlyphs = 0; | - |
1963 | QPainterPrivate::get(p)->drawTextItem(pos, gf, eng); | - |
1964 | } | - |
1965 | - | |
1966 | if (si.analysis.flags == QScriptAnalysis::Space | - |
1967 | && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) { | - |
1968 | QBrush c = format.foreground(); | - |
1969 | if (c.style() != Qt::NoBrush) | - |
1970 | p->setPen(c.color()); | - |
1971 | QChar visualSpace((ushort)0xb7); | - |
1972 | p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace); | - |
1973 | p->setPen(pen); | - |
1974 | } | - |
1975 | } | - |
1976 | eng->drawDecorations(p); | - |
1977 | - | |
1978 | if (eng->hasFormats()) | - |
1979 | p->setPen(pen); | - |
1980 | } | - |
1981 | qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const | - |
1982 | { | - |
1983 | const QScriptLine &line = eng->lines[index]; | - |
1984 | bool lastLine = index >= eng->lines.size() - 1; | - |
1985 | - | |
1986 | QFixed x = line.x + eng->alignLine(line) - eng->leadingSpaceWidth(line); | - |
1987 | - | |
1988 | if (!eng->layoutData) | - |
1989 | eng->itemize(); | - |
1990 | if (!eng->layoutData->items.size()) { | - |
1991 | *cursorPos = line.from; | - |
1992 | return x.toReal(); | - |
1993 | } | - |
1994 | - | |
1995 | int lineEnd = line.from + line.length + line.trailingSpaces; | - |
1996 | int pos = qBound(line.from, *cursorPos, lineEnd); | - |
1997 | int itm; | - |
1998 | const QCharAttributes *attributes = eng->attributes(); | - |
1999 | if (!attributes) { | - |
2000 | *cursorPos = line.from; | - |
2001 | return x.toReal(); | - |
2002 | } | - |
2003 | while (pos < lineEnd && !attributes[pos].graphemeBoundary) | - |
2004 | pos++; | - |
2005 | if (pos == lineEnd) { | - |
2006 | - | |
2007 | itm = eng->findItem(pos-1); | - |
2008 | } | - |
2009 | else | - |
2010 | itm = eng->findItem(pos); | - |
2011 | if (itm < 0) { | - |
2012 | *cursorPos = line.from; | - |
2013 | return x.toReal(); | - |
2014 | } | - |
2015 | eng->shapeLine(line); | - |
2016 | - | |
2017 | const QScriptItem *si = &eng->layoutData->items[itm]; | - |
2018 | if (!si->num_glyphs) | - |
2019 | eng->shape(itm); | - |
2020 | - | |
2021 | const int l = eng->length(itm); | - |
2022 | pos = qBound(0, pos - si->position, l); | - |
2023 | - | |
2024 | QGlyphLayout glyphs = eng->shapedGlyphs(si); | - |
2025 | unsigned short *logClusters = eng->logClusters(si); | - |
2026 | ((!(logClusters)) ? qt_assert("logClusters",__FILE__,26772683) : qt_noop()); | - |
2027 | - | |
2028 | int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; | - |
2029 | if (edge == Trailing && glyph_pos < si->num_glyphs) { | - |
2030 | - | |
2031 | glyph_pos++; | - |
2032 | while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart) | - |
2033 | glyph_pos++; | - |
2034 | } | - |
2035 | - | |
2036 | bool reverse = si->analysis.bidiLevel % 2; | - |
2037 | - | |
2038 | - | |
2039 | - | |
2040 | - | |
2041 | int firstItem = eng->findItem(line.from); | - |
2042 | int lastItem = eng->findItem(lineEnd - 1, itm); | - |
2043 | int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0; | - |
2044 | - | |
2045 | QVarLengthArray<int> visualOrder(nItems); | - |
2046 | QVarLengthArray<uchar> levels(nItems); | - |
2047 | for (int i = 0; i < nItems; ++i) | - |
2048 | levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; | - |
2049 | QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); | - |
2050 | - | |
2051 | for (int i = 0; i < nItems; ++i) { | - |
2052 | int item = visualOrder[i]+firstItem; | - |
2053 | if (item == itm) | - |
2054 | break; | - |
2055 | QScriptItem &si = eng->layoutData->items[item]; | - |
2056 | if (!si.num_glyphs) | - |
2057 | eng->shape(item); | - |
2058 | - | |
2059 | if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { | - |
2060 | x += si.width; | - |
2061 | continue; | - |
2062 | } | - |
2063 | - | |
2064 | const int itemLength = eng->length(item); | - |
2065 | int start = qMax(line.from, si.position); | - |
2066 | int end = qMin(lineEnd, si.position + itemLength); | - |
2067 | - | |
2068 | logClusters = eng->logClusters(&si); | - |
2069 | - | |
2070 | int gs = logClusters[start-si.position]; | - |
2071 | int ge = (end == si.position + itemLength) ? si.num_glyphs-1 : logClusters[end-si.position-1]; | - |
2072 | - | |
2073 | QGlyphLayout glyphs = eng->shapedGlyphs(&si); | - |
2074 | - | |
2075 | while (gs <= ge) { | - |
2076 | x += glyphs.effectiveAdvance(gs); | - |
2077 | ++gs; | - |
2078 | } | - |
2079 | } | - |
2080 | - | |
2081 | logClusters = eng->logClusters(si); | - |
2082 | glyphs = eng->shapedGlyphs(si); | - |
2083 | if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { | - |
2084 | if (pos == (reverse ? 0 : l)) | - |
2085 | x += si->width; | - |
2086 | } else { | - |
2087 | bool rtl = eng->isRightToLeft(); | - |
2088 | bool visual = eng->visualCursorMovement(); | - |
2089 | int end = qMin(lineEnd, si->position + l) - si->position; | - |
2090 | if (reverse) { | - |
2091 | int glyph_end = end == l ? si->num_glyphs : logClusters[end]; | - |
2092 | int glyph_start = glyph_pos; | - |
2093 | if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem))) | - |
2094 | glyph_start++; | - |
2095 | for (int i = glyph_end - 1; i >= glyph_start; i--) | - |
2096 | x += glyphs.effectiveAdvance(i); | - |
2097 | } else { | - |
2098 | int start = qMax(line.from - si->position, 0); | - |
2099 | int glyph_start = logClusters[start]; | - |
2100 | int glyph_end = glyph_pos; | - |
2101 | if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem)) | - |
2102 | glyph_end--; | - |
2103 | for (int i = glyph_start; i <= glyph_end; i++) | - |
2104 | x += glyphs.effectiveAdvance(i); | - |
2105 | } | - |
2106 | x += eng->offsetInLigature(si, pos, end, glyph_pos); | - |
2107 | } | - |
2108 | - | |
2109 | if (eng->option.wrapMode() != QTextOption::NoWrap && x > line.x + line.width) | - |
2110 | x = line.x + line.width; | - |
2111 | if (eng->option.wrapMode() != QTextOption::NoWrap && x < 0) | - |
2112 | x = 0; | - |
2113 | - | |
2114 | *cursorPos = pos + si->position; | - |
2115 | return x.toReal(); | - |
2116 | } | - |
2117 | int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const | - |
2118 | { | - |
2119 | QFixed x = QFixed::fromReal(_x); | - |
2120 | const QScriptLine &line = eng->lines[index]; | - |
2121 | bool lastLine = index >= eng->lines.size() - 1; | - |
2122 | int lineNum = index; | - |
2123 | - | |
2124 | if (!eng->layoutData) | - |
2125 | eng->itemize(); | - |
2126 | - | |
2127 | int line_length = textLength(); | - |
2128 | - | |
2129 | if (!line_length) | - |
2130 | return line.from; | - |
2131 | - | |
2132 | int firstItem = eng->findItem(line.from); | - |
2133 | int lastItem = eng->findItem(line.from + line_length - 1, firstItem); | - |
2134 | int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0; | - |
2135 | - | |
2136 | if (!nItems) | - |
2137 | return 0; | - |
2138 | - | |
2139 | x -= line.x; | - |
2140 | x -= eng->alignLine(line); | - |
2141 | - | |
2142 | - | |
2143 | QVarLengthArray<int> visualOrder(nItems); | - |
2144 | QVarLengthArray<unsigned char> levels(nItems); | - |
2145 | for (int i = 0; i < nItems; ++i) | - |
2146 | levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; | - |
2147 | QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); | - |
2148 | - | |
2149 | bool visual = eng->visualCursorMovement(); | - |
2150 | if (x <= 0) { | - |
2151 | - | |
2152 | int item = visualOrder[0]+firstItem; | - |
2153 | QScriptItem &si = eng->layoutData->items[item]; | - |
2154 | if (!si.num_glyphs) | - |
2155 | eng->shape(item); | - |
2156 | int pos = si.position; | - |
2157 | if (si.analysis.bidiLevel % 2) | - |
2158 | pos += eng->length(item); | - |
2159 | pos = qMax(line.from, pos); | - |
2160 | pos = qMin(line.from + line_length, pos); | - |
2161 | return pos; | - |
2162 | } else if (x < line.textWidth | - |
2163 | || (line.justified && x < line.width)) { | - |
2164 | - | |
2165 | QFixed pos; | - |
2166 | bool rtl = eng->isRightToLeft(); | - |
2167 | - | |
2168 | eng->shapeLine(line); | - |
2169 | QVector<int> insertionPoints; | - |
2170 | if (visual && rtl) | - |
2171 | eng->insertionPointsForLine(lineNum, insertionPoints); | - |
2172 | int nchars = 0; | - |
2173 | for (int i = 0; i < nItems; ++i) { | - |
2174 | int item = visualOrder[i]+firstItem; | - |
2175 | QScriptItem &si = eng->layoutData->items[item]; | - |
2176 | int item_length = eng->length(item); | - |
2177 | - | |
2178 | - | |
2179 | int start = qMax(line.from - si.position, 0); | - |
2180 | int end = qMin(line.from + line_length - si.position, item_length); | - |
2181 | - | |
2182 | unsigned short *logClusters = eng->logClusters(&si); | - |
2183 | - | |
2184 | int gs = logClusters[start]; | - |
2185 | int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1; | - |
2186 | QGlyphLayout glyphs = eng->shapedGlyphs(&si); | - |
2187 | - | |
2188 | QFixed item_width = 0; | - |
2189 | if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { | - |
2190 | item_width = si.width; | - |
2191 | } else { | - |
2192 | int g = gs; | - |
2193 | while (g <= ge) { | - |
2194 | item_width += glyphs.effectiveAdvance(g); | - |
2195 | ++g; | - |
2196 | } | - |
2197 | } | - |
2198 | - | |
2199 | - | |
2200 | if (pos + item_width < x) { | - |
2201 | pos += item_width; | - |
2202 | nchars += end; | - |
2203 | continue; | - |
2204 | } | - |
2205 | - | |
2206 | if (si.analysis.flags >= QScriptAnalysis::TabOrObject) { | - |
2207 | if (cpos == QTextLine::CursorOnCharacter) | - |
2208 | return si.position; | - |
2209 | bool left_half = (x - pos) < item_width/2; | - |
2210 | - | |
2211 | if (bool(si.analysis.bidiLevel % 2) != left_half) | - |
2212 | return si.position; | - |
2213 | return si.position + 1; | - |
2214 | } | - |
2215 | - | |
2216 | int glyph_pos = -1; | - |
2217 | QFixed edge; | - |
2218 | - | |
2219 | if (cpos == QTextLine::CursorOnCharacter) { | - |
2220 | if (si.analysis.bidiLevel % 2) { | - |
2221 | pos += item_width; | - |
2222 | glyph_pos = gs; | - |
2223 | while (gs <= ge) { | - |
2224 | if (glyphs.attributes[gs].clusterStart) { | - |
2225 | if (pos < x) | - |
2226 | break; | - |
2227 | glyph_pos = gs; | - |
2228 | edge = pos; | - |
2229 | } | - |
2230 | pos -= glyphs.effectiveAdvance(gs); | - |
2231 | ++gs; | - |
2232 | } | - |
2233 | } else { | - |
2234 | glyph_pos = gs; | - |
2235 | while (gs <= ge) { | - |
2236 | if (glyphs.attributes[gs].clusterStart) { | - |
2237 | if (pos > x) | - |
2238 | break; | - |
2239 | glyph_pos = gs; | - |
2240 | edge = pos; | - |
2241 | } | - |
2242 | pos += glyphs.effectiveAdvance(gs); | - |
2243 | ++gs; | - |
2244 | } | - |
2245 | } | - |
2246 | } else { | - |
2247 | QFixed dist = 2147483647/256; | - |
2248 | if (si.analysis.bidiLevel % 2) { | - |
2249 | if (!visual || rtl || (lastLine && i == nItems - 1)) { | - |
2250 | pos += item_width; | - |
2251 | while (gs <= ge) { | - |
2252 | if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { | - |
2253 | glyph_pos = gs; | - |
2254 | edge = pos; | - |
2255 | dist = qAbs(x-pos); | - |
2256 | } | - |
2257 | pos -= glyphs.effectiveAdvance(gs); | - |
2258 | ++gs; | - |
2259 | } | - |
2260 | } else { | - |
2261 | while (ge >= gs) { | - |
2262 | if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) { | - |
2263 | glyph_pos = ge; | - |
2264 | edge = pos; | - |
2265 | dist = qAbs(x-pos); | - |
2266 | } | - |
2267 | pos += glyphs.effectiveAdvance(ge); | - |
2268 | --ge; | - |
2269 | } | - |
2270 | } | - |
2271 | } else { | - |
2272 | if (!visual || !rtl || (lastLine && i == 0)) { | - |
2273 | while (gs <= ge) { | - |
2274 | if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { | - |
2275 | glyph_pos = gs; | - |
2276 | edge = pos; | - |
2277 | dist = qAbs(x-pos); | - |
2278 | } | - |
2279 | pos += glyphs.effectiveAdvance(gs); | - |
2280 | ++gs; | - |
2281 | } | - |
2282 | } else { | - |
2283 | QFixed oldPos = pos; | - |
2284 | while (gs <= ge) { | - |
2285 | pos += glyphs.effectiveAdvance(gs); | - |
2286 | if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { | - |
2287 | glyph_pos = gs; | - |
2288 | edge = pos; | - |
2289 | dist = qAbs(x-pos); | - |
2290 | } | - |
2291 | ++gs; | - |
2292 | } | - |
2293 | pos = oldPos; | - |
2294 | } | - |
2295 | } | - |
2296 | if (qAbs(x-pos) < dist) { | - |
2297 | if (visual) { | - |
2298 | if (!rtl && i < nItems - 1) { | - |
2299 | nchars += end; | - |
2300 | continue; | - |
2301 | } | - |
2302 | if (rtl && nchars > 0) | - |
2303 | return insertionPoints[lastLine ? nchars : nchars - 1]; | - |
2304 | } | - |
2305 | return eng->positionInLigature(&si, end, x, pos, -1, | - |
2306 | cpos == QTextLine::CursorOnCharacter); | - |
2307 | } | - |
2308 | } | - |
2309 | ((!(glyph_pos != -1)) ? qt_assert("glyph_pos != -1",__FILE__,29702976) : qt_noop()); | - |
2310 | return eng->positionInLigature(&si, end, x, edge, glyph_pos, | - |
2311 | cpos == QTextLine::CursorOnCharacter); | - |
2312 | } | - |
2313 | } | - |
2314 | - | |
2315 | - | |
2316 | int item = visualOrder[nItems-1]+firstItem; | - |
2317 | QScriptItem &si = eng->layoutData->items[item]; | - |
2318 | if (!si.num_glyphs) | - |
2319 | eng->shape(item); | - |
2320 | int pos = si.position; | - |
2321 | if (!(si.analysis.bidiLevel % 2)) | - |
2322 | pos += eng->length(item); | - |
2323 | pos = qMax(line.from, pos); | - |
2324 | - | |
2325 | int maxPos = line.from + line_length; | - |
2326 | - | |
2327 | - | |
2328 | - | |
2329 | - | |
2330 | - | |
2331 | - | |
2332 | if (this->index < eng->lines.count() - 1) | - |
2333 | --maxPos; | - |
2334 | - | |
2335 | pos = qMin(pos, maxPos); | - |
2336 | return pos; | - |
2337 | } | - |
2338 | - | |
2339 | - | |
Switch to Source code | Preprocessed file |