From 3b9f2025392716a51a49d9c89fc7cd68ac0c782a Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 28 Oct 2024 13:28:00 +0100 Subject: [PATCH] Freetype: Fix artificial oblique combined with other transforms When applying an "obliquen" transformation with Freetype, this applies a 12 degree horizontal shear on the control points of the glyph you have loaded. However, any other transformation we set on the glyph will be applied when loading it. So if you have e.g. a rotation on the glyph as well, then this will be applied first and the rotated glyph would be obliquened instead, now along the wrong arbitrary axis in the rotated coordinate system. To fix this, we detect the case where a transform is applied and multiply in the obliquen in advance. It means we have to duplicate some code from FT_GlyphSlot_Oblique() which might get out of sync (if the slant angle changes in a newer version for instance). We limit this to the cases that are currently broken so that we avoid messing with any working use cases. [ChangeLog][Text] Fixed an issue where artificially obliquened text would look incorrect when other transformations were also applied and the Freetype backend was in use. Pick-to: 6.5 Fixes: QTBUG-97436 Change-Id: I61c5d007e9ea9be2beb283a8b8abbed7723bab38 Reviewed-by: Allan Sandfeld Jensen (cherry picked from commit db8230715aa115dc2da5177bb1824fb40c5f2569) Reviewed-by: Qt Cherry-pick Bot --- src/gui/text/freetype/qfontengine_ft.cpp | 24 +++++++++++++++++------ tests/baseline/text/tst_baseline_text.cpp | 24 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp index d3791f1f6e7..50c52ef3705 100644 --- a/src/gui/text/freetype/qfontengine_ft.cpp +++ b/src/gui/text/freetype/qfontengine_ft.cpp @@ -1120,6 +1120,23 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, FT_Face face = freetype->face; FT_Matrix matrix = freetype->matrix; + bool transform = matrix.xx != 0x10000 + || matrix.yy != 0x10000 + || matrix.xy != 0 + || matrix.yx != 0; + if (obliquen && transform) { + // We have to apply the obliquen transformation before any + // other transforms. This means we need to duplicate Freetype's + // obliquen matrix here and this has to be kept in sync. + FT_Matrix slant; + slant.xx = 0x10000L; + slant.yx = 0; + slant.xy = 0x0366A; + slant.yy = 0x10000L; + + FT_Matrix_Multiply(&matrix, &slant); + matrix = slant; + } FT_Vector v; v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.x.value()); @@ -1130,11 +1147,6 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, int vfactor = 1; int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); - bool transform = matrix.xx != 0x10000 - || matrix.yy != 0x10000 - || matrix.xy != 0 - || matrix.yx != 0; - if (transform || obliquen || (format != Format_Mono && !isScalableBitmap())) load_flags |= FT_LOAD_NO_BITMAP; @@ -1166,7 +1178,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, if (embolden) FT_GlyphSlot_Embolden(slot); - if (obliquen) { + if (obliquen && !transform) { FT_GlyphSlot_Oblique(slot); // While Embolden alters the metrics of the slot, oblique does not, so we need diff --git a/tests/baseline/text/tst_baseline_text.cpp b/tests/baseline/text/tst_baseline_text.cpp index 45c709b92f5..fdb30cf7b6e 100644 --- a/tests/baseline/text/tst_baseline_text.cpp +++ b/tests/baseline/text/tst_baseline_text.cpp @@ -18,6 +18,7 @@ private slots: void tst_render_data(); void tst_render(); void tst_differentScriptsBackgrounds(); + void tst_synthesizedObliqueAndRotation(); private: QDir htmlDir; @@ -102,6 +103,29 @@ void tst_Text::tst_differentScriptsBackgrounds() QBASELINE_CHECK(image, "tst_differentScriptsBackgrounds"); } +void tst_Text::tst_synthesizedObliqueAndRotation() +{ + QFont font(QString::fromLatin1("Abyssinica SIL")); + font.setPixelSize(40); + font.setItalic(true); + + QImage image(800, 600, QImage::Format_ARGB32); + image.fill(Qt::white); + + { + QPainter painter(&image); + painter.setFont(font); + + painter.save(); + painter.translate(200, 450); + painter.rotate(270); + painter.drawText(0, 0, QString::fromLatin1("Foobar")); + painter.restore(); + } + + QBASELINE_CHECK(image, "tst_synthesizedObliqueAndRotation"); +} + QBASELINETEST_MAIN(tst_Text)