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