OberonCore
https://forum.oberoncore.ru/

недочёт в TextViews — "несимметричное" кэширование
https://forum.oberoncore.ru/viewtopic.php?f=134&t=6936
Страница 1 из 1

Автор:  arisu [ Среда, 10 Май, 2023 11:28 ]
Заголовок сообщения:  недочёт в TextViews — "несимметричное" кэширование

нашёл некоторый… скажем так, недочёт в TextViews. как мы знаем, оригинальный виндовый BBCB в принципе забивает большой и толстый на кернинг. лин-версия использует панго (или, в случае LC, свою рисовалку на основе FreeType), и кернинг уважает. это почти работает, за одним интересным исключением.

штука такая, что TextSetters.Reader разбивает текст не только по кусочкам с разными атрибутами, но и на некоторых специальных символах типа переноса и минуса. он это делает для реализации wrapping. также максимальный размер возвращаемого кусочка — 64. и вот тут возникает противоречие между `TextViews.DrawLine()` и `TextViews.GetThisLocation()`. `DrawLine()` кэширует строки кусками по 128, и вдобавок не разбивает их по границам спецсимволов. а `GetThisLocation()` такого не делает. из-за этого в некоторых случаях вычисленая позиция каретки может не соответствовать реальной позиции глифа на экране.

то есть: `GetThisLocation()` двигается ровно по кусочкам, возвращённым Reader, через `StringWidth()`. а теперь представим такой случай: знак минуса имеет ненулевой кернинг с некоторыми буквами (так, например, в вердане: "A-" — тут минус смещают немного влево. `DrawLine()` накопит строку "A-" и нарисует минус с правильным кернингом. а `GetThisLocation()` вычислит сумму длин строк "A" и "-" отдельно, и каретка уедет немного дальше вправо, чем надо.

такая штука очень малозаметна, но тем не менее она существует. если в строке накопится много минусов с кернингом — каретка довольно заметно визуально сместится.

вариантов решения я тут вижу два: или учить `GetThisLocation()` кэшировать текст точно так же, как делает `DrawLine()`, или выкинуть из `DrawLine()` кэширование совсем. второй вариант мне кажется более правильным: просто отключить кэширование в `DrawLine()`. техника сейчас достаточно быстрая, чтобы не имело смысла собирать там кусочки (тем более что частично кусочки уже собирает Reader).

Код:
      PROCEDURE CacheString (x, y: INTEGER; c: INTEGER; IN s: ARRAY OF CHAR; f: Fonts.Font);
      VAR i, j, len: INTEGER;
      BEGIN
         len := LEN(s$);
         IF FALSE THEN (* old code, unused *)
            IF (cache.len + len >= cacheLen) OR (cache.y # y) OR
               (cache.color # c) OR (cache.font # f)
            THEN
               FlushCaches
            END;
            ASSERT(cache.len + len < cacheLen, 100);
            IF cache.len = 0 THEN
               cache.x := x; cache.y := y;
               cache.color := c; cache.font := f
            END;
            i := 0; j := cache.len;
            WHILE i < len DO cache.buf[j] := s[i]; INC(i); INC(j) END;
            cache.len := j
         ELSE
            FlushCaches;
            ASSERT(cache.len = 0);
            cache.x := x; cache.y := y;
            cache.color := c; cache.font := f;
            cache.buf := s$; cache.len := len
         END
      END CacheString;

старый код не удаляем — пусть будет, мало ли. просто вместо этого не склеиваем строки, даже если возможно. это не ломает никакой логики, и решает все потенциальные проблемы с кернингом.

в LC я просто удалил всю логику кэширования из `DrawLine()`. реально она почти ничего не ускоряет, только зря усложняет код.

Автор:  Иван Денисов [ Среда, 10 Май, 2023 11:48 ]
Заголовок сообщения:  Re: BlackBox 2.0

Что-то не получается пока воспроизвести проблему с А-

Вложения:
Aaaa.png
Aaaa.png [ 7.69 КБ | Просмотров: 1117 ]

Автор:  arisu [ Среда, 10 Май, 2023 13:00 ]
Заголовок сообщения:  Re: BlackBox 2.0

это сильно зависит от конкретных шрифтов и шрифтового движка. pango, например, делает кернинг несколько не так, как FreeType (там реально для одного и того же шрифта по какой-то причине отличаются то ли значения кернинга, то ли кернинговые пары). я и налетел на это, когда перешёл с панги на фритайп, и долго искал ошибку в своей реализации HostFonts, хех.

тут сложно конкретно показать воспроизводимость бага, но он есть. я потому и привёл такое длинное описание, чтобы можно было вывести существование бага чисто логическим путём.

в большинстве случаев бага не будет, я тоже его замечал только на конкретных кернинговых парах же. а вот когда я стал писать регулярки типа `[A-F]` — оно полезло.

p.s.: панго, кстати, похоже, не делает кернинг минуса с 'A'. там вообще внизу harfbuzz, а он почти все метрики шрифта обрабатывает сам, минуя фритайп. но где-то кернинг будет — и ой.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/