JEP 263: HiDPI Graphics on Windows and Linux
Графика HiDPI в Windows и Linux
| Автор | Alexander Scherbatiy |
| Ответственный | Alexandr Scherbatiy |
| Тип | Feature |
| Область | JDK |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Компонент | client-libs / java.awt |
| Обсуждение | 2d dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | M |
| Рецензенты | Jim Graham, Kevin Rushforth, Sergey Bylokhov |
| Одобрен | Kevin Rushforth |
| Создан | 2014/08/15 14:43 |
| Обновлён | 2017/02/23 16:42 |
| Задача | 8055212 |
Аннотация
Реализовать поддержку графики HiDPI в Windows и Linux.
Мотивация
У разработчиков и пользователей есть несколько базовых ожиданий от приложений, работающих на дисплеях HiDPI:
-
окна и компоненты GUI должны иметь подходящий размер в соответствии с рекомендациями платформы;
-
текст должен оставаться чётким, несмотря на масштабирование по умолчанию, заданное настройками HiDPI;
-
значки и изображения должны быть сглаженными и желательно иметь детализацию, соответствующую плотности пикселей дисплея.
К сожалению, в Windows и Linux размеры Java-приложений по-прежнему задаются, а сами приложения отрисовываются в пикселях, даже на дисплеях HiDPI, плотность пикселей которых может быть в 2–3 раза выше, чем у обычных дисплеев. Из-за этого компоненты GUI и окна оказываются в 2–3 раза меньше нужного, то есть слишком мелкими, чтобы их можно было прочитать или нормально с ними взаимодействовать.
JDK уже поддерживает дисплеи HiDPI «retina» в Mac OS X и выводит чёткий текст и изображения в размерах, соответствующих плотности дисплея. Поддержка «retina» на Mac уже заложила немалую часть основы для поддержки дисплеев HiDPI на всех платформах, но на разных платформах приложения должны обрабатывать HiDPI по-разному, поэтому, чтобы обобщить сделанное для Mac, нужна дополнительная работа.
Теперь такое же автоматическое масштабирование и подбор размеров нужно обеспечить на платформах Windows и Linux.
Описание
HiDPI в Windows
Уже на протяжении нескольких выпусков (в разных формах ещё со времён Windows XP) панель управления Windows позволяет пользователям разными способами запросить масштабирование компонентов и окон на рабочем столе. В некоторых версиях ОС также есть средства автоматического масштабирования приложений, не объявленных как «DPI-aware» (учитывающие DPI). Масштабирование по умолчанию для приложений, «не учитывающих DPI», может вызывать ряд визуальных артефактов, в том числе размытые окна, неточную компоновку и обрезанный текст, поэтому среда выполнения Java уже некоторое время объявляет себя «DPI-aware», чтобы избежать размытости и проблем с компоновкой. Однако поддержка масштабирования содержимого в соответствии с DPI была непростой задачей, а поскольку для большинства значений плотности дисплеев требовалось масштабирование всего на 25 %, было решено просто игнорировать рекомендуемые правила и политики масштабирования, продолжать отрисовывать компоненты AWT и Swing в масштабе пикселей 1:1 и оставить приложения JDK немного меньше нормы, но с чётким текстом и графикой.
Однако в последнее время плотность пикселей дисплеев резко выросла, и теперь легко найти ноутбуки с экранами, плотность которых в 2–3 раза выше, чем у дисплеев, распространённых в то время, когда принимались эти решения. В результате Java-приложения на таких новых машинах с Windows иногда оказываются настолько мелкими, что ими невозможно пользоваться — речь уже не идёт о выборе «чуть меньше или размытые окна», поэтому нам нужно правильно масштабировать окна приложений.
API Windows предоставляют метрики, механизмы и рекомендации для написания приложений, учитывающих DPI, чтобы UI выглядел единообразно при самых разных настройках DPI дисплея и учитывал предпочтения пользователей, делая UI достаточно крупным, чтобы с его компонентами было удобно взаимодействовать.
Графический API Windows Direct2D автоматически учитывает системное значение DPI, выражает координаты в DIP (аппаратно-независимых пикселях), позволяет задавать DPI для растровых изображений и правильно масштабирует их с учётом DPI. Однако библиотеки AWT и Swing не основаны на графическом API Direct2D.
Windows 7 и более поздние выпуски предоставляют ряд способов получить горизонтальное и вертикальное значения DPI рабочего стола, в том числе метод GetDesktopDpi, а начиная с Windows 8.1 — метод GetDpiForMonitor и сообщения WM_DPICHANGED. Эти значения можно использовать для масштабирования размеров окон, координат мыши и шрифтов при поддержке HiDPI в библиотеках AWT/Swing. Необходимая поддержка масштабирования уже есть в слое отрисовки Java2D, но нам нужно передать эти значения в Swing и AWT и доработать их компоненты, чтобы они распознавали и учитывали коэффициент масштабирования. В рамках этой поддержки нужно убедиться, что нужный коэффициент масштабирования отрисовки передаётся объекту Java2D Graphics, что промежуточные изображения отрисовываются с коэффициентом масштабирования, подходящим для целевой поверхности, а также пересмотреть все допущения о том, как координаты в вызовах отрисовки соотносятся с пикселями.
HiDPI в Linux
Поддержка HiDPI реализована в библиотеках GTK+ 3. Библиотека GTK автоматически масштабирует приложения на стороне клиента, когда используется дисплей HiDPI.
Java2D и AWT используют библиотеку XLib, которая не поддерживает HiDPI. В результате нынешние Java-приложения на дисплеях HiDPI в Linux могут выглядеть в 2–3 раза меньше нужного.
Кроме того, любые Java-приложения, использующие стиль оформления GTK look&feel, могут автоматически получать выгоду от поддержки HiDPI в библиотеке GTK, при этом размер окна и других компонентов может соответствовать компонентам GTK, увеличенным в 2–3 раза для выполнения требований HiDPI. Это может приводить к проблемам, подобным описанным в JDK-8058742.
Альтернативы
Разработчик мог бы вручную масштабировать все элементы GUI в приложении при работе на дисплее HiDPI, но это требует большого объёма рефакторинга приложения, а компоненты Swing и AWT не рассчитаны на корректную работу при попытках масштабировать их извне.
Тестирование
Следующее тестирование нужно проводить на дисплеях HiDPI. Желательно использовать разные масштабы экрана — хорошей минимальной матрицей поддержки были бы 192 DPI и 144 DPI. Обратите внимание, что для дисплея с очень высоким DPI с помощью панели управления Windows можно искусственно задать более низкое значение DPI, поэтому дополнительные системы не обязательно нужны, но тогда их придётся перенастраивать между прогонами тестов. Кроме того, после изменения DPI в Windows обычно требуется перезагрузка, чтобы новое значение DPI стало доступно приложениям.
В Windows настройки DPI задаются в панели управления. В Windows 7, Windows 8.1 и более старых версиях Windows панель управления и допустимые настройки различаются, но все они, как правило, приводят к тому, что приложению передаётся один и тот же тип информации (указанное значение DPI по X и Y), поэтому в настоящее время дополнительное тестирование с разными вариантами панели управления не требуется — это лишь деталь, влияющая на настройку тестовых окружений.
В Linux настройки DPI можно эмулировать с помощью переменной окружения GDK_SCALE для GTK+ 3 или настройки scaling-factor для GNOME 3.
Нужно проверить следующее:
- Текст не должен быть размытым
- Текст в компонентах (метках и кнопках) не должен обрезаться
- Компоновка компонентов UI в AWT/Swing должна оставаться осмысленной (т. е. без наложений и странных промежутков)
- В диалогах и компонентах AWT/Swing должны использоваться значки высокого разрешения, если их предоставляет приложение или тестовый сценарий
- Приложение должно правильно обрабатывать события мыши
- Размер приложений должен быть примерно таким же, как у корректно написанных нативных приложений, учитывающих DPI