void ChatLineModelItem::computeWrapList() const { QString text = _styledMsg.plainContents(); int length = text.length(); if (!length) return; QList<ChatLineModel::Word> wplist; // use a temp list which we'll later copy into a QVector for efficiency QTextBoundaryFinder finder(QTextBoundaryFinder::Line, _styledMsg.plainContents().unicode(), length, TextBoundaryFinderBuffer, TextBoundaryFinderBufferSize); int idx; int oldidx = 0; ChatLineModel::Word word; word.start = 0; qreal wordstartx = 0; QTextLayout layout(_styledMsg.plainContents()); QTextOption option; option.setWrapMode(QTextOption::NoWrap); layout.setTextOption(option); layout.setAdditionalFormats(QtUi::style()->toTextLayoutList(_styledMsg.contentsFormatList(), length, messageLabel())); layout.beginLayout(); QTextLine line = layout.createLine(); line.setNumColumns(length); layout.endLayout(); while ((idx = finder.toNextBoundary()) >= 0 && idx <= length) { // QTextBoundaryFinder has inconsistent behavior in Qt version up to and including 4.6.3 (at least). // It doesn't point to the position we should break, but to the character before that. // Unfortunately Qt decided to fix this by changing the behavior of QTBF, so now we have to add a version // check. At the time of this writing, I'm still trying to get this reverted upstream... // // cf. https://bugs.webkit.org/show_bug.cgi?id=31076 and Qt commit e6ac173 static int needWorkaround = -1; if (needWorkaround < 0) { needWorkaround = 0; QStringList versions = QString(qVersion()).split('.'); if (versions.count() == 3 && versions.at(0).toInt() == 4) { if (versions.at(1).toInt() <= 6 && versions.at(2).toInt() <= 3) needWorkaround = 1; } } if (needWorkaround == 1) { if (idx < length) idx++; } if (idx == oldidx) continue; word.start = oldidx; int wordend = idx; for (; wordend > word.start; wordend--) { if (!text.at(wordend-1).isSpace()) break; } qreal wordendx = line.cursorToX(wordend); qreal trailingendx = line.cursorToX(idx); word.endX = wordendx; word.width = wordendx - wordstartx; word.trailing = trailingendx - wordendx; wordstartx = trailingendx; wplist.append(word); oldidx = idx; } // A QVector needs less space than a QList _wrapList.resize(wplist.count()); for (int i = 0; i < wplist.count(); i++) { _wrapList[i] = wplist.at(i); } }