From 6d39e87f340b46637633a34fc32a72c38356473b Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Tue, 1 Apr 2014 14:29:38 +0300 Subject: [HB] Ensure we always working with non-multi font engine Change-Id: If88385d4cecdc527b7952d34e48f7ba889173c6c Reviewed-by: Lars Knoll --- src/gui/text/qfontengine.cpp | 5 +++++ src/gui/text/qharfbuzzng.cpp | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src/gui/text') diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index a72ac23418..b2254c4826 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -280,6 +280,7 @@ QFixed QFontEngine::underlinePosition() const void *QFontEngine::harfbuzzFont() const { + Q_ASSERT(type() != QFontEngine::Multi); #ifdef QT_ENABLE_HARFBUZZ_NG if (useHarfbuzzNG) return hb_qt_font_get_for_engine(const_cast(this)); @@ -312,6 +313,7 @@ void *QFontEngine::harfbuzzFont() const void *QFontEngine::harfbuzzFace() const { + Q_ASSERT(type() != QFontEngine::Multi); #ifdef QT_ENABLE_HARFBUZZ_NG if (useHarfbuzzNG) return hb_qt_face_get_for_engine(const_cast(this)); @@ -329,6 +331,9 @@ void *QFontEngine::harfbuzzFace() const bool QFontEngine::supportsScript(QChar::Script script) const { + if (type() <= QFontEngine::Multi) + return true; + // ### TODO: This only works for scripts that require OpenType. More generally // for scripts that do not require OpenType we should just look at the list of // supported writing systems in the font's OS/2 table. diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index b0bade83ee..e87747fd1b 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -605,8 +605,6 @@ _hb_qt_reference_table(hb_face_t * /*face*/, hb_tag_t tag, void *user_data) static inline hb_face_t * _hb_qt_face_create(QFontEngine *fe) { - Q_ASSERT(fe); - QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData)); Q_CHECK_PTR(data); data->user_data = fe->faceData.user_data; @@ -633,6 +631,8 @@ _hb_qt_face_release(void *user_data) hb_face_t *hb_qt_face_get_for_engine(QFontEngine *fe) { + Q_ASSERT(fe && fe->type() != QFontEngine::Multi); + if (Q_UNLIKELY(!fe->face_)) { fe->face_ = _hb_qt_face_create(fe); if (Q_UNLIKELY(!fe->face_)) @@ -647,8 +647,6 @@ hb_face_t *hb_qt_face_get_for_engine(QFontEngine *fe) static inline hb_font_t * _hb_qt_font_create(QFontEngine *fe) { - Q_ASSERT(fe); - hb_face_t *face = hb_qt_face_get_for_engine(fe); if (Q_UNLIKELY(!face)) return NULL; @@ -685,6 +683,8 @@ _hb_qt_font_release(void *user_data) hb_font_t *hb_qt_font_get_for_engine(QFontEngine *fe) { + Q_ASSERT(fe && fe->type() != QFontEngine::Multi); + if (Q_UNLIKELY(!fe->font_)) { fe->font_ = _hb_qt_font_create(fe); if (Q_UNLIKELY(!fe->font_)) -- cgit v1.2.3 From d8286729451ce18f07d47a5bc3f5af08eda860fa Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Thu, 3 Apr 2014 03:55:45 +0300 Subject: QTextEngine: Fix visual position movement for tab and object cases QTextLineItemIterator::next() was never updating itemStart and itemEnd for QScriptAnalysis::TabOrObject, thus producing incorrect insertion points for the line that contains tabs and/or objects. Change-Id: Ia964c663cc0636ba6be4500702656f989b252fba Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src/gui/text') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 3b079b7ee3..7390b566e7 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -3520,7 +3520,12 @@ QScriptItem &QTextLineItemIterator::next() if (!si->num_glyphs) eng->shape(item); + itemStart = qMax(line.from, si->position); + itemEnd = qMin(lineEnd, si->position + itemLength); + if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { + glyphsStart = 0; + glyphsEnd = 1; itemWidth = si->width; return *si; } @@ -3528,15 +3533,9 @@ QScriptItem &QTextLineItemIterator::next() unsigned short *logClusters = eng->logClusters(si); QGlyphLayout glyphs = eng->shapedGlyphs(si); - itemStart = qMax(line.from, si->position); glyphsStart = logClusters[itemStart - si->position]; - if (lineEnd < si->position + itemLength) { - itemEnd = lineEnd; - glyphsEnd = logClusters[itemEnd-si->position]; - } else { - itemEnd = si->position + itemLength; - glyphsEnd = si->num_glyphs; - } + glyphsEnd = (itemEnd == si->position + itemLength) ? si->num_glyphs : logClusters[itemEnd - si->position]; + // show soft-hyphen at line-break if (si->position + itemLength >= lineEnd && eng->layoutData->string.at(lineEnd - 1).unicode() == QChar::SoftHyphen) -- cgit v1.2.3 From 0b5911f37619acc20463f01df5588764e22a35b0 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 4 Apr 2014 07:28:20 +0300 Subject: QTextLayout: Fix visual cursor movement in some cases To guarantee proper positioning at the end of the last line in a bidirectional text we have to insert the eol position into the insertion points vector, accordingly to the visual ordering. Detection of the last *logical* item in a *visual* line is unrelaed to the text direction, it is simply `iterator.item == iterator.lastItem`. [ChangeLog][QtGui][QTextLayout] Fixed visual cursor movement in bidirectional text. Task-number: QTBUG-18060 (partially related) Change-Id: I53b6ab889ef580ab0560b620b808b1e09efc0fbd Reviewed-by: Lars Knoll Reviewed-by: Ahmed Saidi --- src/gui/text/qtextengine.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'src/gui/text') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 7390b566e7..a95adc75de 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -3181,23 +3181,19 @@ int QTextEngine::lineNumberForTextPosition(int pos) void QTextEngine::insertionPointsForLine(int lineNum, QVector &insertionPoints) { QTextLineItemIterator iterator(this, lineNum); - bool rtl = isRightToLeft(); bool lastLine = lineNum >= lines.size() - 1; while (!iterator.atEnd()) { - iterator.next(); - const QScriptItem *si = &layoutData->items[iterator.item]; - if (si->analysis.bidiLevel % 2) { - int i = iterator.itemEnd - 1, min = iterator.itemStart; - if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) - i++; - for (; i >= min; i--) + const QScriptItem &si = iterator.next(); + + int end = iterator.itemEnd; + if (lastLine && iterator.item == iterator.lastItem) + ++end; // the last item in the last line -> insert eol position + if (si.analysis.bidiLevel % 2) { + for (int i = end - 1; i >= iterator.itemStart; --i) insertionPoints.push_back(i); } else { - int i = iterator.itemStart, max = iterator.itemEnd; - if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) - max++; - for (; i < max; i++) + for (int i = iterator.itemStart; i < end; ++i) insertionPoints.push_back(i); } } -- cgit v1.2.3 From 47056e78d3d963272e449e8f917ae3208b7aa940 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 4 Apr 2014 07:30:20 +0300 Subject: Optimize QTextEngine::insertionPointsForLine() a bit Reserve the insertionPoints vector capacity prior to multiple append()-s. Change-Id: I97ab5b2a1add9f2e87c04ad0707bf516c13ff4d7 Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/gui/text') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index a95adc75de..53fd37abba 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -3181,6 +3181,9 @@ int QTextEngine::lineNumberForTextPosition(int pos) void QTextEngine::insertionPointsForLine(int lineNum, QVector &insertionPoints) { QTextLineItemIterator iterator(this, lineNum); + + insertionPoints.reserve(iterator.line.length); + bool lastLine = lineNum >= lines.size() - 1; while (!iterator.atEnd()) { -- cgit v1.2.3 From 330f6e359897f77cf50f67141d09e94c371121ff Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 4 Apr 2014 07:31:24 +0300 Subject: QTextLayout: Fix cursor movement from invalid position Actually guarantee cursor doesn't move in this case for both logical and visual modes (just what the documentation says we already do ;) Change-Id: Iabdca7aa1d205672386a0095e3487e585611cdb5 Reviewed-by: Lars Knoll --- src/gui/text/qtextengine.cpp | 15 +++++++++------ src/gui/text/qtextlayout.cpp | 5 ++++- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/gui/text') diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 53fd37abba..35950c709b 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -3138,11 +3138,12 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end, int QTextEngine::previousLogicalPosition(int oldPos) const { const QCharAttributes *attrs = attributes(); - if (!attrs || oldPos < 0) + int len = block.isValid() ? block.length() - 1 + : layoutData->string.length(); + Q_ASSERT(len <= layoutData->string.length()); + if (!attrs || oldPos <= 0 || oldPos > len) return oldPos; - if (oldPos <= 0) - return 0; oldPos--; while (oldPos && !attrs[oldPos].graphemeBoundary) oldPos--; @@ -3224,8 +3225,7 @@ int QTextEngine::beginningOfLine(int lineNum) int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op) { - if (!layoutData) - itemize(); + itemize(); bool moveRight = (op == QTextCursor::Right); bool alignRight = isRightToLeft(); @@ -3233,7 +3233,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos); int lineNum = lineNumberForTextPosition(pos); - Q_ASSERT(lineNum >= 0); + if (lineNum < 0) + return pos; QVector insertionPoints; insertionPointsForLine(lineNum, insertionPoints); @@ -3256,6 +3257,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation if (lineNum > 0) return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1); } + + break; } return pos; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 0c9866c6cf..c3cf2e56bb 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -674,7 +674,10 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const { const QCharAttributes *attributes = d->attributes(); - if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length()) + int len = d->block.isValid() ? d->block.length() - 1 + : d->layoutData->string.length(); + Q_ASSERT(len <= d->layoutData->string.length()); + if (!attributes || oldPos <= 0 || oldPos > len) return oldPos; if (mode == SkipCharacters) { -- cgit v1.2.3 From 1a6011e09f6378e177426d5b1bb783419faea02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Johan=20S=C3=B8rvig?= Date: Fri, 21 Mar 2014 11:36:55 +0100 Subject: QTextImageHandler: Load @2x images on retina Look for and load "@2x" image versions. Adjust getPixmap/ImageSize to take the image devicePxielRatio into account. Use doc->documentLayout()->paintDevice() to get the target window devicePixelRatio (like the existing DPI-based scaling). In practice this pointer may/ will be null, fall back to qApp->devicePixelRatio as usual. Task-number: QTBUG-36383 Change-Id: Ib5e113b67242b5a9b3410272f2183a76a60bc773 Reviewed-by: Gabriel de Dietrich --- src/gui/text/qtextimagehandler.cpp | 42 +++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'src/gui/text') diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp index 9704f7a9dc..02a1091506 100644 --- a/src/gui/text/qtextimagehandler.cpp +++ b/src/gui/text/qtextimagehandler.cpp @@ -42,7 +42,7 @@ #include "qtextimagehandler_p.h" -#include +#include #include #include #include @@ -52,6 +52,21 @@ QT_BEGIN_NAMESPACE +static QString resolve2xFile(const QString &fileName, qreal targetDevicePixelRatio) +{ + if (targetDevicePixelRatio <= 1.0) + return fileName; + + int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); + if (dotIndex != -1) { + QString at2xfileName = fileName; + at2xfileName.insert(dotIndex, QStringLiteral("@2x")); + if (QFile::exists(at2xfileName)) + return at2xfileName; + } + return fileName; +} + static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format) { QPixmap pm; @@ -59,6 +74,8 @@ static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format) QString name = format.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); + QPaintDevice *pdev = doc->documentLayout()->paintDevice(); + name = resolve2xFile(name, pdev ? pdev->devicePixelRatio() : qApp->devicePixelRatio()); QUrl url = QUrl(name); const QVariant data = doc->resource(QTextDocument::ImageResource, url); if (data.type() == QVariant::Pixmap || data.type() == QVariant::Image) { @@ -85,6 +102,9 @@ static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format) doc->addResource(QTextDocument::ImageResource, url, pm); } + if (name.contains(QStringLiteral("@2x"))) + pm.setDevicePixelRatio(2.0); + return pm; } @@ -100,17 +120,20 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format) QSize size(width, height); if (!hasWidth || !hasHeight) { pm = getPixmap(doc, format); + const int pmWidth = pm.width() / pm.devicePixelRatio(); + const int pmHeight = pm.height() / pm.devicePixelRatio(); + if (!hasWidth) { if (!hasHeight) - size.setWidth(pm.width()); + size.setWidth(pmWidth); else - size.setWidth(qRound(height * (pm.width() / (qreal) pm.height()))); + size.setWidth(qRound(height * (pmWidth / (qreal) pmHeight))); } if (!hasHeight) { if (!hasWidth) - size.setHeight(pm.height()); + size.setHeight(pmHeight); else - size.setHeight(qRound(width * (pm.height() / (qreal) pm.width()))); + size.setHeight(qRound(width * (pmHeight / (qreal) pmWidth))); } } @@ -134,6 +157,8 @@ static QImage getImage(QTextDocument *doc, const QTextImageFormat &format) QString name = format.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); + QPaintDevice *pdev = doc->documentLayout()->paintDevice(); + name = resolve2xFile(name, pdev ? pdev->devicePixelRatio() : qApp->devicePixelRatio()); QUrl url = QUrl(name); const QVariant data = doc->resource(QTextDocument::ImageResource, url); if (data.type() == QVariant::Image) { @@ -159,6 +184,9 @@ static QImage getImage(QTextDocument *doc, const QTextImageFormat &format) doc->addResource(QTextDocument::ImageResource, url, image); } + if (name.contains(QStringLiteral("@2x"))) + image.setDevicePixelRatio(2.0); + return image; } @@ -175,9 +203,9 @@ static QSize getImageSize(QTextDocument *doc, const QTextImageFormat &format) if (!hasWidth || !hasHeight) { image = getImage(doc, format); if (!hasWidth) - size.setWidth(image.width()); + size.setWidth(image.width() / image.devicePixelRatio()); if (!hasHeight) - size.setHeight(image.height()); + size.setHeight(image.height() / image.devicePixelRatio()); } qreal scale = 1.0; -- cgit v1.2.3