 |
Ocean, Gradients and Image Caching - oh my
Posted by zixle on September 06, 2005 at 06:00 AM | Comments (3)
One of the biggest features we did in 1.5 was revamping the java look and feel by providing a new theme (OceanTheme). Love it or hate it, Ocean requires a bit more graphics support than the line primitives of yore. In order to make Ocean the default we needed to make sure performance was in line with the old theme (Steel). All of our internal tests show that we succeeded, Ocean performs as well and better in some cases, than Steel. How did we do this?
Before I get into the solution let's first look at how the gradients that Ocean makes such extensive use of are painted. The gradient is not a single gradient, but is made up of four distinct areas:
1. Gradient from color1 - color2
2. Solid rectangle of color2
3. Gradient from color2 back to color1
4. Gradient from color1 to color3
Here's a monsterously large button showing the distinct regions:

This gives a nice radial gradient and is the effect the designers were after. From the description it's pretty obvious this is way more expensive than a simple fillRect. So, how did we speed this up? Image caching! Chet wrote up a great article that in effect describes the approach we took. In a nutshell, we cache the expensive images (gradients, slider thumbs ...) in an offscreen buffer. To avoid taking up excessive amounts of memory we reference these images via SoftReferences. A SoftReference is a step up from a WeakReference in that the referenced object will be released when no one is referencing the object and memory is low. In other words, if memory is tight the image will be chucked. Perfect for this scenario. Additionally we directly use VolatileImages rather than BufferedImages. In this case a VolatileImage is good because it'll most likely live in video memory, and if the image is lost we can trivially recreate it.
We placed all this functionality into the package private abstract class javax.swing.plaf.metal.CachedPainter (in 1.6 this has been moved to sun.swing), take a look if you're curious. This class hides all the image management, and SoftReference trickyness from subclasses, a subclass only need override a single method to do the actual painting. CachedPainter makes use of varags to allow for seamless passing of arguments to the method responsible for the actual painting. It results in lossing some type safety, but it works.
One last thing, for compatability Ocean still uses bold fonts, but this can easily be turned off with the system property swing.boldMetal=false. Oh ya!
Special thank to Romain for helping with the image.
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Not a response to this post per se, but can anyone point out the easiest way to turn off bold metal in pre-1.5 JDKs?
Posted by: sumitkishore on September 06, 2005 at 03:03 PM
-
sumitkishore,
You have two options:
Replace all the UI defaults entries *.Font with a plain font, or plug in a custom MetalTheme that overrides the font based methods.
-Scott
Posted by: zixle on September 06, 2005 at 03:09 PM
-
Thank you for this awesome tip!
I am going to add a CachedPainter to my Look and Feel too. My L&F has lots of complex paint methods in it.
I tried a test panel with eleven JPushButton's on it. The whole panel roughly draws 30 percent faster, when the button backgrounds are drawn from the cache.
-Werner
Posted by: wrandelshofer on September 07, 2005 at 02:16 PM
|