ВозможностиЦеныДокументацияБлог
Получить mote
← Блог
Разработка·2 июля 2026 г.·4 мин чтения

Почему мы доверили отрисовку текста платформе, а не стали рисовать его сами

Случалось ли вам замечать, что хангыль выглядит нормально, а иероглифы — как-то непривычно? Если не рисовать символы самостоятельно, а поручить это текстовому движку платформы, наша задача превращается из «что нарисовать» в «какой шрифт запросить».

m
mote
Сравнение одной и той же строки, отрисованной с помощью корейского и японского подмножеств Noto Sans CJK. Хангыль выглядит одинаково, но начертания некоторых иероглифов, например 骨 и 直, различаются.
Сравнение одной и той же строки, отрисованной с помощью корейского и японского подмножеств Noto Sans CJK. Хангыль выглядит одинаково, но начертания некоторых иероглифов, например 骨 и 直, различаются.

Чтобы текст появился на экране, необходимо выполнить множество операций. Нужно преобразовать символы в формы, разбить текст на строки и отрисовать его в пикселях. Приходится обрабатывать всё: от составления слогов хангыля до иероглифов, эмодзи, арабского письма и подстановки шрифтов.

Мы не стали создавать этот процесс заново. Мы поручили его Pango и HarfBuzz в Linux, DirectWrite в Windows и TextKit 2 в macOS.

Потому что операционные системы совершенствовали эту область на протяжении долгого времени. Если бы мы сделали всё сами, качество, скорее всего, оказалось бы хуже именно в таких сложных аспектах, как символы CJK и специальные возможности. Кроме того, мы считали, что отличие нашего продукта заключается не в самом рендерере, а в типографике и ощущении естественной работы на каждой платформе.

Зато мы сами решили, когда создавать макеты

Создание текстового макета требует времени и памяти. В больших документах могут быть десятки тысяч строк, поэтому создать макеты для всех сразу было невозможно.

Поэтому мы создаём их только для видимых на экране строк и строк рядом с ними. А макеты строк, удалившихся от экрана, сразу удаляем. Даже после долгой прокрутки документа размером 1 МБ активными остаются лишь около сорока–шестидесяти макетов.

Высоту ещё не созданных строк мы заранее оцениваем. Ведь полоса прокрутки должна знать полную длину документа.

Конечно, иногда оценка оказывается неверной. Если заново вычисленная высота отличается от ожидаемой, содержимое экрана может сместиться. В таком случае мы в том же кадре корректируем позицию прокрутки на величину разницы. Для пользователя всё должно выглядеть так, будто ничего не произошло.

Строку, в которой составляется хангыль, мы отображаем без оформления. Иначе, если во время ввода появятся такие свойства, как жирное начертание или скрытие, количество символов, известное редактору метода ввода, может отличаться от количества символов на экране.

Первой проблемой, с которой мы столкнулись, оказался облик иероглифов

Если поручить работу платформе, вместе с ней приходят и её значения по умолчанию.

В стандартном шрифте интерфейса Ubuntu нет хангыля. Поэтому система выбрала вместо него Noto Sans CJK JP. Хангыль отображался хорошо, но некоторые иероглифы имели японские начертания. Причина в том, что один и тот же символ Юникода в Корее и Японии может выглядеть по-разному.

Решение было простым. Мы поставили Noto Sans CJK KR первым в списке шрифтов интерфейса.

Но гораздо важнее было другое. Если мы сами не задаём правила, платформа отвечает, исходя не из языка пользователя, а из собственных значений по умолчанию.

Мы создаём подходящие для разных языков начертания с помощью порядка шрифтов

В стеке шрифтов символы ищутся начиная с первого шрифта. К следующему шрифту переходят только для символов, которых нет в первом.

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

Если поле шрифта для чтения оставить пустым, будет использоваться основной шрифт текста. Если указать его отдельно, он изменится только в режиме чтения. В режиме исходного текста используется шрифт для кода.

Размер символов следует настройкам специальных возможностей операционной системы. Пользователю, увеличившему текст в системе, не нужно повторно настраивать его в каждом приложении.

Вкладка оформления на карточке настроек — в поле шрифта без изменений указан стек, разделённый запятыми, а поле шрифта для чтения пусто, поэтому в нём бледным текстом написано «Как в основном тексте».
Вкладка оформления на карточке настроек — в поле шрифта без изменений указан стек, разделённый запятыми, а поле шрифта для чтения пусто, поэтому в нём бледным текстом написано «Как в основном тексте».

Программа экранного доступа использует ту же основу. Поскольку специальные возможности уже подключены к текстовому слою платформы, нам достаточно точно передать содержимое запрошенной строки.

Если перевод отсутствует, сборка завершается с ошибкой

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

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

Поэтому мы создали проверочный скрипт. Он собирает фразы, которые действительно используются в коде, и сравнивает их с таблицами переводов на 12 языков. Если добавить фразу только для одного языка или забыть перевод, сборка завершается с ошибкой.

В каждой таблице переводов содержится 304 ключа, а в коде фактически используется 282 фразы. Поддерживаемые языки: English, 한국어, 日本語, 简体中文, 繁體中文, Deutsch, Français, Español, Português (Brasil), Русский, Italiano, Polski.

Вкладка общих настроек — в самой верхней строке находится раскрывающийся список языков, в котором выбран корейский, поэтому названия всех расположенных ниже параметров также написаны по-корейски.
Вкладка общих настроек — в самой верхней строке находится раскрывающийся список языков, в котором выбран корейский, поэтому названия всех расположенных ниже параметров также написаны по-корейски.

При смене языка мы открываем новое окно с тем же документом и закрываем прежнее. Если переводить по отдельности сотни уже отображаемых виджетов, велика вероятность что-нибудь пропустить. Мы решили, что безопаснее один раз заново открыть окно в момент смены языка, чем поддерживать сложный путь, который используется крайне редко.

Если поручить работу платформе, результат тоже будет похож на платформу

Даже один и тот же документ не будет выглядеть совершенно одинаково на уровне пикселей в разных операционных системах. Причина в различиях способов сглаживания символов и стандартных шрифтов.

Мы не пытаемся насильно сделать их одинаковыми. Вместо этого мы сохраняем едиными основы документа: пропорции размеров символов, высоту строк и отступы.

Результат подстановки также может различаться в зависимости от установленных шрифтов. Поэтому вместо обещания конкретного результата мы прозрачно показываем порядок, в котором запрашиваются шрифты. Пользователь также может изменить его самостоятельно.

Если мы не рисуем всё сами, это не означает, что с нас снимается ответственность. Нам приходится ещё точнее решать, что именно поручить платформе и в каком порядке отправлять запросы.

← РанееПочему мы построили приложение на едином ядре Rust с отдельными оболочками для каждой платформыПозже →Почему набор текста не замедляется даже в длинных документах
Следите за новостями через RSS.
Оставьте только текст
Русский
© 2026 mote