I've been working on adding support for HiDPI screens. Part of it has
landed in wayland already, some is work-in-progress in Gtk+. Generally
how this work is that on very high resolution monitors we "scale" the UI
so that code works in the old "low dpi" pixels, but we then render it
with a scaling factor.

For icons we can't just scale as that would not look very nice, so
instead we need to supply alternative higher resolution data. Things
kind of work already, like you can pick 96x96 icons when rendering 48x48
icons at scale 2. However, in many cases the larger icons have a lot
more detail that don't really look very well when rendering at the
higher scale. For instance some sort icons have text in them which is
very hard to read, or borders become really thin.

So, attached to the mail is a patch to the icon theme spec that adds a
"Scale" property to the icon directories. With this one could have icons
for size "48" in both scale 1 and 2.


>From c321e1d3eb3c1f7b0ecc3b10af7976902a73b901 Mon Sep 17 00:00:00 2001
From: Alexander Larsson <[email protected]>
Date: Tue, 2 Jul 2013 15:20:48 +0200
Subject: [PATCH] icon-theme-spec: Add icon scale support

This adds support for "pre-scaled" icons aimed at higher resolution displays.
For instance, an icon at scale 2 and size 48 (48@2x) would have the
same kind of detail as a 48@1x icon, but a pixel size of 96x96. A
a 96@1x icon would also be 96x96 but would have more details that would
be hard to see on a high resolution screen.
---
 spec/icon-theme-spec.xml | 122 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 87 insertions(+), 35 deletions(-)

diff --git a/spec/icon-theme-spec.xml b/spec/icon-theme-spec.xml
index 622352d..78ffc74 100644
--- a/spec/icon-theme-spec.xml
+++ b/spec/icon-theme-spec.xml
@@ -5,8 +5,8 @@
 <article id="index">
   <articleinfo>
     <title>Icon Theme Specification</title>
-    <releaseinfo>Version 0.11</releaseinfo>
-    <date>February 7 2006</date>
+    <releaseinfo>Version 0.13</releaseinfo>
+    <date>July 2 2013</date>
     <authorgroup>
       <author>
 	<firstname>Alexander</firstname>
@@ -82,6 +82,21 @@
 	  </para>
 	</listitem>
       </varlistentry>
+      <varlistentry>
+	<term>Icon scale</term>
+	<listitem>
+	  <para>
+          Icons can have a target scale, describing what scale factor
+          they are designed for. For instance, an icon with a
+          directory size of 48 but scale 2 would be 96x96 pixels, but
+          designed to have the same level of detail as a 48x48 icon at
+          scale 1. This is useful on very high resolution displays
+          where a 48x48 icon would be too small (or ugly upscaled) and
+          a normal 96x96 icon would have a lot of detail that would
+          not be visible on the high resolution monitor.
+	  </para>
+	</listitem>
+      </varlistentry>
     </variablelist>
   </sect1>
 
@@ -126,7 +141,7 @@
     <para>
     In the theme directory are also a set of subdirectories containing
     image files. Each directory contains icons designed for a certain
-    nominal icon size, as described by the index.theme file. The
+    nominal icon size and scale, as described by the index.theme file. The
     subdirectories are allowed to be several levels deep, e.g. the
     subdirectory "48x48/apps" in the theme "hicolor" would end up at
     $basedir/hicolor/48x48/apps.
@@ -256,12 +271,21 @@
 	  <row>
 	    <entry>Size</entry>
 	    <entry>
-              Nominal size of the icons in this directory.
+              Nominal (unscaled) size of the icons in this directory.
 	    </entry>
 	    <entry>integer</entry>
 	    <entry>YES</entry>
 	  </row>
 	  <row>
+	    <entry>Scale</entry>
+	    <entry>
+              Target scale of of the icons in this
+              directory. Defaults to the value 1 if not present.
+	    </entry>
+	    <entry>integer</entry>
+	    <entry>NO</entry>
+	  </row>
+	  <row>
 	    <entry>Context</entry>
 	    <entry>
               The context the icon is normally used in. This 
@@ -285,7 +309,7 @@
 	  <row>
 	    <entry>MaxSize</entry>
 	    <entry>
-              Specifies the maximum size that the icons in this
+              Specifies the maximum (unscaled) size that the icons in this
               directory can be scaled to. Defaults to the value
               of Size if not present.
 	    </entry>
@@ -296,7 +320,7 @@
 	  <row>
 	    <entry>MinSize</entry>
 	    <entry>
-              Specifies the minimum size that the icons in this
+              Specifies the minimum (unscaled) size that the icons in this
               directory can be scaled to. Defaults to the value
               of Size if not present.
 	    </entry>
@@ -308,7 +332,7 @@
 	    <entry>Threshold</entry>
 	    <entry>
               The icons in this directory can be used if the size differ
-              at most this much from the desired size. Defaults to 2 if not
+              at most this much from the desired (unscaled) size. Defaults to 2 if not
               present.
 	    </entry>
 	    <entry>integer</entry>
@@ -447,7 +471,7 @@
     The icon lookup mechanism has two global settings, the list of
     base directories and the internal name of the current theme. Given
     these we need to specify how to look up an icon file from the icon
-    name and the nominal size.
+    name, the nominal size and the scale.
     </para>
     <para>
     The lookup is done first in the current theme, and then
@@ -473,19 +497,19 @@
     The exact algorithm (in pseudocode) for looking up an icon in a theme
     (if the implementation supports SVG) is:
     <programlisting>
-FindIcon(icon, size) {
-  filename = FindIconHelper(icon, size, user selected theme);
+FindIcon(icon, size, scale) {
+  filename = FindIconHelper(icon, size, scale, user selected theme);
   if filename != none
     return filename
 
-  filename = FindIconHelper(icon, size, "hicolor");
+  filename = FindIconHelper(icon, size, scale, "hicolor");
   if filename != none
     return filename
 
   return LookupFallbackIcon (icon)
 }
-FindIconHelper(icon, size, theme) {
-  filename = LookupIcon (icon, size, theme)
+FindIconHelper(icon, size, scale, theme) {
+  filename = LookupIcon (icon, size, scale, theme)
   if filename != none
     return filename
 
@@ -493,7 +517,7 @@ FindIconHelper(icon, size, theme) {
     parents = theme.parents
 
   for parent in parents {
-    filename = FindIconHelper (icon, size, parent)
+    filename = FindIconHelper (icon, size, scale, parent)
     if filename != none
       return filename
   }
@@ -502,11 +526,11 @@ FindIconHelper(icon, size, theme) {
      </programlisting>
      With the following helper functions:
      <programlisting>
-LookupIcon (iconname, size, theme) {
+LookupIcon (iconname, size, scale, theme) {
   for each subdir in $(theme subdir list) {
     for each directory in $(basename list) {
       for extension in ("png", "svg", "xpm") {
-        if DirectoryMatchesSize(subdir, size) {
+        if DirectoryMatchesSize(subdir, size, scale) {
           filename = directory/$(themename)/subdir/iconname.extension
           if exist filename
 	    return filename
@@ -519,9 +543,9 @@ LookupIcon (iconname, size, theme) {
     for each directory in $(basename list) {
       for extension in ("png", "svg", "xpm") {
         filename = directory/$(themename)/subdir/iconname.extension
-        if exist filename and DirectorySizeDistance(subdir, size) &lt; minimal_size {
+        if exist filename and DirectorySizeDistance(subdir, size, scale) &lt; minimal_size {
 	   closest_filename = filename
-	   minimal_size = DirectorySizeDistance(subdir, size)
+	   minimal_size = DirectorySizeDistance(subdir, size, scale)
         }
       }
     }
@@ -541,8 +565,10 @@ LookupFallbackIcon (iconname) {
   return none
 }
 
-DirectoryMatchesSize(subdir, iconsize) {
+DirectoryMatchesSize(subdir, iconsize, iconscale) {
   read Type and size data from subdir
+  if Scale != iconscale
+     return False;
   if Type is Fixed
     return Size == iconsize
   if Type is Scaled
@@ -551,21 +577,21 @@ DirectoryMatchesSize(subdir, iconsize) {
     return Size - Threshold &lt;= iconsize &lt;= Size + Threshold
 }
 
-DirectorySizeDistance(subdir, size) {
+DirectorySizeDistance(subdir, iconsize, iconscale) {
   read Type and size data from subdir
   if Type is Fixed
-    return abs(Size - iconsize)
+    return abs(Size*Scale - iconsize*iconscale)
   if Type is Scaled
-    if iconsize &lt; MinSize
-        return MinSize - iconsize
-    if iconsize &gt; MaxSize
-        return iconsize - MaxSize
+    if iconsize*iconscale &lt; MinSize*Scale
+        return MinSize*Scale - iconsize*iconscale
+    if iconsize*iconscale &gt; MaxSize*Scale
+        return iconsize*iconscale - MaxSize*Scale
     return 0
   if Type is Threshold
-    if iconsize &lt; Size - Threshold
-        return MinSize - iconsize
-    if iconsize &gt; Size + Threshold
-        return iconsize - MaxSize
+    if iconsize*iconscale &lt; (Size - Threshold)*Scale
+        return MinSize*Scale - iconsize*iconscale
+    if iconsize*iconsize &gt; (Size + Threshold)*Scale
+        return iconsize*iconsize - MaxSize*Scale
     return 0
 }
 </programlisting>
@@ -578,12 +604,12 @@ DirectorySizeDistance(subdir, size) {
     function that finds the first of a list of icon names in the inheritance
     hierarchy. I.E. It would look something like this:
 <programlisting>
-FindBestIcon(iconList, size) {
-  filename = FindBestIconHelper(iconList, size, user selected theme);
+FindBestIcon(iconList, size, scale) {
+  filename = FindBestIconHelper(iconList, size, scale, user selected theme);
   if filename != none
     return filename
 
-  filename = FindBestIconHelper(iconList, size, "hicolor");
+  filename = FindBestIconHelper(iconList, size, scale, "hicolor");
   if filename != none
     return filename
 
@@ -594,7 +620,7 @@ FindBestIcon(iconList, size) {
   }
   return none;
 }
-FindBestIconHelper(iconList, size, theme) {
+FindBestIconHelper(iconList, size, scale, theme) {
   for icon in iconList {
     filename = LookupIcon (icon, size, theme)
     if filename != none
@@ -605,7 +631,7 @@ FindBestIconHelper(iconList, size, theme) {
     parents = theme.parents
 
   for parent in parents {
-    filename = FindBestIconHelper (iconList, size, parent)
+    filename = FindBestIconHelper (iconList, size, scale, parent)
     if filename != none
       return filename
   }
@@ -627,7 +653,7 @@ Name[sv]=Björk
 Comment=Icon theme with a wooden look
 Comment[sv]=Träinspirerat ikontema
 Inherits=wood,default
-Directories=48x48/apps,48x48/mimetypes,32x32/apps,scalable/apps,scalable/mimetypes
+Directories=48x48/apps,48x48@2/apps48x48/mimetypes,32x32/apps,32x32@2/apps,scalable/apps,scalable/mimetypes
 
 [scalable/apps]
 Size=48
@@ -648,11 +674,23 @@ Size=32
 Type=Fixed
 Context=Applications
 
+[32x32@2/apps]
+Size=32
+Scale=2
+Type=Fixed
+Context=Applications
+
 [48x48/apps]
 Size=48
 Type=Fixed
 Context=Applications
 
+[48x48@2/apps]
+Size=48
+Scale=2
+Type=Fixed
+Context=Applications
+
 [48x48/mimetypes]
 Size=48
 Type=Fixed
@@ -664,7 +702,9 @@ birch/scalable/apps/mozilla.svg
 birch/scalable/mimetypes/mime_text_plain.svg
 birch/scalable/mimetypes/mime_text_plain.icon
 birch/48x48/apps/mozilla.png
+birch/48x48@2/apps/mozilla.png
 birch/32x32/apps/mozilla.png
+birch/32x32@2/apps/mozilla.png
 birch/48x48/mimetypes/mime_text_plain.png
 birch/48x48/mimetypes/mime_text_plain.icon</programlisting>
 Where birch/scalable/mimetypes/mime_text_plain.icon contains:
@@ -742,6 +782,18 @@ AttachPoints=20,20|40,40|50,10|10,50</programlisting>
   <appendix id="changes">
     <title>Change history</title>
     <formalpara>
+      <title>Version 0.13, July 2 2013, Alexander Larsson</title>
+      <para>
+	<itemizedlist>
+	  <listitem>
+	    <para>
+            Add icon Scales.
+	    </para>
+	  </listitem>
+	</itemizedlist>
+      </para>
+    </formalpara>
+    <formalpara>
       <title>Version 0.12, 24 December 2006, Octavio Alvarez</title>    
       <para>
 	<itemizedlist>
-- 
1.8.1.4

_______________________________________________
xdg mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/xdg

Reply via email to