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