From 17934bcc900b8fb280178a7edef065d586ad011b Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 20 Jan 2024 17:16:42 +0000 Subject: [PATCH] Fix #11827: Make Layouter::GetCharPosition() aware of ligatures. (#11831) When ligatures happen the precise individual character position is not known, so instead return the previous position (which is that of the ligature.) (cherry picked from commit d6ccfdbbd9daa6e42a9cbe927a2a6d607ffe1909) --- src/gfx_layout.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 1d662d7b77..392df70515 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -248,9 +248,11 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const } /* We couldn't find the code point index. */ - if (str != ch) { - return { 0, 0 }; - } + if (str != ch) return {0, 0}; + + /* Initial position, returned if character not found. */ + static const Point zero = {0, 0}; + const Point *position = &zero; /* Valid character. */ @@ -260,16 +262,24 @@ Point Layouter::GetCharPosition(std::string_view::const_iterator ch) const const auto &positions = run.GetPositions(); const auto &charmap = run.GetGlyphToCharMap(); - for (int i = 0; i < run.GetGlyphCount(); i++) { - /* Matching glyph? Return position. */ - if ((size_t)charmap[i] == index) { - return positions[i]; - } + /* Run starts after our character, use the last found position. */ + if ((size_t)charmap.front() > index) return *position; + + position = positions.data(); + for (auto it = charmap.begin(); it != charmap.end(); /* nothing */) { + /* Plain honest-to-$deity match. */ + if ((size_t)*it == index) return *position; + ++it; + if (it == charmap.end()) break; + + /* We just passed our character, it's probably a ligature, use the last found position. */ + if ((size_t)*it > index) return *position; + ++position; } } - /* Code point index not found, just give up */ - return { 0, 0 }; + /* At the end of the run but still didn't find our character so probably a trailing ligature, use the last found position. */ + return *position; } /**