On 11/20/2013 3:17 PM, Jim Graham wrote:
In looking through the ToolkitImage code some more it occurs to me
that it was already designed (moreso in a previous life) to hold onto
multiple representations of the image anyway. In a prior life in 1.0
and 1.1 it held separate ImageRepresentation objects for each size it
was scaled to (via drawImage(w,h)), but that was simplified to a
single ImageRep when we converted to Java2D and started doing scaling
on the fly for all drawImage() operations. Still, the concept of an
alternate resolution version of the image is probably more in line
with the ImageRepresentation object within the ToolkitImage than in
having multiple ToolkitImage objects and a wrapper for them.
This would also deal more naturally with the ImageObserver issue since
there really would be only one Image and SG2D would not deal with the
sub-representations, it would be dealt with in the DrawImage pipeline
code when it queries the ToolkitImage for the ImageRepresentation object.
In the end, I think that design would be simpler overall, would it be
possible to shift those gears for this fix? If not, we should
consider it for a near-term future cleanup task perhaps...
I think that it would be better to postpone this cleanup to a
near-term future task.
Thanks,
Alexandr.
...jim
On 11/19/2013 7:58 PM, Jim Graham wrote:
Based on the information below, I have the following suggestions...
We should probably allow asynchronous loading of the scaled
resolution variants. This is a minor variation of what the
ImageObserver was originally designed for, but technically might
violate some developer's expectations if they have only dealt with a
post-Java2D version of Java. Some education might be helpful here.
The wording on drawImage(dxy12, sxy12) should probably be reworded to
indicate that asynchronous scaling would not happen, but alternate
versions of the image may be accessed.
In all cases, if the version of the image that we would ideally want
to show hasn't been loaded, but the standard version has (or if @2x
was loaded, but we want the regular version too?) then we should
probably go with the version that was loaded, but still trigger the
loading of the alternate version and notify their Observer as it is
loaded.
I also examined the places in the code where we notify the
ImageObserver. A search for the observer method should show all
places we call it, but the primary ones look like they are fairly few
places. If we tag the resolution variant images with the composite
image from which they came, then we can have those few places do
something like:
Image obsimg = (img instanceof SunToolkitImage) ? (()
img).getObservedImage() : img;
I think in most cases the img is already known to be our internal
SunToolkit image and so we don't even need to check instanceof...
...jim
On 11/19/2013 7:01 PM, Jim Graham wrote:
I did some more reading about the various ways in which the
ImageObserver is used and noticed the following points, some of
which may be to our advantage.
Many of the drawImage() calls mention that they will notify the
observer as the image is "scaled or converted for the output
device". I believe in the world before 2D, we would often have to
load or convert the image asynchronously for various changes in the
output. When we created the 2D interface and added some on-the-fly
image scaling code, we mentioned that scaling was no longer
asynchronous, but technically the API is still designed for
asynchronous operations when the rendering parameters change.
However, the drawImage() call that takes 8 parameters dxy12, sxy12 -
specifically includes the words:
* This method always uses the unscaled version of the image
* to render the scaled rectangle and performs the required
* scaling on the fly. It does not use a cached, scaled version
* of the image for this operation. Scaling of the image from
source
* to destination is performed such that the first coordinate
* of the source rectangle is mapped to the first coordinate of
* the destination rectangle, and the second source coordinate is
* mapped to the second destination coordinate. The subimage is
* scaled and flipped as needed to preserve those mappings.
public abstract boolean drawImage(Image img,
int dx1, int dy1, int dx2,
int dy2,
int sx1, int sy1, int sx2,
int sy2,
ImageObserver observer);
which basically, at the time it was created in 1.1, was an opt "out"
of the asynchronous operations that might happen when you scaled an
image with drawImage(xywh). As worded, this would suggest that this
method does not use the @2x version and always uses the default
resolution version, but those words were not put there for this
particular intent, they were put there to indicate that we weren't
going to do an off-line scaling of the pixels which sometimes
happened in 1.0.x and possibly 1.1 (for the other calls that
predated 1.1 until Java2D).
I also found the Component.prepareImage() and Component.checkImage()
methods which also take an ImageObserver. Those methods imply that
they will possibly start the process and return information on a
particular version of an image appropriate for the current output
device. There is even a prepareImage(w,h) method that gets an image
ready to render at the indicated size. Given that these methods are
on component, it probably makes sense to have that code look up
which representation would be used for those indicated dimensions on
the indicated output device that the Component is displayed on.
...jim