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