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