QtGui: make some constructors explicit
[profile/ivi/qtbase.git] / src / gui / text / qtextlayout.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qtextlayout.h"
43 #include "qtextengine_p.h"
44
45 #include <qthread.h>
46 #include <qfont.h>
47 #include <qpainter.h>
48 #include <qvarlengtharray.h>
49 #include <qtextformat.h>
50 #include <qabstracttextdocumentlayout.h>
51 #include "qtextdocument_p.h"
52 #include "qtextformat_p.h"
53 #include "qpainterpath.h"
54 #include "qglyphrun.h"
55 #include "qglyphrun_p.h"
56 #include "qrawfont.h"
57 #include "qrawfont_p.h"
58 #include <limits.h>
59
60 #include <qdebug.h>
61
62 #include "qfontengine_p.h"
63 #include <private/qpainter_p.h>
64
65 QT_BEGIN_NAMESPACE
66
67 #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1)
68 #define SuppressText 0x5012
69 #define SuppressBackground 0x513
70
71 /*!
72     \class QTextLayout::FormatRange
73     \reentrant
74
75     \brief The QTextLayout::FormatRange structure is used to apply extra formatting information
76     for a specified area in the text layout's content.
77
78     \sa QTextLayout::setAdditionalFormats(), QTextLayout::draw()
79 */
80
81 /*!
82     \variable QTextLayout::FormatRange::start
83     Specifies the beginning of the format range within the text layout's text.
84 */
85
86 /*!
87     \variable QTextLayout::FormatRange::length
88     Specifies the numer of characters the format range spans.
89 */
90
91 /*!
92     \variable QTextLayout::FormatRange::format
93     Specifies the format to apply.
94 */
95
96 /*!
97     \class QTextInlineObject
98     \reentrant
99
100     \brief The QTextInlineObject class represents an inline object in
101     a QTextLayout.
102
103     \ingroup richtext-processing
104
105     This class is only used if the text layout is used to lay out
106     parts of a QTextDocument.
107
108     The inline object has various attributes that can be set, for
109     example using, setWidth(), setAscent(), and setDescent(). The
110     rectangle it occupies is given by rect(), and its direction by
111     isRightToLeft(). Its position in the text layout is given by at(),
112     and its format is given by format().
113 */
114
115 /*!
116     \fn QTextInlineObject::QTextInlineObject(int i, QTextEngine *e)
117
118     Creates a new inline object for the item at position \a i in the
119     text engine \a e.
120 */
121
122 /*!
123     \fn QTextInlineObject::QTextInlineObject()
124
125     \internal
126 */
127
128 /*!
129     \fn bool QTextInlineObject::isValid() const
130
131     Returns true if this inline object is valid; otherwise returns
132     false.
133 */
134
135 /*!
136     Returns the inline object's rectangle.
137
138     \sa ascent(), descent(), width()
139 */
140 QRectF QTextInlineObject::rect() const
141 {
142     QScriptItem& si = eng->layoutData->items[itm];
143     return QRectF(0, -si.ascent.toReal(), si.width.toReal(), si.height().toReal());
144 }
145
146 /*!
147     Returns the inline object's width.
148
149     \sa ascent(), descent(), rect()
150 */
151 qreal QTextInlineObject::width() const
152 {
153     return eng->layoutData->items[itm].width.toReal();
154 }
155
156 /*!
157     Returns the inline object's ascent.
158
159     \sa descent(), width(), rect()
160 */
161 qreal QTextInlineObject::ascent() const
162 {
163     return eng->layoutData->items[itm].ascent.toReal();
164 }
165
166 /*!
167     Returns the inline object's descent.
168
169     \sa ascent(), width(), rect()
170 */
171 qreal QTextInlineObject::descent() const
172 {
173     return eng->layoutData->items[itm].descent.toReal();
174 }
175
176 /*!
177     Returns the inline object's total height. This is equal to
178     ascent() + descent() + 1.
179
180     \sa ascent(), descent(), width(), rect()
181 */
182 qreal QTextInlineObject::height() const
183 {
184     return eng->layoutData->items[itm].height().toReal();
185 }
186
187 /*!
188     Sets the inline object's width to \a w.
189
190     \sa width(), ascent(), descent(), rect()
191 */
192 void QTextInlineObject::setWidth(qreal w)
193 {
194     eng->layoutData->items[itm].width = QFixed::fromReal(w);
195 }
196
197 /*!
198     Sets the inline object's ascent to \a a.
199
200     \sa ascent(), setDescent(), width(), rect()
201 */
202 void QTextInlineObject::setAscent(qreal a)
203 {
204     eng->layoutData->items[itm].ascent = QFixed::fromReal(a);
205 }
206
207 /*!
208     Sets the inline object's decent to \a d.
209
210     \sa descent(), setAscent(), width(), rect()
211 */
212 void QTextInlineObject::setDescent(qreal d)
213 {
214     eng->layoutData->items[itm].descent = QFixed::fromReal(d);
215 }
216
217 /*!
218     The position of the inline object within the text layout.
219 */
220 int QTextInlineObject::textPosition() const
221 {
222     return eng->layoutData->items[itm].position;
223 }
224
225 /*!
226     Returns an integer describing the format of the inline object
227     within the text layout.
228 */
229 int QTextInlineObject::formatIndex() const
230 {
231     return eng->formatIndex(&eng->layoutData->items[itm]);
232 }
233
234 /*!
235     Returns format of the inline object within the text layout.
236 */
237 QTextFormat QTextInlineObject::format() const
238 {
239     if (!eng->block.docHandle())
240         return QTextFormat();
241     return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm]));
242 }
243
244 /*!
245     Returns if the object should be laid out right-to-left or left-to-right.
246 */
247 Qt::LayoutDirection QTextInlineObject::textDirection() const
248 {
249     return (eng->layoutData->items[itm].analysis.bidiLevel % 2 ? Qt::RightToLeft : Qt::LeftToRight);
250 }
251
252 /*!
253     \class QTextLayout
254     \reentrant
255
256     \brief The QTextLayout class is used to lay out and render text.
257
258     \ingroup richtext-processing
259
260     It offers many features expected from a modern text layout
261     engine, including Unicode compliant rendering, line breaking and
262     handling of cursor positioning. It can also produce and render
263     device independent layout, something that is important for WYSIWYG
264     applications.
265
266     The class has a rather low level API and unless you intend to
267     implement your own text rendering for some specialized widget, you
268     probably won't need to use it directly.
269
270     QTextLayout can be used with both plain and rich text.
271
272     QTextLayout can be used to create a sequence of QTextLine
273     instances with given widths and can position them independently
274     on the screen. Once the layout is done, these lines can be drawn
275     on a paint device.
276
277     The text to be laid out can be provided in the constructor or set with
278     setText().
279
280     The layout can be seen as a sequence of QTextLine objects; use createLine()
281     to create a QTextLine instance, and lineAt() or lineForTextPosition() to retrieve
282     created lines.
283
284     Here is a code snippet that demonstrates the layout phase:
285     \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 0
286
287     The text can then be rendered by calling the layout's draw() function:
288     \snippet doc/src/snippets/code/src_gui_text_qtextlayout.cpp 1
289
290     For a given position in the text you can find a valid cursor position with
291     isValidCursorPosition(), nextCursorPosition(), and previousCursorPosition().
292
293     The QTextLayout itself can be positioned with setPosition(); it has a
294     boundingRect(), and a minimumWidth() and a maximumWidth().
295
296     \sa QStaticText
297 */
298
299 /*!
300     \enum QTextLayout::CursorMode
301
302     \value SkipCharacters
303     \value SkipWords
304 */
305
306 /*!
307     \fn QTextEngine *QTextLayout::engine() const
308     \internal
309
310     Returns the text engine used to render the text layout.
311 */
312
313 /*!
314     Constructs an empty text layout.
315
316     \sa setText()
317 */
318 QTextLayout::QTextLayout()
319 { d = new QTextEngine(); }
320
321 /*!
322     Constructs a text layout to lay out the given \a text.
323 */
324 QTextLayout::QTextLayout(const QString& text)
325 {
326     d = new QTextEngine();
327     d->text = text;
328 }
329
330 /*!
331     Constructs a text layout to lay out the given \a text with the specified
332     \a font.
333
334     All the metric and layout calculations will be done in terms of
335     the paint device, \a paintdevice. If \a paintdevice is 0 the
336     calculations will be done in screen metrics.
337 */
338 QTextLayout::QTextLayout(const QString& text, const QFont &font, QPaintDevice *paintdevice)
339 {
340     QFont f(font);
341     if (paintdevice)
342         f = QFont(font, paintdevice);
343     d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f);
344 }
345
346 /*!
347     \internal
348     Constructs a text layout to lay out the given \a block.
349 */
350 QTextLayout::QTextLayout(const QTextBlock &block)
351 {
352     d = new QTextEngine();
353     d->block = block;
354 }
355
356 /*!
357     Destructs the layout.
358 */
359 QTextLayout::~QTextLayout()
360 {
361     if (!d->stackEngine)
362         delete d;
363 }
364
365 #ifndef QT_NO_RAWFONT
366 /*!
367     \internal
368     Sets a raw font, to be used with QTextLayout::glyphRuns.
369     Note that this only supports the needs of WebKit.
370     Use of this function with e.g. QTextLayout::draw will result
371     in undefined behaviour.
372 */
373 void QTextLayout::setRawFont(const QRawFont &rawFont)
374 {
375     d->rawFont = rawFont;
376     d->useRawFont = true;
377     d->resetFontEngineCache();
378 }
379 #endif
380
381 /*!
382     Sets the layout's font to the given \a font. The layout is
383     invalidated and must be laid out again.
384
385     \sa font()
386 */
387 void QTextLayout::setFont(const QFont &font)
388 {
389     d->fnt = font;
390 #ifndef QT_NO_RAWFONT
391     d->useRawFont = false;
392 #endif
393     d->resetFontEngineCache();
394 }
395
396 /*!
397     Returns the current font that is used for the layout, or a default
398     font if none is set.
399
400     \sa setFont()
401 */
402 QFont QTextLayout::font() const
403 {
404     return d->font();
405 }
406
407 /*!
408     Sets the layout's text to the given \a string. The layout is
409     invalidated and must be laid out again.
410
411     Notice that when using this QTextLayout as part of a QTextDocument this
412     method will have no effect.
413
414     \sa text()
415 */
416 void QTextLayout::setText(const QString& string)
417 {
418     d->invalidate();
419     d->clearLineData();
420     d->text = string;
421 }
422
423 /*!
424     Returns the layout's text.
425
426     \sa setText()
427 */
428 QString QTextLayout::text() const
429 {
430     return d->text;
431 }
432
433 /*!
434     Sets the text option structure that controls the layout process to the
435     given \a option.
436
437     \sa textOption()
438 */
439 void QTextLayout::setTextOption(const QTextOption &option)
440 {
441     d->option = option;
442 }
443
444 /*!
445     Returns the current text option used to control the layout process.
446
447     \sa setTextOption()
448 */
449 QTextOption QTextLayout::textOption() const
450 {
451     return d->option;
452 }
453
454 /*!
455     Sets the \a position and \a text of the area in the layout that is
456     processed before editing occurs. The layout is
457     invalidated and must be laid out again.
458
459     \sa preeditAreaPosition(), preeditAreaText()
460 */
461 void QTextLayout::setPreeditArea(int position, const QString &text)
462 {
463     if (text.isEmpty()) {
464         if (!d->specialData)
465             return;
466         if (d->specialData->addFormats.isEmpty()) {
467             delete d->specialData;
468             d->specialData = 0;
469         } else {
470             d->specialData->preeditText = QString();
471             d->specialData->preeditPosition = -1;
472         }
473     } else {
474         if (!d->specialData)
475             d->specialData = new QTextEngine::SpecialData;
476         d->specialData->preeditPosition = position;
477         d->specialData->preeditText = text;
478     }
479     d->invalidate();
480     d->clearLineData();
481     if (d->block.docHandle())
482         d->block.docHandle()->documentChange(d->block.position(), d->block.length());
483 }
484
485 /*!
486     Returns the position of the area in the text layout that will be
487     processed before editing occurs.
488
489     \sa preeditAreaText()
490 */
491 int QTextLayout::preeditAreaPosition() const
492 {
493     return d->specialData ? d->specialData->preeditPosition : -1;
494 }
495
496 /*!
497     Returns the text that is inserted in the layout before editing occurs.
498
499     \sa preeditAreaPosition()
500 */
501 QString QTextLayout::preeditAreaText() const
502 {
503     return d->specialData ? d->specialData->preeditText : QString();
504 }
505
506
507 /*!
508     Sets the additional formats supported by the text layout to \a formatList.
509
510     \sa additionalFormats(), clearAdditionalFormats()
511 */
512 void QTextLayout::setAdditionalFormats(const QList<FormatRange> &formatList)
513 {
514     if (formatList.isEmpty()) {
515         if (!d->specialData)
516             return;
517         if (d->specialData->preeditText.isEmpty()) {
518             delete d->specialData;
519             d->specialData = 0;
520         } else {
521             d->specialData->addFormats = formatList;
522             d->specialData->addFormatIndices.clear();
523         }
524     } else {
525         if (!d->specialData) {
526             d->specialData = new QTextEngine::SpecialData;
527             d->specialData->preeditPosition = -1;
528         }
529         d->specialData->addFormats = formatList;
530         d->indexAdditionalFormats();
531     }
532     if (d->block.docHandle())
533         d->block.docHandle()->documentChange(d->block.position(), d->block.length());
534     d->resetFontEngineCache();
535 }
536
537 /*!
538     Returns the list of additional formats supported by the text layout.
539
540     \sa setAdditionalFormats(), clearAdditionalFormats()
541 */
542 QList<QTextLayout::FormatRange> QTextLayout::additionalFormats() const
543 {
544     QList<FormatRange> formats;
545     if (!d->specialData)
546         return formats;
547
548     formats = d->specialData->addFormats;
549
550     if (d->specialData->addFormatIndices.isEmpty())
551         return formats;
552
553     const QTextFormatCollection *collection = d->formats();
554
555     for (int i = 0; i < d->specialData->addFormatIndices.count(); ++i)
556         formats[i].format = collection->charFormat(d->specialData->addFormatIndices.at(i));
557
558     return formats;
559 }
560
561 /*!
562     Clears the list of additional formats supported by the text layout.
563
564     \sa additionalFormats(), setAdditionalFormats()
565 */
566 void QTextLayout::clearAdditionalFormats()
567 {
568     setAdditionalFormats(QList<FormatRange>());
569 }
570
571 /*!
572     Enables caching of the complete layout information if \a enable is
573     true; otherwise disables layout caching. Usually
574     QTextLayout throws most of the layouting information away after a
575     call to endLayout() to reduce memory consumption. If you however
576     want to draw the laid out text directly afterwards enabling caching
577     might speed up drawing significantly.
578
579     \sa cacheEnabled()
580 */
581 void QTextLayout::setCacheEnabled(bool enable)
582 {
583     d->cacheGlyphs = enable;
584 }
585
586 /*!
587     Returns true if the complete layout information is cached; otherwise
588     returns false.
589
590     \sa setCacheEnabled()
591 */
592 bool QTextLayout::cacheEnabled() const
593 {
594     return d->cacheGlyphs;
595 }
596
597 /*!
598     Sets the visual cursor movement style to the given \a style. If the
599     QTextLayout is backed by a document, you can ignore this and use the option
600     in QTextDocument, this option is for widgets like QLineEdit or custom
601     widgets without a QTextDocument. Default value is QTextCursor::Logical.
602
603     \sa cursorMoveStyle()
604 */
605 void QTextLayout::setCursorMoveStyle(Qt::CursorMoveStyle style)
606 {
607     d->visualMovement = style == Qt::VisualMoveStyle ? true : false;
608 }
609
610 /*!
611     The cursor movement style of this QTextLayout. The default is
612     Qt::LogicalMoveStyle.
613
614     \sa setCursorMoveStyle()
615 */
616 Qt::CursorMoveStyle QTextLayout::cursorMoveStyle() const
617 {
618     return d->visualMovement ? Qt::VisualMoveStyle : Qt::LogicalMoveStyle;
619 }
620
621 /*!
622     Begins the layout process.
623
624     \sa endLayout()
625 */
626 void QTextLayout::beginLayout()
627 {
628 #ifndef QT_NO_DEBUG
629     if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
630         qWarning("QTextLayout::beginLayout: Called while already doing layout");
631         return;
632     }
633 #endif
634     d->invalidate();
635     d->clearLineData();
636     d->itemize();
637     d->layoutData->layoutState = QTextEngine::InLayout;
638 }
639
640 /*!
641     Ends the layout process.
642
643     \sa beginLayout()
644 */
645 void QTextLayout::endLayout()
646 {
647 #ifndef QT_NO_DEBUG
648     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
649         qWarning("QTextLayout::endLayout: Called without beginLayout()");
650         return;
651     }
652 #endif
653     int l = d->lines.size();
654     if (l && d->lines.at(l-1).length < 0) {
655         QTextLine(l-1, d).setNumColumns(INT_MAX);
656     }
657     d->layoutData->layoutState = QTextEngine::LayoutEmpty;
658     if (!d->cacheGlyphs)
659         d->freeMemory();
660 }
661
662 /*!
663     \since 4.4
664
665     Clears the line information in the layout. After having called
666     this function, lineCount() returns 0.
667 */
668 void QTextLayout::clearLayout()
669 {
670     d->clearLineData();
671 }
672
673 /*!
674     Returns the next valid cursor position after \a oldPos that
675     respects the given cursor \a mode.
676     Returns value of \a oldPos, if \a oldPos is not a valid cursor position.
677
678     \sa isValidCursorPosition(), previousCursorPosition()
679 */
680 int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
681 {
682     const HB_CharAttributes *attributes = d->attributes();
683     int len = d->block.isValid() ? d->block.length() - 1
684                                  : d->layoutData->string.length();
685     Q_ASSERT(len <= d->layoutData->string.length());
686     if (!attributes || oldPos < 0 || oldPos >= len)
687         return oldPos;
688
689     if (mode == SkipCharacters) {
690         oldPos++;
691         while (oldPos < len && !attributes[oldPos].charStop)
692             oldPos++;
693     } else {
694         if (oldPos < len && d->atWordSeparator(oldPos)) {
695             oldPos++;
696             while (oldPos < len && d->atWordSeparator(oldPos))
697                 oldPos++;
698         } else {
699             while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
700                 oldPos++;
701         }
702         while (oldPos < len && d->atSpace(oldPos))
703             oldPos++;
704     }
705
706     return oldPos;
707 }
708
709 /*!
710     Returns the first valid cursor position before \a oldPos that
711     respects the given cursor \a mode.
712     Returns value of \a oldPos, if \a oldPos is not a valid cursor position.
713
714     \sa isValidCursorPosition(), nextCursorPosition()
715 */
716 int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
717 {
718     const HB_CharAttributes *attributes = d->attributes();
719     if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length())
720         return oldPos;
721
722     if (mode == SkipCharacters) {
723         oldPos--;
724         while (oldPos && !attributes[oldPos].charStop)
725             oldPos--;
726     } else {
727         while (oldPos && d->atSpace(oldPos-1))
728             oldPos--;
729
730         if (oldPos && d->atWordSeparator(oldPos-1)) {
731             oldPos--;
732             while (oldPos && d->atWordSeparator(oldPos-1))
733                 oldPos--;
734         } else {
735             while (oldPos && !d->atSpace(oldPos-1) && !d->atWordSeparator(oldPos-1))
736                 oldPos--;
737         }
738     }
739
740     return oldPos;
741 }
742
743 /*!
744     Returns the cursor position to the right of \a oldPos, next to it.
745     It's dependent on the visual position of characters, after bi-directional
746     reordering.
747
748     \sa leftCursorPosition(), nextCursorPosition()
749 */
750 int QTextLayout::rightCursorPosition(int oldPos) const
751 {
752     int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right);
753 //    qDebug("%d -> %d", oldPos, newPos);
754     return newPos;
755 }
756
757 /*!
758     Returns the cursor position to the left of \a oldPos, next to it.
759     It's dependent on the visual position of characters, after bi-directional
760     reordering.
761
762     \sa rightCursorPosition(), previousCursorPosition()
763 */
764 int QTextLayout::leftCursorPosition(int oldPos) const
765 {
766     int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left);
767 //    qDebug("%d -> %d", oldPos, newPos);
768     return newPos;
769 }
770
771 /*!/
772     Returns true if position \a pos is a valid cursor position.
773
774     In a Unicode context some positions in the text are not valid
775     cursor positions, because the position is inside a Unicode
776     surrogate or a grapheme cluster.
777
778     A grapheme cluster is a sequence of two or more Unicode characters
779     that form one indivisible entity on the screen. For example the
780     latin character `\Auml' can be represented in Unicode by two
781     characters, `A' (0x41), and the combining diaresis (0x308). A text
782     cursor can only validly be positioned before or after these two
783     characters, never between them since that wouldn't make sense. In
784     indic languages every syllable forms a grapheme cluster.
785 */
786 bool QTextLayout::isValidCursorPosition(int pos) const
787 {
788     const HB_CharAttributes *attributes = d->attributes();
789     if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length())
790         return false;
791     return attributes[pos].charStop;
792 }
793
794 /*!
795     Returns a new text line to be laid out if there is text to be
796     inserted into the layout; otherwise returns an invalid text line.
797
798     The text layout creates a new line object that starts after the
799     last line in the layout, or at the beginning if the layout is empty.
800     The layout maintains an internal cursor, and each line is filled
801     with text from the cursor position onwards when the
802     QTextLine::setLineWidth() function is called.
803
804     Once QTextLine::setLineWidth() is called, a new line can be created and
805     filled with text. Repeating this process will lay out the whole block
806     of text contained in the QTextLayout. If there is no text left to be
807     inserted into the layout, the QTextLine returned will not be valid
808     (isValid() will return false).
809 */
810 QTextLine QTextLayout::createLine()
811 {
812 #ifndef QT_NO_DEBUG
813     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
814         qWarning("QTextLayout::createLine: Called without layouting");
815         return QTextLine();
816     }
817 #endif
818     if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
819         return QTextLine();
820
821     int l = d->lines.size();
822     if (l && d->lines.at(l-1).length < 0) {
823         QTextLine(l-1, d).setNumColumns(INT_MAX);
824     }
825     int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
826     int strlen = d->layoutData->string.length();
827     if (l && from >= strlen) {
828         if (!d->lines.at(l-1).length || d->layoutData->string.at(strlen - 1) != QChar::LineSeparator)
829             return QTextLine();
830     }
831
832     QScriptLine line;
833     line.from = from;
834     line.length = -1;
835     line.justified = false;
836     line.gridfitted = false;
837
838     d->lines.append(line);
839     return QTextLine(l, d);
840 }
841
842 /*!
843     Returns the number of lines in this text layout.
844
845     \sa lineAt()
846 */
847 int QTextLayout::lineCount() const
848 {
849     return d->lines.size();
850 }
851
852 /*!
853     Returns the \a{i}-th line of text in this text layout.
854
855     \sa lineCount(), lineForTextPosition()
856 */
857 QTextLine QTextLayout::lineAt(int i) const
858 {
859     return i < lineCount() ? QTextLine(i, d) : QTextLine();
860 }
861
862 /*!
863     Returns the line that contains the cursor position specified by \a pos.
864
865     \sa isValidCursorPosition(), lineAt()
866 */
867 QTextLine QTextLayout::lineForTextPosition(int pos) const
868 {
869     int lineNum = d->lineNumberForTextPosition(pos);
870     return lineNum >= 0 ? lineAt(lineNum) : QTextLine();
871 }
872
873 /*!
874     \since 4.2
875
876     The global position of the layout. This is independent of the
877     bounding rectangle and of the layout process.
878
879     \sa setPosition()
880 */
881 QPointF QTextLayout::position() const
882 {
883     return d->position;
884 }
885
886 /*!
887     Moves the text layout to point \a p.
888
889     \sa position()
890 */
891 void QTextLayout::setPosition(const QPointF &p)
892 {
893     d->position = p;
894 }
895
896 /*!
897     The smallest rectangle that contains all the lines in the layout.
898 */
899 QRectF QTextLayout::boundingRect() const
900 {
901     if (d->lines.isEmpty())
902         return QRectF();
903
904     QFixed xmax, ymax;
905     QFixed xmin = d->lines.at(0).x;
906     QFixed ymin = d->lines.at(0).y;
907
908     for (int i = 0; i < d->lines.size(); ++i) {
909         const QScriptLine &si = d->lines[i];
910         xmin = qMin(xmin, si.x);
911         ymin = qMin(ymin, si.y);
912         QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
913         xmax = qMax(xmax, si.x+lineWidth);
914         // ### shouldn't the ascent be used in ymin???
915         ymax = qMax(ymax, si.y+si.height());
916     }
917     return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal());
918 }
919
920 /*!
921     The minimum width the layout needs. This is the width of the
922     layout's smallest non-breakable substring.
923
924     \warning This function only returns a valid value after the layout
925     has been done.
926
927     \sa maximumWidth()
928 */
929 qreal QTextLayout::minimumWidth() const
930 {
931     return d->minWidth.toReal();
932 }
933
934 /*!
935     The maximum width the layout could expand to; this is essentially
936     the width of the entire text.
937
938     \warning This function only returns a valid value after the layout
939     has been done.
940
941     \sa minimumWidth()
942 */
943 qreal QTextLayout::maximumWidth() const
944 {
945     return d->maxWidth.toReal();
946 }
947
948
949 /*!
950     \internal
951 */
952 void QTextLayout::setFlags(int flags)
953 {
954     if (flags & Qt::TextJustificationForced) {
955         d->option.setAlignment(Qt::AlignJustify);
956         d->forceJustification = true;
957     }
958
959     if (flags & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
960         d->ignoreBidi = true;
961         d->option.setTextDirection((flags & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
962     }
963 }
964
965 static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection,
966                                      QPainterPath *region, QRectF boundingRect)
967 {
968     const QScriptLine &line = eng->lines[lineNumber];
969
970     QTextLineItemIterator iterator(eng, lineNumber, pos, selection);
971
972
973
974     const qreal selectionY = pos.y() + line.y.toReal();
975     const qreal lineHeight = line.height().toReal();
976
977     QFixed lastSelectionX = iterator.x;
978     QFixed lastSelectionWidth;
979
980     while (!iterator.atEnd()) {
981         iterator.next();
982
983         QFixed selectionX, selectionWidth;
984         if (iterator.getSelectionBounds(&selectionX, &selectionWidth)) {
985             if (selectionX == lastSelectionX + lastSelectionWidth) {
986                 lastSelectionWidth += selectionWidth;
987                 continue;
988             }
989
990             if (lastSelectionWidth > 0)
991                 region->addRect(boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight));
992
993             lastSelectionX = selectionX;
994             lastSelectionWidth = selectionWidth;
995         }
996     }
997     if (lastSelectionWidth > 0)
998         region->addRect(boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight));
999 }
1000
1001 static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
1002 {
1003     return clip.isValid() ? (rect & clip) : rect;
1004 }
1005
1006
1007 /*!
1008     Returns the glyph indexes and positions for all glyphs in this QTextLayout. This is an
1009     expensive function, and should not be called in a time sensitive context.
1010
1011     \since 4.8
1012
1013     \sa draw(), QPainter::drawGlyphRun()
1014 */
1015 #if !defined(QT_NO_RAWFONT)
1016 QList<QGlyphRun> QTextLayout::glyphRuns(int from, int length) const
1017 {    
1018     if (from < 0)
1019         from = 0;
1020     if (length < 0)
1021         length = text().length();
1022
1023     QHash<QPair<QFontEngine *, int>, QGlyphRun> glyphRunHash;
1024     for (int i=0; i<d->lines.size(); ++i) {
1025         if (d->lines[i].from > from + length)
1026             break;
1027         else if (d->lines[i].from + d->lines[i].length >= from) {
1028             QList<QGlyphRun> glyphRuns = QTextLine(i, d).glyphRuns(from, length);
1029
1030             for (int j = 0; j < glyphRuns.size(); j++) {
1031                 const QGlyphRun &glyphRun = glyphRuns.at(j);
1032                 QRawFont rawFont = glyphRun.rawFont();
1033
1034                 QFontEngine *fontEngine = rawFont.d->fontEngine;
1035                 QGlyphRun::GlyphRunFlags flags = glyphRun.flags();
1036                 QPair<QFontEngine *, int> key(fontEngine, int(flags));
1037                 // merge the glyph runs using the same font
1038                 if (glyphRunHash.contains(key)) {
1039                     QGlyphRun &oldGlyphRun = glyphRunHash[key];
1040
1041                     QVector<quint32> indexes = oldGlyphRun.glyphIndexes();
1042                     QVector<QPointF> positions = oldGlyphRun.positions();
1043
1044                     indexes += glyphRun.glyphIndexes();
1045                     positions += glyphRun.positions();
1046
1047                     oldGlyphRun.setGlyphIndexes(indexes);
1048                     oldGlyphRun.setPositions(positions);
1049                 } else {
1050                     glyphRunHash[key] = glyphRun;
1051                 }
1052             }
1053         }
1054     }
1055
1056     return glyphRunHash.values();
1057 }
1058 #endif // QT_NO_RAWFONT
1059
1060 /*!
1061     Draws the whole layout on the painter \a p at the position specified by \a pos.
1062     The rendered layout includes the given \a selections and is clipped within
1063     the rectangle specified by \a clip.
1064 */
1065 void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections, const QRectF &clip) const
1066 {
1067     if (d->lines.isEmpty())
1068         return;
1069
1070     if (!d->layoutData)
1071         d->itemize();
1072
1073     QPointF position = pos + d->position;
1074
1075     QFixed clipy = (INT_MIN/256);
1076     QFixed clipe = (INT_MAX/256);
1077     if (clip.isValid()) {
1078         clipy = QFixed::fromReal(clip.y() - position.y());
1079         clipe = clipy + QFixed::fromReal(clip.height());
1080     }
1081
1082     int firstLine = 0;
1083     int lastLine = d->lines.size();
1084     for (int i = 0; i < d->lines.size(); ++i) {
1085         QTextLine l(i, d);
1086         const QScriptLine &sl = d->lines[i];
1087
1088         if (sl.y > clipe) {
1089             lastLine = i;
1090             break;
1091         }
1092         if ((sl.y + sl.height()) < clipy) {
1093             firstLine = i;
1094             continue;
1095         }
1096     }
1097
1098     QPainterPath excludedRegion;
1099     QPainterPath textDoneRegion;
1100     for (int i = 0; i < selections.size(); ++i) {
1101         FormatRange selection = selections.at(i);
1102         const QBrush bg = selection.format.background();
1103
1104         QPainterPath region;
1105         region.setFillRule(Qt::WindingFill);
1106
1107         for (int line = firstLine; line < lastLine; ++line) {
1108             const QScriptLine &sl = d->lines[line];
1109             QTextLine tl(line, d);
1110
1111             QRectF lineRect(tl.naturalTextRect());
1112             lineRect.translate(position);
1113             lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0);
1114
1115             bool isLastLineInBlock = (line == d->lines.size()-1);
1116             int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
1117
1118
1119             if (sl.from > selection.start + selection.length || sl.from + sl_length <= selection.start)
1120                 continue; // no actual intersection
1121
1122             const bool selectionStartInLine = sl.from <= selection.start;
1123             const bool selectionEndInLine = selection.start + selection.length < sl.from + sl_length;
1124
1125             if (sl.length && (selectionStartInLine || selectionEndInLine)) {
1126                 addSelectedRegionsToPath(d, line, position, &selection, &region, clipIfValid(lineRect, clip));
1127             } else {
1128                 region.addRect(clipIfValid(lineRect, clip));
1129             }
1130
1131             if (selection.format.boolProperty(QTextFormat::FullWidthSelection)) {
1132                 QRectF fullLineRect(tl.rect());
1133                 fullLineRect.translate(position);
1134                 fullLineRect.setRight(QFIXED_MAX);
1135                 if (!selectionEndInLine)
1136                     region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
1137                 if (!selectionStartInLine)
1138                     region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
1139             } else if (!selectionEndInLine
1140                 && isLastLineInBlock
1141                 &&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
1142                 region.addRect(clipIfValid(QRectF(lineRect.right(), lineRect.top(),
1143                                                   lineRect.height()/4, lineRect.height()), clip));
1144             }
1145
1146         }
1147         {
1148             const QPen oldPen = p->pen();
1149             const QBrush oldBrush = p->brush();
1150
1151             p->setPen(selection.format.penProperty(QTextFormat::OutlinePen));
1152             p->setBrush(selection.format.brushProperty(QTextFormat::BackgroundBrush));
1153             p->drawPath(region);
1154
1155             p->setPen(oldPen);
1156             p->setBrush(oldBrush);
1157         }
1158
1159
1160
1161         bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
1162         bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
1163
1164         if (hasBackground) {
1165             selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
1166             // don't just clear the property, set an empty brush that overrides a potential
1167             // background brush specified in the text
1168             selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());
1169             selection.format.clearProperty(QTextFormat::OutlinePen);
1170         }
1171
1172         selection.format.setProperty(SuppressText, !hasText);
1173
1174         if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty())
1175             continue;
1176
1177         p->save();
1178         p->setClipPath(region, Qt::IntersectClip);
1179
1180         for (int line = firstLine; line < lastLine; ++line) {
1181             QTextLine l(line, d);
1182             l.draw(p, position, &selection);
1183         }
1184         p->restore();
1185
1186         if (hasText) {
1187             textDoneRegion += region;
1188         } else {
1189             if (hasBackground)
1190                 textDoneRegion -= region;
1191         }
1192
1193         excludedRegion += region;
1194     }
1195
1196     QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion;
1197     if (!needsTextButNoBackground.isEmpty()){
1198         p->save();
1199         p->setClipPath(needsTextButNoBackground, Qt::IntersectClip);
1200         FormatRange selection;
1201         selection.start = 0;
1202         selection.length = INT_MAX;
1203         selection.format.setProperty(SuppressBackground, true);
1204         for (int line = firstLine; line < lastLine; ++line) {
1205             QTextLine l(line, d);
1206             l.draw(p, position, &selection);
1207         }
1208         p->restore();
1209     }
1210
1211     if (!excludedRegion.isEmpty()) {
1212         p->save();
1213         QPainterPath path;
1214         QRectF br = boundingRect().translated(position);
1215         br.setRight(QFIXED_MAX);
1216         if (!clip.isNull())
1217             br = br.intersected(clip);
1218         path.addRect(br);
1219         path -= excludedRegion;
1220         p->setClipPath(path, Qt::IntersectClip);
1221     }
1222
1223     for (int i = firstLine; i < lastLine; ++i) {
1224         QTextLine l(i, d);
1225         l.draw(p, position);
1226     }
1227     if (!excludedRegion.isEmpty())
1228         p->restore();
1229
1230
1231     if (!d->cacheGlyphs)
1232         d->freeMemory();
1233 }
1234
1235 /*!
1236     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition) const
1237     \overload
1238
1239     Draws a text cursor with the current pen at the given \a position using the
1240     \a painter specified.
1241     The corresponding position within the text is specified by \a cursorPosition.
1242 */
1243 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
1244 {
1245     drawCursor(p, pos, cursorPosition, 1);
1246 }
1247
1248 /*!
1249     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition, int width) const
1250
1251     Draws a text cursor with the current pen and the specified \a width at the given \a position using the
1252     \a painter specified.
1253     The corresponding position within the text is specified by \a cursorPosition.
1254 */
1255 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const
1256 {
1257     if (d->lines.isEmpty())
1258         return;
1259
1260     if (!d->layoutData)
1261         d->itemize();
1262
1263     QPointF position = pos + d->position;
1264
1265     cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
1266     int line = d->lineNumberForTextPosition(cursorPosition);
1267     if (line < 0)
1268         line = 0;
1269     if (line >= d->lines.size())
1270         return;
1271
1272     QTextLine l(line, d);
1273     const QScriptLine &sl = d->lines[line];
1274
1275     qreal x = position.x() + l.cursorToX(cursorPosition);
1276
1277     int itm;
1278
1279     if (d->visualCursorMovement()) {
1280         if (cursorPosition == sl.from + sl.length)
1281             cursorPosition--;
1282         itm = d->findItem(cursorPosition);
1283     } else
1284         itm = d->findItem(cursorPosition - 1);
1285
1286     QFixed base = sl.base();
1287     QFixed descent = sl.descent;
1288     bool rightToLeft = d->isRightToLeft();
1289     if (itm >= 0) {
1290         const QScriptItem &si = d->layoutData->items.at(itm);
1291         if (si.ascent > 0)
1292             base = si.ascent;
1293         if (si.descent > 0)
1294             descent = si.descent;
1295         rightToLeft = si.analysis.bidiLevel % 2;
1296     }
1297     qreal y = position.y() + (sl.y + sl.base() - base).toReal();
1298     bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
1299                               && (p->transform().type() > QTransform::TxTranslate);
1300     if (toggleAntialiasing)
1301         p->setRenderHint(QPainter::Antialiasing);
1302     p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
1303     if (toggleAntialiasing)
1304         p->setRenderHint(QPainter::Antialiasing, false);
1305     if (d->layoutData->hasBidi) {
1306         const int arrow_extent = 4;
1307         int sign = rightToLeft ? -1 : 1;
1308         p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2));
1309         p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2));
1310     }
1311     return;
1312 }
1313
1314 /*!
1315     \class QTextLine
1316     \reentrant
1317
1318     \brief The QTextLine class represents a line of text inside a QTextLayout.
1319
1320     \ingroup richtext-processing
1321
1322     A text line is usually created by QTextLayout::createLine().
1323
1324     After being created, the line can be filled using the setLineWidth()
1325     or setNumColumns() functions. A line has a number of attributes including the
1326     rectangle it occupies, rect(), its coordinates, x() and y(), its
1327     textLength(), width() and naturalTextWidth(), and its ascent() and decent()
1328     relative to the text. The position of the cursor in terms of the
1329     line is available from cursorToX() and its inverse from
1330     xToCursor(). A line can be moved with setPosition().
1331 */
1332
1333 /*!
1334     \enum QTextLine::Edge
1335
1336     \value Leading
1337     \value Trailing
1338 */
1339
1340 /*!
1341     \enum QTextLine::CursorPosition
1342
1343     \value CursorBetweenCharacters
1344     \value CursorOnCharacter
1345 */
1346
1347 /*!
1348     \fn QTextLine::QTextLine(int line, QTextEngine *e)
1349     \internal
1350
1351     Constructs a new text line using the line at position \a line in
1352     the text engine \a e.
1353 */
1354
1355 /*!
1356     \fn QTextLine::QTextLine()
1357
1358     Creates an invalid line.
1359 */
1360
1361 /*!
1362     \fn bool QTextLine::isValid() const
1363
1364     Returns true if this text line is valid; otherwise returns false.
1365 */
1366
1367 /*!
1368     \fn int QTextLine::lineNumber() const
1369
1370     Returns the position of the line in the text engine.
1371 */
1372
1373
1374 /*!
1375     Returns the line's bounding rectangle.
1376
1377     \sa x(), y(), textLength(), width()
1378 */
1379 QRectF QTextLine::rect() const
1380 {
1381     const QScriptLine& sl = eng->lines[index];
1382     return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());
1383 }
1384
1385 /*!
1386     Returns the rectangle covered by the line.
1387 */
1388 QRectF QTextLine::naturalTextRect() const
1389 {
1390     const QScriptLine& sl = eng->lines[index];
1391     QFixed x = sl.x + eng->alignLine(sl);
1392
1393     QFixed width = sl.textWidth;
1394     if (sl.justified)
1395         width = sl.width;
1396
1397     return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal());
1398 }
1399
1400 /*!
1401     Returns the line's x position.
1402
1403     \sa rect(), y(), textLength(), width()
1404 */
1405 qreal QTextLine::x() const
1406 {
1407     return eng->lines[index].x.toReal();
1408 }
1409
1410 /*!
1411     Returns the line's y position.
1412
1413     \sa x(), rect(), textLength(), width()
1414 */
1415 qreal QTextLine::y() const
1416 {
1417     return eng->lines[index].y.toReal();
1418 }
1419
1420 /*!
1421     Returns the line's width as specified by the layout() function.
1422
1423     \sa naturalTextWidth(), x(), y(), textLength(), rect()
1424 */
1425 qreal QTextLine::width() const
1426 {
1427     return eng->lines[index].width.toReal();
1428 }
1429
1430
1431 /*!
1432     Returns the line's ascent.
1433
1434     \sa descent(), height()
1435 */
1436 qreal QTextLine::ascent() const
1437 {
1438     return eng->lines[index].ascent.toReal();
1439 }
1440
1441 /*!
1442     Returns the line's descent.
1443
1444     \sa ascent(), height()
1445 */
1446 qreal QTextLine::descent() const
1447 {
1448     return eng->lines[index].descent.toReal();
1449 }
1450
1451 /*!
1452     Returns the line's height. This is equal to ascent() + descent()
1453     if leading is not included. If leading is included, this equals to
1454     ascent() + descent() + leading().
1455
1456     \sa ascent(), descent(), leading(), setLeadingIncluded()
1457 */
1458 qreal QTextLine::height() const
1459 {
1460     return eng->lines[index].height().toReal();
1461 }
1462
1463 /*!
1464     \since 4.6
1465
1466     Returns the line's leading.
1467
1468     \sa ascent(), descent(), height()
1469 */
1470 qreal QTextLine::leading() const
1471 {
1472     return eng->lines[index].leading.toReal();
1473 }
1474
1475 /*!
1476     \since 4.6
1477
1478     Includes positive leading into the line's height if \a included is true;
1479     otherwise does not include leading.
1480
1481     By default, leading is not included.
1482
1483     Note that negative leading is ignored, it must be handled
1484     in the code using the text lines by letting the lines overlap.
1485
1486     \sa leadingIncluded()
1487
1488 */
1489 void QTextLine::setLeadingIncluded(bool included)
1490 {
1491     eng->lines[index].leadingIncluded= included;
1492
1493 }
1494
1495 /*!
1496     \since 4.6
1497
1498     Returns true if positive leading is included into the line's height;
1499     otherwise returns false.
1500
1501     By default, leading is not included.
1502
1503     \sa setLeadingIncluded()
1504 */
1505 bool QTextLine::leadingIncluded() const
1506 {
1507     return eng->lines[index].leadingIncluded;
1508 }
1509
1510 /*!
1511     Returns the width of the line that is occupied by text. This is
1512     always \<= to width(), and is the minimum width that could be used
1513     by layout() without changing the line break position.
1514 */
1515 qreal QTextLine::naturalTextWidth() const
1516 {
1517     return eng->lines[index].textWidth.toReal();
1518 }
1519
1520 /*!
1521     \since 4.7
1522     Returns the horizontal advance of the text. The advance of the text
1523     is the distance from its position to the next position at which
1524     text would naturally be drawn.
1525
1526     By adding the advance to the position of the text line and using this
1527     as the position of a second text line, you will be able to position
1528     the two lines side-by-side without gaps in-between.
1529 */
1530 qreal QTextLine::horizontalAdvance() const
1531 {
1532     return eng->lines[index].textAdvance.toReal();
1533 }
1534
1535 /*!
1536     Lays out the line with the given \a width. The line is filled from
1537     its starting position with as many characters as will fit into
1538     the line. In case the text cannot be split at the end of the line,
1539     it will be filled with additional characters to the next whitespace
1540     or end of the text.
1541 */
1542 void QTextLine::setLineWidth(qreal width)
1543 {
1544     QScriptLine &line = eng->lines[index];
1545     if (!eng->layoutData) {
1546         qWarning("QTextLine: Can't set a line width while not layouting.");
1547         return;
1548     }
1549
1550     if (width > QFIXED_MAX)
1551         width = QFIXED_MAX;
1552
1553     line.width = QFixed::fromReal(width);
1554     if (line.length
1555         && line.textWidth <= line.width
1556         && line.from + line.length == eng->layoutData->string.length())
1557         // no need to do anything if the line is already layouted and the last one. This optimization helps
1558         // when using things in a single line layout.
1559         return;
1560     line.length = 0;
1561     line.textWidth = 0;
1562
1563     layout_helper(INT_MAX);
1564 }
1565
1566 /*!
1567     Lays out the line. The line is filled from its starting position
1568     with as many characters as are specified by \a numColumns. In case
1569     the text cannot be split until \a numColumns characters, the line
1570     will be filled with as many characters to the next whitespace or
1571     end of the text.
1572 */
1573 void QTextLine::setNumColumns(int numColumns)
1574 {
1575     QScriptLine &line = eng->lines[index];
1576     line.width = QFIXED_MAX;
1577     line.length = 0;
1578     line.textWidth = 0;
1579     layout_helper(numColumns);
1580 }
1581
1582 /*!
1583     Lays out the line. The line is filled from its starting position
1584     with as many characters as are specified by \a numColumns. In case
1585     the text cannot be split until \a numColumns characters, the line
1586     will be filled with as many characters to the next whitespace or
1587     end of the text. The provided \a alignmentWidth is used as reference
1588     width for alignment.
1589 */
1590 void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth)
1591 {
1592     QScriptLine &line = eng->lines[index];
1593     line.width = QFixed::fromReal(alignmentWidth);
1594     line.length = 0;
1595     line.textWidth = 0;
1596     layout_helper(numColumns);
1597 }
1598
1599 #if 0
1600 #define LB_DEBUG qDebug
1601 #else
1602 #define LB_DEBUG if (0) qDebug
1603 #endif
1604
1605 namespace {
1606
1607     struct LineBreakHelper
1608     {
1609         LineBreakHelper()
1610             : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
1611               manualWrap(false), whiteSpaceOrObject(true)
1612         {
1613         }
1614
1615
1616         QScriptLine tmpData;
1617         QScriptLine spaceData;
1618
1619         QGlyphLayout glyphs;
1620
1621         int glyphCount;
1622         int maxGlyphs;
1623         int currentPosition;
1624         glyph_t previousGlyph;
1625
1626         QFixed minw;
1627         QFixed softHyphenWidth;
1628         QFixed rightBearing;
1629         QFixed minimumRightBearing;
1630
1631         QFontEngine *fontEngine;
1632         const unsigned short *logClusters;
1633
1634         bool manualWrap;
1635         bool whiteSpaceOrObject;
1636
1637         bool checkFullOtherwiseExtend(QScriptLine &line);
1638
1639         QFixed calculateNewWidth(const QScriptLine &line) const {
1640             return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
1641                     - qMin(rightBearing, QFixed());
1642         }
1643
1644         inline glyph_t currentGlyph() const
1645         {            
1646             Q_ASSERT(currentPosition > 0);
1647             Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
1648
1649             return glyphs.glyphs[logClusters[currentPosition - 1]];
1650         }
1651
1652         inline void saveCurrentGlyph()
1653         {
1654             previousGlyph = 0;
1655             if (currentPosition > 0 &&
1656                 logClusters[currentPosition - 1] < glyphs.numGlyphs) {
1657                 previousGlyph = currentGlyph(); // needed to calculate right bearing later
1658             }
1659         }
1660
1661         inline void adjustRightBearing(glyph_t glyph)
1662         {
1663             qreal rb;
1664             fontEngine->getGlyphBearings(glyph, 0, &rb);
1665             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1666         }
1667
1668         inline void adjustRightBearing()
1669         {
1670             if (currentPosition <= 0)
1671                 return;
1672             adjustRightBearing(currentGlyph());
1673         }
1674
1675         inline void adjustPreviousRightBearing()
1676         {
1677             if (previousGlyph > 0)
1678                 adjustRightBearing(previousGlyph);
1679         }
1680
1681         inline void resetRightBearing()
1682         {
1683             rightBearing = QFixed(1); // Any positive number is defined as invalid since only
1684                                       // negative right bearings are interesting to us.
1685         }
1686     };
1687
1688 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
1689 {
1690     LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
1691
1692     QFixed newWidth = calculateNewWidth(line);
1693     if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
1694         return true;
1695
1696     minw = qMax(minw, tmpData.textWidth);
1697     line += tmpData;
1698     line.textWidth += spaceData.textWidth;
1699
1700     line.length += spaceData.length;
1701     tmpData.textWidth = 0;
1702     tmpData.length = 0;
1703     spaceData.textWidth = 0;
1704     spaceData.length = 0;
1705
1706     return false;
1707 }
1708
1709 } // anonymous namespace
1710
1711
1712 static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount,
1713                                   const QScriptItem &current, const unsigned short *logClusters,
1714                                   const QGlyphLayout &glyphs)
1715 {
1716     int glyphPosition = logClusters[pos];
1717     do { // got to the first next cluster
1718         ++pos;
1719         ++line.length;
1720     } while (pos < end && logClusters[pos] == glyphPosition);
1721     do { // calculate the textWidth for the rest of the current cluster.
1722         if (!glyphs.attributes[glyphPosition].dontPrint)
1723             line.textWidth += glyphs.advances_x[glyphPosition];
1724         ++glyphPosition;
1725     } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart);
1726
1727     Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition);
1728
1729     ++glyphCount;
1730 }
1731
1732
1733 // fill QScriptLine
1734 void QTextLine::layout_helper(int maxGlyphs)
1735 {
1736     QScriptLine &line = eng->lines[index];
1737     line.length = 0;
1738     line.trailingSpaces = 0;
1739     line.textWidth = 0;
1740     line.hasTrailingSpaces = false;
1741
1742     if (!eng->layoutData->items.size() || line.from >= eng->layoutData->string.length()) {
1743         line.setDefaultHeight(eng);
1744         return;
1745     }
1746
1747     Q_ASSERT(line.from < eng->layoutData->string.length());
1748
1749     LineBreakHelper lbh;
1750
1751     lbh.maxGlyphs = maxGlyphs;
1752
1753     QTextOption::WrapMode wrapMode = eng->option.wrapMode();
1754     bool breakany = (wrapMode == QTextOption::WrapAnywhere);
1755     lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
1756
1757     int item = -1;
1758     int newItem = eng->findItem(line.from);
1759
1760     LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
1761
1762     Qt::Alignment alignment = eng->option.alignment();
1763
1764     const HB_CharAttributes *attributes = eng->attributes();
1765     if (!attributes)
1766         return;
1767     lbh.currentPosition = line.from;
1768     int end = 0;
1769     lbh.logClusters = eng->layoutData->logClustersPtr;
1770     lbh.previousGlyph = 0;
1771
1772     while (newItem < eng->layoutData->items.size()) {
1773         lbh.resetRightBearing();
1774         lbh.softHyphenWidth = 0;
1775         if (newItem != item) {
1776             item = newItem;
1777             const QScriptItem &current = eng->layoutData->items[item];
1778             if (!current.num_glyphs) {
1779                 eng->shape(item);
1780                 attributes = eng->attributes();
1781                 if (!attributes)
1782                     return;
1783                 lbh.logClusters = eng->layoutData->logClustersPtr;
1784             }
1785             lbh.currentPosition = qMax(line.from, current.position);
1786             end = current.position + eng->length(item);
1787             lbh.glyphs = eng->shapedGlyphs(&current);
1788             QFontEngine *fontEngine = eng->fontEngine(current);
1789             if (lbh.fontEngine != fontEngine) {
1790                 lbh.fontEngine = fontEngine;
1791                 lbh.minimumRightBearing = qMin(QFixed(),
1792                                                QFixed::fromReal(fontEngine->minRightBearing()));
1793             }
1794         }
1795         const QScriptItem &current = eng->layoutData->items[item];
1796
1797         lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
1798                                    current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
1799                                                                             current.ascent);
1800         lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
1801         lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
1802
1803         if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
1804             lbh.whiteSpaceOrObject = true;
1805             if (lbh.checkFullOtherwiseExtend(line))
1806                 goto found;
1807
1808             QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth;
1809             QFixed tabWidth = eng->calculateTabWidth(item, x);
1810
1811             lbh.spaceData.textWidth += tabWidth;
1812             lbh.spaceData.length++;
1813             newItem = item + 1;
1814
1815             QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth();
1816             lbh.glyphCount += qRound(tabWidth / averageCharWidth);
1817
1818             if (lbh.checkFullOtherwiseExtend(line))
1819                 goto found;
1820         } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
1821             lbh.whiteSpaceOrObject = true;
1822             // if the line consists only of the line separator make sure
1823             // we have a sane height
1824             if (!line.length && !lbh.tmpData.length)
1825                 line.setDefaultHeight(eng);
1826             if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
1827                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1828                                current, lbh.logClusters, lbh.glyphs);
1829             } else {
1830                 lbh.tmpData.length++;
1831                 lbh.adjustPreviousRightBearing();
1832             }
1833             line += lbh.tmpData;
1834             goto found;
1835         } else if (current.analysis.flags == QScriptAnalysis::Object) {
1836             lbh.whiteSpaceOrObject = true;
1837             lbh.tmpData.length++;
1838
1839             QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item]));
1840             if (eng->block.docHandle())
1841                 eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format);
1842
1843             lbh.tmpData.textWidth += current.width;
1844
1845             newItem = item + 1;
1846             ++lbh.glyphCount;
1847             if (lbh.checkFullOtherwiseExtend(line))
1848                 goto found;
1849         } else if (attributes[lbh.currentPosition].whiteSpace) {
1850             lbh.whiteSpaceOrObject = true;
1851             while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
1852                 addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
1853                                current, lbh.logClusters, lbh.glyphs);
1854
1855             if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
1856                 lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line.
1857                 goto found;
1858             }
1859         } else {
1860             lbh.whiteSpaceOrObject = false;
1861             bool sb_or_ws = false;
1862             lbh.saveCurrentGlyph();
1863             do {
1864                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1865                                current, lbh.logClusters, lbh.glyphs);
1866
1867                 if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
1868                     sb_or_ws = true;
1869                     break;
1870                 } else if (breakany && attributes[lbh.currentPosition].charStop) {
1871                     break;
1872                 }
1873             } while (lbh.currentPosition < end);
1874             lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
1875
1876             if (lbh.currentPosition && attributes[lbh.currentPosition - 1].lineBreakType == HB_SoftHyphen) {
1877                 // if we are splitting up a word because of
1878                 // a soft hyphen then we ...
1879                 //
1880                 //  a) have to take the width of the soft hyphen into
1881                 //     account to see if the first syllable(s) /and/
1882                 //     the soft hyphen fit into the line
1883                 //
1884                 //  b) if we are so short of available width that the
1885                 //     soft hyphen is the first breakable position, then
1886                 //     we don't want to show it. However we initially
1887                 //     have to take the width for it into account so that
1888                 //     the text document layout sees the overflow and
1889                 //     switch to break-anywhere mode, in which we
1890                 //     want the soft-hyphen to slip into the next line
1891                 //     and thus become invisible again.
1892                 //
1893                 if (line.length)
1894                     lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1895                 else if (breakany)
1896                     lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1897             }
1898
1899             // The actual width of the text needs to take the right bearing into account. The
1900             // right bearing is left-ward, which means that if the rightmost pixel is to the right
1901             // of the advance of the glyph, the bearing will be negative. We flip the sign
1902             // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
1903             // We ignore the right bearing if the minimum negative bearing is too little to
1904             // expand the text beyond the edge.
1905             if (sb_or_ws|breakany) {
1906                 QFixed rightBearing = lbh.rightBearing; // store previous right bearing
1907                 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
1908                     lbh.adjustRightBearing();
1909                 if (lbh.checkFullOtherwiseExtend(line)) {
1910                     // we are too wide, fix right bearing
1911                     if (rightBearing <= 0)
1912                         lbh.rightBearing = rightBearing; // take from cache
1913                     else
1914                         lbh.adjustPreviousRightBearing();
1915
1916                     if (!breakany) {
1917                         line.textWidth += lbh.softHyphenWidth;
1918                     }
1919
1920                     goto found;
1921                 }
1922             }
1923             lbh.saveCurrentGlyph();
1924         }
1925         if (lbh.currentPosition == end)
1926             newItem = item + 1;
1927     }
1928     LB_DEBUG("reached end of line");
1929     lbh.checkFullOtherwiseExtend(line);
1930 found:
1931     if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
1932         lbh.adjustRightBearing();
1933     line.textAdvance = line.textWidth;
1934     line.textWidth -= qMin(QFixed(), lbh.rightBearing);
1935
1936     if (line.length == 0) {
1937         LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
1938                lbh.tmpData.length, lbh.tmpData.textWidth.toReal(),
1939                lbh.spaceData.length, lbh.spaceData.textWidth.toReal());
1940         line += lbh.tmpData;
1941     }
1942
1943     LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(),
1944            line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal());
1945     LB_DEBUG("        : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data());
1946
1947     if (lbh.manualWrap) {
1948         eng->minWidth = qMax(eng->minWidth, line.textWidth);
1949         eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
1950     } else {
1951         eng->minWidth = qMax(eng->minWidth, lbh.minw);
1952         eng->maxWidth += line.textWidth;
1953     }
1954
1955     if (line.textWidth > 0 && item < eng->layoutData->items.size())
1956         eng->maxWidth += lbh.spaceData.textWidth;
1957     if (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
1958         line.textWidth += lbh.spaceData.textWidth;
1959     if (lbh.spaceData.length) {
1960         line.trailingSpaces = lbh.spaceData.length;
1961         line.hasTrailingSpaces = true;
1962     }
1963
1964     line.justified = false;
1965     line.gridfitted = false;
1966
1967     if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) {
1968         if ((lbh.maxGlyphs != INT_MAX && lbh.glyphCount > lbh.maxGlyphs)
1969             || (lbh.maxGlyphs == INT_MAX && line.textWidth > line.width)) {
1970
1971             eng->option.setWrapMode(QTextOption::WrapAnywhere);
1972             line.length = 0;
1973             line.textWidth = 0;
1974             layout_helper(lbh.maxGlyphs);
1975             eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
1976         }
1977     }
1978 }
1979
1980 /*!
1981     Moves the line to position \a pos.
1982 */
1983 void QTextLine::setPosition(const QPointF &pos)
1984 {
1985     eng->lines[index].x = QFixed::fromReal(pos.x());
1986     eng->lines[index].y = QFixed::fromReal(pos.y());
1987 }
1988
1989 /*!
1990     Returns the line's position relative to the text layout's position.
1991 */
1992 QPointF QTextLine::position() const
1993 {
1994     return QPointF(eng->lines[index].x.toReal(), eng->lines[index].y.toReal());
1995 }
1996
1997 // ### DOC: I have no idea what this means/does.
1998 // You create a text layout with a string of text. Once you laid
1999 // it out, it contains a number of QTextLines. from() returns the position
2000 // inside the text string where this line starts. If you e.g. has a
2001 // text of "This is a string", laid out into two lines (the second
2002 // starting at the word 'a'), layout.lineAt(0).from() == 0 and
2003 // layout.lineAt(1).from() == 8.
2004 /*!
2005     Returns the start of the line from the beginning of the string
2006     passed to the QTextLayout.
2007 */
2008 int QTextLine::textStart() const
2009 {
2010     return eng->lines[index].from;
2011 }
2012
2013 /*!
2014     Returns the length of the text in the line.
2015
2016     \sa naturalTextWidth()
2017 */
2018 int QTextLine::textLength() const
2019 {
2020     if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators
2021         && eng->block.isValid() && index == eng->lines.count()-1) {
2022         return eng->lines[index].length - 1;
2023     }
2024     return eng->lines[index].length + eng->lines[index].trailingSpaces;
2025 }
2026
2027 static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, QTextItemInt &gf, QTextEngine *eng,
2028                          int start, int glyph_start)
2029 {
2030     int ge = glyph_start + gf.glyphs.numGlyphs;
2031     int gs = glyph_start;
2032     int end = start + gf.num_chars;
2033     unsigned short *logClusters = eng->logClusters(&si);
2034     QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2035     QFixed orig_width = gf.width;
2036
2037     int *ul = eng->underlinePositions;
2038     if (ul)
2039         while (*ul != -1 && *ul < start)
2040             ++ul;
2041     bool rtl = si.analysis.bidiLevel % 2;
2042     if (rtl)
2043         x += si.width;
2044
2045     do {
2046         int gtmp = ge;
2047         int stmp = end;
2048         if (ul && *ul != -1 && *ul < end) {
2049             stmp = *ul;
2050             gtmp = logClusters[*ul-si.position];
2051         }
2052
2053         gf.glyphs = glyphs.mid(gs, gtmp - gs);
2054         gf.num_chars = stmp - start;
2055         gf.chars = eng->layoutData->string.unicode() + start;
2056         QFixed w = 0;
2057         while (gs < gtmp) {
2058             w += glyphs.effectiveAdvance(gs);
2059             ++gs;
2060         }
2061         start = stmp;
2062         gf.width = w;
2063         if (rtl)
2064             x -= w;
2065         if (gf.num_chars)
2066             QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng);
2067         if (!rtl)
2068             x += w;
2069         if (ul && *ul != -1 && *ul < end) {
2070             // draw underline
2071             gtmp = (*ul == end-1) ? ge : logClusters[*ul+1-si.position];
2072             ++stmp;
2073             gf.glyphs = glyphs.mid(gs, gtmp - gs);
2074             gf.num_chars = stmp - start;
2075             gf.chars = eng->layoutData->string.unicode() + start;
2076             gf.logClusters = logClusters + start - si.position;
2077             w = 0;
2078             while (gs < gtmp) {
2079                 w += glyphs.effectiveAdvance(gs);
2080                 ++gs;
2081             }
2082             ++start;
2083             gf.width = w;
2084             gf.underlineStyle = QTextCharFormat::SingleUnderline;
2085             if (rtl)
2086                 x -= w;
2087             QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng);
2088             if (!rtl)
2089                 x += w;
2090             gf.underlineStyle = QTextCharFormat::NoUnderline;
2091             ++gf.chars;
2092             ++ul;
2093         }
2094     } while (gs < ge);
2095
2096     gf.width = orig_width;
2097 }
2098
2099
2100 static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
2101 {
2102     QBrush c = chf.foreground();
2103     if (c.style() == Qt::NoBrush) {
2104         p->setPen(defaultPen);
2105     }
2106
2107     QBrush bg = chf.background();
2108     if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
2109         p->fillRect(r, bg);
2110     if (c.style() != Qt::NoBrush) {
2111         p->setPen(QPen(c, 0));
2112     }
2113
2114 }
2115
2116 #if !defined(QT_NO_RAWFONT)
2117 static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &glyphLayout,
2118                                   const QPointF &pos, const QGlyphRun::GlyphRunFlags &flags,
2119                                   const QFixed &selectionX, const QFixed &selectionWidth)
2120 {
2121     QGlyphRun glyphRun;
2122
2123     // Make a font for this particular engine
2124     QRawFont font;
2125     QRawFontPrivate *fontD = QRawFontPrivate::get(font);
2126     fontD->fontEngine = fontEngine;
2127     fontD->thread = QThread::currentThread();
2128     fontD->fontEngine->ref.ref();
2129     QVarLengthArray<glyph_t> glyphsArray;
2130     QVarLengthArray<QFixedPoint> positionsArray;
2131
2132     QTextItem::RenderFlags renderFlags;
2133     if (flags.testFlag(QGlyphRun::Overline))
2134         renderFlags |= QTextItem::Overline;
2135     if (flags.testFlag(QGlyphRun::Underline))
2136         renderFlags |= QTextItem::Underline;
2137     if (flags.testFlag(QGlyphRun::StrikeOut))
2138         renderFlags |= QTextItem::StrikeOut;
2139     if (flags.testFlag(QGlyphRun::RightToLeft))
2140         renderFlags |= QTextItem::RightToLeft;
2141
2142     fontEngine->getGlyphPositions(glyphLayout, QTransform(), renderFlags, glyphsArray,
2143                                   positionsArray);
2144     Q_ASSERT(glyphsArray.size() == positionsArray.size());
2145
2146     qreal fontHeight = font.ascent() + font.descent();
2147     qreal minY = 0;
2148     qreal maxY = 0;
2149     QVector<quint32> glyphs;
2150     QVector<QPointF> positions;
2151     for (int i=0; i<glyphsArray.size(); ++i) {
2152         glyphs.append(glyphsArray.at(i) & 0xffffff);
2153
2154         QPointF position = positionsArray.at(i).toPointF() + pos;
2155         positions.append(position);
2156
2157         if (i == 0) {
2158             maxY = minY = position.y();
2159         } else {
2160             minY = qMin(minY, position.y());
2161             maxY = qMax(maxY, position.y());
2162         }
2163     }
2164
2165     qreal height = maxY + fontHeight - minY;
2166
2167     glyphRun.setGlyphIndexes(glyphs);
2168     glyphRun.setPositions(positions);
2169     glyphRun.setFlags(flags);
2170     glyphRun.setRawFont(font);
2171
2172     glyphRun.setBoundingRect(QRectF(selectionX.toReal(), minY, selectionWidth.toReal(), height));
2173
2174     return glyphRun;
2175 }
2176
2177 /*!
2178     Returns the glyph indexes and positions for all glyphs in this QTextLine for characters
2179     in the range defined by \a from and \a length. The \a from index is relative to the beginning
2180     of the text in the containing QTextLayout, and the range must be within the range of QTextLine
2181     as given by functions textStart() and textLength().
2182
2183     If \a from is negative, it will default to textStart(), and if \a length is negative it will
2184     default to the return value of textLength().
2185
2186     \since 5.0
2187
2188     \sa QTextLayout::glyphRuns()
2189 */
2190 QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
2191 {
2192     const QScriptLine &line = eng->lines[index];
2193
2194     if (line.length == 0)
2195         return QList<QGlyphRun>();
2196
2197     if (from < 0)
2198         from = textStart();
2199
2200     if (length < 0)
2201         length = textLength();
2202
2203     if (length == 0)
2204         return QList<QGlyphRun>();
2205
2206     QTextLayout::FormatRange selection;
2207     selection.start = from;
2208     selection.length = length;
2209
2210     QTextLineItemIterator iterator(eng, index, QPointF(), &selection);
2211     qreal y = line.y.toReal() + line.base().toReal();
2212     QList<QGlyphRun> glyphRuns;
2213     while (!iterator.atEnd()) {
2214         QScriptItem &si = iterator.next();
2215         if (si.analysis.flags >= QScriptAnalysis::TabOrObject)
2216             continue;
2217
2218         QPointF pos(iterator.x.toReal(), y);
2219         if (from >= 0 && length >= 0 &&
2220             (from >= si.position + eng->length(&si)
2221              || from + length <= si.position
2222              || from + length <= iterator.itemStart
2223              || from >= iterator.itemEnd)) {
2224             continue;
2225         }
2226
2227         QFont font;
2228         QGlyphRun::GlyphRunFlags flags;
2229         if (!eng->useRawFont) {
2230             font = eng->font(si);
2231             if (font.overline())
2232                 flags |= QGlyphRun::Overline;
2233             if (font.underline())
2234                 flags |= QGlyphRun::Underline;
2235             if (font.strikeOut())
2236                 flags |= QGlyphRun::StrikeOut;
2237         }
2238
2239         bool rtl = false;
2240         if (si.analysis.bidiLevel % 2) {
2241             flags |= QGlyphRun::RightToLeft;
2242             rtl = true;
2243         }
2244
2245         int relativeFrom = qMax(iterator.itemStart, from) - si.position;
2246         int relativeTo = qMin(iterator.itemEnd - 1, from + length - 1) - si.position;
2247
2248         unsigned short *logClusters = eng->logClusters(&si);
2249         int glyphsStart = logClusters[relativeFrom];
2250         int glyphsEnd = (relativeTo == eng->length(&si))
2251                          ? si.num_glyphs - 1
2252                          : logClusters[relativeTo];
2253         // the glyph index right next to the requested range
2254         int nextGlyphIndex = relativeTo < eng->length(&si) - 1 ? logClusters[relativeTo + 1] : si.num_glyphs;
2255         if (nextGlyphIndex - 1 > glyphsEnd)
2256             glyphsEnd = nextGlyphIndex - 1;
2257         bool startsInsideLigature = relativeFrom > 0 && logClusters[relativeFrom - 1] == glyphsStart;
2258         bool endsInsideLigature = nextGlyphIndex == glyphsEnd;
2259
2260         int itemGlyphsStart = logClusters[iterator.itemStart - si.position];
2261         int itemGlyphsEnd = logClusters[iterator.itemEnd - 1 - si.position];
2262
2263         QGlyphLayout glyphLayout = eng->shapedGlyphs(&si);
2264
2265         // Calculate new x position of glyph layout for a subset. This becomes somewhat complex
2266         // when we're breaking a RTL script item, since the expected position passed into
2267         // getGlyphPositions() is the left-most edge of the left-most glyph in an RTL run.
2268         if (relativeFrom != (iterator.itemStart - si.position) && !rtl) {
2269             for (int i=itemGlyphsStart; i<glyphsStart; ++i) {
2270                 QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
2271                 pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
2272                                glyphLayout.advances_y[i].toReal());
2273             }
2274         } else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) {
2275             for (int i=itemGlyphsEnd; i>glyphsEnd; --i) {
2276                 QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
2277                 pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
2278                                glyphLayout.advances_y[i].toReal());
2279             }
2280         }
2281
2282         glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1);
2283
2284         QFixed x;
2285         QFixed width;
2286         iterator.getSelectionBounds(&x, &width);
2287
2288         if (glyphLayout.numGlyphs > 0) {
2289             QFontEngine *mainFontEngine = eng->fontEngine(si);
2290
2291             if (mainFontEngine->type() == QFontEngine::Multi) {
2292                 QFontEngineMulti *multiFontEngine = static_cast<QFontEngineMulti *>(mainFontEngine);
2293                 int end = rtl ? glyphLayout.numGlyphs : 0;
2294                 int start = rtl ? end : 0;
2295                 int which = glyphLayout.glyphs[rtl ? start - 1 : end] >> 24;
2296                 for (; (rtl && start > 0) || (!rtl && end < glyphLayout.numGlyphs);
2297                      rtl ? --start : ++end) {
2298                     const int e = glyphLayout.glyphs[rtl ? start - 1 : end] >> 24;
2299                     if (e == which)
2300                         continue;
2301
2302                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2303                     multiFontEngine->ensureEngineAt(which);
2304
2305                     QGlyphRun::GlyphRunFlags subFlags = flags;
2306                     if (start == 0 && startsInsideLigature)
2307                         subFlags |= QGlyphRun::SplitLigature;
2308
2309                     glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which),
2310                                                       subLayout, pos, subFlags, x, width));
2311                     for (int i = 0; i < subLayout.numGlyphs; i++) {
2312                         pos += QPointF(subLayout.advances_x[i].toReal(),
2313                                        subLayout.advances_y[i].toReal());
2314                     }
2315
2316                     if (rtl)
2317                         end = start;
2318                     else
2319                         start = end;
2320                     which = e;
2321                 }
2322
2323                 QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2324                 multiFontEngine->ensureEngineAt(which);
2325
2326                 QGlyphRun::GlyphRunFlags subFlags = flags;
2327                 if ((start == 0 && startsInsideLigature) || endsInsideLigature)
2328                     subFlags |= QGlyphRun::SplitLigature;
2329
2330                 QGlyphRun glyphRun = glyphRunWithInfo(multiFontEngine->engine(which),
2331                                                       subLayout, pos, subFlags, x, width);
2332                 if (!glyphRun.isEmpty())
2333                     glyphRuns.append(glyphRun);
2334             } else {
2335                 if (startsInsideLigature || endsInsideLigature)
2336                     flags |= QGlyphRun::SplitLigature;
2337                 QGlyphRun glyphRun = glyphRunWithInfo(mainFontEngine, glyphLayout, pos, flags, x,
2338                                                       width);
2339                 if (!glyphRun.isEmpty())
2340                     glyphRuns.append(glyphRun);
2341             }
2342         }
2343     }
2344
2345     return glyphRuns;
2346 }
2347 #endif // QT_NO_RAWFONT
2348
2349 /*!
2350     \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const
2351
2352     Draws a line on the given \a painter at the specified \a position.
2353     The \a selection is reserved for internal use.
2354 */
2355 void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const
2356 {
2357 #ifndef QT_NO_RAWFONT
2358     // Not intended to work with rawfont
2359     Q_ASSERT(!eng->useRawFont);
2360 #endif
2361     const QScriptLine &line = eng->lines[index];
2362     QPen pen = p->pen();
2363
2364     bool noText = (selection && selection->format.property(SuppressText).toBool());
2365
2366     if (!line.length) {
2367         if (selection
2368             && selection->start <= line.from
2369             && selection->start + selection->length > line.from) {
2370
2371             const qreal lineHeight = line.height().toReal();
2372             QRectF r(pos.x() + line.x.toReal(), pos.y() + line.y.toReal(),
2373                      lineHeight / 2, QFontMetrics(eng->font()).width(QLatin1Char(' ')));
2374             setPenAndDrawBackground(p, QPen(), selection->format, r);
2375             p->setPen(pen);
2376         }
2377         return;
2378     }
2379
2380
2381     QTextLineItemIterator iterator(eng, index, pos, selection);
2382     QFixed lineBase = line.base();
2383     eng->clearDecorations();
2384     eng->enableDelayDecorations();
2385
2386     const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase;
2387
2388     bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
2389     while (!iterator.atEnd()) {
2390         QScriptItem &si = iterator.next();
2391
2392         if (selection && selection->start >= 0 && iterator.isOutsideSelection())
2393             continue;
2394
2395         if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator
2396             && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators))
2397             continue;
2398
2399         QFixed itemBaseLine = y;
2400         QFont f = eng->font(si);
2401         QTextCharFormat format;
2402
2403         if (eng->hasFormats() || selection) {
2404             format = eng->format(&si);
2405             if (suppressColors) {
2406                 format.clearForeground();
2407                 format.clearBackground();
2408                 format.clearProperty(QTextFormat::TextUnderlineColor);
2409             }
2410             if (selection)
2411                 format.merge(selection->format);
2412
2413             setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
2414                                                            iterator.itemWidth.toReal(), line.height().toReal()));
2415
2416             QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2417             if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {
2418                 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
2419                 QFixed height = fe->ascent() + fe->descent();
2420                 if (valign == QTextCharFormat::AlignSubScript)
2421                     itemBaseLine += height / 6;
2422                 else if (valign == QTextCharFormat::AlignSuperScript)
2423                     itemBaseLine -= height / 2;
2424             }
2425         }
2426
2427         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2428
2429             if (eng->hasFormats()) {
2430                 p->save();
2431                 if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) {
2432                     QFixed itemY = y - si.ascent;
2433                     if (format.verticalAlignment() == QTextCharFormat::AlignTop) {
2434                         itemY = y - lineBase;
2435                     }
2436
2437                     QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
2438
2439                     eng->docLayout()->drawInlineObject(p, itemRect,
2440                                                        QTextInlineObject(iterator.item, eng),
2441                                                        si.position + eng->block.position(),
2442                                                        format);
2443                     if (selection) {
2444                         QBrush bg = format.brushProperty(ObjectSelectionBrush);
2445                         if (bg.style() != Qt::NoBrush) {
2446                             QColor c = bg.color();
2447                             c.setAlpha(128);
2448                             p->fillRect(itemRect, c);
2449                         }
2450                     }
2451                 } else { // si.isTab
2452                     QFont f = eng->font(si);
2453                     QTextItemInt gf(si, &f, format);
2454                     gf.chars = 0;
2455                     gf.num_chars = 0;
2456                     gf.width = iterator.itemWidth;
2457                     QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng);
2458                     if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) {
2459                         QChar visualTab(0x2192);
2460                         int w = QFontMetrics(f).width(visualTab);
2461                         qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
2462                         if (x < 0)
2463                              p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
2464                                                    iterator.itemWidth.toReal(), line.height().toReal()),
2465                                             Qt::IntersectClip);
2466                         else
2467                              x /= 2; // Centered
2468                         p->drawText(QPointF(iterator.x.toReal() + x,
2469                                             y.toReal()), visualTab);
2470                     }
2471
2472                 }
2473                 p->restore();
2474             }
2475
2476             continue;
2477         }
2478
2479         unsigned short *logClusters = eng->logClusters(&si);
2480         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2481
2482         QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart),
2483                         &f, eng->layoutData->string.unicode() + iterator.itemStart,
2484                         iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format);
2485         gf.logClusters = logClusters + iterator.itemStart - si.position;
2486         gf.width = iterator.itemWidth;
2487         gf.justified = line.justified;
2488         gf.initWithScriptItem(si);
2489
2490         Q_ASSERT(gf.fontEngine);
2491
2492         if (eng->underlinePositions) {
2493             // can't have selections in this case
2494             drawMenuText(p, iterator.x, itemBaseLine, si, gf, eng, iterator.itemStart, iterator.glyphsStart);
2495         } else {
2496             QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
2497             if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) {
2498                 QPainterPath path;
2499                 path.setFillRule(Qt::WindingFill);
2500
2501                 if (gf.glyphs.numGlyphs)
2502                     gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
2503                 if (gf.flags) {
2504                     const QFontEngine *fe = gf.fontEngine;
2505                     const qreal lw = fe->lineThickness().toReal();
2506                     if (gf.flags & QTextItem::Underline) {
2507                         qreal offs = fe->underlinePosition().toReal();
2508                         path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
2509                     }
2510                     if (gf.flags & QTextItem::Overline) {
2511                         qreal offs = fe->ascent().toReal() + 1;
2512                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2513                     }
2514                     if (gf.flags & QTextItem::StrikeOut) {
2515                         qreal offs = fe->ascent().toReal() / 3;
2516                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2517                     }
2518                 }
2519
2520                 p->save();
2521                 p->setRenderHint(QPainter::Antialiasing);
2522                 //Currently QPen with a Qt::NoPen style still returns a default
2523                 //QBrush which != Qt::NoBrush so we need this specialcase to reset it
2524                 if (p->pen().style() == Qt::NoPen)
2525                     p->setBrush(Qt::NoBrush);
2526                 else
2527                     p->setBrush(p->pen().brush());
2528
2529                 p->setPen(format.textOutline());
2530                 p->drawPath(path);
2531                 p->restore();
2532             } else {
2533                 if (noText)
2534                     gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
2535                 QPainterPrivate::get(p)->drawTextItem(pos, gf, eng);
2536             }
2537         }
2538         if (si.analysis.flags == QScriptAnalysis::Space
2539             && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
2540             QBrush c = format.foreground();
2541             if (c.style() != Qt::NoBrush)
2542                 p->setPen(c.color());
2543             QChar visualSpace((ushort)0xb7);
2544             p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
2545             p->setPen(pen);
2546         }
2547     }
2548     eng->drawDecorations(p);
2549
2550     if (eng->hasFormats())
2551         p->setPen(pen);
2552 }
2553
2554 /*!
2555     \fn int QTextLine::cursorToX(int cursorPos, Edge edge) const
2556
2557     \overload
2558 */
2559
2560 /*!
2561     Converts the cursor position \a cursorPos to the corresponding x position
2562     inside the line, taking account of the \a edge.
2563
2564     If \a cursorPos is not a valid cursor position, the nearest valid
2565     cursor position will be used instead, and cpos will be modified to
2566     point to this valid cursor position.
2567
2568     \sa xToCursor()
2569 */
2570 qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
2571 {
2572     if (!eng->layoutData)
2573         eng->itemize();
2574
2575     const QScriptLine &line = eng->lines[index];
2576     bool lastLine = index >= eng->lines.size() - 1;
2577
2578     QFixed x = line.x;
2579     x += eng->alignLine(line);
2580
2581     if (!index && !eng->layoutData->items.size()) {
2582         *cursorPos = 0;
2583         return x.toReal();
2584     }
2585
2586     int pos = *cursorPos;
2587     int itm;
2588     const HB_CharAttributes *attributes = eng->attributes();
2589     while (pos < line.from + line.length && !attributes[pos].charStop)
2590         pos++;
2591     if (pos == line.from + (int)line.length) {
2592         // end of line ensure we have the last item on the line
2593         itm = eng->findItem(pos-1);
2594     }
2595     else
2596         itm = eng->findItem(pos);
2597     eng->shapeLine(line);
2598
2599     const QScriptItem *si = &eng->layoutData->items[itm];
2600     if (!si->num_glyphs)
2601         eng->shape(itm);
2602     pos -= si->position;
2603
2604     QGlyphLayout glyphs = eng->shapedGlyphs(si);
2605     unsigned short *logClusters = eng->logClusters(si);
2606     Q_ASSERT(logClusters);
2607
2608     int l = eng->length(itm);
2609     if (pos > l)
2610         pos = l;
2611     if (pos < 0)
2612         pos = 0;
2613
2614     int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos];
2615     if (edge == Trailing && glyph_pos < si->num_glyphs) {
2616         // trailing edge is leading edge of next cluster
2617         glyph_pos++;
2618         while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart)
2619             glyph_pos++;
2620     }
2621
2622     bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2;
2623
2624     int lineEnd = line.from + line.length;
2625
2626     // add the items left of the cursor
2627
2628     int firstItem = eng->findItem(line.from);
2629     int lastItem = eng->findItem(lineEnd - 1);
2630     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2631
2632     QVarLengthArray<int> visualOrder(nItems);
2633     QVarLengthArray<uchar> levels(nItems);
2634     for (int i = 0; i < nItems; ++i)
2635         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2636     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2637
2638     for (int i = 0; i < nItems; ++i) {
2639         int item = visualOrder[i]+firstItem;
2640         if (item == itm)
2641             break;
2642         QScriptItem &si = eng->layoutData->items[item];
2643         if (!si.num_glyphs)
2644             eng->shape(item);
2645
2646         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2647             x += si.width;
2648             continue;
2649         }
2650         int start = qMax(line.from, si.position);
2651         int end = qMin(lineEnd, si.position + eng->length(item));
2652
2653         logClusters = eng->logClusters(&si);
2654
2655         int gs = logClusters[start-si.position];
2656         int ge = (end == si.position + eng->length(item)) ? si.num_glyphs-1 : logClusters[end-si.position-1];
2657
2658         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2659
2660         while (gs <= ge) {
2661             x += glyphs.effectiveAdvance(gs);
2662             ++gs;
2663         }
2664     }
2665
2666     logClusters = eng->logClusters(si);
2667     glyphs = eng->shapedGlyphs(si);
2668     if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
2669         if (pos == (reverse ? 0 : l))
2670             x += si->width;
2671     } else {
2672         bool rtl = eng->isRightToLeft();
2673         bool visual = eng->visualCursorMovement();
2674         int end = qMin(lineEnd, si->position + l) - si->position;
2675         if (reverse) {
2676             int glyph_end = end == l ? si->num_glyphs : logClusters[end];
2677             int glyph_start = glyph_pos;
2678             if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
2679                 glyph_start++;
2680             for (int i = glyph_end - 1; i >= glyph_start; i--)
2681                 x += glyphs.effectiveAdvance(i);
2682         } else {
2683             int start = qMax(line.from - si->position, 0);
2684             int glyph_start = logClusters[start];
2685             int glyph_end = glyph_pos;
2686             if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
2687                 glyph_end--;
2688             for (int i = glyph_start; i <= glyph_end; i++)
2689                 x += glyphs.effectiveAdvance(i);
2690         }
2691         x += eng->offsetInLigature(si, pos, end, glyph_pos);
2692     }
2693
2694     if (eng->option.wrapMode() != QTextOption::NoWrap && x > line.width)
2695         x = line.width;
2696
2697     *cursorPos = pos + si->position;
2698     return x.toReal();
2699 }
2700
2701 /*!
2702     \fn int QTextLine::xToCursor(qreal x, CursorPosition cpos) const
2703
2704     Converts the x-coordinate \a x, to the nearest matching cursor
2705     position, depending on the cursor position type, \a cpos.
2706
2707     \sa cursorToX()
2708 */
2709 int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
2710 {
2711     QFixed x = QFixed::fromReal(_x);
2712     const QScriptLine &line = eng->lines[index];
2713     bool lastLine = index >= eng->lines.size() - 1;
2714     int lineNum = index;
2715
2716     if (!eng->layoutData)
2717         eng->itemize();
2718
2719     int line_length = textLength();
2720
2721     if (!line_length)
2722         return line.from;
2723
2724     int firstItem = eng->findItem(line.from);
2725     int lastItem = eng->findItem(line.from + line_length - 1);
2726     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2727
2728     if (!nItems)
2729         return 0;
2730
2731     x -= line.x;
2732     x -= eng->alignLine(line);
2733 //     qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
2734
2735     QVarLengthArray<int> visualOrder(nItems);
2736     QVarLengthArray<unsigned char> levels(nItems);
2737     for (int i = 0; i < nItems; ++i)
2738         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2739     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2740
2741     bool visual = eng->visualCursorMovement();
2742     if (x <= 0) {
2743         // left of first item
2744         int item = visualOrder[0]+firstItem;
2745         QScriptItem &si = eng->layoutData->items[item];
2746         if (!si.num_glyphs)
2747             eng->shape(item);
2748         int pos = si.position;
2749         if (si.analysis.bidiLevel % 2)
2750             pos += eng->length(item);
2751         pos = qMax(line.from, pos);
2752         pos = qMin(line.from + line_length, pos);
2753         return pos;
2754     } else if (x < line.textWidth
2755                || (line.justified && x < line.width)) {
2756         // has to be in one of the runs
2757         QFixed pos;
2758         bool rtl = eng->isRightToLeft();
2759
2760         eng->shapeLine(line);
2761         QVector<int> insertionPoints;
2762         if (visual && rtl)
2763             eng->insertionPointsForLine(lineNum, insertionPoints);
2764         int nchars = 0;
2765         for (int i = 0; i < nItems; ++i) {
2766             int item = visualOrder[i]+firstItem;
2767             QScriptItem &si = eng->layoutData->items[item];
2768             int item_length = eng->length(item);
2769 //             qDebug("    item %d, visual %d x_remain=%f", i, item, x.toReal());
2770
2771             int start = qMax(line.from - si.position, 0);
2772             int end = qMin(line.from + line_length - si.position, item_length);
2773
2774             unsigned short *logClusters = eng->logClusters(&si);
2775
2776             int gs = logClusters[start];
2777             int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1;
2778             QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2779
2780             QFixed item_width = 0;
2781             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2782                 item_width = si.width;
2783             } else {
2784                 int g = gs;
2785                 while (g <= ge) {
2786                     item_width += glyphs.effectiveAdvance(g);
2787                     ++g;
2788                 }
2789             }
2790 //             qDebug("      start=%d, end=%d, gs=%d, ge=%d item_width=%f", start, end, gs, ge, item_width.toReal());
2791
2792             if (pos + item_width < x) {
2793                 pos += item_width;
2794                 nchars += end;
2795                 continue;
2796             }
2797 //             qDebug("      inside run");
2798             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2799                 if (cpos == QTextLine::CursorOnCharacter)
2800                     return si.position;
2801                 bool left_half = (x - pos) < item_width/2;
2802
2803                 if (bool(si.analysis.bidiLevel % 2) != left_half)
2804                     return si.position;
2805                 return si.position + 1;
2806             }
2807
2808             int glyph_pos = -1;
2809             QFixed edge;
2810             // has to be inside run
2811             if (cpos == QTextLine::CursorOnCharacter) {
2812                 if (si.analysis.bidiLevel % 2) {
2813                     pos += item_width;
2814                     glyph_pos = gs;
2815                     while (gs <= ge) {
2816                         if (glyphs.attributes[gs].clusterStart) {
2817                             if (pos < x)
2818                                 break;
2819                             glyph_pos = gs;
2820                             edge = pos;
2821                             break;
2822                         }
2823                         pos -= glyphs.effectiveAdvance(gs);
2824                         ++gs;
2825                     }
2826                 } else {
2827                     glyph_pos = gs;
2828                     while (gs <= ge) {
2829                         if (glyphs.attributes[gs].clusterStart) {
2830                             if (pos > x)
2831                                 break;
2832                             glyph_pos = gs;
2833                             edge = pos;
2834                         }
2835                         pos += glyphs.effectiveAdvance(gs);
2836                         ++gs;
2837                     }
2838                 }
2839             } else {
2840                 QFixed dist = INT_MAX/256;
2841                 if (si.analysis.bidiLevel % 2) {
2842                     if (!visual || rtl || (lastLine && i == nItems - 1)) {
2843                         pos += item_width;
2844                         while (gs <= ge) {
2845                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2846                                 glyph_pos = gs;
2847                                 edge = pos;
2848                                 dist = qAbs(x-pos);
2849                             }
2850                             pos -= glyphs.effectiveAdvance(gs);
2851                             ++gs;
2852                         }
2853                     } else {
2854                         while (ge >= gs) {
2855                             if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
2856                                 glyph_pos = ge;
2857                                 edge = pos;
2858                                 dist = qAbs(x-pos);
2859                             }
2860                             pos += glyphs.effectiveAdvance(ge);
2861                             --ge;
2862                         }
2863                     }
2864                 } else {
2865                     if (!visual || !rtl || (lastLine && i == 0)) {
2866                         while (gs <= ge) {
2867                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2868                                 glyph_pos = gs;
2869                                 edge = pos;
2870                                 dist = qAbs(x-pos);
2871                             }
2872                             pos += glyphs.effectiveAdvance(gs);
2873                             ++gs;
2874                         }
2875                     } else {
2876                         QFixed oldPos = pos;
2877                         while (gs <= ge) {
2878                             pos += glyphs.effectiveAdvance(gs);
2879                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2880                                 glyph_pos = gs;
2881                                 edge = pos;
2882                                 dist = qAbs(x-pos);
2883                             }
2884                             ++gs;
2885                         }
2886                         pos = oldPos;
2887                     }
2888                 }
2889                 if (qAbs(x-pos) < dist) {
2890                     if (visual) {
2891                         if (!rtl && i < nItems - 1) {
2892                             nchars += end;
2893                             continue;
2894                         }
2895                         if (rtl && nchars > 0)
2896                             return insertionPoints[lastLine ? nchars : nchars - 1];
2897                     }
2898                     return eng->positionInLigature(&si, end, x, pos, -1,
2899                                                    cpos == QTextLine::CursorOnCharacter);
2900                 }
2901             }
2902             Q_ASSERT(glyph_pos != -1);
2903             return eng->positionInLigature(&si, end, x, edge, glyph_pos,
2904                                            cpos == QTextLine::CursorOnCharacter);
2905         }
2906     }
2907     // right of last item
2908 //     qDebug() << "right of last";
2909     int item = visualOrder[nItems-1]+firstItem;
2910     QScriptItem &si = eng->layoutData->items[item];
2911     if (!si.num_glyphs)
2912         eng->shape(item);
2913     int pos = si.position;
2914     if (!(si.analysis.bidiLevel % 2))
2915         pos += eng->length(item);
2916     pos = qMax(line.from, pos);
2917
2918     int maxPos = line.from + line_length;
2919
2920     // except for the last line we assume that the
2921     // character between lines is a space and we want
2922     // to position the cursor to the left of that
2923     // character.
2924     // ###### breaks with japanese for example
2925     if (this->index < eng->lines.count() - 1)
2926         --maxPos;
2927
2928     pos = qMin(pos, maxPos);
2929     return pos;
2930 }
2931
2932 QT_END_NAMESPACE