2018年4月25日水曜日

Windows 10+高解像度ディスプレイでのアプリのボケはRS2で解消される

勉強の為に引用しました。
http://ascii.jp/elem/000/001/457/1457365/

2017年03月26日 10時00分更新
文● 塩田紳二 編集● ASCII.jp
 Windows 10のInsider Previewのインストールがずっとエラーになっていたので、その原因を探って、記事にしようとしていたのだが、何もせずとも、ある日エラーが解消されてインストールが成功してしまったため、記事にすることができなくなった。
 なので、予定を変更して、Windows 10 Creator's Update(RS2)に実装される高DPI動作について解説する。RS2では長らくWindowsユーザーが悩まされてきたデスクトップアプリケーション(GDIアプリケーション)の仮想DPIによる文字のボケが、ようやく解消される(詳細は次回)。
4Kなどの高解像度ディスプレイでWindows 10を利用すると、アプリ内の文字がボケることが多かった。デバイスマネージャーのようにWindows標準の機能でも該当し、納得が行かない人は多かったはず
RS2では文字の輪郭がはっきりとするようになった
拡大して見比べてみると、左のRS2での表示は文字はクッキリしているが、ビットマップは逆に粗くなっている(Bluetoothアイコンの周辺など)ことがわかる

高解像度ディスプレイを利用するWindowsユーザーが
長らく悩まされてきた文字のボケ

 Windowsが高いDPI値を持つ高解像度ディスプレイを扱う方法については、以前にも記事にしているのだが、それはWindows 8.1の頃の話。そこで今回はWindows 10でDPIスケーリングがどうなって、RS1まではどうだったかを解説し、その上で次回にRS2での変更点の話をする。
 「DPI」とは「Dot Per Inch」の略だが、Windowsのディスプレイ表示機能に関していう場合には、大文字で「DPIスケーリング」と表記する。画面上のドット密度の単位を示す場合には、小文字で「dpi」と使い分けている。
 WindowsではVistaより前は、96dpi(または120dpi)であることを前提に、フォントやグラフィックスの物理的なサイズを決めていて、アプリケーション側はdpi値がどうなっているのかを知る必要がなかった。ただし、マイクロソフトはダイアログボックスのサイズなどに関して一定のルールを設け、ウィンドウが画面をはみ出してボタンが押せなくなったりはしないようにしていた。
 一方でWindows自体は、物理的なディスプレイサイズと解像度から実際のdpi値を設定できる機能も持っていた。世の中には、さまざまな物理サイズ、解像度のディスプレイがあり、解像度と物理サイズの組合せによっては、96dpiを大きく離れるような組合せがふえ、1つのdpi値ではカバーできなくなってしまった。
 これが問題になるのは、ユーザーからみた場合のウィンドウやボタンなどの物理的な大きさがdpi値によって変動し、場合によっては操作が困難になることがあった。
 ところがVistaで、ようやくシステムに設定されているDPI値を得て動作できるアプリケーションを作る環境が整い、Windows 8.1では、モニタごとに異なるdpi値に対応できる仕組みが提供された。こうした機能をマイクロソフトは「DPIスケーリング」(高DPIスケーリング)などと呼んでいる。
 そしてWindows 10のリリース時点では、以下の3つのタイプのデスクトップアプリケーションが存在していた。
DPI unaware:DPIをまったく考慮していない(XP以前)
System DPI aware:起動時にシステムDPI値を取得して動作(Vista以降)
Per-Display DPI aware:ディスプレイごとのDPIに対応できる(Windows 8.1以降)
 このあたりについては、過去の記事にまとめてあるので、これらの記事をチェックしてほしい。
 なお、UWPに関しては、最初からDPI値に応じて表示を切り替える機能が組み込まれているため、DPIスケーリングに関する問題は発生しないようになっている。

Windows 10 RS1までのDPIスケーリング

 Windows 10のリリース時点では、DPIスケーリングで行われる「仮想DPI」により、デスクトップアプリケーションの文字表示が「ボケ」て表示されるという問題があった。
 これは、DPI unawareアプリケーションを適切なウィンドウサイズにするために機械的にウィンドウを拡大表示させていたからだ。またSystem DPI awareアプリケーションでも、ディスプレイの切り替えなどで、DPI値が変化し、仮想DPIが動作して文字がボケて表示されてしまうことがあった。これは、System DPI awareアプリケーションが動的なDPI値の変更には追従しないからだ。
 こうした問題の原因として、Per-Display DPI awareアプリケーション開発の困難さがある。ディスプレイごとに変化するdpi値に対応するにはアプリケーションを大規模に改良する必要があり、対応がなかなか進まなかった。
 しかし、dpi値の変化は、実際には、マルチディスプレイの利用時だけでなく、たとえば、モバイルPCのドッキングによる出力先の変更や、プロジェクタの接続などによっても引き起こされる。System DPI awareアプリケーションは、実行中のdpi値の変化に対応ができないために表示がボケてしまう。再実行すれば、正しく表示することが可能(起動時にdpi値を取得して動作するため)だが、いちいち終了して起動するのはユーザーにとって面倒な作業でしかない。
 このため、高解像度ディスプレイなどでは、多くのデスクトップアプリケーションがボケた表示になってしまう可能性が高かった。それでも利用頻度の低いアプリケーションならば我慢もできようが、メインに利用するアプリケーションでボケた表示のまま作業を続けるのはストレスがある。
 そこで、Windows 10 RS1では、アプリケーションをDPIスケーリングに対応しやすくするために以下の2つの機能が追加されたのだ。
●非クライアント領域(NCA)スケーリング
●DPIスケーリング混在モード
 まず「NCAスケーリング」は、アプリケーションが描画をするクライアント領域以外となる「非クライアント領域」のスケーリングをWindows側に自動で行なわせる機能。ただし、これを有効にするためには、アプリケーション自身がAPIを呼び出す必要がある。つまり、NCAスケーリングに対応したアプリケーションだけが使える機能で既存のWindowsアプリでそのまま有効になるわけではない。
 この話が面倒なのは、そもそもNCAと呼ばれる領域がアプリケーションごとに異なるからだ。現在のデスクトップアプリケーションは、タイトルバーを含め、すべての領域を自分で描画することができる。だからウィドウすべてをクライアントエリアにできる。
 しかし、タイトルバーやメニューバーなどは、自分で描画せずWindowsの処理に任せきりとすることも可能だ。そもそも、最初のWindows 2.x(1.0xはタイリングウィンドウ)では、タイトルバーなどに描画することは不可能だった。なぜなら、表示を高速化するため、ディスプレイドライバの中で描画していたからだ。そのため、タイトルバーやメニューバー、ウィンドウ周囲のボーダー領域などは、クライアント(=アプリケーション自身)が描画できないという意味で「非クライアント領域」と呼ばれていた。当時はアプリケーションはクライアント領域内しか描画することができなかった。
 しかし、ハードウェアの進歩により、描画速度が向上し、タイトルバーなど非クライアント領域の描画は、Windows自身が行なうようになり、これにも伴い非クライアント領域の制御が柔軟にできようになった。
 たとえばEdgeやChromeといったブラウザでは、タイトルバー部分の描画を自分で行っている。ただし、アプリケーションの作り方として、非クライアント領域の描画をWindowsにまかせたままにすることもできる。実際には後者のアプリケーションが大半を占める。
 Windows 8.1で導入されたPer-Display DPI awareの問題点の1つは、dpi値が変化したときに非クライアント領域は再描画されず、そのままになっていたことがある。アプリ側としてはdpi値の変化は問題ないと判断しても、タイトルバーなどの文字がぼけていたり、あるいは不適切なサイズになっている可能性があった。これを解消するには、ウィンドウ全体を再描画させる必要がある。
 RS1で導入されたNCAスケーリングは、dpi値が変化したときに非クライアント領域をWindows自身が再描画して適切なスケーリングをする機能だ。ただし、非クライアント領域でも自分自身で描画しているアプリケーションもあるため、RS1で追加されたEnableNonClientDpiScalingというAPIを呼び出し、非クライアント領域をWindowsが再描画できるようにすることを通知する必要がある。
 つまり、アプリケーションを改良してこのAPIを呼び出すようにしないと、その挙動はRS1以前のWindows 10のときと同じになってしまう。RS1ではDPIスケーリング機能が改良されていたものの、ユーザーとして体感できなかったのは、アプリケーション側の対応が必要な機能だっだからだ。

0 コメント:

コメントを投稿