<AWT Dev> [OpenJDK 2D-Dev] Review request for 8029339 Custom MultiResolution image support on HiDPI displays

Philip Race philip.race at oracle.com
Wed Mar 29 20:52:37 UTC 2017


This would be a reasonable thing to try to fix before 9 GA I think.
Can't affect many tests since the code is new ..

-phil.


On 3/29/17, 1:22 PM, Sergey Bylokhov wrote:
> Hi, Jim, Phil.
> I have started to use MRI and a new Robot in some of the tests and 
> wonder why the MultiResolutionImage does not use generics 
> for getResolutionVariants()?
>
> So for example if we have an API like:
> http://download.java.net/java/jdk9/docs/api/java/awt/Robot.html#createMultiResolutionScreenCapture-java.awt.Rectangle-
> We cannot specify that the MRI contains BufferedImage(not just an 
> image). So the users will need to check it via instance of and cast.
> So in the worse case the user will get something like this:
>
> =====
> Test.java
>             MultiResolutionImage image =
>                     robot.createMultiResolutionScreenCapture(rect);
>             List<Image> resolutionVariants = 
> image.getResolutionVariants();
>
>             if (resolutionVariants.size() > 1) {
>                 Image tmp = resolutionVariants.get(1);
>                 if (tmp instanceof BufferedImage) {
>                     capture = (BufferedImage) tmp;
>                 }
>             } else {
>                 Image tmp = resolutionVariants.get(0);
>                 if (tmp instanceof BufferedImage) {
>                     capture = (BufferedImage) tmp;
>                 }
>             }
> =====
>
> I am not sure but for writing the tests, I feel something like this 
> will be simpler:
> =====
> Robot.java
>     public synchronized MultiResolutionImage<BufferedImage>
>             createMultiResolutionScreenCapture(Rectangle screenRect) {
> //
> Test.java
>             MultiResolutionImage image =
>                     robot.createMultiResolutionScreenCapture(rect);
>             List<BufferedImage> resolutionVariants = 
> image.getResolutionVariants();
>
>             if (resolutionVariants.size() > 1) {
>                     capture = resolutionVariants.get(1);
>             } else {
>                     capture = resolutionVariants.get(0);
>             }
> =====
> Or even this:
> capture = robot.createCompatibleScreenCapture(rect);
>
>
>
>>
>> Hi Alexandr,
>>
>> Sorry that this fell into the cracks.  Here are some fairly minor 
>> updates:
>>
>> AbstractMRI - getGraphics() should include "getGraphics() not 
>> supported on Multi-Resolution Images" as the exception description text.
>>
>> AbstractMRI - getBaseImage() should have doc comments:
>> /**
>> * Return the base image representing the best version of the image
>> * for rendering at the default width and height.
>> * @return the base image of the set of multi-resolution images
>> */
>> (Does it need an @since given that the entire interface is @since 1.9?)
>>
>> BaseMRI - the doc comments (both the class comment and the 
>> constructor comments) don't start with "/**" so they aren't really 
>> doc comments, but they look good so make them so.
>>
>> BaseMRI - class comment - "The implementation will return the first 
>> ... satisfy the rendering request."  Add another sentence right there 
>> "The last image in the array will be returned if no suitable image is 
>> found that is larger than the rendering request."
>>
>> BaseMRI - move "For best effect ..." should be moved to a new 
>> paragraph and mention that no exception will be thrown if the images 
>> are not sorted as suggested.
>>
>> RenderingHints - comments:
>> DEFAULT, SIZE_FIT, DPI_FIT - "an image resolution variant is chosen 
>> ..." (add "an")
>> DEFAULT - "... which may depend on the policies of the platform"
>> SIZE_FIT, DPI_FIT "... on the DPI of ..." (add "the")
>>
>> SunHints - descriptor texts:
>> SIZE_FIT, DPI_FIT "based on the DPI" (add "the")
>>
>> MRCachedImage - remind me what this is used for?
>> MRCachedImage.getResolutionVariant - use ceil or round instead of 
>> (int) cast?  ceil() would match the actions of MRToolkitImage better. 
>>  Also note following comment about precision with SG2D.
>>
>> SG2D/MRI - the interface declares the values as float, the usage in 
>> SG2D computes values in double and then truncates them to int to pass 
>> to the interface - should we upgrade the interface to double for 
>> completeness?  If not, then the usage in SG2D should at least pass in 
>> float precision.
>>
>> SG2D.getResolutionVariant - using destRegionWH to calculate 
>> destImageWH can involve a lot of "do some math and then later have 
>> additional code undo it".  Would it be faster to just compute 
>> destImageWH directly, as in:
>>
>> float destImageWidth, destImageHeight;
>>
>> if (BASE) {
>>    destImageWH = srcWH;
>> } else if (DPI) {
>>    destImageWH = (float) abs(srcWH * devScale);
>> } else {
>>    double destRegionWidth, destRegionHeight;
>>    if (type) {
>>    ...
>>    }
>>    destImageWH = (float) abs(srcWH * destRegionWH / swh);
>> }
>> Image rv = img.getRV(destImageWH);
>>
>> On the other hand, the last "else" is probably the most common case 
>> so this doesn't save anything in the common case, but it avoids a 
>> bunch of math that could introduce rounding error for the BASE/DPI 
>> cases (even though it is done in doubles).
>>
>> Is there intent to have the default case be mapped to DPI_FIT for 
>> Windows?
>>
>> MultiResolutionRenderinHints.java - should have "Test" appended to 
>> the name
>>
>> MRRHTest - why not render to a BufferedImage and avoid Robot?  Could 
>> it tap into internal APIs to create a BImg/compatibleImage with a 
>> given devScale?
>>
>> MRRHTest - why allow up to delta=50 on the comparison?
>>
>> MRRHTest - since the scale factor comes from a dialog, we depend on 
>> running this on a HiDPI display to fully test the hints?  Could using 
>> "scaled compatible images" allow testing this more definitively?
>>
>> MRRHTest - remove println before pushing?
>>
>> MRRHTest - probably shouldn't have a "right answer" for DEFAULT - it 
>> should probably just pass if the operation doesn't throw an exception?
>>
>> ...jim
>>
>>
>> On 4/15/15 7:04 AM, Alexander Scherbatiy wrote:
>>>
>>>   Hello,
>>>
>>>  Could you review the updated fix:
>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.08/ 
>>> <http://cr.openjdk.java.net/%7Ealexsch/8029339/webrev.08/>
>>>
>>>  - SunGraphics2D is updated to calculate the resolution variant size
>>> according to the _BASE, _DPI_FIT, and _SIZE_FIT resolution rendering 
>>> hint
>>>  - MultiResolutionRenderingHints test is added
>>>
>>>  Thanks,
>>>  Alexandr.
>>>
>>>
>>> On 4/7/2015 1:02 PM, Jim Graham wrote:
>>>> This is an interesting suggestion that would let us keep the
>>>> implementation of the various hints centralized and simplify the
>>>> interface to the part of the mechanism that is most tied in to the
>>>> implementation specifics of the database of media variants - which is
>>>> housed in the MRI-implementing object.
>>>>
>>>> I'm not sure we ever identified any need to customize the logic of
>>>> "what size is needed for this render operation" beyond what we
>>>> expressed in the hints, and given that the platform defaults may not
>>>> be easy to express to an arbitrary implementation, it is probably
>>>> better to put that part of the logic in SG2D, controlled by the easy
>>>> to express hints and keep the current API both simple to implement and
>>>> flexible to use.  Even if there was a need to customize that part of
>>>> the operation (the "what size is relevant to this rendering operation"
>>>> decision) beyond what the hints suggest, it would be inappropriate to
>>>> tie that in to the "find me media" aspect of the MRI interface
>>>> anyway.  So, best to keep them separate and have the hints affect what
>>>> SG2D does and have the MRI focused on just storing (possibly creating)
>>>> and managing/finding the variants.
>>>>
>>>>            ...jim
>>>>
>>>> On 4/1/15 6:46 AM, Alexander Scherbatiy wrote:
>>>>> On 3/27/2015 12:48 AM, Jim Graham wrote:
>>>>>> Hi Alexander,
>>>>>
>>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.07/ 
>>>>> <http://cr.openjdk.java.net/%7Ealexsch/8029339/webrev.07/>
>>>>>   I have updated the fix according to the comments except
>>>>> RenderingHints.
>>>>>
>>>>>   RenderingHints are supposed to be set on Graphics2D and they have
>>>>> keys/values which are not relevant to the getResolutionVariant() 
>>>>> method.
>>>>>   Graphics objects chooses an alternative according to the set
>>>>> rendering hints.
>>>>>   May be what SG2D should do just calculate dest image size for the
>>>>> given resolution variant hint (_BASE - base image size, _SIZE_FIT -
>>>>> including scale factor and graphics transform (Mac algorithm),
>>>>> _DPI_FIT - scaled according to the system DPI) and then pass them to
>>>>> the getResolutionVariant() method?
>>>>>
>>>>>  Thanks,
>>>>>  Alexandr.
>>>>>
>>>>>>
>>>>>> MRI.java:
>>>>>>
>>>>>> Who is the intended audience for the recommendation in the interface
>>>>>> to cache image variants?  Are we asking the developers who call the
>>>>>> methods on the interface to cache the answers? That would be unwise
>>>>>> because the list of variants may change over time for some MRIs. Are
>>>>>> we speaking to the implementer? If so, then I think that it is
>>>>>> unnecessary to remind implementers of basic implementation
>>>>>> strategies like "cache complicated objects".
>>>>>>
>>>>>> How about this wording for the getRV() method? - "Gets a specific
>>>>>> image that is the best variant to represent this logical image at
>>>>>> the indicated size and screen resolution."
>>>>>>
>>>>>> Perhaps we should clarify in the doc comments for the dimension
>>>>>> arguments in getRV() that the dimensions are measured in pixels?
>>>>>>
>>>>>> line 56 - delete blank line between doc comment and method 
>>>>>> declaration
>>>>>>
>>>>>> Also, it is probably overkill to document that the interface
>>>>>> getVariants() method returns an unmodifiable list. Responsible
>>>>>> implementations would probably use an unmodifiable list, but I don't
>>>>>> think it should be required by the interface.  We do need to specify
>>>>>> that it isn't required to be modifiable so that a caller doesn't
>>>>>> expect to be able to modify it, but that is a looser spec.  How
>>>>>> about "Gets a readable list of all resolution variants.  Note that
>>>>>> many implementations might return an unmodifiable list."?
>>>>>>
>>>>>> AbstractMIR.java:
>>>>>>
>>>>>> "provides a default implementation for the MRI" or "provides default
>>>>>> implementations of several methods in the <MRI> interface and the
>>>>>> <Image> class"?  Actually, I'll note that it provides none of the
>>>>>> implementations of the MRI methods so maybe it should be "provides
>>>>>> default implementations of several <Image> methods for classes that
>>>>>> want to implement the <MRI> interface"?
>>>>>>
>>>>>> In the doc example - wrap the list to make it unmodifiable
>>>>>>
>>>>>> The doc example could be made 2 or 3 lines shorter by simply
>>>>>> assuming the base image is in index 0 (it's just an example so I'm
>>>>>> not sure the flexibility needs to be a part of the example).
>>>>>>
>>>>>> getGraphics is allowed by the Image interface to return null.
>>>>>> Actually, the exact wording is that it can only be called for
>>>>>> "offscreen images" and a MRI is technically not "an offscreen
>>>>>> image".  Perhaps we should return null here since modifying the base
>>>>>> image is unlikely to modify the variants and arguably it would be
>>>>>> required by the wording in the method docs (even if the base image
>>>>>> was an offscreen, the MRI produced from it stops being an offscreen)?
>>>>>>
>>>>>> Are all of the empty "@Inherit" comments needed?  I thought
>>>>>> inheritance was the default?
>>>>>>
>>>>>> BaseMRI.java:
>>>>>>
>>>>>> "This class is [an] array-based implementation of the {AMRI} class"
>>>>>> (missing "an" and "the")
>>>>>>
>>>>>> We should probably include the comment about the sorting of the
>>>>>> images in the class comments as well as document that the algorithm
>>>>>> is a simple scan from the beginning for the first image large enough
>>>>>> (and default == last image).  The algorithm also might not work very
>>>>>> well if the images are not monotonically both wider and taller.  How
>>>>>> about adding this to the class comments:
>>>>>>
>>>>>> "The implementation will return the first image variant in the array
>>>>>> that is large enough to satisfy the rendering request. For best
>>>>>> effect the array of images should be sorted with each image being
>>>>>> both wider and taller than the previous image. The base image need
>>>>>> not be the first image in the array."
>>>>>>
>>>>>> getVariants() - you need to return an unmodifiable list. asList()
>>>>>> returns a list that "writes back" to the array.  You need to use
>>>>>> Collections.unmodifiableList(Arrays.asList(array)).
>>>>>>
>>>>>> RenderingHints.java:
>>>>>>
>>>>>> Where do we process this hint?  Don't we need to pass it to the
>>>>>> getVariant() method?
>>>>>>
>>>>>> I don't understand the hint values other than the one that always
>>>>>> uses the base image.  Default I guess gives us the ability to use
>>>>>> the Mac algorithm of "next larger size" on Mac and "based on Screen
>>>>>> DPI" on Windows, but the 3rd value "ON" is so vague as to not have
>>>>>> any meaning.  Perhaps we should just delete it, but then do we just
>>>>>> always do the Mac method? Or do we vaguely have our internal images
>>>>>> have a platform-specific method and the Abstract/Base classes just
>>>>>> do what they want with no control from the user?  In FX we are also
>>>>>> still struggling with this issue and we may likely just do what the
>>>>>> Mac does in all cases, but perhaps AWT needs to "behave like the
>>>>>> platform" more?  If we are going to have actual values, then we need
>>>>>> to have them do something, which means:
>>>>>>
>>>>>> - SG2D needs to track the hint just like we do the other hints that
>>>>>> affect our processing
>>>>>> - MRI.getVariant() needs to have the hint as an argument
>>>>>> - BaseMRI should probably do something with that hint
>>>>>> - hint values should include:
>>>>>>    - ..._DEFAULT - implementation gets to decide
>>>>>>    - ..._BASE - always use the base image
>>>>>>    - ..._SIZE_FIT - Mac algorithm of smallest image that is big 
>>>>>> enough
>>>>>>    - ..._DPI_FIT - choose based on DPI of the screen, ignoring
>>>>>> transform
>>>>>>
>>>>>> line 978 - missing blank line between fields
>>>>>>
>>>>>> SG2D.java:
>>>>>>
>>>>>> - The interface says that you will be passing in the "logical DPI"
>>>>>> of the display, but here you are actually passing in the screen's
>>>>>> scale factor.
>>>>>>
>>>>>> BaseMRITest.java:
>>>>>>
>>>>>> - testBaseMRI also passes in a scale rather than a DPI to the MRI
>>>>>> method.
>>>>>>
>>>>>> - How does the modification test pass when the implementation
>>>>>> doesn't use unmodifiable lists?
>>>>>>
>>>>>> MRITest.java:
>>>>>>
>>>>>> - also uses scale rather than DPI in several places
>>>>>>
>>>>>>        ...jim
>>>>>>
>>>>>> On 3/13/15 6:34 AM, Alexander Scherbatiy wrote:
>>>>>>>
>>>>>>>   Hello,
>>>>>>>
>>>>>>>   Could you review the proposed API based on MultiresolutionImage
>>>>>>> interface:
>>>>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.06/ 
>>>>>>> <http://cr.openjdk.java.net/%7Ealexsch/8029339/webrev.06/>
>>>>>>>
>>>>>>>  - return unmodifiable list comment is added to the
>>>>>>> getResolutionVariants() method javadoc in MultiresolutionImage
>>>>>>> interface
>>>>>>>  - base image size arguments are removed form the
>>>>>>> getResolutionVariant(...) method in MultiresolutionImage interface
>>>>>>>  - BaseMultiResolutionImage class that allows to create a
>>>>>>> multi-resolution image based on resolution variant array is added
>>>>>>>  - the test for the BaseMultiResolutionImage is added
>>>>>>>
>>>>>>>  Thanks,
>>>>>>>  Alexandr.
>>>>>>>
>>>>>>> On 2/14/2015 3:23 AM, Jim Graham wrote:
>>>>>>>> The second solution looks good.  I'd make it standard practice
>>>>>>>> (perhaps even mentioned in the documentation) to return 
>>>>>>>> unmodifiable
>>>>>>>> lists from the getVariants() method.  The Collections class 
>>>>>>>> provides
>>>>>>>> easy methods to create these lists, and it sends a clear message to
>>>>>>>> the caller that the list was provided for them to read, but not 
>>>>>>>> write
>>>>>>>> to.  Otherwise they may add a new image to the list you 
>>>>>>>> provided them
>>>>>>>> and wonder why it wasn't showing up.  Also, an unmodifiable 
>>>>>>>> list can
>>>>>>>> be cached and reused for subsequent calls without having to 
>>>>>>>> create a
>>>>>>>> new list every time.
>>>>>>>>
>>>>>>>> In getResolutionVariant() was there a reason why the base 
>>>>>>>> dimensions
>>>>>>>> were provided as float?  The destination dimensions make sense as
>>>>>>>> float since they could be the result of a scale, but the source
>>>>>>>> dimensions are typically getWidth/getHeight() on the base image.  A
>>>>>>>> related question would be if they are needed at all, since the
>>>>>>>> implementation should probably already be aware of what the base
>>>>>>>> image
>>>>>>>> is and what its dimensions are.  I'm guessing they are provided
>>>>>>>> because the implementation in SG2D already knows them and it 
>>>>>>>> makes it
>>>>>>>> easier to forward the implementation on to a shared (static?) 
>>>>>>>> method?
>>>>>>>>
>>>>>>>> With respect to default implementations, I take it that the
>>>>>>>> BaseMRI is
>>>>>>>> along the pattern that we see in Swing for Base classes. Would 
>>>>>>>> it be
>>>>>>>> helpful to provide an implementation (in addition or instead) that
>>>>>>>> allows a developer to take a bunch of images and quickly make 
>>>>>>>> an MRI
>>>>>>>> without having to override anything?  The implementations of
>>>>>>>> getBaseImage() and getResolutionVariants() are pretty 
>>>>>>>> straightforward
>>>>>>>> and a fairly reasonable default algorithm can be provided for
>>>>>>>> getRV(dimensions).  This question is more of an idle question 
>>>>>>>> for my
>>>>>>>> own curiosity than a stumbling block...
>>>>>>>>
>>>>>>>>            ...jim
>>>>>>>>
>>>>>>>> On 1/22/2015 6:49 AM, Alexander Scherbatiy wrote:
>>>>>>>>>
>>>>>>>>>   Hi Phil,
>>>>>>>>>
>>>>>>>>>   I have prepared two versions of the proposed API:
>>>>>>>>>
>>>>>>>>>   I) Resolution variants are added directly to the Image:
>>>>>>>>> http://cr.openjdk.java.net/~alexsch/8029339/list/webrev.00 
>>>>>>>>> <http://cr.openjdk.java.net/%7Ealexsch/8029339/list/webrev.00>
>>>>>>>>>
>>>>>>>>>   II)  MultiResolutionImage interface is used:
>>>>>>>>> http://cr.openjdk.java.net/~alexsch/8029339/webrev.05
>>>>>>>>>
>>>>>>>>>   It could help to decide which way should be chosen for the the
>>>>>>>>> multi-resolution image support.
>>>>>>>>>
>>>>>>>>>   Below are some comments:
>>>>>>>>>
>>>>>>>>>   1. High level goal:
>>>>>>>>>      Introduce an API that allows to create and handle an image
>>>>>>>>> with
>>>>>>>>> resolution variants.
>>>>>>>>>
>>>>>>>>>   2. What is not subject of the provided API
>>>>>>>>>     - Scale naming convention for high-resolution images
>>>>>>>>>     - Providing pixel scale factor for the screen/window
>>>>>>>>>
>>>>>>>>>   3. Use cases
>>>>>>>>>    3.1 Loading and drawing high-resolution icons in IntelliJ IDEA
>>>>>>>>>      A high-resolution image is loaded from resources and 
>>>>>>>>> stored in
>>>>>>>>> JBHiDPIScaledImage class  which is a subclass of the buffered 
>>>>>>>>> image.
>>>>>>>>>      The high-resolution image is used to create a disabled icon
>>>>>>>>> in the
>>>>>>>>> IconLoader.getDisabledIcon(icon) method.
>>>>>>>>> https://github.com/JetBrains/intellij-community/blob/master/platform/util/src/com/intellij/openapi/util/IconLoader.java
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>    3.2 Loading and drawing high-resolution icons in NetBeans
>>>>>>>>>      NetBeans does not have support for the high-resolution icons
>>>>>>>>> loading.
>>>>>>>>>      It loads an icon from the file system using
>>>>>>>>> Toolkit.getDefaultToolkit().getImage(url) method or from resources
>>>>>>>>>      by  ImageReader  and store it in ToolTipImage class which is
>>>>>>>>> subclass of the buffered image.
>>>>>>>>>      ImageUtilities.createDisabledIcon(icon) method creates a
>>>>>>>>> disabled
>>>>>>>>> icon by applying  RGBImageFilter to the icon.
>>>>>>>>> http://hg.netbeans.org/main/file/97dcf49eb4a7/openide.util/src/org/openide/util/ImageUtilities.java
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>    3.3 Loading system icons in JDK 1.8
>>>>>>>>>      JDK requests icons from the native system for system L&Fs and
>>>>>>>>> applies filters for them.
>>>>>>>>>      See for example AquaUtils.generateLightenedImage() method:
>>>>>>>>> http://hg.openjdk.java.net/jdk9/client/jdk/file/e6f48c4fad38/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>   4. HiDPI support for Images on different OSes
>>>>>>>>>
>>>>>>>>>     4.1 Mac OS X
>>>>>>>>>       Cocoa API contains NSImage that allows to work with image
>>>>>>>>> representations: add/remove/get all representations.
>>>>>>>>>       It picks up an image with necessary resolution based on the
>>>>>>>>> screen backing store pixel scale factor and applied transforms.
>>>>>>>>> https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>     4.2 Linux
>>>>>>>>>       GTK+ 3 API has gtkcssimagescaled lib (it seems that it 
>>>>>>>>> is not
>>>>>>>>> public/stable)
>>>>>>>>>       that parses the -gtk-scaled css property and draws a
>>>>>>>>> GtkCssImage
>>>>>>>>> according to the given scale factor.
>>>>>>>>>
>>>>>>>>>       I have not found information about the HiDPI support in 
>>>>>>>>> Xlib.
>>>>>>>>>
>>>>>>>>>     4.3 Windows
>>>>>>>>>       I have only found the tutorial that suggests to select and
>>>>>>>>> draw a
>>>>>>>>> bitmap using the queried DPI
>>>>>>>>>       and scale the coordinates for drawing a rectangular frame
>>>>>>>>> http://msdn.microsoft.com/en-us/library/dd464659%28v=vs.85%29.aspx
>>>>>>>>>
>>>>>>>>>       Windows also provides the horizontal and vertical DPI of the
>>>>>>>>> desktop
>>>>>>>>> http://msdn.microsoft.com/en-us/library/windows/apps/dd371316
>>>>>>>>>
>>>>>>>>>   5. Pseudo API
>>>>>>>>>      Below are some ways which illustrates how multi-resolution
>>>>>>>>> images
>>>>>>>>> can be created and used.
>>>>>>>>>
>>>>>>>>>     5.1 Resolution variants are stored directly in Image class.
>>>>>>>>>     To query a resolution variant it needs to compare the
>>>>>>>>> resolution
>>>>>>>>> variant width/height
>>>>>>>>>     with the requested high-resolution size.
>>>>>>>>>     ------------
>>>>>>>>>     public abstract class Image {
>>>>>>>>>
>>>>>>>>>         public void addResolutionVariant(Image image) {...}
>>>>>>>>>         public List<Image> getResolutionVariants() {...}
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>     // create a disabled image with resolution variants
>>>>>>>>>
>>>>>>>>>     Image disabledImage = getDisabledImage(image);
>>>>>>>>>
>>>>>>>>>     for (Image rv : image.getResolutionVariants()) {
>>>>>>>>> disabledImage.addResolutionVariant(getDisabledImage(rv));
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>     This approach requires that all resolution variants have been
>>>>>>>>> created even not of them are really used.
>>>>>>>>>
>>>>>>>>>     5.2  Resolution variants are stored in a separate object that
>>>>>>>>> allows to create them by demand.
>>>>>>>>>     To query a resolution variant it needs to compare the
>>>>>>>>> resolution
>>>>>>>>> variant scale factor
>>>>>>>>>     with the requested scale (that can include both screen DPI
>>>>>>>>> scale
>>>>>>>>> and applied transforms).
>>>>>>>>>     ------------
>>>>>>>>>     public abstract class Image {
>>>>>>>>>
>>>>>>>>>         public static interface ResolutionVariant {
>>>>>>>>>             Image getImage();
>>>>>>>>>             float getScaleFactor();
>>>>>>>>>         }
>>>>>>>>>
>>>>>>>>>         public void addResolutionVariant(ResolutionVariant
>>>>>>>>> resolutionVariant) {...}
>>>>>>>>>         public List<ResolutionVariant> getResolutionVariants()
>>>>>>>>> {...}
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>     // create a disabled image with resolution variants
>>>>>>>>>     Image disabledImage = getDisabledImage(image);
>>>>>>>>>
>>>>>>>>>     for (Image.ResolutionVariant rv :
>>>>>>>>> image.getResolutionVariants()) {
>>>>>>>>>         disabledImage.addResolutionVariant(new
>>>>>>>>> Image.ResolutionVariant() {
>>>>>>>>>
>>>>>>>>>             public Image getImage() {
>>>>>>>>>                 return getDisabledImage(rv.getImage());
>>>>>>>>>             }
>>>>>>>>>
>>>>>>>>>             public float getScaleFactor() {
>>>>>>>>>                 return rv.getScaleFactor();
>>>>>>>>>             }
>>>>>>>>>         });
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>
>>>>>>>>>     It does not have problem if a predefined set of images is
>>>>>>>>> provided
>>>>>>>>> (like image.png and image at 2x.png on the file system).
>>>>>>>>>     This does not cover cases where a resolution variant can be
>>>>>>>>> created
>>>>>>>>> using the exact requested size (like loading icons from the native
>>>>>>>>> system).
>>>>>>>>>     A resolution variant can be queried based on a scale 
>>>>>>>>> factor and
>>>>>>>>> applied transforms.
>>>>>>>>>
>>>>>>>>>     5.3 The provided example allows to create a resolution variant
>>>>>>>>> using the requested high-resolution image size.
>>>>>>>>>     ------------
>>>>>>>>>     public interface MultiResolutionImage {
>>>>>>>>>         Image getResolutionVariant(float width, float height);
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>     // create a multi-resolution image
>>>>>>>>>     Image mrImage = new AbstractMultiResolutionImage() {
>>>>>>>>>
>>>>>>>>>             public Image getResolutionVariant(float width, float
>>>>>>>>> height) {
>>>>>>>>>                 // create and return a resolution variant with
>>>>>>>>> exact
>>>>>>>>> requested width/height size
>>>>>>>>>             }
>>>>>>>>>
>>>>>>>>>             protected Image getBaseImage() {
>>>>>>>>>                 return baseImage;
>>>>>>>>>             }
>>>>>>>>>         };
>>>>>>>>>     ------------
>>>>>>>>>     // create a disabled image with resolution variants
>>>>>>>>>     Image disabledImage = null;
>>>>>>>>>     if (image instanceof MultiResolutionImage) {
>>>>>>>>>         final MultiResolutionImage mrImage = 
>>>>>>>>> (MultiResolutionImage)
>>>>>>>>> image;
>>>>>>>>>         disabledImage = new AbstractMultiResolutionImage(){
>>>>>>>>>
>>>>>>>>>             public Image getResolutionVariant(float width, float
>>>>>>>>> height) {
>>>>>>>>>                 return
>>>>>>>>> getDisabledImage(mrImage.getResolutionVariant(width, height));
>>>>>>>>>             }
>>>>>>>>>
>>>>>>>>>             protected Image getBaseImage() {
>>>>>>>>>                 return getDisabledImage(mrImage);
>>>>>>>>>             }
>>>>>>>>>         };
>>>>>>>>>     } else {
>>>>>>>>>         disabledImage = getDisabledImage(image);
>>>>>>>>>     }
>>>>>>>>>     ------------
>>>>>>>>>
>>>>>>>>>   Thanks,
>>>>>>>>>   Alexandr.
>>>>>>>
>>>>>
>>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/awt-dev/attachments/20170329/00ec8559/attachment-0001.html>


More information about the awt-dev mailing list