<AWT Dev> RFR: 8182043 Access to Windows Large Icons
Alexander Zuev
alexander.zuev at oracle.com
Tue Jul 21 21:33:18 UTC 2020
Hi Alexey,
first of all - the new and improved webrev is available at
http://cr.openjdk.java.net/~kizune/8182043/webrev.03/
I returned the limitation of icon sizes in the result which should
enhance the performance, also i fixed some corner cases and improved
docuentation. More details inline.
/Alex
On 7/15/2020 4:46 PM, Alexey Ivanov wrote:
> Hi Alexander,
>
> I've run some tests and this version works good. However, I noticed
> the new version is slower than before, it could be due to the fact
> that the entire set of icons is extracted from the native. On average,
> JFileChooser is 100ms slower to show on the screen.
That should be dealt with in the new patch.
>
> I think we should limit the number of icons that we extract as you did
> in webrev.01.
Done.
>
> If I request the icon of size 16:
> FileSystemView.getFileSystemView().getSystemIcon(new File("C:\"), 16);
> the resulting icon contains icon sizes 16, 24, 32, 48, 64, 72, 96,
> 128, 256.
>
> Hardly the icon of size 96 and above will ever be used: 96px is 6
> times 16px. Getting 48px-sized icon corresponds to 300% scaling, it
> may be reasonable, yet still unlikely to be used.
>
> Then if I request the icon of size 48:
> FileSystemView.getFileSystemView().getSystemIcon(new File("C:\"), 48);
> the resulting icon contains the same set of sizes. But the sizes
> smaller than the base size will never be used. I believe scaling
> factors less than 100% are not supported.
I still tend to leave it on - it does not hurt performance much and
>
> So we should decide up to which resolution we get the icons. Getting
> icons up to 200% makes sense.
>
> What about the lower limit? if the requested size matches one from our
> list, nothing to decide. What if size of 33 is requested? Scaling up
> 32×32 icon will likely give a better result than scaling down 48×48.
That's why in my code i do keep lower resolution images and when asked
about the resolution variant i'm returning closest resolution to one
asked so in your case if i got asked for 33 pixel icon i will present
the 32 pixel one.
>
>
> Will such an implementation be good enough? This would resolve this
> RFE: provide access to Windows large icon.
>
>
> Then another problem which we're trying to solve: make JFileChooser
> support High DPI environments. In majority of cases, JFileChooser will
> use another method to extract the icon:
> Win32ShellFolder2.getIcon(boolean). This function uses SHGFI_SMALLICON
> or SHGFI_LARGEICON parameters to SHGetFileInfo, and therefore the size
> is limited to 16×16 and 32×32. It will return the icon of the
> currently configured size for the shell icon, small and large
> correspondingly; however, this parameter cannot be easily changed. On
> the other hand, the shell icon size takes DPI into account, and the
> size of the returned icon may differ from 16 and 32.
>
> This situation where the size was different from the requested one was
> handled by wrapping the icon into MultiResolutionIconImage:
>
> Win32ShellFolder2.makeIcon(long hIcon, int size)
> - return size == baseSize
> - ? img
> - : new MultiResolutionIconImage(baseSize, img);
> + new BufferedImage(iconSize, iconSize,
> BufferedImage.TYPE_INT_ARGB);
> + img.setRGB(0, 0, iconSize, iconSize, iconBits, 0,
> iconSize);
> + return img;
>
> The new code works well for getIcon(int size) which wraps a set of
> icons into MultiResolutionIconImage.
>
> I think the calls to getIcon(boolean getLargeIcon) should still wrap
> the result into MultiResolutionIconImage if the size differs from the
> requested one.
Right now the icon got wrapped in the multiresolutionimage when more
than one variant is available.
I can change it to wrap it every time even if the bigger or smaller
variant is not available but i do not see
how it can benefit the file manager itself.
>
> The code at
> 1158 if (newIcon.getWidth(null) == s) {
> 1159 multiResolutionIcon.put(s, newIcon);
> 1160 }
> handles the same situation. Yet here, we'll throw away the icon if its
> size is not equal to the requested one. I wonder if this condition is
> ever false, however.
I removed this condition for i found a corner case when it is 100% false
- the dynamically generated icons in AppData/Roaming folder if promary
monitor is set to any zoom factor.
> To provide better support for High DPI environments in JFileChooser,
> getIcon(boolean getLargeIcon) should also return a set of icons.
It does right now. And result is better than it was before.
>
> This also applies to Win32ShellFolder2.getSystemIcon(SystemIcon
> iconType) which returns standard icons for message boxes, or JOptionPane.
>
>
>> But there's one catch: new way of retrieving icons does not get the
>> custom drive
>> icon (can be seen at disk C: - the windows logo identifying the
>> windows system drive
>> is no longer present). I am questioning myself, what is better: to
>> have better icon quality
>> and missing custom disk logo or to have custom disk logo and mediocre
>> icon quality?
>
> Which is weird, but I also noticed it.
>
> I wonder why different APIs in Windows give different icons:
> SHGetFileInfo which is used in getIcon(boolean getLargeIcon), and
> IExtractIcon::GetIconLocation and IExtractIcon::Extract which are used
> in getIcon(int size) that calls extractIcon(). The former function,
> SHGetFileInfo, can also decorate icons with link (shortcut) overlay
> whereas the latter does not seem to provide such an option.
There is a way to try to get overlay for the icon but it also works
inconsistently.
> As for High DPI environments and memory footprint, getting icon sizes
> according to the display scaling looks like an ideal solution. But it
> seems too tricky. The MultiResolutionIconImage should store all the
> details of the file or the shell folder to be able to fetch a
> different size of DPI changes. Eventually, keeping lots of objects to
> achieve that could have larger footprint than storing a set of icons
> all the time.
>
> Overall, the current approach of fetching a set of icons to cater for
> the most common scaling factors looks sensible.
>
>
> Regards,
> Alexey
>
> On 09/07/2020 00:21, Alexey Ivanov wrote:
>> Hi Alexander,
>>
>> Sorry for my belated review.
>>
>> *FileSystemView.java*
>> I couldn't build JDK because of the warning about empty <p> in
>> javadoc for getSystemIcon(File f, int size).
>>
>> <p> is not needed before <pre>. Yet <p> should be added after each
>> empty line in the javadoc to start a new paragraph, otherwise all the
>> text is presented one long description.
>>
>> 276 * @param size width and height of the icon in pixels to be
>> scaled
>> 277 * (valid range: 1 to 256)
>>
>> I'd drop "to be scaled"; width and height are the base size of the
>> icon for the case.
>>
>>
>> *ShellFolder.java*
>> 205 * @param size size of the icon > 0(Valid range: 1 to 256)
>>
>> I recommend adding space before the opening parenthesis and use
>> lower-case in the parentheses as in FileSystemView.java.
>>
>>
>> *Win32ShellFolder2.java*
>> 80 private final static int[] ICON_RESOLUTIONS
>> 81 = {8, 16, 24, 32, 48, 64, 72, 96, 128, 256};
>> Shall we drop 8 from the list? The size of 8×8 is non-standard for
>> Windows, is it provided by any Windows Shell interfaces?
>>
>>
>> *Win32ShellFolder2.java*
>> The trickery with newIcon2 in getIcon(final boolean getLargeIcon) is
>> for getting both 16×16 and 32×32 and returning them as
>> MultiResolutionImage, isn't it?
>>
>> I guess the best results would be if we get a list of 16×16, 24×24,
>> and 32×32 icons when small icon is requested, and 32×32, 48×48, and
>> 64×64 when large icon is requested, which would cover scaling factors
>> of 100%, 150%, and 200%.
>>
>> I don't think we'll ever need small icon when large one is requested,
>> and if I read the code correctly this is what would happen). However,
>> JFileChooser does not seem to allow for large icons in its file view,
>> thus adding the larger icon makes the rendering crispier in High DPI
>> environments.
>>
>> 1154 if (size > 512 || size < 4) {
>> 1155 return newIcon;
>> 1156 }
>> I can understand that there are no useful resolutions if size of 512
>> or larger is requested. Should it be 256 or rather
>> ICON_RESOLUTIONS[ICON_RESOLUTIONS.length - 1]?
>>
>> Javadoc states the valid range ends at 256.
>>
>> As for the minimum size… In my opinion, icon size less than 8 is not
>> viable; on the other hand we can't make any assumptions. So if the
>> requested size is less than 4, then we'll return only 8×8 icon (or
>> 16×16, if 8 is dropped from the list). Do I get it right?
>>
>>
>> *ShellFolder2.cpp*
>> 981 hres = pIcon->Extract(szBuf, index, &hIcon,
>> &hIconLow, (16 << 16) + size);
>> 982 if (size < 24) {
>>
>> I wonder why you extract two icons, you never use both. This adds a
>> delay: only one of the extracted icons is ever used.
>> If the idea is to limit the size by 16, then min(16, size) passed as
>> the icon size would do the trick.
>>
>>
>> With this new version, I noticed that JFileChooser takes longer to
>> appear and then longer to populate the file list.
>>
>> I'm still playing around with the build but I wanted to provide my
>> feedback.
>>
>>
>> Regards,
>> Alexey
>>
>> On 29/06/2020 15:27, Alexander Zuev wrote:
>>> Alexey, Sergey,
>>>
>>> here's the latest version of the fix:
>>>
>>> http://cr.openjdk.java.net/~kizune/8182043/webrev.02/
>>>
>>> It adds one more native method - hiResIconAvailable
>>> that queries if system will be able to provide high resolution icons
>>> for a given file.
>>> Now i have tested three approaches with the FileManager:
>>> The old one - at magnification 150% can be seen here:
>>> http://cr.openjdk.java.net/~kizune/8182043/example/fchooser_old_150.PNG
>>> I changed the behavior by making the icon loaded by the FileChooser
>>> a MultiResolutionIcon
>>> carrying both small and large icons at the same time.
>>> The result looks much better - here's the same view with the
>>> intermediate fix:
>>> http://cr.openjdk.java.net/~kizune/8182043/example/fchooser_inter_150.PNG
>>>
>>> But then i added the new native method and in FileChooser i'm
>>> getting the multiResolutionIcon
>>> for all the files for which it is possible. The result looks much
>>> crisper:
>>> http://cr.openjdk.java.net/~kizune/8182043/example/fchooser_new_150.PNG
>>> But there's one catch: new way of retrieving icons does not get the
>>> custom drive
>>> icon (can be seen at disk C: - the windows logo identifying the
>>> windows system drive
>>> is no longer present). I am questioning myself, what is better: to
>>> have better icon quality
>>> and missing custom disk logo or to have custom disk logo and
>>> mediocre icon quality?
>>>
>>> /Alex
>>>
>>>
>>> On 22-Jun-20 11:27, Alexander Zuev wrote:
>>>> Hi Alexey,
>>>>
>>>> sorry for late responce, after fixing that initial error with the
>>>> wrong
>>>> icon sizes pulled i found a lot of corner cases that needed some
>>>> additional digging.
>>>>
>>>> On 18-Jun-20 20:56, Alexey Ivanov wrote:
>>>>> On 18/06/2020 02:30, Sergey Bylokhov wrote:
>>>>>> On 6/17/20 5:50 pm, Sergey Bylokhov wrote:
>>>>>>
>>>>>>> I guess it is too early to compare behavior before and after the
>>>>>>> fix since the fix has a few bugs.
>>>>>>> - It does not fetch several sizes, as it was expected from the
>>>>>>> code, but load only one native size
>>>>>>> and map it to the different resolutions.
>>>>>
>>>>> Yes, I re-read your message and found this mistake.
>>>>> I fixed it locally.
>>>>>
>>>>> Then I noticed JFileChooser does not really use the new method
>>>>> which returns MRI, so this explains why JFileChooser never adjusts
>>>>> the icons according the screen DPI.
>>>>>
>>>>> I modified Win32ShellFolder2.getIcon(boolean) to use getIcon(size)
>>>>> instead of getIcon(getAbsolutePath(), getLargeIcon), and now the
>>>>> file icons are updated when JFileChooser window is moved from
>>>>> standard DPI monitor to a High DPI one (150%) and back. I noticed
>>>>> one artefact though: the customised icons from disk drives
>>>>> disappeared, some file icons look clipped, on either monitor.
>>>> I also noticed this behavior, some icons retrieved with the
>>>> extractIcon method got clipped or improperly scaled.
>>>> I tried to dig deeper and found that it happens when
>>>> pIcon->GetIconLocation function returns "*"
>>>> as location of the resource file. I haven't found exact reason for
>>>> that but when this is the case then
>>>> getIconBits function always retrieves 32x32 icon no matter what
>>>> icon size we requested.
>>>> We then scale it down to 16x16 and the result is unpleasant.
>>>> I'm trying to find another way of retrieving the custom icon but
>>>> for now i would say that
>>>> for the small icons the approach of getIcon function which uses
>>>> SHGetFileInfo holds better results.
>>>>
>>>> So far the approach that seems to be working is to check if we have
>>>> a high resolution
>>>> icon available by requesting icon location. If icon location is not
>>>> known we can get both
>>>> low and high resolution icons from SHGetFileInfo and store them in
>>>> the MRI. If high res icon available
>>>> then fetch all the standard resolution icons and also return them
>>>> as MRI.
>>>>
>>>> /Alex
>>>
>>
>
More information about the awt-dev
mailing list