Qt 4.8
qtextlayout.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 <qmath.h>
48 #include <qpainter.h>
49 #include <qvarlengtharray.h>
50 #include <qtextformat.h>
52 #include "qtextdocument_p.h"
53 #include "qtextformat_p.h"
54 #include "qstyleoption.h"
55 #include "qpainterpath.h"
56 #include "qglyphrun.h"
57 #include "qglyphrun_p.h"
58 #include "qrawfont.h"
59 #include "qrawfont_p.h"
60 #include <limits.h>
61 
62 #include <qdebug.h>
63 
64 #include "qfontengine_p.h"
65 
66 #if !defined(QT_NO_FREETYPE)
67 # include "qfontengine_ft_p.h"
68 #endif
69 
71 
72 #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1)
73 #define SuppressText 0x5012
74 #define SuppressBackground 0x513
75 
164 {
166  return QRectF(0, -si.ascent.toReal(), si.width.toReal(), si.height().toReal());
167 }
168 
175 {
176  return eng->layoutData->items[itm].width.toReal();
177 }
178 
185 {
186  return eng->layoutData->items[itm].ascent.toReal();
187 }
188 
195 {
196  return eng->layoutData->items[itm].descent.toReal();
197 }
198 
206 {
207  return eng->layoutData->items[itm].height().toReal();
208 }
209 
216 {
217  eng->layoutData->items[itm].width = QFixed::fromReal(w);
218 }
219 
226 {
227  eng->layoutData->items[itm].ascent = QFixed::fromReal(a);
228 }
229 
236 {
237  eng->layoutData->items[itm].descent = QFixed::fromReal(d);
238 }
239 
244 {
245  return eng->layoutData->items[itm].position;
246 }
247 
253 {
254  return eng->formatIndex(&eng->layoutData->items[itm]);
255 }
256 
261 {
262  if (!eng->block.docHandle())
263  return QTextFormat();
264  return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm]));
265 }
266 
271 {
272  return (eng->layoutData->items[itm].analysis.bidiLevel % 2 ? Qt::RightToLeft : Qt::LeftToRight);
273 }
274 
345 { d = new QTextEngine(); }
346 
351 {
352  d = new QTextEngine();
353  d->text = text;
354 }
355 
364 QTextLayout::QTextLayout(const QString& text, const QFont &font, QPaintDevice *paintdevice)
365 {
366  QFont f(font);
367  if (paintdevice)
368  f = QFont(font, paintdevice);
369  d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f.d.data());
370 }
371 
380 {
381  d = new QTextEngine();
382  d->block = block;
383 }
384 
389 {
390  if (!d->stackEngine)
391  delete d;
392 }
393 
400 void QTextLayout::setFont(const QFont &font)
401 {
402  d->fnt = font;
403  d->resetFontEngineCache();
404 }
405 
413 {
414  return d->font();
415 }
416 
426 void QTextLayout::setText(const QString& string)
427 {
428  d->invalidate();
429  d->clearLineData();
430  d->text = string;
431 }
432 
439 {
440  return d->text;
441 }
442 
450 {
451  d->option = option;
452 }
453 
460 {
461  return d->option;
462 }
463 
471 {
472  if (text.isEmpty()) {
473  if (!d->specialData)
474  return;
475  if (d->specialData->addFormats.isEmpty()) {
476  delete d->specialData;
477  d->specialData = 0;
478  } else {
479  d->specialData->preeditText = QString();
480  d->specialData->preeditPosition = -1;
481  }
482  } else {
483  if (!d->specialData)
484  d->specialData = new QTextEngine::SpecialData;
485  d->specialData->preeditPosition = position;
486  d->specialData->preeditText = text;
487  }
488  d->invalidate();
489  d->clearLineData();
490  if (d->block.docHandle())
491  d->block.docHandle()->documentChange(d->block.position(), d->block.length());
492 }
493 
501 {
502  return d->specialData ? d->specialData->preeditPosition : -1;
503 }
504 
511 {
512  return d->specialData ? d->specialData->preeditText : QString();
513 }
514 
515 
522 {
523  if (formatList.isEmpty()) {
524  if (!d->specialData)
525  return;
526  if (d->specialData->preeditText.isEmpty()) {
527  delete d->specialData;
528  d->specialData = 0;
529  } else {
530  d->specialData->addFormats = formatList;
531  d->specialData->addFormatIndices.clear();
532  }
533  } else {
534  if (!d->specialData) {
535  d->specialData = new QTextEngine::SpecialData;
536  d->specialData->preeditPosition = -1;
537  }
538  d->specialData->addFormats = formatList;
539  d->indexAdditionalFormats();
540  }
541  if (d->block.docHandle())
542  d->block.docHandle()->documentChange(d->block.position(), d->block.length());
543  d->resetFontEngineCache();
544 }
545 
552 {
553  QList<FormatRange> formats;
554  if (!d->specialData)
555  return formats;
556 
557  formats = d->specialData->addFormats;
558 
559  if (d->specialData->addFormatIndices.isEmpty())
560  return formats;
561 
562  const QTextFormatCollection *collection = d->formats();
563 
564  for (int i = 0; i < d->specialData->addFormatIndices.count(); ++i)
565  formats[i].format = collection->charFormat(d->specialData->addFormatIndices.at(i));
566 
567  return formats;
568 }
569 
576 {
577  setAdditionalFormats(QList<FormatRange>());
578 }
579 
591 {
592  d->cacheGlyphs = enable;
593 }
594 
602 {
603  return d->cacheGlyphs;
604 }
605 
620 {
621  d->visualMovement = style == Qt::VisualMoveStyle ? true : false;
622 }
623 
636 {
637  return d->visualMovement ? Qt::VisualMoveStyle : Qt::LogicalMoveStyle;
638 }
639 
646 {
647 #ifndef QT_NO_DEBUG
648  if (d->layoutData && d->layoutData->layoutState == QTextEngine::InLayout) {
649  qWarning("QTextLayout::beginLayout: Called while already doing layout");
650  return;
651  }
652 #endif
653  d->invalidate();
654  d->clearLineData();
655  d->itemize();
656  d->layoutData->layoutState = QTextEngine::InLayout;
657 }
658 
665 {
666 #ifndef QT_NO_DEBUG
667  if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
668  qWarning("QTextLayout::endLayout: Called without beginLayout()");
669  return;
670  }
671 #endif
672  int l = d->lines.size();
673  if (l && d->lines.at(l-1).length < 0) {
675  }
676  d->layoutData->layoutState = QTextEngine::LayoutEmpty;
677  if (!d->cacheGlyphs)
678  d->freeMemory();
679 }
680 
691 {
692  d->clearLineData();
693 }
694 
702 int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
703 {
704  const HB_CharAttributes *attributes = d->attributes();
705  int len = d->block.isValid() ? d->block.length() - 1
706  : d->layoutData->string.length();
707  Q_ASSERT(len <= d->layoutData->string.length());
708  if (!attributes || oldPos < 0 || oldPos >= len)
709  return oldPos;
710 
711  if (mode == SkipCharacters) {
712  oldPos++;
713  while (oldPos < len && !attributes[oldPos].charStop)
714  oldPos++;
715  } else {
716  if (oldPos < len && d->atWordSeparator(oldPos)) {
717  oldPos++;
718  while (oldPos < len && d->atWordSeparator(oldPos))
719  oldPos++;
720  } else {
721  while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos))
722  oldPos++;
723  }
724  while (oldPos < len && d->atSpace(oldPos))
725  oldPos++;
726  }
727 
728  return oldPos;
729 }
730 
739 {
740  const HB_CharAttributes *attributes = d->attributes();
741  if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length())
742  return oldPos;
743 
744  if (mode == SkipCharacters) {
745  oldPos--;
746  while (oldPos && !attributes[oldPos].charStop)
747  oldPos--;
748  } else {
749  while (oldPos && d->atSpace(oldPos-1))
750  oldPos--;
751 
752  if (oldPos && d->atWordSeparator(oldPos-1)) {
753  oldPos--;
754  while (oldPos && d->atWordSeparator(oldPos-1))
755  oldPos--;
756  } else {
757  while (oldPos && !d->atSpace(oldPos-1) && !d->atWordSeparator(oldPos-1))
758  oldPos--;
759  }
760  }
761 
762  return oldPos;
763 }
764 
777 int QTextLayout::rightCursorPosition(int oldPos) const
778 {
779  int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right);
780 // qDebug("%d -> %d", oldPos, newPos);
781  return newPos;
782 }
783 
796 int QTextLayout::leftCursorPosition(int oldPos) const
797 {
798  int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left);
799 // qDebug("%d -> %d", oldPos, newPos);
800  return newPos;
801 }
802 
803 /*!/
804  Returns true if position \a pos is a valid cursor position.
805 
806  In a Unicode context some positions in the text are not valid
807  cursor positions, because the position is inside a Unicode
808  surrogate or a grapheme cluster.
809 
810  A grapheme cluster is a sequence of two or more Unicode characters
811  that form one indivisible entity on the screen. For example the
812  latin character `\Auml' can be represented in Unicode by two
813  characters, `A' (0x41), and the combining diaresis (0x308). A text
814  cursor can only validly be positioned before or after these two
815  characters, never between them since that wouldn't make sense. In
816  indic languages every syllable forms a grapheme cluster.
817 */
819 {
820  const HB_CharAttributes *attributes = d->attributes();
821  if (!attributes || pos < 0 || pos > (int)d->layoutData->string.length())
822  return false;
823  return attributes[pos].charStop;
824 }
825 
843 {
844 #ifndef QT_NO_DEBUG
845  if (!d->layoutData || d->layoutData->layoutState == QTextEngine::LayoutEmpty) {
846  qWarning("QTextLayout::createLine: Called without layouting");
847  return QTextLine();
848  }
849 #endif
850  if (d->layoutData->layoutState == QTextEngine::LayoutFailed)
851  return QTextLine();
852 
853  int l = d->lines.size();
854  if (l && d->lines.at(l-1).length < 0) {
856  }
857  int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
858  int strlen = d->layoutData->string.length();
859  if (l && from >= strlen) {
860  if (!d->lines.at(l-1).length || d->layoutData->string.at(strlen - 1) != QChar::LineSeparator)
861  return QTextLine();
862  }
863 
864  QScriptLine line;
865  line.from = from;
866  line.length = -1;
867  line.justified = false;
868  line.gridfitted = false;
869 
870  d->lines.append(line);
871  return QTextLine(l, d);
872 }
873 
880 {
881  return d->lines.size();
882 }
883 
890 {
891  return QTextLine(i, d);
892 }
893 
900 {
901  int lineNum = d->lineNumberForTextPosition(pos);
902  return lineNum >= 0 ? lineAt(lineNum) : QTextLine();
903 }
904 
917 {
918  return d->position;
919 }
920 
927 {
928  d->position = p;
929 }
930 
935 {
936  if (d->lines.isEmpty())
937  return QRectF();
938 
939  QFixed xmax, ymax;
940  QFixed xmin = d->lines.at(0).x;
941  QFixed ymin = d->lines.at(0).y;
942 
943  for (int i = 0; i < d->lines.size(); ++i) {
944  const QScriptLine &si = d->lines[i];
945  xmin = qMin(xmin, si.x);
946  ymin = qMin(ymin, si.y);
947  QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
948  xmax = qMax(xmax, si.x+lineWidth);
949  // ### shouldn't the ascent be used in ymin???
950  ymax = qMax(ymax, si.y+si.height());
951  }
952  return QRectF(xmin.toReal(), ymin.toReal(), (xmax-xmin).toReal(), (ymax-ymin).toReal());
953 }
954 
965 {
966  return d->minWidth.toReal();
967 }
968 
979 {
980  return d->maxWidth.toReal();
981 }
982 
983 
987 void QTextLayout::setFlags(int flags)
988 {
989  if (flags & Qt::TextJustificationForced) {
990  d->option.setAlignment(Qt::AlignJustify);
991  d->forceJustification = true;
992  }
993 
995  d->ignoreBidi = true;
996  d->option.setTextDirection((flags & Qt::TextForceLeftToRight) ? Qt::LeftToRight : Qt::RightToLeft);
997  }
998 }
999 
1000 static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection,
1001  QPainterPath *region, QRectF boundingRect)
1002 {
1003  const QScriptLine &line = eng->lines[lineNumber];
1004 
1005  QTextLineItemIterator iterator(eng, lineNumber, pos, selection);
1006 
1007 
1008 
1009  const qreal selectionY = pos.y() + line.y.toReal();
1010  const qreal lineHeight = line.height().toReal();
1011 
1012  QFixed lastSelectionX = iterator.x;
1013  QFixed lastSelectionWidth;
1014 
1015  while (!iterator.atEnd()) {
1016  iterator.next();
1017 
1018  QFixed selectionX, selectionWidth;
1019  if (iterator.getSelectionBounds(&selectionX, &selectionWidth)) {
1020  if (selectionX == lastSelectionX + lastSelectionWidth) {
1021  lastSelectionWidth += selectionWidth;
1022  continue;
1023  }
1024 
1025  if (lastSelectionWidth > 0) {
1026  QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
1027  rect.moveLeft(qFloor(rect.left()));
1028  rect.moveTop(qFloor(rect.top()));
1029  region->addRect(rect);
1030  }
1031 
1032  lastSelectionX = selectionX;
1033  lastSelectionWidth = selectionWidth;
1034  }
1035  }
1036  if (lastSelectionWidth > 0) {
1037  QRectF rect = boundingRect & QRectF(lastSelectionX.toReal(), selectionY, lastSelectionWidth.toReal(), lineHeight);
1038  rect.moveLeft(qFloor(rect.left()));
1039  rect.moveTop(qFloor(rect.top()));
1040  region->addRect(rect);
1041  }
1042 }
1043 
1044 static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
1045 {
1046  return clip.isValid() ? (rect & clip) : rect;
1047 }
1048 
1049 
1058 #if !defined(QT_NO_RAWFONT)
1060 {
1061  QList<QGlyphRun> glyphs;
1062  for (int i=0; i<d->lines.size(); ++i)
1063  glyphs += QTextLine(i, d).glyphs(-1, -1);
1064 
1065  return glyphs;
1066 }
1067 #endif // QT_NO_RAWFONT
1068 
1074 void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections, const QRectF &clip) const
1075 {
1076  if (d->lines.isEmpty())
1077  return;
1078 
1079  if (!d->layoutData)
1080  d->itemize();
1081 
1082  QPointF position = pos + d->position;
1083 
1084  QFixed clipy = (INT_MIN/256);
1085  QFixed clipe = (INT_MAX/256);
1086  if (clip.isValid()) {
1087  clipy = QFixed::fromReal(clip.y() - position.y());
1088  clipe = clipy + QFixed::fromReal(clip.height());
1089  }
1090 
1091  int firstLine = 0;
1092  int lastLine = d->lines.size();
1093  for (int i = 0; i < d->lines.size(); ++i) {
1094  QTextLine l(i, d);
1095  const QScriptLine &sl = d->lines[i];
1096 
1097  if (sl.y > clipe) {
1098  lastLine = i;
1099  break;
1100  }
1101  if ((sl.y + sl.height()) < clipy) {
1102  firstLine = i;
1103  continue;
1104  }
1105  }
1106 
1107  QPainterPath excludedRegion;
1108  QPainterPath textDoneRegion;
1109  for (int i = 0; i < selections.size(); ++i) {
1110  FormatRange selection = selections.at(i);
1111  const QBrush bg = selection.format.background();
1112 
1113  QPainterPath region;
1114  region.setFillRule(Qt::WindingFill);
1115 
1116  for (int line = firstLine; line < lastLine; ++line) {
1117  const QScriptLine &sl = d->lines[line];
1118  QTextLine tl(line, d);
1119 
1120  QRectF lineRect(tl.naturalTextRect());
1121  lineRect.translate(position);
1122  lineRect.adjust(0, 0, d->leadingSpaceWidth(sl).toReal(), 0);
1123 
1124  bool isLastLineInBlock = (line == d->lines.size()-1);
1125  int sl_length = sl.length + (isLastLineInBlock? 1 : 0); // the infamous newline
1126 
1127 
1128  if (sl.from > selection.start + selection.length || sl.from + sl_length <= selection.start)
1129  continue; // no actual intersection
1130 
1131  const bool selectionStartInLine = sl.from <= selection.start;
1132  const bool selectionEndInLine = selection.start + selection.length < sl.from + sl_length;
1133 
1134  if (sl.length && (selectionStartInLine || selectionEndInLine)) {
1135  addSelectedRegionsToPath(d, line, position, &selection, &region, clipIfValid(lineRect, clip));
1136  } else {
1137  region.addRect(clipIfValid(lineRect, clip));
1138  }
1139 
1141  QRectF fullLineRect(tl.rect());
1142  fullLineRect.translate(position);
1143  fullLineRect.setRight(QFIXED_MAX);
1144  if (!selectionEndInLine)
1145  region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
1146  if (!selectionStartInLine)
1147  region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
1148  } else if (!selectionEndInLine
1149  && isLastLineInBlock
1150  &&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
1151  region.addRect(clipIfValid(QRectF(lineRect.right(), lineRect.top(),
1152  lineRect.height()/4, lineRect.height()), clip));
1153  }
1154 
1155  }
1156  {
1157  const QPen oldPen = p->pen();
1158  const QBrush oldBrush = p->brush();
1159 
1162  p->drawPath(region);
1163 
1164  p->setPen(oldPen);
1165  p->setBrush(oldBrush);
1166  }
1167 
1168 
1169 
1170  bool hasText = (selection.format.foreground().style() != Qt::NoBrush);
1171  bool hasBackground= (selection.format.background().style() != Qt::NoBrush);
1172 
1173  if (hasBackground) {
1175  // don't just clear the property, set an empty brush that overrides a potential
1176  // background brush specified in the text
1179  }
1180 
1181  selection.format.setProperty(SuppressText, !hasText);
1182 
1183  if (hasText && !hasBackground && !(textDoneRegion & region).isEmpty())
1184  continue;
1185 
1186  p->save();
1187  p->setClipPath(region, Qt::IntersectClip);
1188 
1189  for (int line = firstLine; line < lastLine; ++line) {
1190  QTextLine l(line, d);
1191  l.draw(p, position, &selection);
1192  }
1193  p->restore();
1194 
1195  if (hasText) {
1196  textDoneRegion += region;
1197  } else {
1198  if (hasBackground)
1199  textDoneRegion -= region;
1200  }
1201 
1202  excludedRegion += region;
1203  }
1204 
1205  QPainterPath needsTextButNoBackground = excludedRegion - textDoneRegion;
1206  if (!needsTextButNoBackground.isEmpty()){
1207  p->save();
1208  p->setClipPath(needsTextButNoBackground, Qt::IntersectClip);
1209  FormatRange selection;
1210  selection.start = 0;
1211  selection.length = INT_MAX;
1212  selection.format.setProperty(SuppressBackground, true);
1213  for (int line = firstLine; line < lastLine; ++line) {
1214  QTextLine l(line, d);
1215  l.draw(p, position, &selection);
1216  }
1217  p->restore();
1218  }
1219 
1220  if (!excludedRegion.isEmpty()) {
1221  p->save();
1222  QPainterPath path;
1223  QRectF br = boundingRect().translated(position);
1224  br.setRight(QFIXED_MAX);
1225  if (!clip.isNull())
1226  br = br.intersected(clip);
1227  path.addRect(br);
1228  path -= excludedRegion;
1229  p->setClipPath(path, Qt::IntersectClip);
1230  }
1231 
1232  for (int i = firstLine; i < lastLine; ++i) {
1233  QTextLine l(i, d);
1234  l.draw(p, position);
1235  }
1236  if (!excludedRegion.isEmpty())
1237  p->restore();
1238 
1239 
1240  if (!d->cacheGlyphs)
1241  d->freeMemory();
1242 }
1243 
1252 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
1253 {
1254  drawCursor(p, pos, cursorPosition, 1);
1255 }
1256 
1264 void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition, int width) const
1265 {
1266  if (d->lines.isEmpty())
1267  return;
1268 
1269  if (!d->layoutData)
1270  d->itemize();
1271 
1272  QPointF position = pos + d->position;
1273 
1274  cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
1275  int line = d->lineNumberForTextPosition(cursorPosition);
1276  if (line < 0)
1277  line = 0;
1278  if (line >= d->lines.size())
1279  return;
1280 
1281  QTextLine l(line, d);
1282  const QScriptLine &sl = d->lines[line];
1283 
1284  qreal x = position.x() + l.cursorToX(cursorPosition);
1285 
1286  int itm;
1287 
1288  if (d->visualCursorMovement()) {
1289  if (cursorPosition == sl.from + sl.length)
1290  cursorPosition--;
1291  itm = d->findItem(cursorPosition);
1292  } else
1293  itm = d->findItem(cursorPosition - 1);
1294 
1295  QFixed base = sl.base();
1296  QFixed descent = sl.descent;
1297  bool rightToLeft = d->isRightToLeft();
1298  if (itm >= 0) {
1299  const QScriptItem &si = d->layoutData->items.at(itm);
1300  if (si.ascent > 0)
1301  base = si.ascent;
1302  if (si.descent > 0)
1303  descent = si.descent;
1304  rightToLeft = si.analysis.bidiLevel % 2;
1305  }
1306  qreal y = position.y() + (sl.y + sl.base() - base).toReal();
1307  bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
1308  && (p->transform().type() > QTransform::TxTranslate);
1309  if (toggleAntialiasing)
1311 #if defined(QT_MAC_USE_COCOA)
1312  // Always draw the cursor aligned to pixel boundary.
1313  x = qRound(x);
1314 #endif
1315  p->fillRect(QRectF(x, y, qreal(width), (base + descent + 1).toReal()), p->pen().brush());
1316  if (toggleAntialiasing)
1318  if (d->layoutData->hasBidi) {
1319  const int arrow_extent = 4;
1320  int sign = rightToLeft ? -1 : 1;
1321  p->drawLine(QLineF(x, y, x + (sign * arrow_extent/2), y + arrow_extent/2));
1322  p->drawLine(QLineF(x, y+arrow_extent, x + (sign * arrow_extent/2), y + arrow_extent/2));
1323  }
1324  return;
1325 }
1326 
1405 {
1406  const QScriptLine& sl = eng->lines[i];
1407  return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());
1408 }
1409 
1414 {
1415  const QScriptLine& sl = eng->lines[i];
1416  QFixed x = sl.x + eng->alignLine(sl);
1417 
1418  QFixed width = sl.textWidth;
1419  if (sl.justified)
1420  width = sl.width;
1421 
1422  return QRectF(x.toReal(), sl.y.toReal(), width.toReal(), sl.height().toReal());
1423 }
1424 
1431 {
1432  return eng->lines[i].x.toReal();
1433 }
1434 
1441 {
1442  return eng->lines[i].y.toReal();
1443 }
1444 
1451 {
1452  return eng->lines[i].width.toReal();
1453 }
1454 
1455 
1462 {
1463  return eng->lines[i].ascent.toReal();
1464 }
1465 
1472 {
1473  return eng->lines[i].descent.toReal();
1474 }
1475 
1484 {
1485  return eng->lines[i].height().toReal();
1486 }
1487 
1499 {
1500  return eng->lines[i].leading.toReal();
1501 }
1502 
1521 {
1522  eng->lines[i].leadingIncluded= included;
1523 
1524 }
1525 
1540 {
1541  return eng->lines[i].leadingIncluded;
1542 }
1543 
1550 {
1551  return eng->lines[i].textWidth.toReal();
1552 }
1553 
1568 {
1569  return eng->lines[i].textAdvance.toReal();
1570 }
1571 
1580 {
1581  QScriptLine &line = eng->lines[i];
1582  if (!eng->layoutData) {
1583  qWarning("QTextLine: Can't set a line width while not layouting.");
1584  return;
1585  }
1586 
1587  if (width > QFIXED_MAX)
1588  width = QFIXED_MAX;
1589 
1590  line.width = QFixed::fromReal(width);
1591  if (line.length
1592  && line.textWidth <= line.width
1593  && line.from + line.length == eng->layoutData->string.length())
1594  // no need to do anything if the line is already layouted and the last one. This optimization helps
1595  // when using things in a single line layout.
1596  return;
1597  line.length = 0;
1598  line.textWidth = 0;
1599 
1600  layout_helper(INT_MAX);
1601 }
1602 
1610 void QTextLine::setNumColumns(int numColumns)
1611 {
1612  QScriptLine &line = eng->lines[i];
1613  line.width = QFIXED_MAX;
1614  line.length = 0;
1615  line.textWidth = 0;
1616  layout_helper(numColumns);
1617 }
1618 
1627 void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth)
1628 {
1629  QScriptLine &line = eng->lines[i];
1630  line.width = QFixed::fromReal(alignmentWidth);
1631  line.length = 0;
1632  line.textWidth = 0;
1633  layout_helper(numColumns);
1634 }
1635 
1636 #if 0
1637 #define LB_DEBUG qDebug
1638 #else
1639 #define LB_DEBUG if (0) qDebug
1640 #endif
1641 
1642 namespace {
1643 
1644  struct LineBreakHelper
1645  {
1646  LineBreakHelper()
1647  : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(0), logClusters(0),
1648  manualWrap(false), whiteSpaceOrObject(true)
1649  {
1650  }
1651 
1652 
1653  QScriptLine tmpData;
1654  QScriptLine spaceData;
1655 
1656  QGlyphLayout glyphs;
1657 
1658  int glyphCount;
1659  int maxGlyphs;
1660  int currentPosition;
1661  glyph_t previousGlyph;
1662 
1663  QFixed minw;
1664  QFixed softHyphenWidth;
1665  QFixed rightBearing;
1666  QFixed minimumRightBearing;
1667 
1668  QFontEngine *fontEngine;
1669  QFontEngine *previousFontEngine;
1670  const unsigned short *logClusters;
1671 
1672  bool manualWrap;
1673  bool whiteSpaceOrObject;
1674 
1675  bool checkFullOtherwiseExtend(QScriptLine &line);
1676 
1677  QFixed calculateNewWidth(const QScriptLine &line) const {
1678  return line.textWidth + tmpData.textWidth + spaceData.textWidth + softHyphenWidth
1679  - qMin(rightBearing, QFixed());
1680  }
1681 
1682  inline glyph_t currentGlyph() const
1683  {
1684  Q_ASSERT(currentPosition > 0);
1685  Q_ASSERT(logClusters[currentPosition - 1] < glyphs.numGlyphs);
1686 
1687  return glyphs.glyphs[logClusters[currentPosition - 1]];
1688  }
1689 
1690  inline void resetPreviousGlyph()
1691  {
1692  previousGlyph = 0;
1693  previousFontEngine = 0;
1694  }
1695 
1696  inline void saveCurrentGlyph()
1697  {
1698  resetPreviousGlyph();
1699  if (currentPosition > 0 &&
1700  logClusters[currentPosition - 1] < glyphs.numGlyphs) {
1701  previousGlyph = currentGlyph(); // needed to calculate right bearing later
1702  previousFontEngine = fontEngine;
1703  }
1704  }
1705 
1706  inline void adjustRightBearing(glyph_t glyph)
1707  {
1708  qreal rb;
1709  fontEngine->getGlyphBearings(glyph, 0, &rb);
1710  rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1711  }
1712 
1713  inline void adjustRightBearing()
1714  {
1715  if (currentPosition <= 0)
1716  return;
1717  adjustRightBearing(currentGlyph());
1718  }
1719 
1720  inline void adjustPreviousRightBearing()
1721  {
1722  if (previousGlyph > 0 && previousFontEngine) {
1723  qreal rb;
1724  previousFontEngine->getGlyphBearings(previousGlyph, 0, &rb);
1725  rightBearing = qMin(QFixed(), QFixed::fromReal(rb));
1726  }
1727  }
1728 
1729  inline void resetRightBearing()
1730  {
1731  rightBearing = QFixed(1); // Any positive number is defined as invalid since only
1732  // negative right bearings are interesting to us.
1733  }
1734  };
1735 
1736 inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
1737 {
1738  LB_DEBUG("possible break width %f, spacew=%f", tmpData.textWidth.toReal(), spaceData.textWidth.toReal());
1739 
1740  QFixed newWidth = calculateNewWidth(line);
1741  if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
1742  return true;
1743 
1744  minw = qMax(minw, tmpData.textWidth);
1745  line += tmpData;
1746  line.textWidth += spaceData.textWidth;
1747 
1748  line.length += spaceData.length;
1749  tmpData.textWidth = 0;
1750  tmpData.length = 0;
1751  spaceData.textWidth = 0;
1752  spaceData.length = 0;
1753 
1754  return false;
1755 }
1756 
1757 } // anonymous namespace
1758 
1759 
1760 static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount,
1761  const QScriptItem &current, const unsigned short *logClusters,
1762  const QGlyphLayout &glyphs)
1763 {
1764  int glyphPosition = logClusters[pos];
1765  do { // got to the first next cluster
1766  ++pos;
1767  ++line.length;
1768  } while (pos < end && logClusters[pos] == glyphPosition);
1769  do { // calculate the textWidth for the rest of the current cluster.
1770  if (!glyphs.attributes[glyphPosition].dontPrint)
1771  line.textWidth += glyphs.advances_x[glyphPosition];
1772  ++glyphPosition;
1773  } while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart);
1774 
1775  Q_ASSERT((pos == end && glyphPosition == current.num_glyphs) || logClusters[pos] == glyphPosition);
1776 
1777  ++glyphCount;
1778 }
1779 
1780 
1781 // fill QScriptLine
1782 void QTextLine::layout_helper(int maxGlyphs)
1783 {
1784  QScriptLine &line = eng->lines[i];
1785  line.length = 0;
1786  line.trailingSpaces = 0;
1787  line.textWidth = 0;
1788  line.hasTrailingSpaces = false;
1789 
1790  if (!eng->layoutData->items.size() || line.from >= eng->layoutData->string.length()) {
1791  line.setDefaultHeight(eng);
1792  return;
1793  }
1794 
1795  Q_ASSERT(line.from < eng->layoutData->string.length());
1796 
1797  LineBreakHelper lbh;
1798 
1799  lbh.maxGlyphs = maxGlyphs;
1800 
1801  QTextOption::WrapMode wrapMode = eng->option.wrapMode();
1802  bool breakany = (wrapMode == QTextOption::WrapAnywhere);
1803  lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap);
1804 
1805  int item = -1;
1806  int newItem = eng->findItem(line.from);
1807 
1808  LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal());
1809 
1810  Qt::Alignment alignment = eng->option.alignment();
1811 
1812  const HB_CharAttributes *attributes = eng->attributes();
1813  if (!attributes)
1814  return;
1815  lbh.currentPosition = line.from;
1816  int end = 0;
1817  lbh.logClusters = eng->layoutData->logClustersPtr;
1818  lbh.resetPreviousGlyph();
1819 
1820  while (newItem < eng->layoutData->items.size()) {
1821  lbh.resetRightBearing();
1822  lbh.softHyphenWidth = 0;
1823  if (newItem != item) {
1824  item = newItem;
1825  const QScriptItem &current = eng->layoutData->items[item];
1826  if (!current.num_glyphs) {
1827  eng->shape(item);
1828  attributes = eng->attributes();
1829  if (!attributes)
1830  return;
1831  lbh.logClusters = eng->layoutData->logClustersPtr;
1832  }
1833  lbh.currentPosition = qMax(line.from, current.position);
1834  end = current.position + eng->length(item);
1835  lbh.glyphs = eng->shapedGlyphs(&current);
1836  QFontEngine *fontEngine = eng->fontEngine(current);
1837  if (lbh.fontEngine != fontEngine) {
1838  lbh.fontEngine = fontEngine;
1839  lbh.minimumRightBearing = qMin(QFixed(),
1840  QFixed::fromReal(fontEngine->minRightBearing()));
1841  }
1842  }
1843  const QScriptItem &current = eng->layoutData->items[item];
1844 
1845  lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
1846  current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
1847  current.ascent);
1848  lbh.tmpData.ascent = qMax(lbh.tmpData.ascent, current.ascent);
1849  lbh.tmpData.descent = qMax(lbh.tmpData.descent, current.descent);
1850 
1852  lbh.whiteSpaceOrObject = true;
1853  if (lbh.checkFullOtherwiseExtend(line))
1854  goto found;
1855 
1856  QFixed x = line.x + line.textWidth + lbh.tmpData.textWidth + lbh.spaceData.textWidth;
1857  QFixed tabWidth = eng->calculateTabWidth(item, x);
1858 
1859  lbh.spaceData.textWidth += tabWidth;
1860  lbh.spaceData.length++;
1861  newItem = item + 1;
1862 
1863  QFixed averageCharWidth = eng->fontEngine(current)->averageCharWidth();
1864  lbh.glyphCount += qRound(tabWidth / averageCharWidth);
1865 
1866  if (lbh.checkFullOtherwiseExtend(line))
1867  goto found;
1869  lbh.whiteSpaceOrObject = true;
1870  // if the line consists only of the line separator make sure
1871  // we have a sane height
1872  if (!line.length && !lbh.tmpData.length)
1873  line.setDefaultHeight(eng);
1875  addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1876  current, lbh.logClusters, lbh.glyphs);
1877  } else {
1878  lbh.tmpData.length++;
1879  lbh.adjustPreviousRightBearing();
1880  }
1881  line += lbh.tmpData;
1882  goto found;
1883  } else if (current.analysis.flags == QScriptAnalysis::Object) {
1884  lbh.whiteSpaceOrObject = true;
1885  lbh.tmpData.length++;
1886 
1888  if (eng->block.docHandle())
1890 
1891  lbh.tmpData.textWidth += current.width;
1892 
1893  newItem = item + 1;
1894  ++lbh.glyphCount;
1895  if (lbh.checkFullOtherwiseExtend(line))
1896  goto found;
1897  } else if (attributes[lbh.currentPosition].whiteSpace) {
1898  lbh.whiteSpaceOrObject = true;
1899  while (lbh.currentPosition < end && attributes[lbh.currentPosition].whiteSpace)
1900  addNextCluster(lbh.currentPosition, end, lbh.spaceData, lbh.glyphCount,
1901  current, lbh.logClusters, lbh.glyphs);
1902 
1903  if (!lbh.manualWrap && lbh.spaceData.textWidth > line.width) {
1904  lbh.spaceData.textWidth = line.width; // ignore spaces that fall out of the line.
1905  goto found;
1906  }
1907  } else {
1908  lbh.whiteSpaceOrObject = false;
1909  bool sb_or_ws = false;
1910  lbh.saveCurrentGlyph();
1911  do {
1912  addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount,
1913  current, lbh.logClusters, lbh.glyphs);
1914 
1915  if (attributes[lbh.currentPosition].whiteSpace || attributes[lbh.currentPosition-1].lineBreakType != HB_NoBreak) {
1916  sb_or_ws = true;
1917  break;
1918  } else if (breakany && attributes[lbh.currentPosition].charStop) {
1919  break;
1920  }
1921  } while (lbh.currentPosition < end);
1922  lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
1923 
1924  if (lbh.currentPosition && attributes[lbh.currentPosition - 1].lineBreakType == HB_SoftHyphen) {
1925  // if we are splitting up a word because of
1926  // a soft hyphen then we ...
1927  //
1928  // a) have to take the width of the soft hyphen into
1929  // account to see if the first syllable(s) /and/
1930  // the soft hyphen fit into the line
1931  //
1932  // b) if we are so short of available width that the
1933  // soft hyphen is the first breakable position, then
1934  // we don't want to show it. However we initially
1935  // have to take the width for it into account so that
1936  // the text document layout sees the overflow and
1937  // switch to break-anywhere mode, in which we
1938  // want the soft-hyphen to slip into the next line
1939  // and thus become invisible again.
1940  //
1941  if (line.length)
1942  lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1943  else if (breakany)
1944  lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
1945  }
1946 
1947  // The actual width of the text needs to take the right bearing into account. The
1948  // right bearing is left-ward, which means that if the rightmost pixel is to the right
1949  // of the advance of the glyph, the bearing will be negative. We flip the sign
1950  // for the code to be more readable. Logic borrowed from qfontmetrics.cpp.
1951  // We ignore the right bearing if the minimum negative bearing is too little to
1952  // expand the text beyond the edge.
1953  if (sb_or_ws|breakany) {
1954  QFixed rightBearing = lbh.rightBearing; // store previous right bearing
1955 #if !defined(Q_WS_MAC)
1956  if (lbh.calculateNewWidth(line) - lbh.minimumRightBearing > line.width)
1957 #endif
1958  lbh.adjustRightBearing();
1959  if (lbh.checkFullOtherwiseExtend(line)) {
1960  // we are too wide, fix right bearing
1961  if (rightBearing <= 0)
1962  lbh.rightBearing = rightBearing; // take from cache
1963  else
1964  lbh.adjustPreviousRightBearing();
1965 
1966  if (!breakany) {
1967  line.textWidth += lbh.softHyphenWidth;
1968  }
1969 
1970  goto found;
1971  }
1972  }
1973  lbh.saveCurrentGlyph();
1974  }
1975  if (lbh.currentPosition == end)
1976  newItem = item + 1;
1977  }
1978  LB_DEBUG("reached end of line");
1979  lbh.checkFullOtherwiseExtend(line);
1980 found:
1981  if (lbh.rightBearing > 0 && !lbh.whiteSpaceOrObject) // If right bearing has not yet been adjusted
1982  lbh.adjustRightBearing();
1983  line.textAdvance = line.textWidth;
1984  line.textWidth -= qMin(QFixed(), lbh.rightBearing);
1985 
1986  if (line.length == 0) {
1987  LB_DEBUG("no break available in line, adding temp: length %d, width %f, space: length %d, width %f",
1988  lbh.tmpData.length, lbh.tmpData.textWidth.toReal(),
1989  lbh.spaceData.length, lbh.spaceData.textWidth.toReal());
1990  line += lbh.tmpData;
1991  }
1992 
1993  LB_DEBUG("line length = %d, ascent=%f, descent=%f, textWidth=%f (spacew=%f)", line.length, line.ascent.toReal(),
1994  line.descent.toReal(), line.textWidth.toReal(), lbh.spaceData.width.toReal());
1995  LB_DEBUG(" : '%s'", eng->layoutData->string.mid(line.from, line.length).toUtf8().data());
1996 
1997  if (lbh.manualWrap) {
1998  eng->minWidth = qMax(eng->minWidth, line.textWidth);
1999  eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
2000  } else {
2001  eng->minWidth = qMax(eng->minWidth, lbh.minw);
2002  eng->maxWidth += line.textWidth;
2003  }
2004 
2005  if (line.textWidth > 0 && item < eng->layoutData->items.size())
2006  eng->maxWidth += lbh.spaceData.textWidth;
2008  line.textWidth += lbh.spaceData.textWidth;
2009  if (lbh.spaceData.length) {
2010  line.trailingSpaces = lbh.spaceData.length;
2011  line.hasTrailingSpaces = true;
2012  }
2013 
2014  line.justified = false;
2015  line.gridfitted = false;
2016 
2018  if ((lbh.maxGlyphs != INT_MAX && lbh.glyphCount > lbh.maxGlyphs)
2019  || (lbh.maxGlyphs == INT_MAX && line.textWidth > line.width)) {
2020 
2022  line.length = 0;
2023  line.textWidth = 0;
2024  layout_helper(lbh.maxGlyphs);
2026  }
2027  }
2028 }
2029 
2034 {
2035  eng->lines[i].x = QFixed::fromReal(pos.x());
2036  eng->lines[i].y = QFixed::fromReal(pos.y());
2037 }
2038 
2043 {
2044  return QPointF(eng->lines[i].x.toReal(), eng->lines[i].y.toReal());
2045 }
2046 
2047 // ### DOC: I have no idea what this means/does.
2048 // You create a text layout with a string of text. Once you laid
2049 // it out, it contains a number of QTextLines. from() returns the position
2050 // inside the text string where this line starts. If you e.g. has a
2051 // text of "This is a string", laid out into two lines (the second
2052 // starting at the word 'a'), layout.lineAt(0).from() == 0 and
2053 // layout.lineAt(1).from() == 8.
2059 {
2060  return eng->lines[i].from;
2061 }
2062 
2069 {
2071  && eng->block.isValid() && i == eng->lines.count()-1) {
2072  return eng->lines[i].length - 1;
2073  }
2074  return eng->lines[i].length + eng->lines[i].trailingSpaces;
2075 }
2076 
2078  int start, int glyph_start)
2079 {
2080  int ge = glyph_start + gf.glyphs.numGlyphs;
2081  int gs = glyph_start;
2082  int end = start + gf.num_chars;
2083  unsigned short *logClusters = eng->logClusters(&si);
2084  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2085  QFixed orig_width = gf.width;
2086 
2087  int *ul = eng->underlinePositions;
2088  if (ul)
2089  while (*ul != -1 && *ul < start)
2090  ++ul;
2091  bool rtl = si.analysis.bidiLevel % 2;
2092  if (rtl)
2093  x += si.width;
2094 
2095  do {
2096  int gtmp = ge;
2097  int stmp = end;
2098  if (ul && *ul != -1 && *ul < end) {
2099  stmp = *ul;
2100  gtmp = logClusters[*ul-si.position];
2101  }
2102 
2103  gf.glyphs = glyphs.mid(gs, gtmp - gs);
2104  gf.num_chars = stmp - start;
2105  gf.chars = eng->layoutData->string.unicode() + start;
2106  QFixed w = 0;
2107  while (gs < gtmp) {
2108  w += glyphs.effectiveAdvance(gs);
2109  ++gs;
2110  }
2111  start = stmp;
2112  gf.width = w;
2113  if (rtl)
2114  x -= w;
2115  if (gf.num_chars)
2116  p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2117  if (!rtl)
2118  x += w;
2119  if (ul && *ul != -1 && *ul < end) {
2120  // draw underline
2121  gtmp = (*ul == end-1) ? ge : logClusters[*ul+1-si.position];
2122  ++stmp;
2123  gf.glyphs = glyphs.mid(gs, gtmp - gs);
2124  gf.num_chars = stmp - start;
2125  gf.chars = eng->layoutData->string.unicode() + start;
2126  gf.logClusters = logClusters + start - si.position;
2127  w = 0;
2128  while (gs < gtmp) {
2129  w += glyphs.effectiveAdvance(gs);
2130  ++gs;
2131  }
2132  ++start;
2133  gf.width = w;
2135  if (rtl)
2136  x -= w;
2137  p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf);
2138  if (!rtl)
2139  x += w;
2141  ++gf.chars;
2142  ++ul;
2143  }
2144  } while (gs < ge);
2145 
2146  gf.width = orig_width;
2147 }
2148 
2149 
2150 static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
2151 {
2152  QBrush c = chf.foreground();
2153  if (c.style() == Qt::NoBrush) {
2154  p->setPen(defaultPen);
2155  }
2156 
2157  QBrush bg = chf.background();
2158  if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
2159  p->fillRect(QRectF(qFloor(r.x()), qFloor(r.y()), r.width(), r.height()), bg);
2160  if (c.style() != Qt::NoBrush) {
2161  p->setPen(QPen(c, 0));
2162  }
2163 
2164 }
2165 
2166 namespace {
2167  struct GlyphInfo
2168  {
2169  GlyphInfo(const QGlyphLayout &layout, const QPointF &position,
2170  const QTextItemInt::RenderFlags &renderFlags)
2171  : glyphLayout(layout), itemPosition(position), flags(renderFlags)
2172  {
2173  }
2174 
2175  QGlyphLayout glyphLayout;
2176  QPointF itemPosition;
2177  QTextItem::RenderFlags flags;
2178  };
2179 }
2180 
2196 #if !defined(QT_NO_RAWFONT)
2197 QList<QGlyphRun> QTextLine::glyphs(int from, int length) const
2198 {
2199  const QScriptLine &line = eng->lines[i];
2200 
2201  if (line.length == 0)
2202  return QList<QGlyphRun>();
2203 
2204  QHash<QFontEngine *, GlyphInfo> glyphLayoutHash;
2205 
2206  QTextLineItemIterator iterator(eng, i);
2207  qreal y = line.y.toReal() + line.base().toReal();
2208  while (!iterator.atEnd()) {
2209  QScriptItem &si = iterator.next();
2211  continue;
2212 
2213  QPointF pos(iterator.x.toReal(), y);
2214  if (from >= 0 && length >= 0 &&
2215  (from >= si.position + eng->length(&si) || from + length <= si.position))
2216  continue;
2217 
2218  QFont font = eng->font(si);
2219 
2220  QTextItem::RenderFlags flags;
2221  if (font.overline())
2222  flags |= QTextItem::Overline;
2223  if (font.underline())
2224  flags |= QTextItem::Underline;
2225  if (font.strikeOut())
2226  flags |= QTextItem::StrikeOut;
2227  if (si.analysis.bidiLevel % 2)
2228  flags |= QTextItem::RightToLeft;
2229 
2230  QGlyphLayout glyphLayout = eng->shapedGlyphs(&si).mid(iterator.glyphsStart,
2231  iterator.glyphsEnd - iterator.glyphsStart);
2232 
2233  if (glyphLayout.numGlyphs > 0) {
2234  QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
2235  if (mainFontEngine->type() == QFontEngine::Multi) {
2236  QFontEngineMulti *multiFontEngine = static_cast<QFontEngineMulti *>(mainFontEngine);
2237  int start = 0;
2238  int end;
2239  int which = glyphLayout.glyphs[0] >> 24;
2240  for (end = 0; end < glyphLayout.numGlyphs; ++end) {
2241  const int e = glyphLayout.glyphs[end] >> 24;
2242  if (e == which)
2243  continue;
2244 
2245  QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2246  glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2247  GlyphInfo(subLayout, pos, flags));
2248  for (int i = 0; i < subLayout.numGlyphs; i++)
2249  pos += QPointF(subLayout.advances_x[i].toReal(),
2250  subLayout.advances_y[i].toReal());
2251 
2252  start = end;
2253  which = e;
2254  }
2255 
2256  QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
2257  glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
2258  GlyphInfo(subLayout, pos, flags));
2259 
2260  } else {
2261  glyphLayoutHash.insertMulti(mainFontEngine,
2262  GlyphInfo(glyphLayout, pos, flags));
2263  }
2264  }
2265  }
2266 
2268 
2269  QList<QFontEngine *> keys = glyphLayoutHash.uniqueKeys();
2270  for (int i=0; i<keys.size(); ++i) {
2271  QFontEngine *fontEngine = keys.at(i);
2272 
2273  // Make a font for this particular engine
2274  QRawFont font;
2275  QRawFontPrivate *fontD = QRawFontPrivate::get(font);
2276  fontD->fontEngine = fontEngine;
2277  fontD->fontEngine->ref.ref();
2278 
2279 #if defined(Q_WS_WIN)
2280  if (fontEngine->supportsSubPixelPositions())
2282  else
2284 #elif defined(Q_WS_MAC)
2286 #elif !defined(QT_NO_FREETYPE)
2287  if (fontEngine->type() == QFontEngine::Freetype) {
2288  QFontEngineFT *freeTypeEngine = static_cast<QFontEngineFT *>(fontEngine);
2289  switch (freeTypeEngine->defaultHintStyle()) {
2292  break;
2295  break;
2299  break;
2300  };
2301  }
2302 #endif
2303 
2304  QList<GlyphInfo> glyphLayouts = glyphLayoutHash.values(fontEngine);
2305  for (int j=0; j<glyphLayouts.size(); ++j) {
2306  const QPointF &pos = glyphLayouts.at(j).itemPosition;
2307  const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout;
2308  const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags;
2309 
2310  QVarLengthArray<glyph_t> glyphsArray;
2311  QVarLengthArray<QFixedPoint> positionsArray;
2312 
2313  fontEngine->getGlyphPositions(glyphLayout, QTransform(), flags, glyphsArray,
2314  positionsArray);
2315  Q_ASSERT(glyphsArray.size() == positionsArray.size());
2316 
2317  QVector<quint32> glyphs;
2319  for (int i=0; i<glyphsArray.size(); ++i) {
2320  glyphs.append(glyphsArray.at(i) & 0xffffff);
2321  positions.append(positionsArray.at(i).toPointF() + pos);
2322  }
2323 
2324  QGlyphRun glyphIndexes;
2325  glyphIndexes.setGlyphIndexes(glyphs);
2326  glyphIndexes.setPositions(positions);
2327 
2328  glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline));
2329  glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline));
2330  glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
2331  glyphIndexes.setRawFont(font);
2332 
2333  QPair<QFontEngine *, int> key(fontEngine, int(flags));
2334  if (!glyphsHash.contains(key)) {
2335  glyphsHash.insert(key, glyphIndexes);
2336  } else {
2337  QGlyphRun &glyphRun = glyphsHash[key];
2338 
2339  QVector<quint32> indexes = glyphRun.glyphIndexes();
2340  QVector<QPointF> positions = glyphRun.positions();
2341 
2342  indexes += glyphIndexes.glyphIndexes();
2343  positions += glyphIndexes.positions();
2344 
2345  glyphRun.setGlyphIndexes(indexes);
2346  glyphRun.setPositions(positions);
2347  }
2348  }
2349  }
2350 
2351  return glyphsHash.values();
2352 }
2353 #endif // QT_NO_RAWFONT
2354 
2361 void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatRange *selection) const
2362 {
2363  const QScriptLine &line = eng->lines[i];
2364  QPen pen = p->pen();
2365 
2366  bool noText = (selection && selection->format.property(SuppressText).toBool());
2367 
2368  if (!line.length) {
2369  if (selection
2370  && selection->start <= line.from
2371  && selection->start + selection->length > line.from) {
2372 
2373  const qreal lineHeight = line.height().toReal();
2374  QRectF r(pos.x() + line.x.toReal(), pos.y() + line.y.toReal(),
2375  lineHeight / 2, QFontMetrics(eng->font()).width(QLatin1Char(' ')));
2376  setPenAndDrawBackground(p, QPen(), selection->format, r);
2377  p->setPen(pen);
2378  }
2379  return;
2380  }
2381 
2382 
2383  QTextLineItemIterator iterator(eng, i, pos, selection);
2384  QFixed lineBase = line.base();
2385 
2386  const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase;
2387 
2388  bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
2389  while (!iterator.atEnd()) {
2390  QScriptItem &si = iterator.next();
2391 
2392  if (selection && selection->start >= 0 && iterator.isOutsideSelection())
2393  continue;
2394 
2397  continue;
2398 
2399  QFixed itemBaseLine = y;
2400  QFont f = eng->font(si);
2402 
2403  if (eng->hasFormats() || selection) {
2404  format = eng->format(&si);
2405  if (suppressColors) {
2406  format.clearForeground();
2407  format.clearBackground();
2409  }
2410  if (selection)
2411  format.merge(selection->format);
2412 
2413  setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
2414  iterator.itemWidth.toReal(), line.height().toReal()));
2415 
2419  QFixed height = fe->ascent() + fe->descent();
2420  if (valign == QTextCharFormat::AlignSubScript)
2421  itemBaseLine += height / 6;
2422  else if (valign == QTextCharFormat::AlignSuperScript)
2423  itemBaseLine -= height / 2;
2424  }
2425  }
2426 
2428 
2429  if (eng->hasFormats()) {
2430  p->save();
2432  QFixed itemY = y - si.ascent;
2433  if (format.verticalAlignment() == QTextCharFormat::AlignTop) {
2434  itemY = y - lineBase;
2435  }
2436 
2437  QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
2438 
2439  eng->docLayout()->drawInlineObject(p, itemRect,
2440  QTextInlineObject(iterator.item, eng),
2441  si.position + eng->block.position(),
2442  format);
2443  if (selection) {
2445  if (bg.style() != Qt::NoBrush) {
2446  QColor c = bg.color();
2447  c.setAlpha(128);
2448  p->fillRect(itemRect, c);
2449  }
2450  }
2451  } else { // si.isTab
2452  QFont f = eng->font(si);
2453  QTextItemInt gf(si, &f, format);
2454  gf.chars = 0;
2455  gf.num_chars = 0;
2456  gf.width = iterator.itemWidth;
2457  p->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf);
2459  QChar visualTab(0x2192);
2460  int w = QFontMetrics(f).width(visualTab);
2461  qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
2462  if (x < 0)
2463  p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
2464  iterator.itemWidth.toReal(), line.height().toReal()),
2466  else
2467  x /= 2; // Centered
2468  p->drawText(QPointF(iterator.x.toReal() + x,
2469  y.toReal()), visualTab);
2470  }
2471 
2472  }
2473  p->restore();
2474  }
2475 
2476  continue;
2477  }
2478 
2479  unsigned short *logClusters = eng->logClusters(&si);
2480  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2481 
2482  QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart),
2483  &f, eng->layoutData->string.unicode() + iterator.itemStart,
2484  iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format);
2485  gf.logClusters = logClusters + iterator.itemStart - si.position;
2486  gf.width = iterator.itemWidth;
2487  gf.justified = line.justified;
2488  gf.initWithScriptItem(si);
2489 
2490  Q_ASSERT(gf.fontEngine);
2491 
2492  if (eng->underlinePositions) {
2493  // can't have selections in this case
2494  drawMenuText(p, iterator.x, itemBaseLine, si, gf, eng, iterator.itemStart, iterator.glyphsStart);
2495  } else {
2496  QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
2498  QPainterPath path;
2500 
2501  if (gf.glyphs.numGlyphs)
2502  gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
2503  if (gf.flags) {
2504  const QFontEngine *fe = gf.fontEngine;
2505  const qreal lw = fe->lineThickness().toReal();
2506  if (gf.flags & QTextItem::Underline) {
2507  qreal offs = fe->underlinePosition().toReal();
2508  path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
2509  }
2510  if (gf.flags & QTextItem::Overline) {
2511  qreal offs = fe->ascent().toReal() + 1;
2512  path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2513  }
2514  if (gf.flags & QTextItem::StrikeOut) {
2515  qreal offs = fe->ascent().toReal() / 3;
2516  path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
2517  }
2518  }
2519 
2520  p->save();
2522  //Currently QPen with a Qt::NoPen style still returns a default
2523  //QBrush which != Qt::NoBrush so we need this specialcase to reset it
2524  if (p->pen().style() == Qt::NoPen)
2525  p->setBrush(Qt::NoBrush);
2526  else
2527  p->setBrush(p->pen().brush());
2528 
2529  p->setPen(format.textOutline());
2530  p->drawPath(path);
2531  p->restore();
2532  } else {
2533  if (noText)
2534  gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
2535  p->drawTextItem(pos, gf);
2536  }
2537  }
2540  QBrush c = format.foreground();
2541  if (c.style() != Qt::NoBrush)
2542  p->setPen(c.color());
2543  QChar visualSpace((ushort)0xb7);
2544  p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
2545  p->setPen(pen);
2546  }
2547  }
2548 
2549 
2550  if (eng->hasFormats())
2551  p->setPen(pen);
2552 }
2553 
2570 qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
2571 {
2572  if (!eng->layoutData)
2573  eng->itemize();
2574 
2575  const QScriptLine &line = eng->lines[i];
2576  bool lastLine = i >= eng->lines.size() - 1;
2577 
2578  QFixed x = line.x;
2579  x += eng->alignLine(line) - eng->leadingSpaceWidth(line);
2580 
2581  if (!i && !eng->layoutData->items.size()) {
2582  *cursorPos = 0;
2583  return x.toReal();
2584  }
2585 
2586  int lineEnd = line.from + line.length + line.trailingSpaces;
2587  int pos = *cursorPos;
2588  int itm;
2589  const HB_CharAttributes *attributes = eng->attributes();
2590  if (!attributes) {
2591  *cursorPos = 0;
2592  return x.toReal();
2593  }
2594  while (pos < lineEnd && !attributes[pos].charStop)
2595  pos++;
2596  if (pos == lineEnd) {
2597  // end of line ensure we have the last item on the line
2598  itm = eng->findItem(pos-1);
2599  }
2600  else
2601  itm = eng->findItem(pos);
2602  eng->shapeLine(line);
2603 
2604  const QScriptItem *si = &eng->layoutData->items[itm];
2605  if (!si->num_glyphs)
2606  eng->shape(itm);
2607  pos -= si->position;
2608 
2609  QGlyphLayout glyphs = eng->shapedGlyphs(si);
2610  unsigned short *logClusters = eng->logClusters(si);
2611  Q_ASSERT(logClusters);
2612 
2613  int l = eng->length(itm);
2614  if (pos > l)
2615  pos = l;
2616  if (pos < 0)
2617  pos = 0;
2618 
2619  int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos];
2620  if (edge == Trailing) {
2621  // trailing edge is leading edge of next cluster
2622  while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart)
2623  glyph_pos++;
2624  }
2625 
2626  bool reverse = eng->layoutData->items[itm].analysis.bidiLevel % 2;
2627 
2628 
2629  // add the items left of the cursor
2630 
2631  int firstItem = eng->findItem(line.from);
2632  int lastItem = eng->findItem(lineEnd - 1);
2633  int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2634 
2635  QVarLengthArray<int> visualOrder(nItems);
2636  QVarLengthArray<uchar> levels(nItems);
2637  for (int i = 0; i < nItems; ++i)
2638  levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2639  QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2640 
2641  for (int i = 0; i < nItems; ++i) {
2642  int item = visualOrder[i]+firstItem;
2643  if (item == itm)
2644  break;
2645  QScriptItem &si = eng->layoutData->items[item];
2646  if (!si.num_glyphs)
2647  eng->shape(item);
2648 
2650  x += si.width;
2651  continue;
2652  }
2653  int start = qMax(line.from, si.position);
2654  int end = qMin(lineEnd, si.position + eng->length(item));
2655 
2656  logClusters = eng->logClusters(&si);
2657 
2658  int gs = logClusters[start-si.position];
2659  int ge = (end == si.position + eng->length(item)) ? si.num_glyphs-1 : logClusters[end-si.position-1];
2660 
2661  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2662 
2663  while (gs <= ge) {
2664  x += glyphs.effectiveAdvance(gs);
2665  ++gs;
2666  }
2667  }
2668 
2669  logClusters = eng->logClusters(si);
2670  glyphs = eng->shapedGlyphs(si);
2672  if (pos == (reverse ? 0 : l))
2673  x += si->width;
2674  } else {
2675  bool rtl = eng->isRightToLeft();
2676  bool visual = eng->visualCursorMovement();
2677  int end = qMin(lineEnd, si->position + l) - si->position;
2678  if (reverse) {
2679  int glyph_end = end == l ? si->num_glyphs : logClusters[end];
2680  int glyph_start = glyph_pos;
2681  if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
2682  glyph_start++;
2683  for (int i = glyph_end - 1; i >= glyph_start; i--)
2684  x += glyphs.effectiveAdvance(i);
2685  } else {
2686  int start = qMax(line.from - si->position, 0);
2687  int glyph_start = logClusters[start];
2688  int glyph_end = glyph_pos;
2689  if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
2690  glyph_end--;
2691  for (int i = glyph_start; i <= glyph_end; i++)
2692  x += glyphs.effectiveAdvance(i);
2693  }
2694  x += eng->offsetInLigature(si, pos, end, glyph_pos);
2695  }
2696 
2697  if (eng->option.wrapMode() != QTextOption::NoWrap && x > line.x + line.width)
2698  x = line.x + line.width;
2699 
2700  if (eng->option.wrapMode() != QTextOption::NoWrap && x < 0)
2701  x = 0;
2702 
2703  *cursorPos = pos + si->position;
2704  return x.toReal();
2705 }
2706 
2719 {
2720  QFixed x = QFixed::fromReal(_x);
2721  const QScriptLine &line = eng->lines[i];
2722  bool lastLine = i >= eng->lines.size() - 1;
2723  int lineNum = i;
2724 
2725  if (!eng->layoutData)
2726  eng->itemize();
2727 
2728  int line_length = textLength();
2729 
2730  if (!line_length)
2731  return line.from;
2732 
2733  int firstItem = eng->findItem(line.from);
2734  int lastItem = eng->findItem(line.from + line_length - 1);
2735  int nItems = (firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0;
2736 
2737  if (!nItems)
2738  return 0;
2739 
2740  x -= line.x;
2741  x -= eng->alignLine(line);
2742 // qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
2743 
2744  QVarLengthArray<int> visualOrder(nItems);
2745  QVarLengthArray<unsigned char> levels(nItems);
2746  for (int i = 0; i < nItems; ++i)
2747  levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
2748  QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
2749 
2750  bool visual = eng->visualCursorMovement();
2751  if (x <= 0) {
2752  // left of first item
2753  int item = visualOrder[0]+firstItem;
2754  QScriptItem &si = eng->layoutData->items[item];
2755  if (!si.num_glyphs)
2756  eng->shape(item);
2757  int pos = si.position;
2758  if (si.analysis.bidiLevel % 2)
2759  pos += eng->length(item);
2760  pos = qMax(line.from, pos);
2761  pos = qMin(line.from + line_length, pos);
2762  return pos;
2763  } else if (x < line.textWidth
2764  || (line.justified && x < line.width)) {
2765  // has to be in one of the runs
2766  QFixed pos;
2767  bool rtl = eng->isRightToLeft();
2768 
2769  eng->shapeLine(line);
2770  QVector<int> insertionPoints;
2771  if (visual && rtl)
2772  eng->insertionPointsForLine(lineNum, insertionPoints);
2773  int nchars = 0;
2774  for (int i = 0; i < nItems; ++i) {
2775  int item = visualOrder[i]+firstItem;
2776  QScriptItem &si = eng->layoutData->items[item];
2777  int item_length = eng->length(item);
2778 // qDebug(" item %d, visual %d x_remain=%f", i, item, x.toReal());
2779 
2780  int start = qMax(line.from - si.position, 0);
2781  int end = qMin(line.from + line_length - si.position, item_length);
2782 
2783  unsigned short *logClusters = eng->logClusters(&si);
2784 
2785  int gs = logClusters[start];
2786  int ge = (end == item_length ? si.num_glyphs : logClusters[end]) - 1;
2787  QGlyphLayout glyphs = eng->shapedGlyphs(&si);
2788 
2789  QFixed item_width = 0;
2791  item_width = si.width;
2792  } else {
2793  int g = gs;
2794  while (g <= ge) {
2795  item_width += glyphs.effectiveAdvance(g);
2796  ++g;
2797  }
2798  }
2799 // qDebug(" start=%d, end=%d, gs=%d, ge=%d item_width=%f", start, end, gs, ge, item_width.toReal());
2800 
2801  if (pos + item_width < x) {
2802  pos += item_width;
2803  nchars += end;
2804  continue;
2805  }
2806 // qDebug(" inside run");
2808  if (cpos == QTextLine::CursorOnCharacter)
2809  return si.position;
2810  bool left_half = (x - pos) < item_width/2;
2811 
2812  if (bool(si.analysis.bidiLevel % 2) != left_half)
2813  return si.position;
2814  return si.position + 1;
2815  }
2816 
2817  int glyph_pos = -1;
2818  QFixed edge;
2819  // has to be inside run
2820  if (cpos == QTextLine::CursorOnCharacter) {
2821  if (si.analysis.bidiLevel % 2) {
2822  pos += item_width;
2823  glyph_pos = gs;
2824  while (gs <= ge) {
2825  if (glyphs.attributes[gs].clusterStart) {
2826  if (pos < x)
2827  break;
2828  glyph_pos = gs;
2829  edge = pos;
2830  break;
2831  }
2832  pos -= glyphs.effectiveAdvance(gs);
2833  ++gs;
2834  }
2835  } else {
2836  glyph_pos = gs;
2837  while (gs <= ge) {
2838  if (glyphs.attributes[gs].clusterStart) {
2839  if (pos > x)
2840  break;
2841  glyph_pos = gs;
2842  edge = pos;
2843  }
2844  pos += glyphs.effectiveAdvance(gs);
2845  ++gs;
2846  }
2847  }
2848  } else {
2849  QFixed dist = INT_MAX/256;
2850  if (si.analysis.bidiLevel % 2) {
2851  if (!visual || rtl || (lastLine && i == nItems - 1)) {
2852  pos += item_width;
2853  while (gs <= ge) {
2854  if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2855  glyph_pos = gs;
2856  edge = pos;
2857  dist = qAbs(x-pos);
2858  }
2859  pos -= glyphs.effectiveAdvance(gs);
2860  ++gs;
2861  }
2862  } else {
2863  while (ge >= gs) {
2864  if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
2865  glyph_pos = ge;
2866  edge = pos;
2867  dist = qAbs(x-pos);
2868  }
2869  pos += glyphs.effectiveAdvance(ge);
2870  --ge;
2871  }
2872  }
2873  } else {
2874  if (!visual || !rtl || (lastLine && i == 0)) {
2875  while (gs <= ge) {
2876  if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2877  glyph_pos = gs;
2878  edge = pos;
2879  dist = qAbs(x-pos);
2880  }
2881  pos += glyphs.effectiveAdvance(gs);
2882  ++gs;
2883  }
2884  } else {
2885  QFixed oldPos = pos;
2886  while (gs <= ge) {
2887  pos += glyphs.effectiveAdvance(gs);
2888  if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
2889  glyph_pos = gs;
2890  edge = pos;
2891  dist = qAbs(x-pos);
2892  }
2893  ++gs;
2894  }
2895  pos = oldPos;
2896  }
2897  }
2898  if (qAbs(x-pos) < dist) {
2899  if (visual) {
2900  if (!rtl && i < nItems - 1) {
2901  nchars += end;
2902  continue;
2903  }
2904  if (rtl && nchars > 0)
2905  return insertionPoints[lastLine ? nchars : nchars - 1];
2906  }
2907  return eng->positionInLigature(&si, end, x, pos, -1,
2909  }
2910  }
2911  Q_ASSERT(glyph_pos != -1);
2912  return eng->positionInLigature(&si, end, x, edge, glyph_pos,
2914  }
2915  }
2916  // right of last item
2917 // qDebug() << "right of last";
2918  int item = visualOrder[nItems-1]+firstItem;
2919  QScriptItem &si = eng->layoutData->items[item];
2920  if (!si.num_glyphs)
2921  eng->shape(item);
2922  int pos = si.position;
2923  if (!(si.analysis.bidiLevel % 2))
2924  pos += eng->length(item);
2925  pos = qMax(line.from, pos);
2926 
2927  int maxPos = line.from + line_length;
2928 
2929  // except for the last line we assume that the
2930  // character between lines is a space and we want
2931  // to position the cursor to the left of that
2932  // character.
2933  // ###### breaks with japanese for example
2934  if (this->i < eng->lines.count() - 1)
2935  --maxPos;
2936 
2937  pos = qMin(pos, maxPos);
2938  return pos;
2939 }
2940 
QAtomicInt ref
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
virtual QFixed lineThickness() const
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
QTextCharFormat format(const QScriptItem *si) const
double d
Definition: qnumeric_p.h:62
void setAdditionalFormats(const QList< FormatRange > &overrides)
Sets the additional formats supported by the text layout to formatList.
static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection, QPainterPath *region, QRectF boundingRect)
QTextCharFormat charFormat(int index) const
Definition: qtextformat_p.h:85
void moveTop(qreal pos)
Moves the rectangle vertically, leaving the rectangle&#39;s top line at the given y coordinate.
Definition: qrect.h:691
QTextOption textOption() const
Returns the current text option used to control the layout process.
virtual qreal minRightBearing() const
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
Definition: qpainterpath.h:392
qreal descent() const
Returns the line&#39;s descent.
void setText(const QString &string)
Sets the layout&#39;s text to the given string.
The QTextLayout::FormatRange structure is used to apply extra formatting information for a specified ...
Definition: qtextlayout.h:128
virtual QFixed averageCharWidth() const
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
bool isRightToLeft() const
int width(const QString &, int len=-1) const
Returns the width in pixels of the first len characters of text.
unsigned short trailingSpaces
bool isValidCursorPosition(int pos) const
/ Returns true if position pos is a valid cursor position.
void drawPath(const QPainterPath &path)
Draws the given painter path using the current pen for outline and the current brush for filling...
Definition: qpainter.cpp:3502
QFont font(const QScriptItem &si) const
QFixed * advances_y
QPointF position() const
The global position of the layout.
The QTextCharFormat class provides formatting information for characters in a QTextDocument.
Definition: qtextformat.h:372
double qreal
Definition: qglobal.h:1193
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
The QFontMetrics class provides font metrics information.
Definition: qfontmetrics.h:65
void setStrikeOut(bool strikeOut)
Indicates that this QGlyphRun should be painted with an strike out decoration if strikeOut is true...
Definition: qglyphrun.cpp:353
const QTransform & transform() const
Returns the world transformation matrix.
Definition: qpainter.cpp:9558
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
qreal y() const
Returns the line&#39;s y position.
void clearAdditionalFormats()
Clears the list of additional formats supported by the text layout.
const QColor & color() const
Returns the brush color.
Definition: qbrush.h:183
QRectF rect() const
Returns the line&#39;s bounding rectangle.
qreal horizontalAdvance() const
Returns the horizontal advance of the text.
void setPosition(const QPointF &pos)
Moves the line to position pos.
#define QFIXED_MAX
Definition: qfixed_p.h:158
static void addNextCluster(int &pos, int end, QScriptLine &line, int &glyphCount, const QScriptItem &current, const unsigned short *logClusters, const QGlyphLayout &glyphs)
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QFixed * advances_x
bool isValid() const
Returns true if the rectangle is valid, otherwise returns false.
Definition: qrect.h:661
qreal maximumWidth() const
The maximum width the layout could expand to; this is essentially the width of the entire text...
void moveLeft(qreal pos)
Moves the rectangle horizontally, leaving the rectangle&#39;s left edge at the given x coordinate...
Definition: qrect.h:689
QScriptItem & next()
static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, QTextItemInt &gf, QTextEngine *eng, int start, int glyph_start)
const QChar * chars
void setUnderline(bool underline)
Indicates that this QGlyphRun should be painted with an underline decoration if underline is true...
Definition: qglyphrun.cpp:328
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
int count(const T &t) const
Returns the number of occurrences of value in the vector.
Definition: qvector.h:742
HB_Glyph * glyphs
bool underline() const
Returns true if underline has been set; otherwise returns false.
Definition: qfont.cpp:1320
QList< QGlyphRun > glyphs(int from, int length) const
Returns the glyph indexes and positions for all glyphs in this QTextLine which reside in QScriptItems...
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
QFixed calculateTabWidth(int index, QFixed x) const
returns the width of tab at index (in the tabs array) with the tab-start at position x ...
Qt::PenStyle style() const
Returns the pen style.
Definition: qpen.cpp:428
static QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
int qFloor(qreal v)
Definition: qmath.h:73
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
virtual void drawInlineObject(QPainter *painter, const QRectF &rect, QTextInlineObject object, int posInDocument, const QTextFormat &format)
This function is called to draw the inline object, object, with the given painter within the rectangl...
void setPositions(const QVector< QPointF > &positions)
Sets the positions of the edge of the baseline for each glyph in this set of glyph indexes to positio...
Definition: qglyphrun.cpp:244
QBrush brushProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn&#39;t of QVariant::Brush type...
static C reverse(const C &l)
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip region to the given rectangle using the given clip operation...
Definition: qpainter.cpp:2801
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
void clearBackground()
Clears the brush used to paint the document&#39;s background.
Definition: qtextformat.h:347
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
void setFont(const QFont &f)
Sets the layout&#39;s font to the given font.
int findItem(int strPos) const
qreal left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:525
The QTextLine class represents a line of text inside a QTextLayout.
Definition: qtextlayout.h:197
static qreal position(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
static QRawFontPrivate * get(const QRawFont &font)
Definition: qrawfont_p.h:109
void restore()
Restores the current painter state (pops a saved state off the stack).
Definition: qpainter.cpp:1620
int * underlinePositions
WrapMode
This enum describes how text is wrapped in a document.
Definition: qtextoption.h:102
int textLength() const
Returns the length of the text in the line.
void drawCursor(QPainter *p, const QPointF &pos, int cursorPosition) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal height() const
Returns the inline object&#39;s total height.
void insertionPointsForLine(int lineNum, QVector< int > &insertionPoints)
Flags flags() const
Returns the flags associated with the option.
Definition: qtextoption.h:121
qreal leading() const
Returns the line&#39;s leading.
QFontEngine * fontEngine(const QScriptItem &si, QFixed *ascent=0, QFixed *descent=0, QFixed *leading=0) const
QRectF boundingRect() const
The smallest rectangle that contains all the lines in the layout.
QScriptItemArray items
int nextCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the next valid cursor position after oldPos that respects the given cursor mode...
bool toBool() const
Returns the variant as a bool if the variant has type() Bool.
Definition: qvariant.cpp:2691
const unsigned short * logClusters
long ASN1_INTEGER_get ASN1_INTEGER * a
void setLineWidth(qreal width)
Lays out the line with the given width.
bool ref()
Atomically increments the value of this QAtomicInt.
QTextEngine * eng
Definition: qtextlayout.h:96
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos)
QFixed textWidth
void drawLine(const QLineF &line)
Draws a line defined by line.
Definition: qpainter.h:573
int start
Specifies the beginning of the format range within the text layout&#39;s text.
Definition: qtextlayout.h:129
LayoutData * layoutData
QRectF intersected(const QRectF &other) const
Returns the intersection of this rectangle and the given rectangle.
Definition: qrect.h:818
unsigned short * logClusters(const QScriptItem *si) const
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool hasFormats() const
QFixed height() const
qreal ascent() const
Returns the inline object&#39;s ascent.
QTextFormat format(int idx) const
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
QVector< QPointF > positions() const
Returns the position of the edge of the baseline for each glyph in this set of glyph indexes...
Definition: qglyphrun.cpp:228
QGlyphLayout mid(int position, int n=-1) const
static QFixed fromReal(qreal r)
Definition: qfixed_p.h:70
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QVector class is a template class that provides a dynamic array.
Definition: qdatastream.h:64
TransformationType type() const
Returns the transformation type of this matrix.
const HB_CharAttributes * attributes() const
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
QFont font() const
Returns the current font that is used for the layout, or a default font if none is set...
static const uint base
Definition: qurl.cpp:268
virtual Type type() const =0
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
qreal ascent() const
Returns the line&#39;s ascent.
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
QStringList keys
void clearForeground()
Clears the brush used to paint the document&#39;s foreground.
Definition: qtextformat.h:354
void setRight(qreal pos)
Sets the right edge of the rectangle to the given x coordinate.
Definition: qrect.h:672
void save()
Saves the current painter state (pushes the state onto a stack).
Definition: qpainter.cpp:1590
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
static int sign(int x)
QTextLine lineForTextPosition(int pos) const
Returns the line that contains the cursor position specified by pos.
void setDescent(qreal d)
Sets the inline object&#39;s decent to d.
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing=0, qreal *rightBearing=0)
The QLineF class provides a two-dimensional vector using floating point precision.
Definition: qline.h:212
int position() const
Returns the index of the block&#39;s first character within the document.
bool leadingIncluded() const
Returns true if positive leading is included into the line&#39;s height; otherwise returns false...
static const QRectF boundingRect(const QPointF *points, int pointCount)
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule of the painter path to the given fillRule.
QGlyphLayout glyphs
void setNumColumns(int columns)
Lays out the line.
VerticalAlignment
This enum describes the ways that adjacent characters can be vertically aligned.
Definition: qtextformat.h:375
QTextLayout()
Constructs an empty text layout.
void shapeLine(const QScriptLine &line)
void drawText(const QPointF &p, const QString &s)
Draws the given text with the currently defined text direction, beginning at the given position...
Definition: qpainter.cpp:6231
T * data() const
Returns a pointer to the shared data object.
Definition: qshareddata.h:145
void setRenderHint(RenderHint hint, bool on=true)
Sets the given render hint on the painter if on is true; otherwise clears the render hint...
Definition: qpainter.cpp:7620
qreal cursorToX(int *cursorPos, Edge edge=Leading) const
Converts the cursor position cursorPos to the corresponding x position inside the line...
QString text() const
Returns the layout&#39;s text.
const QPen & pen() const
Returns the painter&#39;s current pen.
Definition: qpainter.cpp:4152
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
static bool isEmpty(const char *str)
bool overline() const
Returns true if overline has been set; otherwise returns false.
Definition: qfont.cpp:1344
const QChar * unicode() const
Returns a &#39;\0&#39;-terminated Unicode representation of the string.
Definition: qstring.h:706
The QTextFormat class provides formatting information for a QTextDocument.
Definition: qtextformat.h:129
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
QFixed height() const
void setCursorMoveStyle(Qt::CursorMoveStyle style)
Set the cursor movement style.
QVector< quint32 > glyphIndexes() const
Returns the glyph indexes for this QGlyphRun object.
Definition: qglyphrun.cpp:202
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
QGlyphLayout shapedGlyphs(const QScriptItem *si) const
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
virtual QFixed ascent() const =0
const char * layout
virtual QFixed descent() const =0
LayoutDirection
Definition: qnamespace.h:1580
unsigned short bidiLevel
static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder)
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
Q_CORE_EXPORT void qWarning(const char *,...)
Internal QTextItem.
void layout_helper(int numGlyphs)
The QTextBlock class provides a container for text fragments in a QTextDocument.
Definition: qtextobject.h:199
qreal x() const
Returns the line&#39;s x position.
unsigned short num_glyphs
void addRect(const QRectF &rect)
Adds the given rectangle to this path as a closed subpath.
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
Qt::LayoutDirection textDirection() const
Returns if the object should be laid out right-to-left or left-to-right.
int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter)
QBrush brush() const
Returns the brush used to fill strokes generated with this pen.
Definition: qpen.cpp:797
uint hasTrailingSpaces
void draw(QPainter *p, const QPointF &pos, const QVector< FormatRange > &selections=QVector< FormatRange >(), const QRectF &clip=QRectF()) const
Draws the whole layout on the painter p at the position specified by pos.
QBrush background() const
Returns the brush used to paint the document&#39;s background.
Definition: qtextformat.h:345
Qt::BrushStyle style() const
Returns the brush style.
Definition: qbrush.h:182
QScriptLineArray lines
void itemize() const
#define SuppressBackground
Definition: qtextlayout.cpp:74
const T & at(int idx) const
QTextOption option
The QGlyphRun class provides direct access to the internal glyphs in a font.
Definition: qglyphrun.h:59
void translate(qreal dx, qreal dy)
Moves the rectangle dx along the x-axis and dy along the y-axis, relative to the current position...
Definition: qrect.h:716
QList< QGlyphRun > glyphRuns() const
Returns the glyph indexes and positions for all glyphs in this QTextLayout.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
int preeditAreaPosition() const
Returns the position of the area in the text layout that will be processed before editing occurs...
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
void setFlags(int flags)
QFixed descent
QFontEngine * engineForScript(int script) const
Definition: qfont.cpp:294
void setLeadingIncluded(bool included)
Includes positive leading into the line&#39;s height if included is true; otherwise does not include lead...
unsigned short flags
QTextBlock block
const QBrush & brush() const
Returns the painter&#39;s current brush.
Definition: qpainter.cpp:4232
unsigned short * logClustersPtr
QPointF position() const
Returns the line&#39;s position relative to the text layout&#39;s position.
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition: qstring.h:505
#define ObjectSelectionBrush
Definition: qtextlayout.cpp:72
QFixed leading
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
qreal minimumWidth() const
The minimum width the layout needs.
VerticalAlignment verticalAlignment() const
Returns the vertical alignment used for characters with this format.
Definition: qtextformat.h:486
QString preeditAreaText() const
Returns the text that is inserted in the layout before editing occurs.
void setWidth(qreal w)
Sets the inline object&#39;s width to w.
QFixed textAdvance
QFixed descent
void setDefaultHeight(QTextEngine *eng)
void shape(int item) const
unsigned short script
#define SuppressText
Definition: qtextlayout.cpp:73
QTextCharFormat::UnderlineStyle underlineStyle
void setPosition(const QPointF &p)
Moves the text layout to point p.
void setOverline(bool overline)
Indicates that this QGlyphRun should be painted with an overline decoration if overline is true...
Definition: qglyphrun.cpp:303
qreal descent() const
Returns the inline object&#39;s descent.
QPointF toPointF() const
Definition: qfixed_p.h:194
The QRawFont class provides access to a single physical instance of a font.
Definition: qrawfont.h:63
void merge(const QTextFormat &other)
Merges the other format with this format; where there are conflicts the other format takes precedence...
CursorMoveStyle
This enum describes the movement style available to text cursors.
Definition: qnamespace.h:1790
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
unsigned short ushort
Definition: qglobal.h:995
Qt::CursorMoveStyle cursorMoveStyle() const
The cursor movement style of this QTextLayout.
void setAscent(qreal a)
Sets the inline object&#39;s ascent to a.
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
QFixed maxWidth
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
qreal naturalTextWidth() const
Returns the width of the line that is occupied by text.
QList< FormatRange > additionalFormats() const
Returns the list of additional formats supported by the text layout.
void setTextOption(const QTextOption &option)
Sets the text option structure that controls the layout process to the given option.
QList< T > values() const
Returns a list containing all the values in the hash, in an arbitrary order.
Definition: qhash.h:693
QVariant property(int propertyId) const
Returns the property specified by the given propertyId.
int key
void drawTextItem(const QPointF &p, const QTextItem &ti)
Draws the text item ti at position p.
Definition: qpainter.cpp:6864
QExplicitlySharedDataPointer< QFontPrivate > d
Definition: qfont.h:343
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
void setBrush(const QBrush &brush)
Sets the painter&#39;s brush to the given brush.
Definition: qpainter.cpp:4171
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
void setAlpha(int alpha)
Sets the alpha of this color to alpha.
Definition: qcolor.cpp:1094
bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const
int length(int item) const
void setPen(const QColor &color)
Sets the painter&#39;s pen to have style Qt::SolidLine, width 0 and the specified color.
Definition: qpainter.cpp:4047
QBrush foreground() const
Returns the brush used to render foreground details, such as text, frame outlines, and table borders.
Definition: qtextformat.h:352
bool boolProperty(int propertyId) const
Returns the value of the property specified by propertyId.
QFixed alignLine(const QScriptLine &line)
qreal width() const
Returns the line&#39;s width as specified by the layout() function.
QFont::HintingPreference hintingPreference
Definition: qrawfont_p.h:112
if(void) toggleToolbarShown
WrapMode wrapMode() const
Returns the text wrap mode defined by the option.
Definition: qtextoption.h:110
QFactoryLoader * l
int rightCursorPosition(int oldPos) const
Returns the cursor position to the right of oldPos, next to it.
qreal toReal() const
Definition: qfixed_p.h:77
The QTextOption class provides a description of general rich text properties.
Definition: qtextoption.h:59
~QTextLayout()
Destructs the layout.
signed int length
int formatIndex(const QScriptItem *si) const
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
bool cacheEnabled() const
Returns true if the complete layout information is cached; otherwise returns false.
void clearLayout()
Clears the line information in the layout.
static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
QFixed effectiveAdvance(int item) const
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
Definition: qtextobject.h:208
qreal top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:526
QFixed base() const
Qt::Alignment alignment() const
Returns the text alignment defined by the option.
Definition: qtextoption.h:97
int length
Specifies the numer of characters the format range spans.
Definition: qtextlayout.h:130
HB_GlyphAttributes * attributes
#define LB_DEBUG
QTextCharFormat format
Specifies the format to apply.
Definition: qtextlayout.h:131
void setWrapMode(WrapMode wrap)
Sets the option&#39;s text wrap mode to the given mode.
Definition: qtextoption.h:109
QFontEngine * fontEngine
Definition: qrawfont_p.h:111
virtual void positionInlineObject(QTextInlineObject item, int posInDocument, const QTextFormat &format)
Lays out the inline object item using the given text format.
HintStyle defaultHintStyle() const
RenderHints renderHints() const
Returns a flag that specifies the rendering hints that are set for this painter.
Definition: qpainter.cpp:7675
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
void setCacheEnabled(bool enable)
Enables caching of the complete layout information if enable is true; otherwise disables layout cachi...
void setClipPath(const QPainterPath &path, Qt::ClipOperation op=Qt::ReplaceClip)
Enables clipping, and sets the clip path for the painter to the given path, with the clip operation...
Definition: qpainter.cpp:3365
qreal width() const
Returns the inline object&#39;s width.
int leftCursorPosition(int oldPos) const
Returns the cursor position to the left of oldPos, next to it.
void endLayout()
Ends the layout process.
QTextDocumentPrivate * docHandle() const
Definition: qtextobject.h:283
int textPosition() const
The position of the inline object within the text layout.
QRectF translated(qreal dx, qreal dy) const
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis...
Definition: qrect.h:740
QRectF rect() const
Returns the inline object&#39;s rectangle.
bool strikeOut() const
Returns true if strikeout has been set; otherwise returns false.
Definition: qfont.cpp:1367
bool isOutsideSelection() const
static const KeyPair *const end
int previousCursorPosition(int oldPos, CursorMode mode=SkipCharacters) const
Returns the first valid cursor position before oldPos that respects the given cursor mode...
QPen penProperty(int propertyId) const
Returns the value of the property given by propertyId; if the property isn&#39;t of QVariant::Pen type...
int xToCursor(qreal x, CursorPosition=CursorBetweenCharacters) const
Converts the x-coordinate x, to the nearest matching cursor position, depending on the cursor positio...
void setPreeditArea(int position, const QString &text)
Sets the position and text of the area in the layout that is processed before editing occurs...
QTextFormatCollection * formats() const
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QFixed minWidth
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:655
bool visualCursorMovement() const
int formatIndex() const
Returns an integer describing the format of the inline object within the text layout.
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
void draw(QPainter *p, const QPointF &point, const QTextLayout::FormatRange *selection=0) const
Draws a line on the given painter at the specified position.
#define INT_MAX
qreal height() const
Returns the line&#39;s height.
QAbstractTextDocumentLayout * docLayout() const
unsigned int glyph_t
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
virtual QFixed underlinePosition() const
void beginLayout()
Begins the layout process.
QFixed leadingSpaceWidth(const QScriptLine &line)
QFontEngine * engine(int at) const
int textStart() const
Returns the start of the line from the beginning of the string passed to the QTextLayout.
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
Definition: qpainter.cpp:7420
void setGlyphIndexes(const QVector< quint32 > &glyphIndexes)
Set the glyph indexes for this QGlyphRun object to glyphIndexes.
Definition: qglyphrun.cpp:217
#define text
Definition: qobjectdefs.h:80
QPen textOutline() const
Returns the pen used to draw the outlines of characters in this format.
Definition: qtextformat.h:491
int size() const
static qreal toReal(Register *reg, int type, bool *ok=0)
int lineCount() const
Returns the number of lines in this text layout.
virtual bool supportsSubPixelPositions() const
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void setRawFont(const QRawFont &rawFont)
Sets the font specified by rawFont to be the font used to look up the glyph indexes.
Definition: qglyphrun.cpp:191
QRectF naturalTextRect() const
Returns the rectangle covered by the line.
QTextFormat format() const
Returns format of the inline object within the text layout.
QScriptAnalysis analysis