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