openjdk.ruOpenJDK на русском

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