Merge remote branch 'origin/4.8' into 4.8-from-4.7
[qt:qt.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->resetFontEngineCache();
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->resetFontEngineCache();
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     \since 4.8
583
584     Set the cursor movement style. If the QTextLayout is backed by
585     a document, you can ignore this and use the option in QTextDocument,
586     this option is for widgets like QLineEdit or custom widgets without
587     a QTextDocument. Default value is Qt::LogicalMoveStyle.
588
589     \sa cursorMoveStyle()
590 */
591 void QTextLayout::setCursorMoveStyle(Qt::CursorMoveStyle style)
592 {
593     d->visualMovement = style == Qt::VisualMoveStyle ? true : false;
594 }
595
596 /*!
597     \since 4.8
598
599     The cursor movement style of this QTextLayout. The default is
600     Qt::LogicalMoveStyle.
601
602     \sa setCursorMoveStyle()
603 */
604 Qt::CursorMoveStyle QTextLayout::cursorMoveStyle() const
605 {
606     return d->visualMovement ? Qt::VisualMoveStyle : Qt::LogicalMoveStyle;
607 }
608
609 /*!
610     Begins the layout process.
611
612     \sa endLayout()
613 */
614 void QTextLayout::beginLayout()
615 {
616 #ifndef QT_NO_DEBUG
617     if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
618         qWarning("QTextLayout::beginLayout: Called while already doing layout");
619         return;
620     }
621 #endif
622     d->invalidate();
623     d->clearLineData();
624     d->itemize();
625     d->layoutData->layoutState = QTextEngine::InLayout;
626 }
627
628 /*!
629     Ends the layout process.
630
631     \sa beginLayout()
632 */
633 void QTextLayout::endLayout()
634 {
635 #ifndef QT_NO_DEBUG
636     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
637         qWarning("QTextLayout::endLayout: Called without beginLayout()");
638         return;
639     }
640 #endif
641     int l = d->lines.size();
642     if (l && d->lines.at(l-1).length < 0) {
643         QTextLine(l-1, d).setNumColumns(INT_MAX);
644     }
645     d->layoutData->layoutState = QTextEngine::LayoutEmpty;
646     if (!d->cacheGlyphs)
647         d->freeMemory();
648 }
649
650 /*!
651     \since 4.4
652
653     Clears the line information in the layout. After having called
654     this function, lineCount() returns 0.
655 */
656 void QTextLayout::clearLayout()
657 {
658     d->clearLineData();
659 }
660
661 /*!
662     Returns the next valid cursor position after \a oldPos that
663     respects the given cursor \a mode.
664     Returns value of \a oldPos, if \a oldPos is not a valid cursor position.
665
666     \sa isValidCursorPosition(), previousCursorPosition()
667 */
668 int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
669 {
670     const HB_CharAttributes *attributes = d->attributes();
671     int len = d->block.isValid() ? d->block.length() - 1
672                                  : d->layoutData->string.length();
673     Q_ASSERT(len <= d->layoutData->string.length());
674     if (!attributes || oldPos < 0 || oldPos >= len)
675         return oldPos;
676
677     if (mode == SkipCharacters) {
678         oldPos++;
679         while (oldPos < len && !attributes[oldPos].charStop)
680             oldPos++;
681     } else {
682         if (oldPos < len && d->atWordSeparator(oldPos)) {
683             oldPos++;
684             while (oldPos < len && d->atWordSeparator(oldPos))
685                 oldPos++;
686         } else {
687             while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
688                 oldPos++;
689         }
690         while (oldPos < len && d->atSpace(oldPos))
691             oldPos++;
692     }
693
694     return oldPos;
695 }
696
697 /*!
698     Returns the first valid cursor position before \a oldPos that
699     respects the given cursor \a mode.
700     Returns value of \a oldPos, if \a oldPos is not a valid cursor position.
701
702     \sa isValidCursorPosition(), nextCursorPosition()
703 */
704 int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
705 {
706     const HB_CharAttributes *attributes = d->attributes();
707     if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length())
708         return oldPos;
709
710     if (mode == SkipCharacters) {
711         oldPos--;
712         while (oldPos && !attributes[oldPos].charStop)
713             oldPos--;
714     } else {
715         while (oldPos && d->atSpace(oldPos-1))
716             oldPos--;
717
718         if (oldPos && d->atWordSeparator(oldPos-1)) {
719             oldPos--;
720             while (oldPos && d->atWordSeparator(oldPos-1))
721                 oldPos--;
722         } else {
723             while (oldPos && !d->atSpace(oldPos-1) && !d->atWordSeparator(oldPos-1))
724                 oldPos--;
725         }
726     }
727
728     return oldPos;
729 }
730
731 /*!
732     \since 4.8
733
734     Returns the cursor position to the right of \a oldPos, next to it.
735     The position is dependent on the visual position of characters, after
736     bi-directional reordering.
737
738     \sa leftCursorPosition(), nextCursorPosition()
739 */
740 int QTextLayout::rightCursorPosition(int oldPos) const
741 {
742     int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right);
743 //    qDebug("%d -> %d", oldPos, newPos);
744     return newPos;
745 }
746
747 /*!
748     \since 4.8
749
750     Returns the cursor position to the left of \a oldPos, next to it.
751     The position is dependent on the visual position of characters, after
752     bi-directional reordering.
753
754     \sa rightCursorPosition(), previousCursorPosition()
755 */
756 int QTextLayout::leftCursorPosition(int oldPos) const
757 {
758     int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left);
759 //    qDebug("%d -> %d", oldPos, newPos);
760     return newPos;
761 }
762
763 /*!/
764     Returns true if position \a pos is a valid cursor position.
765
766     In a Unicode context some positions in the text are not valid
767     cursor positions, because the position is inside a Unicode
768     surrogate or a grapheme cluster.
769
770     A grapheme cluster is a sequence of two or more Unicode characters
771     that form one indivisible entity on the screen. For example the
772     latin character `\Auml' can be represented in Unicode by two
773     characters, `A' (0x41), and the combining diaresis (0x308). A text
774     cursor can only validly be positioned before or after these two
775     characters, never between them since that wouldn't make sense. In
776     indic languages every syllable forms a grapheme cluster.
777 */
778 bool QTextLayout::isValidCursorPosition(int pos) const
779 {
780     const HB_CharAttributes *attributes = d->attributes();
781     if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length())
782         return false;
783     return attributes[pos].charStop;
784 }
785
786 /*!
787     Returns a new text line to be laid out if there is text to be
788     inserted into the layout; otherwise returns an invalid text line.
789
790     The text layout creates a new line object that starts after the
791     last line in the layout, or at the beginning if the layout is empty.
792     The layout maintains an internal cursor, and each line is filled
793     with text from the cursor position onwards when the
794     QTextLine::setLineWidth() function is called.
795
796     Once QTextLine::setLineWidth() is called, a new line can be created and
797     filled with text. Repeating this process will lay out the whole block
798     of text contained in the QTextLayout. If there is no text left to be
799     inserted into the layout, the QTextLine returned will not be valid
800     (isValid() will return false).
801 */
802 QTextLine QTextLayout::createLine()
803 {
804 #ifndef QT_NO_DEBUG
805     if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
806         qWarning("QTextLayout::createLine: Called without layouting");
807         return QTextLine();
808     }
809 #endif
810     if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
811         return QTextLine();
812
813     int l = d->lines.size();
814     if (l && d->lines.at(l-1).length < 0) {
815         QTextLine(l-1, d).setNumColumns(INT_MAX);
816     }
817     int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
818     int strlen = d->layoutData->string.length();
819     if (l && from >= strlen) {
820         if (!d->lines.at(l-1).length || d->layoutData->string.at(strlen - 1) != QChar::LineSeparator)
821             return QTextLine();
822     }
823
824     QScriptLine line;
825     line.from = from;
826     line.length = -1;
827     line.justified = false;
828     line.gridfitted = false;
829
830     d->lines.append(line);
831     return QTextLine(l, d);
832 }
833
834 /*!
835     Returns the number of lines in this text layout.
836
837     \sa lineAt()
838 */
839 int QTextLayout::lineCount() const
840 {
841     return d->lines.size();
842 }
843
844 /*!
845     Returns the \a{i}-th line of text in this text layout.
846
847     \sa lineCount(), lineForTextPosition()
848 */
849 QTextLine QTextLayout::lineAt(int i) const
850 {
851     return QTextLine(i, d);
852 }
853
854 /*!
855     Returns the line that contains the cursor position specified by \a pos.
856
857     \sa isValidCursorPosition(), lineAt()
858 */
859 QTextLine QTextLayout::lineForTextPosition(int pos) const
860 {
861     int lineNum = d->lineNumberForTextPosition(pos);
862     return lineNum >= 0 ? lineAt(lineNum) : QTextLine();
863 }
864
865 /*!
866     \since 4.2
867
868     The global position of the layout. This is independent of the
869     bounding rectangle and of the layout process.
870
871     \sa setPosition()
872 */
873 QPointF QTextLayout::position() const
874 {
875     return d->position;
876 }
877
878 /*!
879     Moves the text layout to point \a p.
880
881     \sa position()
882 */
883 void QTextLayout::setPosition(const QPointF &p)
884 {
885     d->position = p;
886 }
887
888 /*!
889     The smallest rectangle that contains all the lines in the layout.
890 */
891 QRectF QTextLayout::boundingRect() const
892 {
893     if (d->lines.isEmpty())
894         return QRectF();
895
896     QFixed xmax, ymax;
897     QFixed xmin = d->lines.at(0).x;
898     QFixed ymin = d->lines.at(0).y;
899
900     for (int i = 0; i < d->lines.size(); ++i) {
901         const QScriptLine &si = d->lines[i];
902         xmin = qMin(xmin, si.x);
903         ymin = qMin(ymin, si.y);
904         QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
905         xmax = qMax(xmax, si.x+lineWidth);
906         // ### shouldn't the ascent be used in ymin???
907         ymax = qMax(ymax, si.y+si.height());
908     }
909     return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal());
910 }
911
912 /*!
913     The minimum width the layout needs. This is the width of the
914     layout's smallest non-breakable substring.
915
916     \warning This function only returns a valid value after the layout
917     has been done.
918
919     \sa maximumWidth()
920 */
921 qreal QTextLayout::minimumWidth() const
922 {
923     return d->minWidth.toReal();
924 }
925
926 /*!
927     The maximum width the layout could expand to; this is essentially
928     the width of the entire text.
929
930     \warning This function only returns a valid value after the layout
931     has been done.
932
933     \sa minimumWidth()
934 */
935 qreal QTextLayout::maximumWidth() const
936 {
937     return d->maxWidth.toReal();
938 }
939
940
941 /*!
942     \internal
943 */
944 void QTextLayout::setFlags(int flags)
945 {
946     if (flags & Qt::TextJustificationForced) {
947         d->option.setAlignment(Qt::AlignJustify);
948         d->forceJustification = true;
949     }
950
951     if (flags & (Qt::TextForceLeftToRight|Qt::TextForceRightToLeft)) {
952         d->ignoreBidi = true;
953         d->option.setTextDirection((flags & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
954     }
955 }
956
957 static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection,
958                                      QPainterPath *region, QRectF boundingRect)
959 {
960     const QScriptLine &line = eng->lines[lineNumber];
961
962     QTextLineItemIterator iterator(eng, lineNumber, pos, selection);
963
964
965
966     const qreal selectionY = pos.y() + line.y.toReal();
967     const qreal lineHeight = line.height().toReal();
968
969     QFixed lastSelectionX = iterator.x;
970     QFixed lastSelectionWidth;
971
972     while (!iterator.atEnd()) {
973         iterator.next();
974
975         QFixed selectionX, selectionWidth;
976         if (iterator.getSelectionBounds(&selectionX, &selectionWidth)) {
977             if (selectionX == lastSelectionX + lastSelectionWidth) {
978                 lastSelectionWidth += selectionWidth;
979                 continue;
980             }
981
982             if (lastSelectionWidth > 0)
983                 region->addRect(boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight));
984
985             lastSelectionX = selectionX;
986             lastSelectionWidth = selectionWidth;
987         }
988     }
989     if (lastSelectionWidth > 0)
990         region->addRect(boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight));
991 }
992
993 static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
994 {
995     return clip.isValid() ? (rect & clip) : rect;
996 }
997
998
999 /*!
1000     Returns the glyph indexes and positions for all glyphs in this QTextLayout. This is an
1001     expensive function, and should not be called in a time sensitive context.
1002
1003     \since 4.8
1004
1005     \sa draw(), QPainter::drawGlyphRun()
1006 */
1007 #if !defined(QT_NO_RAWFONT)
1008 QList<QGlyphRun> QTextLayout::glyphRuns() const
1009 {
1010     QList<QGlyphRun> glyphs;
1011     for (int i=0; i<d->lines.size(); ++i)
1012         glyphs += QTextLine(i, d).glyphs(-1, -1);
1013
1014     return glyphs;
1015 }
1016 #endif // QT_NO_RAWFONT
1017
1018 /*!
1019     Draws the whole layout on the painter \a p at the position specified by \a pos.
1020     The rendered layout includes the given \a selections and is clipped within
1021     the rectangle specified by \a clip.
1022 */
1023 void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections, const QRectF &clip) const
1024 {
1025     if (d->lines.isEmpty())
1026         return;
1027
1028     if (!d->layoutData)
1029         d->itemize();
1030
1031     QPointF position = pos + d->position;
1032
1033     QFixed clipy = (INT_MIN/256);
1034     QFixed clipe = (INT_MAX/256);
1035     if (clip.isValid()) {
1036         clipy = QFixed::fromReal(clip.y() - position.y());
1037         clipe = clipy + QFixed::fromReal(clip.height());
1038     }
1039
1040     int firstLine = 0;
1041     int lastLine = d->lines.size();
1042     for (int i = 0; i < d->lines.size(); ++i) {
1043         QTextLine l(i, d);
1044         const QScriptLine &sl = d->lines[i];
1045
1046         if (sl.y > clipe) {
1047             lastLine = i;
1048             break;
1049         }
1050         if ((sl.y + sl.height()) < clipy) {
1051             firstLine = i;
1052             continue;
1053         }
1054     }
1055
1056     QPainterPath excludedRegion;
1057     QPainterPath textDoneRegion;
1058     for (int i = 0; i < selections.size(); ++i) {
1059         FormatRange selection = selections.at(i);
1060         const QBrush bg = selection.format.background();
1061
1062         QPainterPath region;
1063         region.setFillRule(Qt::WindingFill);
1064
1065         for (int line = firstLine; line < lastLine; ++line) {
1066             const QScriptLine &sl = d->lines[line];
1067             QTextLine tl(line, d);
1068
1069             QRectF lineRect(tl.naturalTextRect());
1070             lineRect.translate(position);
1071             lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0);
1072
1073             bool isLastLineInBlock = (line == d->lines.size()-1);
1074             int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
1075
1076
1077             if (sl.from > selection.start + selection.length || sl.from + sl_length <= selection.start)
1078                 continue; // no actual intersection
1079
1080             const bool selectionStartInLine = sl.from <= selection.start;
1081             const bool selectionEndInLine = selection.start + selection.length < sl.from + sl_length;
1082
1083             if (sl.length && (selectionStartInLine || selectionEndInLine)) {
1084                 addSelectedRegionsToPath(d, line, position, &selection, &region, clipIfValid(lineRect, clip));
1085             } else {
1086                 region.addRect(clipIfValid(lineRect, clip));
1087             }
1088
1089             if (selection.format.boolProperty(QTextFormat::FullWidthSelection)) {
1090                 QRectF fullLineRect(tl.rect());
1091                 fullLineRect.translate(position);
1092                 fullLineRect.setRight(QFIXED_MAX);
1093                 if (!selectionEndInLine)
1094                     region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
1095                 if (!selectionStartInLine)
1096                     region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
1097             } else if (!selectionEndInLine
1098                 && isLastLineInBlock
1099                 &&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
1100                 region.addRect(clipIfValid(QRectF(lineRect.right(), lineRect.top(),
1101                                                   lineRect.height()/4, lineRect.height()), clip));
1102             }
1103
1104         }
1105         {
1106             const QPen oldPen = p->pen();
1107             const QBrush oldBrush = p->brush();
1108
1109             p->setPen(selection.format.penProperty(QTextFormat::OutlinePen));
1110             p->setBrush(selection.format.brushProperty(QTextFormat::BackgroundBrush));
1111             p->drawPath(region);
1112
1113             p->setPen(oldPen);
1114             p->setBrush(oldBrush);
1115         }
1116
1117
1118
1119         bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
1120         bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
1121
1122         if (hasBackground) {
1123             selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
1124             // don't just clear the property, set an empty brush that overrides a potential
1125             // background brush specified in the text
1126             selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());
1127             selection.format.clearProperty(QTextFormat::OutlinePen);
1128         }
1129
1130         selection.format.setProperty(SuppressText, !hasText);
1131
1132         if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty())
1133             continue;
1134
1135         p->save();
1136         p->setClipPath(region, Qt::IntersectClip);
1137
1138         for (int line = firstLine; line < lastLine; ++line) {
1139             QTextLine l(line, d);
1140             l.draw(p, position, &selection);
1141         }
1142         p->restore();
1143
1144         if (hasText) {
1145             textDoneRegion += region;
1146         } else {
1147             if (hasBackground)
1148                 textDoneRegion -= region;
1149         }
1150
1151         excludedRegion += region;
1152     }
1153
1154     QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion;
1155     if (!needsTextButNoBackground.isEmpty()){
1156         p->save();
1157         p->setClipPath(needsTextButNoBackground, Qt::IntersectClip);
1158         FormatRange selection;
1159         selection.start = 0;
1160         selection.length = INT_MAX;
1161         selection.format.setProperty(SuppressBackground, true);
1162         for (int line = firstLine; line < lastLine; ++line) {
1163             QTextLine l(line, d);
1164             l.draw(p, position, &selection);
1165         }
1166         p->restore();
1167     }
1168
1169     if (!excludedRegion.isEmpty()) {
1170         p->save();
1171         QPainterPath path;
1172         QRectF br = boundingRect().translated(position);
1173         br.setRight(QFIXED_MAX);
1174         if (!clip.isNull())
1175             br = br.intersected(clip);
1176         path.addRect(br);
1177         path -= excludedRegion;
1178         p->setClipPath(path, Qt::IntersectClip);
1179     }
1180
1181     for (int i = firstLine; i < lastLine; ++i) {
1182         QTextLine l(i, d);
1183         l.draw(p, position);
1184     }
1185     if (!excludedRegion.isEmpty())
1186         p->restore();
1187
1188
1189     if (!d->cacheGlyphs)
1190         d->freeMemory();
1191 }
1192
1193 /*!
1194     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition) const
1195     \overload
1196
1197     Draws a text cursor with the current pen at the given \a position using the
1198     \a painter specified.
1199     The corresponding position within the text is specified by \a cursorPosition.
1200 */
1201 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
1202 {
1203     drawCursor(p, pos, cursorPosition, 1);
1204 }
1205
1206 /*!
1207     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition, int width) const
1208
1209     Draws a text cursor with the current pen and the specified \a width at the given \a position using the
1210     \a painter specified.
1211     The corresponding position within the text is specified by \a cursorPosition.
1212 */
1213 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const
1214 {
1215     if (d->lines.isEmpty())
1216         return;
1217
1218     if (!d->layoutData)
1219         d->itemize();
1220
1221     QPointF position = pos + d->position;
1222
1223     cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
1224     int line = d->lineNumberForTextPosition(cursorPosition);
1225     if (line < 0)
1226         line = 0;
1227     if (line >= d->lines.size())
1228         return;
1229
1230     QTextLine l(line, d);
1231     const QScriptLine &sl = d->lines[line];
1232
1233     qreal x = position.x() + l.cursorToX(cursorPosition);
1234
1235     int itm;
1236
1237     if (d->visualCursorMovement()) {
1238         if (cursorPosition == sl.from + sl.length)
1239             cursorPosition--;
1240         itm = d->findItem(cursorPosition);
1241     } else
1242         itm = d->findItem(cursorPosition - 1);
1243
1244     QFixed base = sl.base();
1245     QFixed descent = sl.descent;
1246     bool rightToLeft = d->isRightToLeft();
1247     if (itm >= 0) {
1248         const QScriptItem &si = d->layoutData->items.at(itm);
1249         if (si.ascent > 0)
1250             base = si.ascent;
1251         if (si.descent > 0)
1252             descent = si.descent;
1253         rightToLeft = si.analysis.bidiLevel % 2;
1254     }
1255     qreal y = position.y() + (sl.y + sl.base() - base).toReal();
1256     bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
1257                               && (p->transform().type() > QTransform::TxTranslate);
1258     if (toggleAntialiasing)
1259         p->setRenderHint(QPainter::Antialiasing);
1260 #if defined(QT_MAC_USE_COCOA)
1261     // Always draw the cursor aligned to pixel boundary.
1262     x = qRound(x);
1263 #endif
1264     p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
1265     if (toggleAntialiasing)
1266         p->setRenderHint(QPainter::Antialiasing, false);
1267     if (d->layoutData->hasBidi) {
1268         const int arrow_extent = 4;
1269         int sign = rightToLeft ? -1 : 1;
1270         p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2));
1271         p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2));
1272     }
1273     return;
1274 }
1275
1276 /*!
1277     \class QTextLine
1278     \reentrant
1279
1280     \brief The QTextLine class represents a line of text inside a QTextLayout.
1281
1282     \ingroup richtext-processing
1283
1284     A text line is usually created by QTextLayout::createLine().
1285
1286     After being created, the line can be filled using the setLineWidth()
1287     or setNumColumns() functions. A line has a number of attributes including the
1288     rectangle it occupies, rect(), its coordinates, x() and y(), its
1289     textLength(), width() and naturalTextWidth(), and its ascent() and decent()
1290     relative to the text. The position of the cursor in terms of the
1291     line is available from cursorToX() and its inverse from
1292     xToCursor(). A line can be moved with setPosition().
1293 */
1294
1295 /*!
1296     \enum QTextLine::Edge
1297
1298     \value Leading
1299     \value Trailing
1300 */
1301
1302 /*!
1303     \enum QTextLine::CursorPosition
1304
1305     \value CursorBetweenCharacters
1306     \value CursorOnCharacter
1307 */
1308
1309 /*!
1310     \fn QTextLine::QTextLine(int line, QTextEngine *e)
1311     \internal
1312
1313     Constructs a new text line using the line at position \a line in
1314     the text engine \a e.
1315 */
1316
1317 /*!
1318     \fn QTextLine::QTextLine()
1319
1320     Creates an invalid line.
1321 */
1322
1323 /*!
1324     \fn bool QTextLine::isValid() const
1325
1326     Returns true if this text line is valid; otherwise returns false.
1327 */
1328
1329 /*!
1330     \fn int QTextLine::lineNumber() const
1331
1332     Returns the position of the line in the text engine.
1333 */
1334
1335
1336 /*!
1337     Returns the line's bounding rectangle.
1338
1339     \sa x(), y(), textLength(), width()
1340 */
1341 QRectF QTextLine::rect() const
1342 {
1343     const QScriptLine& sl = eng->lines[i];
1344     return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());
1345 }
1346
1347 /*!
1348     Returns the rectangle covered by the line.
1349 */
1350 QRectF QTextLine::naturalTextRect() const
1351 {
1352     const QScriptLine& sl = eng->lines[i];
1353     QFixed x = sl.x + eng->alignLine(sl);
1354
1355     QFixed width = sl.textWidth;
1356     if (sl.justified)
1357         width = sl.width;
1358
1359     return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal());
1360 }
1361
1362 /*!
1363     Returns the line's x position.
1364
1365     \sa rect(), y(), textLength(), width()
1366 */
1367 qreal QTextLine::x() const
1368 {
1369     return eng->lines[i].x.toReal();
1370 }
1371
1372 /*!
1373     Returns the line's y position.
1374
1375     \sa x(), rect(), textLength(), width()
1376 */
1377 qreal QTextLine::y() const
1378 {
1379     return eng->lines[i].y.toReal();
1380 }
1381
1382 /*!
1383     Returns the line's width as specified by the layout() function.
1384
1385     \sa naturalTextWidth(), x(), y(), textLength(), rect()
1386 */
1387 qreal QTextLine::width() const
1388 {
1389     return eng->lines[i].width.toReal();
1390 }
1391
1392
1393 /*!
1394     Returns the line's ascent.
1395
1396     \sa descent(), height()
1397 */
1398 qreal QTextLine::ascent() const
1399 {
1400     return eng->lines[i].ascent.toReal();
1401 }
1402
1403 /*!
1404     Returns the line's descent.
1405
1406     \sa ascent(), height()
1407 */
1408 qreal QTextLine::descent() const
1409 {
1410     return eng->lines[i].descent.toReal();
1411 }
1412
1413 /*!
1414     Returns the line's height. This is equal to ascent() + descent() + 1
1415     if leading is not included. If leading is included, this equals to
1416     ascent() + descent() + leading() + 1.
1417
1418     \sa ascent(), descent(), leading(), setLeadingIncluded()
1419 */
1420 qreal QTextLine::height() const
1421 {
1422     return eng->lines[i].height().toReal();
1423 }
1424
1425 /*!
1426     \since 4.6
1427
1428     Returns the line's leading.
1429
1430     \sa ascent(), descent(), height()
1431 */
1432 qreal QTextLine::leading() const
1433 {
1434     return eng->lines[i].leading.toReal();
1435 }
1436
1437 /*!
1438     \since 4.6
1439
1440     Includes positive leading into the line's height if \a included is true;
1441     otherwise does not include leading.
1442
1443     By default, leading is not included.
1444
1445     Note that negative leading is ignored, it must be handled
1446     in the code using the text lines by letting the lines overlap.
1447
1448     \sa leadingIncluded()
1449
1450 */
1451 void QTextLine::setLeadingIncluded(bool included)
1452 {
1453     eng->lines[i].leadingIncluded= included;
1454
1455 }
1456
1457 /*!
1458     \since 4.6
1459
1460     Returns true if positive leading is included into the line's height;
1461     otherwise returns false.
1462
1463     By default, leading is not included.
1464
1465     \sa setLeadingIncluded()
1466 */
1467 bool QTextLine::leadingIncluded() const
1468 {
1469     return eng->lines[i].leadingIncluded;
1470 }
1471
1472 /*!
1473     Returns the width of the line that is occupied by text. This is
1474     always \<= to width(), and is the minimum width that could be used
1475     by layout() without changing the line break position.
1476 */
1477 qreal QTextLine::naturalTextWidth() const
1478 {
1479     return eng->lines[i].textWidth.toReal();
1480 }
1481
1482 /*!
1483     \since 4.7
1484     Returns the horizontal advance of the text. The advance of the text
1485     is the distance from its position to the next position at which
1486     text would naturally be drawn.
1487
1488     By adding the advance to the position of the text line and using this
1489     as the position of a second text line, you will be able to position
1490     the two lines side-by-side without gaps in-between.
1491 */
1492 qreal QTextLine::horizontalAdvance() const
1493 {
1494     return eng->lines[i].textAdvance.toReal();
1495 }
1496
1497 /*!
1498     Lays out the line with the given \a width. The line is filled from
1499     its starting position with as many characters as will fit into
1500     the line. In case the text cannot be split at the end of the line,
1501     it will be filled with additional characters to the next whitespace
1502     or end of the text.
1503 */
1504 void QTextLine::setLineWidth(qreal width)
1505 {
1506     QScriptLine &line = eng->lines[i];
1507     if (!eng->layoutData) {
1508         qWarning("QTextLine: Can't set a line width while not layouting.");
1509         return;
1510     }
1511
1512     if (width > QFIXED_MAX)
1513         width = QFIXED_MAX;
1514
1515     line.width = QFixed::fromReal(width);
1516     if (line.length
1517         && line.textWidth <= line.width
1518         && line.from + line.length == eng->layoutData->string.length())
1519         // no need to do anything if the line is already layouted and the last one. This optimization helps
1520         // when using things in a single line layout.
1521         return;
1522     line.length = 0;
1523     line.textWidth = 0;
1524
1525     layout_helper(INT_MAX);
1526 }
1527
1528 /*!
1529     Lays out the line. The line is filled from its starting position
1530     with as many characters as are specified by \a numColumns. In case
1531     the text cannot be split until \a numColumns characters, the line
1532     will be filled with as many characters to the next whitespace or
1533     end of the text.
1534 */
1535 void QTextLine::setNumColumns(int numColumns)
1536 {
1537     QScriptLine &line = eng->lines[i];
1538     line.width = QFIXED_MAX;
1539     line.length = 0;
1540     line.textWidth = 0;
1541     layout_helper(numColumns);
1542 }
1543
1544 /*!
1545     Lays out the line. The line is filled from its starting position
1546     with as many characters as are specified by \a numColumns. In case
1547     the text cannot be split until \a numColumns characters, the line
1548     will be filled with as many characters to the next whitespace or
1549     end of the text. The provided \a alignmentWidth is used as reference
1550     width for alignment.
1551 */
1552 void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth)
1553 {
1554     QScriptLine &line = eng->lines[i];
1555     line.width = QFixed::fromReal(alignmentWidth);
1556     line.length = 0;
1557     line.textWidth = 0;
1558     layout_helper(numColumns);
1559 }
1560
1561 #if 0
1562 #define LB_DEBUG qDebug
1563 #else
1564 #define LB_DEBUG if (0) qDebug
1565 #endif
1566
1567 namespace {
1568
1569     struct LineBreakHelper
1570     {
1571         LineBreakHelper()
1572             : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
1573               manualWrap(false), whiteSpaceOrObject(true)
1574         {
1575         }
1576
1577
1578         QScriptLine tmpData;
1579         QScriptLine spaceData;
1580
1581         QGlyphLayout glyphs;
1582
1583         int glyphCount;
1584         int maxGlyphs;
1585         int currentPosition;
1586         glyph_t previousGlyph;
1587
1588         QFixed minw;
1589         QFixed softHyphenWidth;
1590         QFixed rightBearing;
1591         QFixed minimumRightBearing;
1592
1593         QFontEngine *fontEngine;
1594         QFontEngine *previousFontEngine;
1595         const unsigned short *logClusters;
1596
1597         bool manualWrap;
1598         bool whiteSpaceOrObject;
1599
1600         bool checkFullOtherwiseExtend(QScriptLine &line);
1601
1602         QFixed calculateNewWidth(const QScriptLine &line) const {
1603             return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
1604                     - qMin(rightBearing, QFixed());
1605         }
1606
1607         inline glyph_t currentGlyph() const
1608         {            
1609             Q_ASSERT(currentPosition > 0);
1610             Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
1611
1612             return glyphs.glyphs[logClusters[currentPosition - 1]];
1613         }
1614
1615         inline void resetPreviousGlyph()
1616         {
1617             previousGlyph = 0;
1618             previousFontEngine = 0;
1619         }
1620
1621         inline void saveCurrentGlyph()
1622         {
1623             resetPreviousGlyph();
1624             if (currentPosition > 0 &&
1625                 logClusters[currentPosition - 1] < glyphs.numGlyphs) {
1626                 previousGlyph = currentGlyph(); // needed to calculate right bearing later
1627                 previousFontEngine = fontEngine;
1628             }
1629         }
1630
1631         inline void adjustRightBearing(glyph_t glyph)
1632         {
1633             qreal rb;
1634             fontEngine->getGlyphBearings(glyph, 0, &rb);
1635             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1636         }
1637
1638         inline void adjustRightBearing()
1639         {
1640             if (currentPosition <= 0)
1641                 return;
1642             adjustRightBearing(currentGlyph());
1643         }
1644
1645         inline void adjustPreviousRightBearing()
1646         {
1647             if (previousGlyph > 0 && previousFontEngine) {
1648                 qreal rb;
1649                 previousFontEngine->getGlyphBearings(previousGlyph, 0, &rb);
1650                 rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1651             }
1652         }
1653
1654         inline void resetRightBearing()
1655         {
1656             rightBearing = QFixed(1); // Any positive number is defined as invalid since only
1657                                       // negative right bearings are interesting to us.
1658         }
1659     };
1660
1661 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
1662 {
1663     LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
1664
1665     QFixed newWidth = calculateNewWidth(line);
1666     if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
1667         return true;
1668
1669     minw = qMax(minw, tmpData.textWidth);
1670     line += tmpData;
1671     line.textWidth += spaceData.textWidth;
1672
1673     line.length += spaceData.length;
1674     tmpData.textWidth = 0;
1675     tmpData.length = 0;
1676     spaceData.textWidth = 0;
1677     spaceData.length = 0;
1678
1679     return false;
1680 }
1681
1682 } // anonymous namespace
1683
1684
1685 static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount,
1686                                   const QScriptItem &current, const unsigned short *logClusters,
1687                                   const QGlyphLayout &glyphs)
1688 {
1689     int glyphPosition = logClusters[pos];
1690     do { // got to the first next cluster
1691         ++pos;
1692         ++line.length;
1693     } while (pos < end && logClusters[pos] == glyphPosition);
1694     do { // calculate the textWidth for the rest of the current cluster.
1695         if (!glyphs.attributes[glyphPosition].dontPrint)
1696             line.textWidth += glyphs.advances_x[glyphPosition];
1697         ++glyphPosition;
1698     } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart);
1699
1700     Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition);
1701
1702     ++glyphCount;
1703 }
1704
1705
1706 // fill QScriptLine
1707 void QTextLine::layout_helper(int maxGlyphs)
1708 {
1709     QScriptLine &line = eng->lines[i];
1710     line.length = 0;
1711     line.trailingSpaces = 0;
1712     line.textWidth = 0;
1713     line.hasTrailingSpaces = false;
1714
1715     if (!eng->layoutData->items.size() || line.from >= eng->layoutData->string.length()) {
1716         line.setDefaultHeight(eng);
1717         return;
1718     }
1719
1720     Q_ASSERT(line.from < eng->layoutData->string.length());
1721
1722     LineBreakHelper lbh;
1723
1724     lbh.maxGlyphs = maxGlyphs;
1725
1726     QTextOption::WrapMode wrapMode = eng->option.wrapMode();
1727     bool breakany = (wrapMode == QTextOption::WrapAnywhere);
1728     lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
1729
1730     int item = -1;
1731     int newItem = eng->findItem(line.from);
1732
1733     LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
1734
1735     Qt::Alignment alignment = eng->option.alignment();
1736
1737     const HB_CharAttributes *attributes = eng->attributes();
1738     if (!attributes)
1739         return;
1740     lbh.currentPosition = line.from;
1741     int end = 0;
1742     lbh.logClusters = eng->layoutData->logClustersPtr;
1743     lbh.resetPreviousGlyph();
1744
1745     while (newItem < eng->layoutData->items.size()) {
1746         lbh.resetRightBearing();
1747         lbh.softHyphenWidth = 0;
1748         if (newItem != item) {
1749             item = newItem;
1750             const QScriptItem &current = eng->layoutData->items[item];
1751             if (!current.num_glyphs) {
1752                 eng->shape(item);
1753                 attributes = eng->attributes();
1754                 if (!attributes)
1755                     return;
1756                 lbh.logClusters = eng->layoutData->logClustersPtr;
1757             }
1758             lbh.currentPosition = qMax(line.from, current.position);
1759             end = current.position + eng->length(item);
1760             lbh.glyphs = eng->shapedGlyphs(&current);
1761             QFontEngine *fontEngine = eng->fontEngine(current);
1762             if (lbh.fontEngine != fontEngine) {
1763                 lbh.fontEngine = fontEngine;
1764                 lbh.minimumRightBearing = qMin(QFixed(),
1765                                                QFixed::fromReal(fontEngine->minRightBearing()));
1766             }
1767         }
1768         const QScriptItem &current = eng->layoutData->items[item];
1769
1770         lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
1771                                    current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
1772                                                                             current.ascent);
1773         lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
1774         lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
1775
1776         if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
1777             lbh.whiteSpaceOrObject = true;
1778             if (lbh.checkFullOtherwiseExtend(line))
1779                 goto found;
1780
1781             QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth;
1782             QFixed tabWidth = eng->calculateTabWidth(item, x);
1783
1784             lbh.spaceData.textWidth += tabWidth;
1785             lbh.spaceData.length++;
1786             newItem = item + 1;
1787
1788             QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth();
1789             lbh.glyphCount += qRound(tabWidth / averageCharWidth);
1790
1791             if (lbh.checkFullOtherwiseExtend(line))
1792                 goto found;
1793         } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
1794             lbh.whiteSpaceOrObject = true;
1795             // if the line consists only of the line separator make sure
1796             // we have a sane height
1797             if (!line.length && !lbh.tmpData.length)
1798                 line.setDefaultHeight(eng);
1799             if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
1800                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1801                                current, lbh.logClusters, lbh.glyphs);
1802             } else {
1803                 lbh.tmpData.length++;
1804                 lbh.adjustPreviousRightBearing();
1805             }
1806             line += lbh.tmpData;
1807             goto found;
1808         } else if (current.analysis.flags == QScriptAnalysis::Object) {
1809             lbh.whiteSpaceOrObject = true;
1810             lbh.tmpData.length++;
1811
1812             QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item]));
1813             if (eng->block.docHandle())
1814                 eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format);
1815
1816             lbh.tmpData.textWidth += current.width;
1817
1818             newItem = item + 1;
1819             ++lbh.glyphCount;
1820             if (lbh.checkFullOtherwiseExtend(line))
1821                 goto found;
1822         } else if (attributes[lbh.currentPosition].whiteSpace) {
1823             lbh.whiteSpaceOrObject = true;
1824             while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
1825                 addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
1826                                current, lbh.logClusters, lbh.glyphs);
1827
1828             if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
1829                 lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line.
1830                 goto found;
1831             }
1832         } else {
1833             lbh.whiteSpaceOrObject = false;
1834             bool sb_or_ws = false;
1835             lbh.saveCurrentGlyph();
1836             do {
1837                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1838                                current, lbh.logClusters, lbh.glyphs);
1839
1840                 if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
1841                     sb_or_ws = true;
1842                     break;
1843                 } else if (breakany && attributes[lbh.currentPosition].charStop) {
1844                     break;
1845                 }
1846             } while (lbh.currentPosition < end);
1847             lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
1848
1849             if (lbh.currentPosition && attributes[lbh.currentPosition - 1].lineBreakType == HB_SoftHyphen) {
1850                 // if we are splitting up a word because of
1851                 // a soft hyphen then we ...
1852                 //
1853                 //  a) have to take the width of the soft hyphen into
1854                 //     account to see if the first syllable(s) /and/
1855                 //     the soft hyphen fit into the line
1856                 //
1857                 //  b) if we are so short of available width that the
1858                 //     soft hyphen is the first breakable position, then
1859                 //     we don't want to show it. However we initially
1860                 //     have to take the width for it into account so that
1861                 //     the text document layout sees the overflow and
1862                 //     switch to break-anywhere mode, in which we
1863                 //     want the soft-hyphen to slip into the next line
1864                 //     and thus become invisible again.
1865                 //
1866                 if (line.length)
1867                     lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1868                 else if (breakany)
1869                     lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1870             }
1871
1872             // The actual width of the text needs to take the right bearing into account. The
1873             // right bearing is left-ward, which means that if the rightmost pixel is to the right
1874             // of the advance of the glyph, the bearing will be negative. We flip the sign
1875             // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
1876             // We ignore the right bearing if the minimum negative bearing is too little to
1877             // expand the text beyond the edge.
1878             if (sb_or_ws|breakany) {
1879                 QFixed rightBearing = lbh.rightBearing; // store previous right bearing
1880 #if !defined(Q_WS_MAC)
1881                 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
1882 #endif
1883                     lbh.adjustRightBearing();
1884                 if (lbh.checkFullOtherwiseExtend(line)) {
1885                     // we are too wide, fix right bearing
1886                     if (rightBearing <= 0)
1887                         lbh.rightBearing = rightBearing; // take from cache
1888                     else
1889                         lbh.adjustPreviousRightBearing();
1890
1891                     if (!breakany) {
1892                         line.textWidth += lbh.softHyphenWidth;
1893                     }
1894
1895                     goto found;
1896                 }
1897             }
1898             lbh.saveCurrentGlyph();
1899         }
1900         if (lbh.currentPosition == end)
1901             newItem = item + 1;
1902     }
1903     LB_DEBUG("reached end of line");
1904     lbh.checkFullOtherwiseExtend(line);
1905 found:
1906     if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
1907         lbh.adjustRightBearing();
1908     line.textAdvance = line.textWidth;
1909     line.textWidth -= qMin(QFixed(), lbh.rightBearing);
1910
1911     if (line.length == 0) {
1912         LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
1913                lbh.tmpData.length, lbh.tmpData.textWidth.toReal(),
1914                lbh.spaceData.length, lbh.spaceData.textWidth.toReal());
1915         line += lbh.tmpData;
1916     }
1917
1918     LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(),
1919            line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal());
1920     LB_DEBUG("        : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data());
1921
1922     if (lbh.manualWrap) {
1923         eng->minWidth = qMax(eng->minWidth, line.textWidth);
1924         eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
1925     } else {
1926         eng->minWidth = qMax(eng->minWidth, lbh.minw);
1927         eng->maxWidth += line.textWidth;
1928     }
1929
1930     if (line.textWidth > 0 && item < eng->layoutData->items.size())
1931         eng->maxWidth += lbh.spaceData.textWidth;
1932     if (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
1933         line.textWidth += lbh.spaceData.textWidth;
1934     if (lbh.spaceData.length) {
1935         line.trailingSpaces = lbh.spaceData.length;
1936         line.hasTrailingSpaces = true;
1937     }
1938
1939     line.justified = false;
1940     line.gridfitted = false;
1941
1942     if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) {
1943         if ((lbh.maxGlyphs != INT_MAX && lbh.glyphCount > lbh.maxGlyphs)
1944             || (lbh.maxGlyphs == INT_MAX && line.textWidth > line.width)) {
1945
1946             eng->option.setWrapMode(QTextOption::WrapAnywhere);
1947             line.length = 0;
1948             line.textWidth = 0;
1949             layout_helper(lbh.maxGlyphs);
1950             eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
1951         }
1952     }
1953 }
1954
1955 /*!
1956     Moves the line to position \a pos.
1957 */
1958 void QTextLine::setPosition(const QPointF &pos)
1959 {
1960     eng->lines[i].x = QFixed::fromReal(pos.x());
1961     eng->lines[i].y = QFixed::fromReal(pos.y());
1962 }
1963
1964 /*!
1965     Returns the line's position relative to the text layout's position.
1966 */
1967 QPointF QTextLine::position() const
1968 {
1969     return QPointF(eng->lines[i].x.toReal(), eng->lines[i].y.toReal());
1970 }
1971
1972 // ### DOC: I have no idea what this means/does.
1973 // You create a text layout with a string of text. Once you laid
1974 // it out, it contains a number of QTextLines. from() returns the position
1975 // inside the text string where this line starts. If you e.g. has a
1976 // text of "This is a string", laid out into two lines (the second
1977 // starting at the word 'a'), layout.lineAt(0).from() == 0 and
1978 // layout.lineAt(1).from() == 8.
1979 /*!
1980     Returns the start of the line from the beginning of the string
1981     passed to the QTextLayout.
1982 */
1983 int QTextLine::textStart() const
1984 {
1985     return eng->lines[i].from;
1986 }
1987
1988 /*!
1989     Returns the length of the text in the line.
1990
1991     \sa naturalTextWidth()
1992 */
1993 int QTextLine::textLength() const
1994 {
1995     if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators
1996         && eng->block.isValid() && i == eng->lines.count()-1) {
1997         return eng->lines[i].length - 1;
1998     }
1999     return eng->lines[i].length + eng->lines[i].trailingSpaces;
2000 }
2001
2002 static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, QTextItemInt &gf, QTextEngine *eng,
2003                          int start, int glyph_start)
2004 {
2005     int ge = glyph_start + gf.glyphs.numGlyphs;
2006     int gs = glyph_start;
2007     int end = start + gf.num_chars;
2008     unsigned short *logClusters = eng->logClusters(&si);
2009     QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2010     QFixed orig_width = gf.width;
2011
2012     int *ul = eng->underlinePositions;
2013     if (ul)
2014         while (*ul != -1 && *ul < start)
2015             ++ul;
2016     bool rtl = si.analysis.bidiLevel % 2;
2017     if (rtl)
2018         x += si.width;
2019
2020     do {
2021         int gtmp = ge;
2022         int stmp = end;
2023         if (ul && *ul != -1 && *ul < end) {
2024             stmp = *ul;
2025             gtmp = logClusters[*ul-si.position];
2026         }
2027
2028         gf.glyphs = glyphs.mid(gs, gtmp - gs);
2029         gf.num_chars = stmp - start;
2030         gf.chars = eng->layoutData->string.unicode() + start;
2031         QFixed w = 0;
2032         while (gs < gtmp) {
2033             w += glyphs.effectiveAdvance(gs);
2034             ++gs;
2035         }
2036         start = stmp;
2037         gf.width = w;
2038         if (rtl)
2039             x -= w;
2040         if (gf.num_chars)
2041             p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2042         if (!rtl)
2043             x += w;
2044         if (ul && *ul != -1 && *ul < end) {
2045             // draw underline
2046             gtmp = (*ul == end-1) ? ge : logClusters[*ul+1-si.position];
2047             ++stmp;
2048             gf.glyphs = glyphs.mid(gs, gtmp - gs);
2049             gf.num_chars = stmp - start;
2050             gf.chars = eng->layoutData->string.unicode() + start;
2051             gf.logClusters = logClusters + start - si.position;
2052             w = 0;
2053             while (gs < gtmp) {
2054                 w += glyphs.effectiveAdvance(gs);
2055                 ++gs;
2056             }
2057             ++start;
2058             gf.width = w;
2059             gf.underlineStyle = QTextCharFormat::SingleUnderline;
2060             if (rtl)
2061                 x -= w;
2062             p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2063             if (!rtl)
2064                 x += w;
2065             gf.underlineStyle = QTextCharFormat::NoUnderline;
2066             ++gf.chars;
2067             ++ul;
2068         }
2069     } while (gs < ge);
2070
2071     gf.width = orig_width;
2072 }
2073
2074
2075 static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
2076 {
2077     QBrush c = chf.foreground();
2078     if (c.style() == Qt::NoBrush) {
2079         p->setPen(defaultPen);
2080     }
2081
2082     QBrush bg = chf.background();
2083     if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
2084         p->fillRect(r, bg);
2085     if (c.style() != Qt::NoBrush) {
2086         p->setPen(QPen(c, 0));
2087     }
2088
2089 }
2090
2091 namespace {
2092     struct GlyphInfo
2093     {
2094         GlyphInfo(const QGlyphLayout &layout, const QPointF &position,
2095                   const QTextItemInt::RenderFlags &renderFlags)
2096             : glyphLayout(layout), itemPosition(position), flags(renderFlags)
2097         {
2098         }
2099
2100         QGlyphLayout glyphLayout;
2101         QPointF itemPosition;
2102         QTextItem::RenderFlags flags;
2103     };
2104 }
2105
2106 /*!
2107     \internal
2108
2109     Returns the glyph indexes and positions for all glyphs in this QTextLine which reside in
2110     QScriptItems that overlap with the range defined by \a from and \a length. The arguments
2111     specify characters, relative to the text in the layout. Note that it is not possible to
2112     use this function to retrieve a subset of the glyphs in a QScriptItem.
2113
2114     \since 4.8
2115
2116     \sa QTextLayout::glyphRuns()
2117 */
2118 #if !defined(QT_NO_RAWFONT)
2119 QList<QGlyphRun> QTextLine::glyphs(int from, int length) const
2120 {
2121     const QScriptLine &line = eng->lines[i];
2122
2123     if (line.length == 0)
2124         return QList<QGlyphRun>();
2125
2126     QHash<QFontEngine *, GlyphInfo> glyphLayoutHash;
2127
2128     QTextLineItemIterator iterator(eng, i);
2129     qreal y = line.y.toReal() + line.base().toReal();
2130     while (!iterator.atEnd()) {
2131         QScriptItem &si = iterator.next();
2132         if (si.analysis.flags >= QScriptAnalysis::TabOrObject)
2133             continue;
2134
2135         QPointF pos(iterator.x.toReal(), y);
2136         if (from >= 0 && length >= 0 &&
2137             (from >= si.position + eng->length(&si) || from + length <= si.position))
2138             continue;
2139
2140         QFont font = eng->font(si);
2141
2142         QTextItem::RenderFlags flags;
2143         if (font.overline())
2144             flags |= QTextItem::Overline;
2145         if (font.underline())
2146             flags |= QTextItem::Underline;
2147         if (font.strikeOut())
2148             flags |= QTextItem::StrikeOut;
2149         if (si.analysis.bidiLevel % 2)
2150             flags |= QTextItem::RightToLeft;
2151
2152         QGlyphLayout glyphLayout = eng->shapedGlyphs(&si).mid(iterator.glyphsStart,
2153                                                               iterator.glyphsEnd - iterator.glyphsStart);
2154
2155         if (glyphLayout.numGlyphs > 0) {
2156             QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
2157             if (mainFontEngine->type() == QFontEngine::Multi) {
2158                 QFontEngineMulti *multiFontEngine = static_cast<QFontEngineMulti *>(mainFontEngine);
2159                 int start = 0;
2160                 int end;
2161                 int which = glyphLayout.glyphs[0] >> 24;
2162                 for (end = 0; end < glyphLayout.numGlyphs; ++end) {
2163                     const int e = glyphLayout.glyphs[end] >> 24;
2164                     if (e == which)
2165                         continue;
2166
2167                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2168                     glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2169                                                 GlyphInfo(subLayout, pos, flags));
2170                     for (int i = 0; i < subLayout.numGlyphs; i++)
2171                         pos += QPointF(subLayout.advances_x[i].toReal(),
2172                                        subLayout.advances_y[i].toReal());
2173
2174                     start = end;
2175                     which = e;
2176                 }
2177
2178                 QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2179                 glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2180                                             GlyphInfo(subLayout, pos, flags));
2181
2182             } else {
2183                 glyphLayoutHash.insertMulti(mainFontEngine,
2184                                             GlyphInfo(glyphLayout, pos, flags));
2185             }
2186         }
2187     }
2188
2189     QHash<QPair<QFontEngine *, int>, QGlyphRun> glyphsHash;
2190
2191     QList<QFontEngine *> keys = glyphLayoutHash.uniqueKeys();
2192     for (int i=0; i<keys.size(); ++i) {
2193         QFontEngine *fontEngine = keys.at(i);
2194
2195         // Make a font for this particular engine
2196         QRawFont font;
2197         QRawFontPrivate *fontD = QRawFontPrivate::get(font);
2198         fontD->fontEngine = fontEngine;
2199         fontD->fontEngine->ref.ref();
2200
2201 #if defined(Q_WS_WIN)
2202         if (fontEngine->supportsSubPixelPositions())
2203             fontD->hintingPreference = QFont::PreferVerticalHinting;
2204         else
2205             fontD->hintingPreference = QFont::PreferFullHinting;
2206 #elif defined(Q_WS_MAC)
2207         fontD->hintingPreference = QFont::PreferNoHinting;
2208 #elif !defined(QT_NO_FREETYPE)
2209         if (fontEngine->type() == QFontEngine::Freetype) {
2210             QFontEngineFT *freeTypeEngine = static_cast<QFontEngineFT *>(fontEngine);
2211             switch (freeTypeEngine->defaultHintStyle()) {
2212             case QFontEngineFT::HintNone:
2213                 fontD->hintingPreference = QFont::PreferNoHinting;
2214                 break;
2215             case QFontEngineFT::HintLight:
2216                 fontD->hintingPreference = QFont::PreferVerticalHinting;
2217                 break;
2218             case QFontEngineFT::HintMedium:
2219             case QFontEngineFT::HintFull:
2220                 fontD->hintingPreference = QFont::PreferFullHinting;
2221                 break;
2222             };
2223         }
2224 #endif
2225
2226         QList<GlyphInfo> glyphLayouts = glyphLayoutHash.values(fontEngine);
2227         for (int j=0; j<glyphLayouts.size(); ++j) {
2228             const QPointF &pos = glyphLayouts.at(j).itemPosition;
2229             const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout;
2230             const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags;            
2231
2232             QVarLengthArray<glyph_t> glyphsArray;
2233             QVarLengthArray<QFixedPoint> positionsArray;
2234
2235             fontEngine->getGlyphPositions(glyphLayout, QTransform(), flags, glyphsArray,
2236                                           positionsArray);
2237             Q_ASSERT(glyphsArray.size() == positionsArray.size());
2238
2239             QVector<quint32> glyphs;
2240             QVector<QPointF> positions;
2241             for (int i=0; i<glyphsArray.size(); ++i) {
2242                 glyphs.append(glyphsArray.at(i) & 0xffffff);
2243                 positions.append(positionsArray.at(i).toPointF() + pos);
2244             }
2245
2246             QGlyphRun glyphIndexes;
2247             glyphIndexes.setGlyphIndexes(glyphs);
2248             glyphIndexes.setPositions(positions);
2249
2250             glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline));
2251             glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline));
2252             glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
2253             glyphIndexes.setRawFont(font);
2254
2255             QPair<QFontEngine *, int> key(fontEngine, int(flags));
2256             if (!glyphsHash.contains(key)) {
2257                 glyphsHash.insert(key, glyphIndexes);
2258             } else {
2259                 QGlyphRun &glyphRun = glyphsHash[key];
2260
2261                 QVector<quint32> indexes = glyphRun.glyphIndexes();
2262                 QVector<QPointF> positions = glyphRun.positions();
2263
2264                 indexes += glyphIndexes.glyphIndexes();
2265                 positions += glyphIndexes.positions();
2266
2267                 glyphRun.setGlyphIndexes(indexes);
2268                 glyphRun.setPositions(positions);
2269             }
2270         }
2271     }
2272
2273     return glyphsHash.values();
2274 }
2275 #endif // QT_NO_RAWFONT
2276
2277 /*!
2278     \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const
2279
2280     Draws a line on the given \a painter at the specified \a position.
2281     The \a selection is reserved for internal use.
2282 */
2283 void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const
2284 {
2285     const QScriptLine &line = eng->lines[i];
2286     QPen pen = p->pen();
2287
2288     bool noText = (selection && selection->format.property(SuppressText).toBool());
2289
2290     if (!line.length) {
2291         if (selection
2292             && selection->start <= line.from
2293             && selection->start + selection->length > line.from) {
2294
2295             const qreal lineHeight = line.height().toReal();
2296             QRectF r(pos.x() + line.x.toReal(), pos.y() + line.y.toReal(),
2297                      lineHeight / 2, QFontMetrics(eng->font()).width(QLatin1Char(' ')));
2298             setPenAndDrawBackground(p, QPen(), selection->format, r);
2299             p->setPen(pen);
2300         }
2301         return;
2302     }
2303
2304
2305     QTextLineItemIterator iterator(eng, i, pos, selection);
2306     QFixed lineBase = line.base();
2307
2308     const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase;
2309
2310     bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
2311     while (!iterator.atEnd()) {
2312         QScriptItem &si = iterator.next();
2313
2314         if (selection && selection->start >= 0 && iterator.isOutsideSelection())
2315             continue;
2316
2317         if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator
2318             && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators))
2319             continue;
2320
2321         QFixed itemBaseLine = y;
2322         QFont f = eng->font(si);
2323         QTextCharFormat format;
2324
2325         if (eng->hasFormats() || selection) {
2326             format = eng->format(&si);
2327             if (suppressColors) {
2328                 format.clearForeground();
2329                 format.clearBackground();
2330                 format.clearProperty(QTextFormat::TextUnderlineColor);
2331             }
2332             if (selection)
2333                 format.merge(selection->format);
2334
2335             setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
2336                                                            iterator.itemWidth.toReal(), line.height().toReal()));
2337
2338             QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2339             if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {
2340                 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
2341                 QFixed height = fe->ascent() + fe->descent();
2342                 if (valign == QTextCharFormat::AlignSubScript)
2343                     itemBaseLine += height / 6;
2344                 else if (valign == QTextCharFormat::AlignSuperScript)
2345                     itemBaseLine -= height / 2;
2346             }
2347         }
2348
2349         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2350
2351             if (eng->hasFormats()) {
2352                 p->save();
2353                 if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) {
2354                     QFixed itemY = y - si.ascent;
2355                     if (format.verticalAlignment() == QTextCharFormat::AlignTop) {
2356                         itemY = y - lineBase;
2357                     }
2358
2359                     QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
2360
2361                     eng->docLayout()->drawInlineObject(p, itemRect,
2362                                                        QTextInlineObject(iterator.item, eng),
2363                                                        si.position + eng->block.position(),
2364                                                        format);
2365                     if (selection) {
2366                         QBrush bg = format.brushProperty(ObjectSelectionBrush);
2367                         if (bg.style() != Qt::NoBrush) {
2368                             QColor c = bg.color();
2369                             c.setAlpha(128);
2370                             p->fillRect(itemRect, c);
2371                         }
2372                     }
2373                 } else { // si.isTab
2374                     QFont f = eng->font(si);
2375                     QTextItemInt gf(si, &f, format);
2376                     gf.chars = 0;
2377                     gf.num_chars = 0;
2378                     gf.width = iterator.itemWidth;
2379                     p->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf);
2380                     if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) {
2381                         QChar visualTab(0x2192);
2382                         int w = QFontMetrics(f).width(visualTab);
2383                         qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
2384                         if (x < 0)
2385                              p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
2386                                                    iterator.itemWidth.toReal(), line.height().toReal()),
2387                                             Qt::IntersectClip);
2388                         else
2389                              x /= 2; // Centered
2390                         p->drawText(QPointF(iterator.x.toReal() + x,
2391                                             y.toReal()), visualTab);
2392                     }
2393
2394                 }
2395                 p->restore();
2396             }
2397
2398             continue;
2399         }
2400
2401         unsigned short *logClusters = eng->logClusters(&si);
2402         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2403
2404         QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart),
2405                         &f, eng->layoutData->string.unicode() + iterator.itemStart,
2406                         iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format);
2407         gf.logClusters = logClusters + iterator.itemStart - si.position;
2408         gf.width = iterator.itemWidth;
2409         gf.justified = line.justified;
2410         gf.initWithScriptItem(si);
2411
2412         Q_ASSERT(gf.fontEngine);
2413
2414         if (eng->underlinePositions) {
2415             // can't have selections in this case
2416             drawMenuText(p, iterator.x, itemBaseLine, si, gf, eng, iterator.itemStart, iterator.glyphsStart);
2417         } else {
2418             QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
2419             if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) {
2420                 QPainterPath path;
2421                 path.setFillRule(Qt::WindingFill);
2422
2423                 if (gf.glyphs.numGlyphs)
2424                     gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
2425                 if (gf.flags) {
2426                     const QFontEngine *fe = gf.fontEngine;
2427                     const qreal lw = fe->lineThickness().toReal();
2428                     if (gf.flags & QTextItem::Underline) {
2429                         qreal offs = fe->underlinePosition().toReal();
2430                         path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
2431                     }
2432                     if (gf.flags & QTextItem::Overline) {
2433                         qreal offs = fe->ascent().toReal() + 1;
2434                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2435                     }
2436                     if (gf.flags & QTextItem::StrikeOut) {
2437                         qreal offs = fe->ascent().toReal() / 3;
2438                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2439                     }
2440                 }
2441
2442                 p->save();
2443                 p->setRenderHint(QPainter::Antialiasing);
2444                 //Currently QPen with a Qt::NoPen style still returns a default
2445                 //QBrush which != Qt::NoBrush so we need this specialcase to reset it
2446                 if (p->pen().style() == Qt::NoPen)
2447                     p->setBrush(Qt::NoBrush);
2448                 else
2449                     p->setBrush(p->pen().brush());
2450
2451                 p->setPen(format.textOutline());
2452                 p->drawPath(path);
2453                 p->restore();
2454             } else {
2455                 if (noText)
2456                     gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
2457                 p->drawTextItem(pos, gf);
2458             }
2459         }
2460         if (si.analysis.flags == QScriptAnalysis::Space
2461             && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
2462             QBrush c = format.foreground();
2463             if (c.style() != Qt::NoBrush)
2464                 p->setPen(c.color());
2465             QChar visualSpace((ushort)0xb7);
2466             p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
2467             p->setPen(pen);
2468         }
2469     }
2470
2471
2472     if (eng->hasFormats())
2473         p->setPen(pen);
2474 }
2475
2476 /*!
2477     \fn int QTextLine::cursorToX(int cursorPos, Edge edge) const
2478
2479     \overload
2480 */
2481
2482 /*!
2483     Converts the cursor position \a cursorPos to the corresponding x position
2484     inside the line, taking account of the \a edge.
2485
2486     If \a cursorPos is not a valid cursor position, the nearest valid
2487     cursor position will be used instead, and cpos will be modified to
2488     point to this valid cursor position.
2489
2490     \sa xToCursor()
2491 */
2492 qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
2493 {
2494     if (!eng->layoutData)
2495         eng->itemize();
2496
2497     const QScriptLine &line = eng->lines[i];
2498     bool lastLine = i >= eng->lines.size() - 1;
2499
2500     QFixed x = line.x;
2501     x += eng->alignLine(line);
2502
2503     if (!i && !eng->layoutData->items.size()) {
2504         *cursorPos = 0;
2505         return x.toReal();
2506     }
2507
2508     int pos = *cursorPos;
2509     int itm;
2510     if (pos == line.from + (int)line.length) {
2511         // end of line ensure we have the last item on the line
2512         itm = eng->findItem(pos-1);
2513     }
2514     else
2515         itm = eng->findItem(pos);
2516     eng->shapeLine(line);
2517
2518     const QScriptItem *si = &eng->layoutData->items[itm];
2519     if (!si->num_glyphs)
2520         eng->shape(itm);
2521     pos -= si->position;
2522
2523     QGlyphLayout glyphs = eng->shapedGlyphs(si);
2524     unsigned short *logClusters = eng->logClusters(si);
2525     Q_ASSERT(logClusters);
2526
2527     int l = eng->length(itm);
2528     if (pos > l)
2529         pos = l;
2530     if (pos < 0)
2531         pos = 0;
2532
2533     int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos];
2534     if (edge == Trailing) {
2535         // trailing edge is leading edge of next cluster
2536         while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart)
2537             glyph_pos++;
2538     }
2539
2540     bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2;
2541
2542     int lineEnd = line.from + line.length;
2543
2544     // add the items left of the cursor
2545
2546     int firstItem = eng->findItem(line.from);
2547     int lastItem = eng->findItem(lineEnd - 1);
2548     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2549
2550     QVarLengthArray<int> visualOrder(nItems);
2551     QVarLengthArray<uchar> levels(nItems);
2552     for (int i = 0; i < nItems; ++i)
2553         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2554     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2555
2556     for (int i = 0; i < nItems; ++i) {
2557         int item = visualOrder[i]+firstItem;
2558         if (item == itm)
2559             break;
2560         QScriptItem &si = eng->layoutData->items[item];
2561         if (!si.num_glyphs)
2562             eng->shape(item);
2563
2564         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2565             x += si.width;
2566             continue;
2567         }
2568         int start = qMax(line.from, si.position);
2569         int end = qMin(lineEnd, si.position + eng->length(item));
2570
2571         logClusters = eng->logClusters(&si);
2572
2573         int gs = logClusters[start-si.position];
2574         int ge = (end == si.position + eng->length(item)) ? si.num_glyphs-1 : logClusters[end-si.position-1];
2575
2576         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2577
2578         while (gs <= ge) {
2579             x += glyphs.effectiveAdvance(gs);
2580             ++gs;
2581         }
2582     }
2583
2584     logClusters = eng->logClusters(si);
2585     glyphs = eng->shapedGlyphs(si);
2586     if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
2587         if (pos == (reverse ? 0 : l))
2588             x += si->width;
2589     } else {
2590         bool rtl = eng->isRightToLeft();
2591         bool visual = eng->visualCursorMovement();
2592         int end = qMin(lineEnd, si->position + l) - si->position;
2593         if (reverse) {
2594             int glyph_end = end == l ? si->num_glyphs : logClusters[end];
2595             int glyph_start = glyph_pos;
2596             if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
2597                 glyph_start++;
2598             for (int i = glyph_end - 1; i >= glyph_start; i--)
2599                 x += glyphs.effectiveAdvance(i);
2600         } else {
2601             int start = qMax(line.from - si->position, 0);
2602             int glyph_start = logClusters[start];
2603             int glyph_end = glyph_pos;
2604             if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
2605                 glyph_end--;
2606             for (int i = glyph_start; i <= glyph_end; i++)
2607                 x += glyphs.effectiveAdvance(i);
2608         }
2609         x += eng->offsetInLigature(si, pos, end, glyph_pos);
2610     }
2611
2612     *cursorPos = pos + si->position;
2613     return x.toReal();
2614 }
2615
2616 /*!
2617     \fn int QTextLine::xToCursor(qreal x, CursorPosition cpos) const
2618
2619     Converts the x-coordinate \a x, to the nearest matching cursor
2620     position, depending on the cursor position type, \a cpos.
2621
2622     \sa cursorToX()
2623 */
2624 int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
2625 {
2626     QFixed x = QFixed::fromReal(_x);
2627     const QScriptLine &line = eng->lines[i];
2628     bool lastLine = i >= eng->lines.size() - 1;
2629     int lineNum = i;
2630
2631     if (!eng->layoutData)
2632         eng->itemize();
2633
2634     int line_length = textLength();
2635
2636     if (!line_length)
2637         return line.from;
2638
2639     int firstItem = eng->findItem(line.from);
2640     int lastItem = eng->findItem(line.from + line_length - 1);
2641     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2642
2643     if (!nItems)
2644         return 0;
2645
2646     x -= line.x;
2647     x -= eng->alignLine(line);
2648 //     qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
2649
2650     QVarLengthArray<int> visualOrder(nItems);
2651     QVarLengthArray<unsigned char> levels(nItems);
2652     for (int i = 0; i < nItems; ++i)
2653         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2654     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2655
2656     bool visual = eng->visualCursorMovement();
2657     if (x <= 0) {
2658         // left of first item
2659         int item = visualOrder[0]+firstItem;
2660         QScriptItem &si = eng->layoutData->items[item];
2661         if (!si.num_glyphs)
2662             eng->shape(item);
2663         int pos = si.position;
2664         if (si.analysis.bidiLevel % 2)
2665             pos += eng->length(item);
2666         pos = qMax(line.from, pos);
2667         pos = qMin(line.from + line_length, pos);
2668         return pos;
2669     } else if (x < line.textWidth
2670                || (line.justified && x < line.width)) {
2671         // has to be in one of the runs
2672         QFixed pos;
2673         bool rtl = eng->isRightToLeft();
2674
2675         eng->shapeLine(line);
2676         QVector<int> insertionPoints;
2677         if (visual && rtl)
2678             eng->insertionPointsForLine(lineNum, insertionPoints);
2679         int nchars = 0;
2680         for (int i = 0; i < nItems; ++i) {
2681             int item = visualOrder[i]+firstItem;
2682             QScriptItem &si = eng->layoutData->items[item];
2683             int item_length = eng->length(item);
2684 //             qDebug("    item %d, visual %d x_remain=%f", i, item, x.toReal());
2685
2686             int start = qMax(line.from - si.position, 0);
2687             int end = qMin(line.from + line_length - si.position, item_length);
2688
2689             unsigned short *logClusters = eng->logClusters(&si);
2690
2691             int gs = logClusters[start];
2692             int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1;
2693             QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2694
2695             QFixed item_width = 0;
2696             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2697                 item_width = si.width;
2698             } else {
2699                 int g = gs;
2700                 while (g <= ge) {
2701                     item_width += glyphs.effectiveAdvance(g);
2702                     ++g;
2703                 }
2704             }
2705 //             qDebug("      start=%d, end=%d, gs=%d, ge=%d item_width=%f", start, end, gs, ge, item_width.toReal());
2706
2707             if (pos + item_width < x) {
2708                 pos += item_width;
2709                 nchars += end;
2710                 continue;
2711             }
2712 //             qDebug("      inside run");
2713             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2714                 if (cpos == QTextLine::CursorOnCharacter)
2715                     return si.position;
2716                 bool left_half = (x - pos) < item_width/2;
2717
2718                 if (bool(si.analysis.bidiLevel % 2) != left_half)
2719                     return si.position;
2720                 return si.position + 1;
2721             }
2722
2723             int glyph_pos = -1;
2724             QFixed edge;
2725             // has to be inside run
2726             if (cpos == QTextLine::CursorOnCharacter) {
2727                 if (si.analysis.bidiLevel % 2) {
2728                     pos += item_width;
2729                     glyph_pos = gs;
2730                     while (gs <= ge) {
2731                         if (glyphs.attributes[gs].clusterStart) {
2732                             if (pos < x)
2733                                 break;
2734                             glyph_pos = gs;
2735                             edge = pos;
2736                             break;
2737                         }
2738                         pos -= glyphs.effectiveAdvance(gs);
2739                         ++gs;
2740                     }
2741                 } else {
2742                     glyph_pos = gs;
2743                     while (gs <= ge) {
2744                         if (glyphs.attributes[gs].clusterStart) {
2745                             if (pos > x)
2746                                 break;
2747                             glyph_pos = gs;
2748                             edge = pos;
2749                         }
2750                         pos += glyphs.effectiveAdvance(gs);
2751                         ++gs;
2752                     }
2753                 }
2754             } else {
2755                 QFixed dist = INT_MAX/256;
2756                 if (si.analysis.bidiLevel % 2) {
2757                     if (!visual || rtl || (lastLine && i == nItems - 1)) {
2758                         pos += item_width;
2759                         while (gs <= ge) {
2760                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2761                                 glyph_pos = gs;
2762                                 edge = pos;
2763                                 dist = qAbs(x-pos);
2764                             }
2765                             pos -= glyphs.effectiveAdvance(gs);
2766                             ++gs;
2767                         }
2768                     } else {
2769                         while (ge >= gs) {
2770                             if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
2771                                 glyph_pos = ge;
2772                                 edge = pos;
2773                                 dist = qAbs(x-pos);
2774                             }
2775                             pos += glyphs.effectiveAdvance(ge);
2776                             --ge;
2777                         }
2778                     }
2779                 } else {
2780                     if (!visual || !rtl || (lastLine && i == 0)) {
2781                         while (gs <= ge) {
2782                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2783                                 glyph_pos = gs;
2784                                 edge = pos;
2785                                 dist = qAbs(x-pos);
2786                             }
2787                             pos += glyphs.effectiveAdvance(gs);
2788                             ++gs;
2789                         }
2790                     } else {
2791                         QFixed oldPos = pos;
2792                         while (gs <= ge) {
2793                             pos += glyphs.effectiveAdvance(gs);
2794                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2795                                 glyph_pos = gs;
2796                                 edge = pos;
2797                                 dist = qAbs(x-pos);
2798                             }
2799                             ++gs;
2800                         }
2801                         pos = oldPos;
2802                     }
2803                 }
2804                 if (qAbs(x-pos) < dist) {
2805                     if (visual) {
2806                         if (!rtl && i < nItems - 1) {
2807                             nchars += end;
2808                             continue;
2809                         }
2810                         if (rtl && nchars > 0)
2811                             return insertionPoints[lastLine ? nchars : nchars - 1];
2812                     }
2813                     return eng->positionInLigature(&si, end, x, pos, -1,
2814                                                    cpos == QTextLine::CursorOnCharacter);
2815                 }
2816             }
2817             Q_ASSERT(glyph_pos != -1);
2818             return eng->positionInLigature(&si, end, x, edge, glyph_pos,
2819                                            cpos == QTextLine::CursorOnCharacter);
2820         }
2821     }
2822     // right of last item
2823 //     qDebug() << "right of last";
2824     int item = visualOrder[nItems-1]+firstItem;
2825     QScriptItem &si = eng->layoutData->items[item];
2826     if (!si.num_glyphs)
2827         eng->shape(item);
2828     int pos = si.position;
2829     if (!(si.analysis.bidiLevel % 2))
2830         pos += eng->length(item);
2831     pos = qMax(line.from, pos);
2832
2833     int maxPos = line.from + line_length;
2834
2835     // except for the last line we assume that the
2836     // character between lines is a space and we want
2837     // to position the cursor to the left of that
2838     // character.
2839     // ###### breaks with japanese for example
2840     if (this->i < eng->lines.count() - 1)
2841         --maxPos;
2842
2843     pos = qMin(pos, maxPos);
2844     return pos;
2845 }
2846
2847 QT_END_NAMESPACE