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