Support visual cursor movement for BIDI text
[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 "qglyphs.h"
56 #include "qglyphs_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::drawGlyphs()
998 */
999 #if !defined(QT_NO_RAWFONT)
1000 QList<QGlyphs> QTextLayout::glyphs() const
1001 {
1002     QList<QGlyphs> 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
1064             bool isLastLineInBlock = (line == d->lines.size()-1);
1065             int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
1066
1067
1068             if (sl.from > selection.start + selection.length || sl.from + sl_length <= selection.start)
1069                 continue; // no actual intersection
1070
1071             const bool selectionStartInLine = sl.from <= selection.start;
1072             const bool selectionEndInLine = selection.start + selection.length < sl.from + sl_length;
1073
1074             if (sl.length && (selectionStartInLine || selectionEndInLine)) {
1075                 addSelectedRegionsToPath(d, line, position, &selection, &region, clipIfValid(lineRect, clip));
1076             } else {
1077                 region.addRect(clipIfValid(lineRect, clip));
1078             }
1079
1080             if (selection.format.boolProperty(QTextFormat::FullWidthSelection)) {
1081                 QRectF fullLineRect(tl.rect());
1082                 fullLineRect.translate(position);
1083                 fullLineRect.setRight(QFIXED_MAX);
1084                 if (!selectionEndInLine)
1085                     region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
1086                 if (!selectionStartInLine)
1087                     region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
1088             } else if (!selectionEndInLine
1089                 && isLastLineInBlock
1090                 &&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
1091                 region.addRect(clipIfValid(QRectF(lineRect.right(), lineRect.top(),
1092                                                   lineRect.height()/4, lineRect.height()), clip));
1093             }
1094
1095         }
1096         {
1097             const QPen oldPen = p->pen();
1098             const QBrush oldBrush = p->brush();
1099
1100             p->setPen(selection.format.penProperty(QTextFormat::OutlinePen));
1101             p->setBrush(selection.format.brushProperty(QTextFormat::BackgroundBrush));
1102             p->drawPath(region);
1103
1104             p->setPen(oldPen);
1105             p->setBrush(oldBrush);
1106         }
1107
1108
1109
1110         bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
1111         bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
1112
1113         if (hasBackground) {
1114             selection.format.setProperty(ObjectSelectionBrush, selection.format.property(QTextFormat::BackgroundBrush));
1115             // don't just clear the property, set an empty brush that overrides a potential
1116             // background brush specified in the text
1117             selection.format.setProperty(QTextFormat::BackgroundBrush, QBrush());
1118             selection.format.clearProperty(QTextFormat::OutlinePen);
1119         }
1120
1121         selection.format.setProperty(SuppressText, !hasText);
1122
1123         if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty())
1124             continue;
1125
1126         p->save();
1127         p->setClipPath(region, Qt::IntersectClip);
1128
1129         for (int line = firstLine; line < lastLine; ++line) {
1130             QTextLine l(line, d);
1131             l.draw(p, position, &selection);
1132         }
1133         p->restore();
1134
1135         if (hasText) {
1136             textDoneRegion += region;
1137         } else {
1138             if (hasBackground)
1139                 textDoneRegion -= region;
1140         }
1141
1142         excludedRegion += region;
1143     }
1144
1145     QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion;
1146     if (!needsTextButNoBackground.isEmpty()){
1147         p->save();
1148         p->setClipPath(needsTextButNoBackground, Qt::IntersectClip);
1149         FormatRange selection;
1150         selection.start = 0;
1151         selection.length = INT_MAX;
1152         selection.format.setProperty(SuppressBackground, true);
1153         for (int line = firstLine; line < lastLine; ++line) {
1154             QTextLine l(line, d);
1155             l.draw(p, position, &selection);
1156         }
1157         p->restore();
1158     }
1159
1160     if (!excludedRegion.isEmpty()) {
1161         p->save();
1162         QPainterPath path;
1163         QRectF br = boundingRect().translated(position);
1164         br.setRight(QFIXED_MAX);
1165         if (!clip.isNull())
1166             br = br.intersected(clip);
1167         path.addRect(br);
1168         path -= excludedRegion;
1169         p->setClipPath(path, Qt::IntersectClip);
1170     }
1171
1172     for (int i = firstLine; i < lastLine; ++i) {
1173         QTextLine l(i, d);
1174         l.draw(p, position);
1175     }
1176     if (!excludedRegion.isEmpty())
1177         p->restore();
1178
1179
1180     if (!d->cacheGlyphs)
1181         d->freeMemory();
1182 }
1183
1184 /*!
1185     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition) const
1186     \overload
1187
1188     Draws a text cursor with the current pen at the given \a position using the
1189     \a painter specified.
1190     The corresponding position within the text is specified by \a cursorPosition.
1191 */
1192 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
1193 {
1194     drawCursor(p, pos, cursorPosition, 1);
1195 }
1196
1197 /*!
1198     \fn void QTextLayout::drawCursor(QPainter *painter, const QPointF &position, int cursorPosition, int width) const
1199
1200     Draws a text cursor with the current pen and the specified \a width at the given \a position using the
1201     \a painter specified.
1202     The corresponding position within the text is specified by \a cursorPosition.
1203 */
1204 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const
1205 {
1206     if (d->lines.isEmpty())
1207         return;
1208
1209     if (!d->layoutData)
1210         d->itemize();
1211
1212     QPointF position = pos + d->position;
1213     QFixed pos_x = QFixed::fromReal(position.x());
1214     QFixed pos_y = QFixed::fromReal(position.y());
1215
1216     cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
1217     int line = d->lineNumberForTextPosition(cursorPosition);
1218     if (line < 0)
1219         line = 0;
1220     if (line >= d->lines.size())
1221         return;
1222
1223     QTextLine l(line, d);
1224     const QScriptLine &sl = d->lines[line];
1225
1226     qreal x = position.x() + l.cursorToX(cursorPosition);
1227
1228     int itm;
1229
1230     if (d->visualCursorMovement()) {
1231         if (cursorPosition == sl.from + sl.length)
1232             cursorPosition--;
1233         itm = d->findItem(cursorPosition);
1234     } else
1235         itm = d->findItem(cursorPosition - 1);
1236
1237     QFixed base = sl.base();
1238     QFixed descent = sl.descent;
1239     bool rightToLeft = d->isRightToLeft();
1240     if (itm >= 0) {
1241         const QScriptItem &si = d->layoutData->items.at(itm);
1242         if (si.ascent > 0)
1243             base = si.ascent;
1244         if (si.descent > 0)
1245             descent = si.descent;
1246         rightToLeft = si.analysis.bidiLevel % 2;
1247     }
1248     qreal y = position.y() + (sl.y + sl.base() - base).toReal();
1249     bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
1250                               && (p->transform().type() > QTransform::TxTranslate);
1251     if (toggleAntialiasing)
1252         p->setRenderHint(QPainter::Antialiasing);
1253 #if defined(QT_MAC_USE_COCOA)
1254     // Always draw the cursor aligned to pixel boundary.
1255     x = qRound(x);
1256 #endif
1257     p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
1258     if (toggleAntialiasing)
1259         p->setRenderHint(QPainter::Antialiasing, false);
1260     if (d->layoutData->hasBidi) {
1261         const int arrow_extent = 4;
1262         int sign = rightToLeft ? -1 : 1;
1263         p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2));
1264         p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2));
1265     }
1266     return;
1267 }
1268
1269 /*!
1270     \class QTextLine
1271     \reentrant
1272
1273     \brief The QTextLine class represents a line of text inside a QTextLayout.
1274
1275     \ingroup richtext-processing
1276
1277     A text line is usually created by QTextLayout::createLine().
1278
1279     After being created, the line can be filled using the setLineWidth()
1280     or setNumColumns() functions. A line has a number of attributes including the
1281     rectangle it occupies, rect(), its coordinates, x() and y(), its
1282     textLength(), width() and naturalTextWidth(), and its ascent() and decent()
1283     relative to the text. The position of the cursor in terms of the
1284     line is available from cursorToX() and its inverse from
1285     xToCursor(). A line can be moved with setPosition().
1286 */
1287
1288 /*!
1289     \enum QTextLine::Edge
1290
1291     \value Leading
1292     \value Trailing
1293 */
1294
1295 /*!
1296     \enum QTextLine::CursorPosition
1297
1298     \value CursorBetweenCharacters
1299     \value CursorOnCharacter
1300 */
1301
1302 /*!
1303     \fn QTextLine::QTextLine(int line, QTextEngine *e)
1304     \internal
1305
1306     Constructs a new text line using the line at position \a line in
1307     the text engine \a e.
1308 */
1309
1310 /*!
1311     \fn QTextLine::QTextLine()
1312
1313     Creates an invalid line.
1314 */
1315
1316 /*!
1317     \fn bool QTextLine::isValid() const
1318
1319     Returns true if this text line is valid; otherwise returns false.
1320 */
1321
1322 /*!
1323     \fn int QTextLine::lineNumber() const
1324
1325     Returns the position of the line in the text engine.
1326 */
1327
1328
1329 /*!
1330     Returns the line's bounding rectangle.
1331
1332     \sa x(), y(), textLength(), width()
1333 */
1334 QRectF QTextLine::rect() const
1335 {
1336     const QScriptLine& sl = eng->lines[i];
1337     return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());
1338 }
1339
1340 /*!
1341     Returns the rectangle covered by the line.
1342 */
1343 QRectF QTextLine::naturalTextRect() const
1344 {
1345     const QScriptLine& sl = eng->lines[i];
1346     QFixed x = sl.x + eng->alignLine(sl);
1347
1348     QFixed width = sl.textWidth;
1349     if (sl.justified)
1350         width = sl.width;
1351
1352     return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal());
1353 }
1354
1355 /*!
1356     Returns the line's x position.
1357
1358     \sa rect(), y(), textLength(), width()
1359 */
1360 qreal QTextLine::x() const
1361 {
1362     return eng->lines[i].x.toReal();
1363 }
1364
1365 /*!
1366     Returns the line's y position.
1367
1368     \sa x(), rect(), textLength(), width()
1369 */
1370 qreal QTextLine::y() const
1371 {
1372     return eng->lines[i].y.toReal();
1373 }
1374
1375 /*!
1376     Returns the line's width as specified by the layout() function.
1377
1378     \sa naturalTextWidth(), x(), y(), textLength(), rect()
1379 */
1380 qreal QTextLine::width() const
1381 {
1382     return eng->lines[i].width.toReal();
1383 }
1384
1385
1386 /*!
1387     Returns the line's ascent.
1388
1389     \sa descent(), height()
1390 */
1391 qreal QTextLine::ascent() const
1392 {
1393     return eng->lines[i].ascent.toReal();
1394 }
1395
1396 /*!
1397     Returns the line's descent.
1398
1399     \sa ascent(), height()
1400 */
1401 qreal QTextLine::descent() const
1402 {
1403     return eng->lines[i].descent.toReal();
1404 }
1405
1406 /*!
1407     Returns the line's height. This is equal to ascent() + descent() + 1
1408     if leading is not included. If leading is included, this equals to
1409     ascent() + descent() + leading() + 1.
1410
1411     \sa ascent(), descent(), leading(), setLeadingIncluded()
1412 */
1413 qreal QTextLine::height() const
1414 {
1415     return eng->lines[i].height().toReal();
1416 }
1417
1418 /*!
1419     \since 4.6
1420
1421     Returns the line's leading.
1422
1423     \sa ascent(), descent(), height()
1424 */
1425 qreal QTextLine::leading() const
1426 {
1427     return eng->lines[i].leading.toReal();
1428 }
1429
1430 /*!
1431     \since 4.6
1432
1433     Includes positive leading into the line's height if \a included is true;
1434     otherwise does not include leading.
1435
1436     By default, leading is not included.
1437
1438     Note that negative leading is ignored, it must be handled
1439     in the code using the text lines by letting the lines overlap.
1440
1441     \sa leadingIncluded()
1442
1443 */
1444 void QTextLine::setLeadingIncluded(bool included)
1445 {
1446     eng->lines[i].leadingIncluded= included;
1447
1448 }
1449
1450 /*!
1451     \since 4.6
1452
1453     Returns true if positive leading is included into the line's height;
1454     otherwise returns false.
1455
1456     By default, leading is not included.
1457
1458     \sa setLeadingIncluded()
1459 */
1460 bool QTextLine::leadingIncluded() const
1461 {
1462     return eng->lines[i].leadingIncluded;
1463 }
1464
1465 /*!
1466     Returns the width of the line that is occupied by text. This is
1467     always \<= to width(), and is the minimum width that could be used
1468     by layout() without changing the line break position.
1469 */
1470 qreal QTextLine::naturalTextWidth() const
1471 {
1472     return eng->lines[i].textWidth.toReal();
1473 }
1474
1475 /*!
1476     \since 4.7
1477     Returns the horizontal advance of the text. The advance of the text
1478     is the distance from its position to the next position at which
1479     text would naturally be drawn.
1480
1481     By adding the advance to the position of the text line and using this
1482     as the position of a second text line, you will be able to position
1483     the two lines side-by-side without gaps in-between.
1484 */
1485 qreal QTextLine::horizontalAdvance() const
1486 {
1487     return eng->lines[i].textAdvance.toReal();
1488 }
1489
1490 /*!
1491     Lays out the line with the given \a width. The line is filled from
1492     its starting position with as many characters as will fit into
1493     the line. In case the text cannot be split at the end of the line,
1494     it will be filled with additional characters to the next whitespace
1495     or end of the text.
1496 */
1497 void QTextLine::setLineWidth(qreal width)
1498 {
1499     QScriptLine &line = eng->lines[i];
1500     if (!eng->layoutData) {
1501         qWarning("QTextLine: Can't set a line width while not layouting.");
1502         return;
1503     }
1504
1505     if (width > QFIXED_MAX)
1506         width = QFIXED_MAX;
1507
1508     line.width = QFixed::fromReal(width);
1509     if (line.length
1510         && line.textWidth <= line.width
1511         && line.from + line.length == eng->layoutData->string.length())
1512         // no need to do anything if the line is already layouted and the last one. This optimization helps
1513         // when using things in a single line layout.
1514         return;
1515     line.length = 0;
1516     line.textWidth = 0;
1517
1518     layout_helper(INT_MAX);
1519 }
1520
1521 /*!
1522     Lays out the line. The line is filled from its starting position
1523     with as many characters as are specified by \a numColumns. In case
1524     the text cannot be split until \a numColumns characters, the line
1525     will be filled with as many characters to the next whitespace or
1526     end of the text.
1527 */
1528 void QTextLine::setNumColumns(int numColumns)
1529 {
1530     QScriptLine &line = eng->lines[i];
1531     line.width = QFIXED_MAX;
1532     line.length = 0;
1533     line.textWidth = 0;
1534     layout_helper(numColumns);
1535 }
1536
1537 /*!
1538     Lays out the line. The line is filled from its starting position
1539     with as many characters as are specified by \a numColumns. In case
1540     the text cannot be split until \a numColumns characters, the line
1541     will be filled with as many characters to the next whitespace or
1542     end of the text. The provided \a alignmentWidth is used as reference
1543     width for alignment.
1544 */
1545 void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth)
1546 {
1547     QScriptLine &line = eng->lines[i];
1548     line.width = QFixed::fromReal(alignmentWidth);
1549     line.length = 0;
1550     line.textWidth = 0;
1551     layout_helper(numColumns);
1552 }
1553
1554 #if 0
1555 #define LB_DEBUG qDebug
1556 #else
1557 #define LB_DEBUG if (0) qDebug
1558 #endif
1559
1560 namespace {
1561
1562     struct LineBreakHelper
1563     {
1564         LineBreakHelper()
1565             : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
1566               manualWrap(false), whiteSpaceOrObject(true)
1567         {
1568         }
1569
1570
1571         QScriptLine tmpData;
1572         QScriptLine spaceData;
1573
1574         QGlyphLayout glyphs;
1575
1576         int glyphCount;
1577         int maxGlyphs;
1578         int currentPosition;
1579         glyph_t previousGlyph;
1580
1581         QFixed minw;
1582         QFixed softHyphenWidth;
1583         QFixed rightBearing;
1584         QFixed minimumRightBearing;
1585
1586         QFontEngine *fontEngine;
1587         const unsigned short *logClusters;
1588
1589         bool manualWrap;
1590         bool whiteSpaceOrObject;
1591
1592         bool checkFullOtherwiseExtend(QScriptLine &line);
1593
1594         QFixed calculateNewWidth(const QScriptLine &line) const {
1595             return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
1596                     - qMin(rightBearing, QFixed());
1597         }
1598
1599         inline glyph_t currentGlyph() const
1600         {            
1601             Q_ASSERT(currentPosition > 0);
1602             Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
1603
1604             return glyphs.glyphs[logClusters[currentPosition - 1]];
1605         }
1606
1607         inline void saveCurrentGlyph()
1608         {
1609             previousGlyph = 0;
1610             if (currentPosition > 0 &&
1611                 logClusters[currentPosition - 1] < glyphs.numGlyphs) {
1612                 previousGlyph = currentGlyph(); // needed to calculate right bearing later
1613             }
1614         }
1615
1616         inline void adjustRightBearing(glyph_t glyph)
1617         {
1618             qreal rb;
1619             fontEngine->getGlyphBearings(glyph, 0, &rb);
1620             rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1621         }
1622
1623         inline void adjustRightBearing()
1624         {
1625             if (currentPosition <= 0)
1626                 return;
1627             adjustRightBearing(currentGlyph());
1628         }
1629
1630         inline void adjustPreviousRightBearing()
1631         {
1632             if (previousGlyph > 0)
1633                 adjustRightBearing(previousGlyph);
1634         }
1635
1636         inline void resetRightBearing()
1637         {
1638             rightBearing = QFixed(1); // Any positive number is defined as invalid since only
1639                                       // negative right bearings are interesting to us.
1640         }
1641     };
1642
1643 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
1644 {
1645     LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
1646
1647     QFixed newWidth = calculateNewWidth(line);
1648     if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
1649         return true;
1650
1651     minw = qMax(minw, tmpData.textWidth);
1652     line += tmpData;
1653     line.textWidth += spaceData.textWidth;
1654
1655     line.length += spaceData.length;
1656     tmpData.textWidth = 0;
1657     tmpData.length = 0;
1658     spaceData.textWidth = 0;
1659     spaceData.length = 0;
1660
1661     return false;
1662 }
1663
1664 } // anonymous namespace
1665
1666
1667 static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount,
1668                                   const QScriptItem &current, const unsigned short *logClusters,
1669                                   const QGlyphLayout &glyphs)
1670 {
1671     int glyphPosition = logClusters[pos];
1672     do { // got to the first next cluster
1673         ++pos;
1674         ++line.length;
1675     } while (pos < end && logClusters[pos] == glyphPosition);
1676     do { // calculate the textWidth for the rest of the current cluster.
1677         if (!glyphs.attributes[glyphPosition].dontPrint)
1678             line.textWidth += glyphs.advances_x[glyphPosition];
1679         ++glyphPosition;
1680     } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart);
1681
1682     Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition);
1683
1684     ++glyphCount;
1685 }
1686
1687
1688 // fill QScriptLine
1689 void QTextLine::layout_helper(int maxGlyphs)
1690 {
1691     QScriptLine &line = eng->lines[i];
1692     line.length = 0;
1693     line.textWidth = 0;
1694     line.hasTrailingSpaces = false;
1695
1696     if (!eng->layoutData->items.size() || line.from >= eng->layoutData->string.length()) {
1697         line.setDefaultHeight(eng);
1698         return;
1699     }
1700
1701     Q_ASSERT(line.from < eng->layoutData->string.length());
1702
1703     LineBreakHelper lbh;
1704
1705     lbh.maxGlyphs = maxGlyphs;
1706
1707     QTextOption::WrapMode wrapMode = eng->option.wrapMode();
1708     bool breakany = (wrapMode == QTextOption::WrapAnywhere);
1709     lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
1710
1711     int item = -1;
1712     int newItem = eng->findItem(line.from);
1713
1714     LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
1715
1716     Qt::Alignment alignment = eng->option.alignment();
1717
1718     const HB_CharAttributes *attributes = eng->attributes();
1719     if (!attributes)
1720         return;
1721     lbh.currentPosition = line.from;
1722     int end = 0;
1723     lbh.logClusters = eng->layoutData->logClustersPtr;
1724     lbh.previousGlyph = 0;
1725
1726     while (newItem < eng->layoutData->items.size()) {
1727         lbh.resetRightBearing();
1728         lbh.softHyphenWidth = 0;
1729         if (newItem != item) {
1730             item = newItem;
1731             const QScriptItem &current = eng->layoutData->items[item];
1732             if (!current.num_glyphs) {
1733                 eng->shape(item);
1734                 attributes = eng->attributes();
1735                 if (!attributes)
1736                     return;
1737                 lbh.logClusters = eng->layoutData->logClustersPtr;
1738             }
1739             lbh.currentPosition = qMax(line.from, current.position);
1740             end = current.position + eng->length(item);
1741             lbh.glyphs = eng->shapedGlyphs(&current);
1742             QFontEngine *fontEngine = eng->fontEngine(current);
1743             if (lbh.fontEngine != fontEngine) {
1744                 lbh.fontEngine = fontEngine;
1745                 lbh.minimumRightBearing = qMin(QFixed(),
1746                                                QFixed::fromReal(fontEngine->minRightBearing()));
1747             }
1748         }
1749         const QScriptItem &current = eng->layoutData->items[item];
1750
1751         lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
1752                                    current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
1753                                                                             current.ascent);
1754         lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
1755         lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
1756
1757         if (current.analysis.flags == QScriptAnalysis::Tab && (alignment & (Qt::AlignLeft | Qt::AlignRight | Qt::AlignCenter | Qt::AlignJustify))) {
1758             lbh.whiteSpaceOrObject = true;
1759             if (lbh.checkFullOtherwiseExtend(line))
1760                 goto found;
1761
1762             QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth;
1763             QFixed tabWidth = eng->calculateTabWidth(item, x);
1764
1765             lbh.spaceData.textWidth += tabWidth;
1766             lbh.spaceData.length++;
1767             newItem = item + 1;
1768
1769             QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth();
1770             lbh.glyphCount += qRound(tabWidth / averageCharWidth);
1771
1772             if (lbh.checkFullOtherwiseExtend(line))
1773                 goto found;
1774         } else if (current.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator) {
1775             lbh.whiteSpaceOrObject = true;
1776             // if the line consists only of the line separator make sure
1777             // we have a sane height
1778             if (!line.length && !lbh.tmpData.length)
1779                 line.setDefaultHeight(eng);
1780             if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators) {
1781                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1782                                current, lbh.logClusters, lbh.glyphs);
1783             } else {
1784                 lbh.tmpData.length++;
1785                 lbh.adjustPreviousRightBearing();
1786             }
1787             line += lbh.tmpData;
1788             goto found;
1789         } else if (current.analysis.flags == QScriptAnalysis::Object) {
1790             lbh.whiteSpaceOrObject = true;
1791             lbh.tmpData.length++;
1792
1793             QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item]));
1794             if (eng->block.docHandle())
1795                 eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format);
1796
1797             lbh.tmpData.textWidth += current.width;
1798
1799             newItem = item + 1;
1800             ++lbh.glyphCount;
1801             if (lbh.checkFullOtherwiseExtend(line))
1802                 goto found;
1803         } else if (attributes[lbh.currentPosition].whiteSpace) {
1804             lbh.whiteSpaceOrObject = true;
1805             while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
1806                 addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
1807                                current, lbh.logClusters, lbh.glyphs);
1808
1809             if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
1810                 lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line.
1811                 goto found;
1812             }
1813         } else {
1814             lbh.whiteSpaceOrObject = false;
1815             bool sb_or_ws = false;
1816             lbh.saveCurrentGlyph();
1817             do {
1818                 addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1819                                current, lbh.logClusters, lbh.glyphs);
1820
1821                 if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
1822                     sb_or_ws = true;
1823                     break;
1824                 } else if (breakany && attributes[lbh.currentPosition].charStop) {
1825                     break;
1826                 }
1827             } while (lbh.currentPosition < end);
1828             lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
1829
1830             if (lbh.currentPosition && attributes[lbh.currentPosition - 1].lineBreakType == HB_SoftHyphen) {
1831                 // if we are splitting up a word because of
1832                 // a soft hyphen then we ...
1833                 //
1834                 //  a) have to take the width of the soft hyphen into
1835                 //     account to see if the first syllable(s) /and/
1836                 //     the soft hyphen fit into the line
1837                 //
1838                 //  b) if we are so short of available width that the
1839                 //     soft hyphen is the first breakable position, then
1840                 //     we don't want to show it. However we initially
1841                 //     have to take the width for it into account so that
1842                 //     the text document layout sees the overflow and
1843                 //     switch to break-anywhere mode, in which we
1844                 //     want the soft-hyphen to slip into the next line
1845                 //     and thus become invisible again.
1846                 //
1847                 if (line.length)
1848                     lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1849                 else if (breakany)
1850                     lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1851             }
1852
1853             // The actual width of the text needs to take the right bearing into account. The
1854             // right bearing is left-ward, which means that if the rightmost pixel is to the right
1855             // of the advance of the glyph, the bearing will be negative. We flip the sign
1856             // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
1857             // We ignore the right bearing if the minimum negative bearing is too little to
1858             // expand the text beyond the edge.
1859             if (sb_or_ws|breakany) {
1860                 QFixed rightBearing = lbh.rightBearing; // store previous right bearing
1861 #if !defined(Q_WS_MAC)
1862                 if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
1863 #endif
1864                     lbh.adjustRightBearing();
1865                 if (lbh.checkFullOtherwiseExtend(line)) {
1866                     // we are too wide, fix right bearing
1867                     if (rightBearing <= 0)
1868                         lbh.rightBearing = rightBearing; // take from cache
1869                     else
1870                         lbh.adjustPreviousRightBearing();
1871
1872                     if (!breakany) {
1873                         line.textWidth += lbh.softHyphenWidth;
1874                     }
1875
1876                     goto found;
1877                 }
1878             }
1879             lbh.saveCurrentGlyph();
1880         }
1881         if (lbh.currentPosition == end)
1882             newItem = item + 1;
1883     }
1884     LB_DEBUG("reached end of line");
1885     lbh.checkFullOtherwiseExtend(line);
1886 found:
1887     if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
1888         lbh.adjustRightBearing();
1889     line.textAdvance = line.textWidth;
1890     line.textWidth -= qMin(QFixed(), lbh.rightBearing);
1891
1892     if (line.length == 0) {
1893         LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
1894                lbh.tmpData.length, lbh.tmpData.textWidth.toReal(),
1895                lbh.spaceData.length, lbh.spaceData.textWidth.toReal());
1896         line += lbh.tmpData;
1897     }
1898
1899     LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(),
1900            line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal());
1901     LB_DEBUG("        : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data());
1902
1903     if (lbh.manualWrap) {
1904         eng->minWidth = qMax(eng->minWidth, line.textWidth);
1905         eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
1906     } else {
1907         eng->minWidth = qMax(eng->minWidth, lbh.minw);
1908         eng->maxWidth += line.textWidth;
1909     }
1910
1911     if (line.textWidth > 0 && item < eng->layoutData->items.size())
1912         eng->maxWidth += lbh.spaceData.textWidth;
1913     if (eng->option.flags() & QTextOption::IncludeTrailingSpaces)
1914         line.textWidth += lbh.spaceData.textWidth;
1915     if (lbh.spaceData.length) {
1916         line.length += lbh.spaceData.length;
1917         line.hasTrailingSpaces = true;
1918     }
1919
1920     line.justified = false;
1921     line.gridfitted = false;
1922
1923     if (eng->option.wrapMode() == QTextOption::WrapAtWordBoundaryOrAnywhere) {
1924         if ((lbh.maxGlyphs != INT_MAX && lbh.glyphCount > lbh.maxGlyphs)
1925             || (lbh.maxGlyphs == INT_MAX && line.textWidth > line.width)) {
1926
1927             eng->option.setWrapMode(QTextOption::WrapAnywhere);
1928             line.length = 0;
1929             line.textWidth = 0;
1930             layout_helper(lbh.maxGlyphs);
1931             eng->option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
1932         }
1933     }
1934 }
1935
1936 /*!
1937     Moves the line to position \a pos.
1938 */
1939 void QTextLine::setPosition(const QPointF &pos)
1940 {
1941     eng->lines[i].x = QFixed::fromReal(pos.x());
1942     eng->lines[i].y = QFixed::fromReal(pos.y());
1943 }
1944
1945 /*!
1946     Returns the line's position relative to the text layout's position.
1947 */
1948 QPointF QTextLine::position() const
1949 {
1950     return QPointF(eng->lines[i].x.toReal(), eng->lines[i].y.toReal());
1951 }
1952
1953 // ### DOC: I have no idea what this means/does.
1954 // You create a text layout with a string of text. Once you laid
1955 // it out, it contains a number of QTextLines. from() returns the position
1956 // inside the text string where this line starts. If you e.g. has a
1957 // text of "This is a string", laid out into two lines (the second
1958 // starting at the word 'a'), layout.lineAt(0).from() == 0 and
1959 // layout.lineAt(1).from() == 8.
1960 /*!
1961     Returns the start of the line from the beginning of the string
1962     passed to the QTextLayout.
1963 */
1964 int QTextLine::textStart() const
1965 {
1966     return eng->lines[i].from;
1967 }
1968
1969 /*!
1970     Returns the length of the text in the line.
1971
1972     \sa naturalTextWidth()
1973 */
1974 int QTextLine::textLength() const
1975 {
1976     if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators
1977         && eng->block.isValid() && i == eng->lines.count()-1) {
1978         return eng->lines[i].length - 1;
1979     }
1980     return eng->lines[i].length;
1981 }
1982
1983 static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, QTextItemInt &gf, QTextEngine *eng,
1984                          int start, int glyph_start)
1985 {
1986     int ge = glyph_start + gf.glyphs.numGlyphs;
1987     int gs = glyph_start;
1988     int end = start + gf.num_chars;
1989     unsigned short *logClusters = eng->logClusters(&si);
1990     QGlyphLayout glyphs = eng->shapedGlyphs(&si);
1991     QFixed orig_width = gf.width;
1992
1993     int *ul = eng->underlinePositions;
1994     if (ul)
1995         while (*ul != -1 && *ul < start)
1996             ++ul;
1997     bool rtl = si.analysis.bidiLevel % 2;
1998     if (rtl)
1999         x += si.width;
2000
2001     do {
2002         int gtmp = ge;
2003         int stmp = end;
2004         if (ul && *ul != -1 && *ul < end) {
2005             stmp = *ul;
2006             gtmp = logClusters[*ul-si.position];
2007         }
2008
2009         gf.glyphs = glyphs.mid(gs, gtmp - gs);
2010         gf.num_chars = stmp - start;
2011         gf.chars = eng->layoutData->string.unicode() + start;
2012         QFixed w = 0;
2013         while (gs < gtmp) {
2014             w += glyphs.effectiveAdvance(gs);
2015             ++gs;
2016         }
2017         start = stmp;
2018         gf.width = w;
2019         if (rtl)
2020             x -= w;
2021         if (gf.num_chars)
2022             p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2023         if (!rtl)
2024             x += w;
2025         if (ul && *ul != -1 && *ul < end) {
2026             // draw underline
2027             gtmp = (*ul == end-1) ? ge : logClusters[*ul+1-si.position];
2028             ++stmp;
2029             gf.glyphs = glyphs.mid(gs, gtmp - gs);
2030             gf.num_chars = stmp - start;
2031             gf.chars = eng->layoutData->string.unicode() + start;
2032             gf.logClusters = logClusters + start - si.position;
2033             w = 0;
2034             while (gs < gtmp) {
2035                 w += glyphs.effectiveAdvance(gs);
2036                 ++gs;
2037             }
2038             ++start;
2039             gf.width = w;
2040             gf.underlineStyle = QTextCharFormat::SingleUnderline;
2041             if (rtl)
2042                 x -= w;
2043             p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2044             if (!rtl)
2045                 x += w;
2046             gf.underlineStyle = QTextCharFormat::NoUnderline;
2047             ++gf.chars;
2048             ++ul;
2049         }
2050     } while (gs < ge);
2051
2052     gf.width = orig_width;
2053 }
2054
2055
2056 static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
2057 {
2058     QBrush c = chf.foreground();
2059     if (c.style() == Qt::NoBrush) {
2060         p->setPen(defaultPen);
2061     }
2062
2063     QBrush bg = chf.background();
2064     if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
2065         p->fillRect(r, bg);
2066     if (c.style() != Qt::NoBrush) {
2067         p->setPen(QPen(c, 0));
2068     }
2069
2070 }
2071
2072 namespace {
2073     struct GlyphInfo
2074     {
2075         GlyphInfo(const QGlyphLayout &layout, const QPointF &position,
2076                   const QTextItemInt::RenderFlags &renderFlags)
2077             : glyphLayout(layout), itemPosition(position), flags(renderFlags)
2078         {
2079         }
2080
2081         QGlyphLayout glyphLayout;
2082         QPointF itemPosition;
2083         QTextItem::RenderFlags flags;
2084     };
2085 }
2086
2087 /*!
2088     \internal
2089
2090     Returns the glyph indexes and positions for all glyphs in this QTextLine which reside in
2091     QScriptItems that overlap with the range defined by \a from and \a length. The arguments
2092     specify characters, relative to the text in the layout. Note that it is not possible to
2093     use this function to retrieve a subset of the glyphs in a QScriptItem.
2094
2095     \since 4.8
2096
2097     \sa QTextLayout::glyphs()
2098 */
2099 #if !defined(QT_NO_RAWFONT)
2100 QList<QGlyphs> QTextLine::glyphs(int from, int length) const
2101 {
2102     const QScriptLine &line = eng->lines[i];
2103
2104     if (line.length == 0)
2105         return QList<QGlyphs>();
2106
2107     QHash<QFontEngine *, GlyphInfo> glyphLayoutHash;
2108
2109     QTextLineItemIterator iterator(eng, i);
2110     qreal y = line.y.toReal() + line.base().toReal();
2111     while (!iterator.atEnd()) {
2112         QScriptItem &si = iterator.next();
2113         if (si.analysis.flags >= QScriptAnalysis::TabOrObject)
2114             continue;
2115
2116         QPointF pos(iterator.x.toReal(), y);
2117         if (from >= 0 && length >= 0 &&
2118             (from >= si.position + eng->length(&si) || from + length <= si.position))
2119             continue;
2120
2121         QFont font = eng->font(si);
2122
2123         QTextItem::RenderFlags flags;
2124         if (font.overline())
2125             flags |= QTextItem::Overline;
2126         if (font.underline())
2127             flags |= QTextItem::Underline;
2128         if (font.strikeOut())
2129             flags |= QTextItem::StrikeOut;
2130         if (si.analysis.bidiLevel % 2)
2131             flags |= QTextItem::RightToLeft;
2132
2133         QGlyphLayout glyphLayout = eng->shapedGlyphs(&si).mid(iterator.glyphsStart,
2134                                                               iterator.glyphsEnd - iterator.glyphsStart);
2135
2136         if (glyphLayout.numGlyphs > 0) {
2137             QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
2138             if (mainFontEngine->type() == QFontEngine::Multi) {
2139                 QFontEngineMulti *multiFontEngine = static_cast<QFontEngineMulti *>(mainFontEngine);
2140                 int start = 0;
2141                 int end;
2142                 int which = glyphLayout.glyphs[0] >> 24;
2143                 for (end = 0; end < glyphLayout.numGlyphs; ++end) {
2144                     const int e = glyphLayout.glyphs[end] >> 24;
2145                     if (e == which)
2146                         continue;
2147
2148                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2149                     glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2150                                                 GlyphInfo(subLayout, pos, flags));
2151                     for (int i = 0; i < subLayout.numGlyphs; i++)
2152                         pos += QPointF(subLayout.advances_x[i].toReal(),
2153                                        subLayout.advances_y[i].toReal());
2154
2155                     start = end;
2156                     which = e;
2157                 }
2158
2159                 QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2160                 glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2161                                             GlyphInfo(subLayout, pos, flags));
2162
2163             } else {
2164                 glyphLayoutHash.insertMulti(mainFontEngine,
2165                                             GlyphInfo(glyphLayout, pos, flags));
2166             }
2167         }
2168     }
2169
2170     QHash<QPair<QFontEngine *, int>, QGlyphs> glyphsHash;
2171
2172     QList<QFontEngine *> keys = glyphLayoutHash.uniqueKeys();
2173     for (int i=0; i<keys.size(); ++i) {
2174         QFontEngine *fontEngine = keys.at(i);
2175
2176         // Make a font for this particular engine
2177         QRawFont font;
2178         QRawFontPrivate *fontD = QRawFontPrivate::get(font);
2179         fontD->fontEngine = fontEngine;
2180         fontD->fontEngine->ref.ref();
2181
2182 #if defined(Q_WS_WIN)
2183         if (fontEngine->supportsSubPixelPositions())
2184             fontD->hintingPreference = QFont::PreferVerticalHinting;
2185         else
2186             fontD->hintingPreference = QFont::PreferFullHinting;
2187 #elif defined(Q_WS_MAC)
2188         fontD->hintingPreference = QFont::PreferNoHinting;
2189 #elif !defined(QT_NO_FREETYPE)
2190         if (fontEngine->type() == QFontEngine::Freetype) {
2191             QFontEngineFT *freeTypeEngine = static_cast<QFontEngineFT *>(fontEngine);
2192             switch (freeTypeEngine->defaultHintStyle()) {
2193             case QFontEngineFT::HintNone:
2194                 fontD->hintingPreference = QFont::PreferNoHinting;
2195                 break;
2196             case QFontEngineFT::HintLight:
2197                 fontD->hintingPreference = QFont::PreferVerticalHinting;
2198                 break;
2199             case QFontEngineFT::HintMedium:
2200             case QFontEngineFT::HintFull:
2201                 fontD->hintingPreference = QFont::PreferFullHinting;
2202                 break;
2203             };
2204         }
2205 #endif
2206
2207         QList<GlyphInfo> glyphLayouts = glyphLayoutHash.values(fontEngine);
2208         for (int j=0; j<glyphLayouts.size(); ++j) {
2209             const QPointF &pos = glyphLayouts.at(j).itemPosition;
2210             const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout;
2211             const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags;            
2212
2213             QVarLengthArray<glyph_t> glyphsArray;
2214             QVarLengthArray<QFixedPoint> positionsArray;
2215
2216             fontEngine->getGlyphPositions(glyphLayout, QTransform(), flags, glyphsArray,
2217                                           positionsArray);
2218             Q_ASSERT(glyphsArray.size() == positionsArray.size());
2219
2220             QVector<quint32> glyphs;
2221             QVector<QPointF> positions;
2222             for (int i=0; i<glyphsArray.size(); ++i) {
2223                 glyphs.append(glyphsArray.at(i) & 0xffffff);
2224                 positions.append(positionsArray.at(i).toPointF() + pos);
2225             }
2226
2227             QGlyphs glyphIndexes;
2228             glyphIndexes.setGlyphIndexes(glyphs);
2229             glyphIndexes.setPositions(positions);
2230
2231             glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline));
2232             glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline));
2233             glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
2234             glyphIndexes.setFont(font);
2235
2236             QPair<QFontEngine *, int> key(fontEngine, int(flags));
2237             if (!glyphsHash.contains(key))
2238                 glyphsHash.insert(key, glyphIndexes);
2239             else
2240                 glyphsHash[key] += glyphIndexes;
2241         }
2242     }
2243
2244     return glyphsHash.values();
2245 }
2246 #endif // QT_NO_RAWFONT
2247
2248 /*!
2249     \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const
2250
2251     Draws a line on the given \a painter at the specified \a position.
2252     The \a selection is reserved for internal use.
2253 */
2254 void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const
2255 {
2256     const QScriptLine &line = eng->lines[i];
2257     QPen pen = p->pen();
2258
2259     bool noText = (selection && selection->format.property(SuppressText).toBool());
2260
2261     if (!line.length) {
2262         if (selection
2263             && selection->start <= line.from
2264             && selection->start + selection->length > line.from) {
2265
2266             const qreal lineHeight = line.height().toReal();
2267             QRectF r(pos.x() + line.x.toReal(), pos.y() + line.y.toReal(),
2268                      lineHeight / 2, QFontMetrics(eng->font()).width(QLatin1Char(' ')));
2269             setPenAndDrawBackground(p, QPen(), selection->format, r);
2270             p->setPen(pen);
2271         }
2272         return;
2273     }
2274
2275
2276     QTextLineItemIterator iterator(eng, i, pos, selection);
2277     QFixed lineBase = line.base();
2278
2279     const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase;
2280
2281     bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
2282     while (!iterator.atEnd()) {
2283         QScriptItem &si = iterator.next();
2284
2285         if (selection && selection->start >= 0 && iterator.isOutsideSelection())
2286             continue;
2287
2288         if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator
2289             && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators))
2290             continue;
2291
2292         QFixed itemBaseLine = y;
2293         QFont f = eng->font(si);
2294         QTextCharFormat format;
2295
2296         if (eng->hasFormats() || selection) {
2297             format = eng->format(&si);
2298             if (suppressColors) {
2299                 format.clearForeground();
2300                 format.clearBackground();
2301                 format.clearProperty(QTextFormat::TextUnderlineColor);
2302             }
2303             if (selection)
2304                 format.merge(selection->format);
2305
2306             setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
2307                                                            iterator.itemWidth.toReal(), line.height().toReal()));
2308
2309             QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2310             if (valign == QTextCharFormat::AlignSuperScript || valign == QTextCharFormat::AlignSubScript) {
2311                 QFontEngine *fe = f.d->engineForScript(si.analysis.script);
2312                 QFixed height = fe->ascent() + fe->descent();
2313                 if (valign == QTextCharFormat::AlignSubScript)
2314                     itemBaseLine += height / 6;
2315                 else if (valign == QTextCharFormat::AlignSuperScript)
2316                     itemBaseLine -= height / 2;
2317             }
2318         }
2319
2320         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2321
2322             if (eng->hasFormats()) {
2323                 p->save();
2324                 if (si.analysis.flags == QScriptAnalysis::Object && eng->block.docHandle()) {
2325                     QFixed itemY = y - si.ascent;
2326                     if (format.verticalAlignment() == QTextCharFormat::AlignTop) {
2327                         itemY = y - lineBase;
2328                     }
2329
2330                     QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
2331
2332                     eng->docLayout()->drawInlineObject(p, itemRect,
2333                                                        QTextInlineObject(iterator.item, eng),
2334                                                        si.position + eng->block.position(),
2335                                                        format);
2336                     if (selection) {
2337                         QBrush bg = format.brushProperty(ObjectSelectionBrush);
2338                         if (bg.style() != Qt::NoBrush) {
2339                             QColor c = bg.color();
2340                             c.setAlpha(128);
2341                             p->fillRect(itemRect, c);
2342                         }
2343                     }
2344                 } else { // si.isTab
2345                     QFont f = eng->font(si);
2346                     QTextItemInt gf(si, &f, format);
2347                     gf.chars = 0;
2348                     gf.num_chars = 0;
2349                     gf.width = iterator.itemWidth;
2350                     p->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf);
2351                     if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) {
2352                         QChar visualTab(0x2192);
2353                         int w = QFontMetrics(f).width(visualTab);
2354                         qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
2355                         if (x < 0)
2356                              p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
2357                                                    iterator.itemWidth.toReal(), line.height().toReal()),
2358                                             Qt::IntersectClip);
2359                         else
2360                              x /= 2; // Centered
2361                         p->drawText(QPointF(iterator.x.toReal() + x,
2362                                             y.toReal()), visualTab);
2363                     }
2364
2365                 }
2366                 p->restore();
2367             }
2368
2369             continue;
2370         }
2371
2372         unsigned short *logClusters = eng->logClusters(&si);
2373         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2374
2375         QTextItemInt gf(si, &f, format);
2376         gf.glyphs = glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart);
2377         gf.chars = eng->layoutData->string.unicode() + iterator.itemStart;
2378         gf.logClusters = logClusters + iterator.itemStart - si.position;
2379         gf.num_chars = iterator.itemEnd - iterator.itemStart;
2380         gf.width = iterator.itemWidth;
2381         gf.justified = line.justified;
2382
2383         Q_ASSERT(gf.fontEngine);
2384
2385         if (eng->underlinePositions) {
2386             // can't have selections in this case
2387             drawMenuText(p, iterator.x, itemBaseLine, si, gf, eng, iterator.itemStart, iterator.glyphsStart);
2388         } else {
2389             QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
2390             if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) {
2391                 QPainterPath path;
2392                 path.setFillRule(Qt::WindingFill);
2393
2394                 if (gf.glyphs.numGlyphs)
2395                     gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
2396                 if (gf.flags) {
2397                     const QFontEngine *fe = gf.fontEngine;
2398                     const qreal lw = fe->lineThickness().toReal();
2399                     if (gf.flags & QTextItem::Underline) {
2400                         qreal offs = fe->underlinePosition().toReal();
2401                         path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
2402                     }
2403                     if (gf.flags & QTextItem::Overline) {
2404                         qreal offs = fe->ascent().toReal() + 1;
2405                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2406                     }
2407                     if (gf.flags & QTextItem::StrikeOut) {
2408                         qreal offs = fe->ascent().toReal() / 3;
2409                         path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2410                     }
2411                 }
2412
2413                 p->save();
2414                 p->setRenderHint(QPainter::Antialiasing);
2415                 //Currently QPen with a Qt::NoPen style still returns a default
2416                 //QBrush which != Qt::NoBrush so we need this specialcase to reset it
2417                 if (p->pen().style() == Qt::NoPen)
2418                     p->setBrush(Qt::NoBrush);
2419                 else
2420                     p->setBrush(p->pen().brush());
2421
2422                 p->setPen(format.textOutline());
2423                 p->drawPath(path);
2424                 p->restore();
2425             } else {
2426                 if (noText)
2427                     gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
2428                 p->drawTextItem(pos, gf);
2429             }
2430         }
2431         if (si.analysis.flags == QScriptAnalysis::Space
2432             && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
2433             QBrush c = format.foreground();
2434             if (c.style() != Qt::NoBrush)
2435                 p->setPen(c.color());
2436             QChar visualSpace((ushort)0xb7);
2437             p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
2438             p->setPen(pen);
2439         }
2440     }
2441
2442
2443     if (eng->hasFormats())
2444         p->setPen(pen);
2445 }
2446
2447 /*!
2448     \fn int QTextLine::cursorToX(int cursorPos, Edge edge) const
2449
2450     \overload
2451 */
2452
2453 /*!
2454     Converts the cursor position \a cursorPos to the corresponding x position
2455     inside the line, taking account of the \a edge.
2456
2457     If \a cursorPos is not a valid cursor position, the nearest valid
2458     cursor position will be used instead, and cpos will be modified to
2459     point to this valid cursor position.
2460
2461     \sa xToCursor()
2462 */
2463 qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
2464 {
2465     if (!eng->layoutData)
2466         eng->itemize();
2467
2468     const QScriptLine &line = eng->lines[i];
2469     bool lastLine = i >= eng->lines.size() - 1;
2470
2471     QFixed x = line.x;
2472     x += eng->alignLine(line);
2473
2474     if (!i && !eng->layoutData->items.size()) {
2475         *cursorPos = 0;
2476         return x.toReal();
2477     }
2478
2479     int pos = *cursorPos;
2480     int itm;
2481     if (pos == line.from + (int)line.length) {
2482         // end of line ensure we have the last item on the line
2483         itm = eng->findItem(pos-1);
2484     }
2485     else
2486         itm = eng->findItem(pos);
2487     eng->shapeLine(line);
2488
2489     const QScriptItem *si = &eng->layoutData->items[itm];
2490     if (!si->num_glyphs)
2491         eng->shape(itm);
2492     pos -= si->position;
2493
2494     QGlyphLayout glyphs = eng->shapedGlyphs(si);
2495     unsigned short *logClusters = eng->logClusters(si);
2496     Q_ASSERT(logClusters);
2497
2498     int l = eng->length(itm);
2499     if (pos > l)
2500         pos = l;
2501     if (pos < 0)
2502         pos = 0;
2503
2504     int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos];
2505     if (edge == Trailing) {
2506         // trailing edge is leading edge of next cluster
2507         while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart)
2508             glyph_pos++;
2509     }
2510
2511     bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2;
2512
2513     int lineEnd = line.from + line.length;
2514
2515     // add the items left of the cursor
2516
2517     int firstItem = eng->findItem(line.from);
2518     int lastItem = eng->findItem(lineEnd - 1);
2519     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2520
2521     QVarLengthArray<int> visualOrder(nItems);
2522     QVarLengthArray<uchar> levels(nItems);
2523     for (int i = 0; i < nItems; ++i)
2524         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2525     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2526
2527     for (int i = 0; i < nItems; ++i) {
2528         int item = visualOrder[i]+firstItem;
2529         if (item == itm)
2530             break;
2531         QScriptItem &si = eng->layoutData->items[item];
2532         if (!si.num_glyphs)
2533             eng->shape(item);
2534
2535         if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2536             x += si.width;
2537             continue;
2538         }
2539         int start = qMax(line.from, si.position);
2540         int end = qMin(lineEnd, si.position + eng->length(item));
2541
2542         logClusters = eng->logClusters(&si);
2543
2544         int gs = logClusters[start-si.position];
2545         int ge = (end == si.position + eng->length(item)) ? si.num_glyphs-1 : logClusters[end-si.position-1];
2546
2547         QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2548
2549         while (gs <= ge) {
2550             x += glyphs.effectiveAdvance(gs);
2551             ++gs;
2552         }
2553     }
2554
2555     logClusters = eng->logClusters(si);
2556     glyphs = eng->shapedGlyphs(si);
2557     if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
2558         if (pos == (reverse ? 0 : l))
2559             x += si->width;
2560     } else {
2561         bool rtl = eng->isRightToLeft();
2562         bool visual = eng->visualCursorMovement();
2563         if (reverse) {
2564             int end = qMin(lineEnd, si->position + l) - si->position;
2565             int glyph_end = end == l ? si->num_glyphs : logClusters[end];
2566             int glyph_start = glyph_pos;
2567             if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
2568                 glyph_start++;
2569             for (int i = glyph_end - 1; i >= glyph_start; i--)
2570                 x += glyphs.effectiveAdvance(i);
2571         } else {
2572             int start = qMax(line.from - si->position, 0);
2573             int glyph_start = logClusters[start];
2574             int glyph_end = glyph_pos;
2575             if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
2576                 glyph_end--;
2577             for (int i = glyph_start; i <= glyph_end; i++)
2578                 x += glyphs.effectiveAdvance(i);
2579         }
2580         x += eng->offsetInLigature(si, pos, line.length, glyph_pos);
2581     }
2582
2583     *cursorPos = pos + si->position;
2584     return x.toReal();
2585 }
2586
2587 /*!
2588     \fn int QTextLine::xToCursor(qreal x, CursorPosition cpos) const
2589
2590     Converts the x-coordinate \a x, to the nearest matching cursor
2591     position, depending on the cursor position type, \a cpos.
2592
2593     \sa cursorToX()
2594 */
2595 int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
2596 {
2597     QFixed x = QFixed::fromReal(_x);
2598     const QScriptLine &line = eng->lines[i];
2599     bool lastLine = i >= eng->lines.size() - 1;
2600     int lineNum = i;
2601
2602     if (!eng->layoutData)
2603         eng->itemize();
2604
2605     int line_length = textLength();
2606
2607     if (!line_length)
2608         return line.from;
2609
2610     int firstItem = eng->findItem(line.from);
2611     int lastItem = eng->findItem(line.from + line_length - 1);
2612     int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2613
2614     if (!nItems)
2615         return 0;
2616
2617     x -= line.x;
2618     x -= eng->alignLine(line);
2619 //     qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
2620
2621     QVarLengthArray<int> visualOrder(nItems);
2622     QVarLengthArray<unsigned char> levels(nItems);
2623     for (int i = 0; i < nItems; ++i)
2624         levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2625     QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2626
2627     bool visual = eng->visualCursorMovement();
2628     if (x <= 0) {
2629         // left of first item
2630         int item = visualOrder[0]+firstItem;
2631         QScriptItem &si = eng->layoutData->items[item];
2632         if (!si.num_glyphs)
2633             eng->shape(item);
2634         int pos = si.position;
2635         if (si.analysis.bidiLevel % 2)
2636             pos += eng->length(item);
2637         pos = qMax(line.from, pos);
2638         pos = qMin(line.from + line_length, pos);
2639         return pos;
2640     } else if (x < line.textWidth
2641                || (line.justified && x < line.width)) {
2642         // has to be in one of the runs
2643         QFixed pos;
2644         bool rtl = eng->isRightToLeft();
2645
2646         eng->shapeLine(line);
2647         QVector<int> insertionPoints;
2648         if (visual && rtl)
2649             eng->insertionPointsForLine(lineNum, insertionPoints);
2650         int nchars = 0;
2651         for (int i = 0; i < nItems; ++i) {
2652             int item = visualOrder[i]+firstItem;
2653             QScriptItem &si = eng->layoutData->items[item];
2654             int item_length = eng->length(item);
2655 //             qDebug("    item %d, visual %d x_remain=%f", i, item, x.toReal());
2656
2657             int start = qMax(line.from - si.position, 0);
2658             int end = qMin(line.from + line_length - si.position, item_length);
2659
2660             unsigned short *logClusters = eng->logClusters(&si);
2661
2662             int gs = logClusters[start];
2663             int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1;
2664             QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2665
2666             QFixed item_width = 0;
2667             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2668                 item_width = si.width;
2669             } else {
2670                 int g = gs;
2671                 while (g <= ge) {
2672                     item_width += glyphs.effectiveAdvance(g);
2673                     ++g;
2674                 }
2675             }
2676 //             qDebug("      start=%d, end=%d, gs=%d, ge=%d item_width=%f", start, end, gs, ge, item_width.toReal());
2677
2678             if (pos + item_width < x) {
2679                 pos += item_width;
2680                 nchars += end;
2681                 continue;
2682             }
2683 //             qDebug("      inside run");
2684             if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
2685                 if (cpos == QTextLine::CursorOnCharacter)
2686                     return si.position;
2687                 bool left_half = (x - pos) < item_width/2;
2688
2689                 if (bool(si.analysis.bidiLevel % 2) != left_half)
2690                     return si.position;
2691                 return si.position + 1;
2692             }
2693
2694             int glyph_pos = -1;
2695             // has to be inside run
2696             if (cpos == QTextLine::CursorOnCharacter) {
2697                 if (si.analysis.bidiLevel % 2) {
2698                     pos += item_width;
2699                     glyph_pos = gs;
2700                     while (gs <= ge) {
2701                         if (glyphs.attributes[gs].clusterStart) {
2702                             if (pos < x)
2703                                 break;
2704                             glyph_pos = gs;
2705                             break;
2706                         }
2707                         pos -= glyphs.effectiveAdvance(gs);
2708                         ++gs;
2709                     }
2710                 } else {
2711                     glyph_pos = gs;
2712                     while (gs <= ge) {
2713                         if (glyphs.attributes[gs].clusterStart) {
2714                             if (pos > x)
2715                                 break;
2716                             glyph_pos = gs;
2717                         }
2718                         pos += glyphs.effectiveAdvance(gs);
2719                         ++gs;
2720                     }
2721                 }
2722             } else {
2723                 QFixed dist = INT_MAX/256;
2724                 if (si.analysis.bidiLevel % 2) {
2725                     if (!visual || rtl || (lastLine && i == nItems - 1)) {
2726                         pos += item_width;
2727                         while (gs <= ge) {
2728                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2729                                 glyph_pos = gs;
2730                                 dist = qAbs(x-pos);
2731                             }
2732                             pos -= glyphs.effectiveAdvance(gs);
2733                             ++gs;
2734                         }
2735                     } else {
2736                         while (ge >= gs) {
2737                             if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
2738                                 glyph_pos = ge;
2739                                 dist = qAbs(x-pos);
2740                             }
2741                             pos += glyphs.effectiveAdvance(ge);
2742                             --ge;
2743                         }
2744                     }
2745                 } else {
2746                     if (!visual || !rtl || (lastLine && i == 0)) {
2747                         while (gs <= ge) {
2748                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2749                                 glyph_pos = gs;
2750                                 dist = qAbs(x-pos);
2751                             }
2752                             pos += glyphs.effectiveAdvance(gs);
2753                             ++gs;
2754                         }
2755                     } else {
2756                         QFixed oldPos = pos;
2757                         while (gs <= ge) {
2758                             pos += glyphs.effectiveAdvance(gs);
2759                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2760                                 glyph_pos = gs;
2761                                 dist = qAbs(x-pos);
2762                             }
2763                             ++gs;
2764                         }
2765                         pos = oldPos;
2766                     }
2767                 }
2768                 if (qAbs(x-pos) < dist) {
2769                     if (visual) {
2770                         if (!rtl && i < nItems - 1) {
2771                             nchars += end;
2772                             continue;
2773                         }
2774                         if (rtl && nchars > 0)
2775                             return insertionPoints[lastLine ? nchars : nchars - 1];
2776                     }
2777                     return si.position + end;
2778                 }
2779             }
2780             Q_ASSERT(glyph_pos != -1);
2781             int j;
2782             for (j = 0; j < eng->length(item); ++j)
2783                 if (logClusters[j] == glyph_pos)
2784                     break;
2785 //             qDebug("at pos %d (in run: %d)", si.position + j, j);
2786             return si.position + j;
2787         }
2788     }
2789     // right of last item
2790 //     qDebug() << "right of last";
2791     int item = visualOrder[nItems-1]+firstItem;
2792     QScriptItem &si = eng->layoutData->items[item];
2793     if (!si.num_glyphs)
2794         eng->shape(item);
2795     int pos = si.position;
2796     if (!(si.analysis.bidiLevel % 2))
2797         pos += eng->length(item);
2798     pos = qMax(line.from, pos);
2799
2800     int maxPos = line.from + line_length;
2801
2802     // except for the last line we assume that the
2803     // character between lines is a space and we want
2804     // to position the cursor to the left of that
2805     // character.
2806     // ###### breaks with japanese for example
2807     if (this->i < eng->lines.count() - 1)
2808         --maxPos;
2809
2810     pos = qMin(pos, maxPos);
2811     return pos;
2812 }
2813
2814 QT_END_NAMESPACE