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