Add a way to disable image inlining on a per-image basis.
Patch by: bobv
Review by: rjrjr

Review at http://gwt-code-reviews.appspot.com/1451809


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10268 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/resources/client/ImageResource.java b/user/src/com/google/gwt/resources/client/ImageResource.java
index 31aefde..0266048 100644
--- a/user/src/com/google/gwt/resources/client/ImageResource.java
+++ b/user/src/com/google/gwt/resources/client/ImageResource.java
@@ -56,6 +56,14 @@
     int height() default -1;
 
     /**
+     * Set to {@code true} to require the ImageResource to be downloaded as a
+     * separate resource at runtime. Specifically, this will disable the use of
+     * {@code data:} URLs or other bundling optimizations for the image. This
+     * can be used for infrequently-displayed images.
+     */
+    boolean preventInlining() default false;
+
+    /**
      * This option affects the image bundling optimization to allow the image to
      * be used with the {@link CssResource} {@code @sprite} rule where
      * repetition of the image is desired.
diff --git a/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java b/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java
index 9f53c5d..1d86ad1 100644
--- a/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/ImageResourceGenerator.java
@@ -191,9 +191,11 @@
    * bytes should be associated with.
    */
   static class BundleKey extends StringKey {
-    private static String key(ResourceContext context,
-        ImageResourceDeclaration image) {
-      if (image.getRepeatStyle() == RepeatStyle.Both) {
+    private static String key(ImageResourceDeclaration image, boolean isExternal) {
+      if (isExternal) {
+        return "External: " + image.get();
+      }
+      if (image.isPreventInlining() || image.getRepeatStyle() == RepeatStyle.Both) {
         return "Unbundled: " + image.get();
       }
       return "Arranged: " + image.getRepeatStyle().toString();
@@ -201,13 +203,8 @@
 
     private final RepeatStyle repeatStyle;
 
-    public BundleKey(ImageResourceDeclaration image) {
-      super("External: " + image.get());
-      this.repeatStyle = image.getRepeatStyle();
-    }
-
-    public BundleKey(ResourceContext context, ImageResourceDeclaration image) {
-      super(key(context, image));
+    public BundleKey(ImageResourceDeclaration image, boolean isExternal) {
+      super(key(image, isExternal));
       this.repeatStyle = image.getRepeatStyle();
     }
 
@@ -314,7 +311,7 @@
           String.class.getCanonicalName());
 
       String contentsExpression = context.deploy(
-          localized.getUrl(), null, false);
+          localized.getUrl(), null, image.isPreventInlining());
       normalContentsFieldName = fields.define(stringType, "externalImage",
           contentsExpression, true, true);
 
@@ -326,7 +323,7 @@
 
         byte[] rtlData = ImageBundleBuilder.toPng(logger, rect);
         String rtlContentsUrlExpression = context.deploy(image.getName()
-            + "_rtl.png", "image/png", rtlData, false);
+            + "_rtl.png", "image/png", rtlData, image.isPreventInlining());
         rtlContentsFieldName = fields.define(stringType, "externalImage_rtl",
             rtlContentsUrlExpression, true, true);
       }
@@ -384,6 +381,10 @@
     public boolean isFlipRtl() {
       return options == null ? false : options.flipRtl();
     }
+    
+    public boolean isPreventInlining() {
+      return options == null ? false : options.preventInlining();
+    }
   }
 
   /**
@@ -474,7 +475,7 @@
     sw.println('"' + name + "\",");
 
     ImageResourceDeclaration image = new ImageResourceDeclaration(method);
-    DisplayedImage bundle = getImage(context, image);
+    DisplayedImage bundle = getImage(image);
     ImageRect rect = bundle.getImageRect(image);
     assert rect != null : "No ImageRect ever computed for " + name;
 
@@ -542,10 +543,13 @@
     LocalizedImage localizedImage;
     ImageRect rect;
     try {
-      BundledImage bundledImage = (BundledImage) getImage(context, image);
+      BundledImage bundledImage = (BundledImage) getImage(image);
       localizedImage = bundledImage.addImage(logger, context, image);
       rect = bundledImage.getImageRect(image);
       displayed = bundledImage;
+      if (image.isPreventInlining()) {
+        cannotBundle = true;
+      }
     } catch (CannotBundleImageException e) {
       cannotBundle = true;
       localizedImage = e.getLocalizedImage();
@@ -587,7 +591,7 @@
       }
       ExternalImage externalImage = new ExternalImage(image, localizedImage,
           rect);
-      shared.externalImages.put(new BundleKey(image), externalImage);
+      shared.externalImages.put(new BundleKey(image, true), externalImage);
       displayed = externalImage;
     }
 
@@ -620,14 +624,13 @@
     return sb.toString();
   }
 
-  private DisplayedImage getImage(ResourceContext context,
-      ImageResourceDeclaration image) {
-    DisplayedImage toReturn = shared.externalImages.get(new BundleKey(image));
+  private DisplayedImage getImage(ImageResourceDeclaration image) {
+    DisplayedImage toReturn = shared.externalImages.get(new BundleKey(image, true));
     if (toReturn != null) {
       return toReturn;
     }
 
-    BundleKey key = new BundleKey(context, image);
+    BundleKey key = new BundleKey(image, false);
     toReturn = shared.bundledImages.get(key);
     if (toReturn == null) {
       BundledImage bundled = new BundledImage();
diff --git a/user/test/com/google/gwt/resources/client/ImageResourceTest.java b/user/test/com/google/gwt/resources/client/ImageResourceTest.java
index ac3e9ef..07f1420 100644
--- a/user/test/com/google/gwt/resources/client/ImageResourceTest.java
+++ b/user/test/com/google/gwt/resources/client/ImageResourceTest.java
@@ -31,7 +31,17 @@
  * Tests ImageResource generation.
  */
 public class ImageResourceTest extends GWTTestCase {
-  static interface Resources extends ClientBundle {
+  interface ExternalResources extends ClientBundle {
+    @ImageOptions(preventInlining = true)
+    @Source("16x16.png")
+    ImageResource i16x16();
+
+    @ImageOptions(preventInlining = true)
+    @Source("32x32.png")
+    ImageResource i32x32();    
+  }
+
+  interface Resources extends ClientBundle {
     @Source("animated.gif")
     ImageResource animated();
 
@@ -166,4 +176,22 @@
     assertEquals(128, r.scaledUp().getWidth());
     assertEquals(128, r.scaledUp().getHeight());
   }
+
+  public void testPreventInlining() {
+    ExternalResources r = GWT.create(ExternalResources.class);
+    ImageResource a = r.i16x16();
+    ImageResource b = r.i32x32();
+
+    // Should never be a data URL
+    assertFalse(a.getURL().startsWith("data:"));
+    assertFalse(b.getURL().startsWith("data:"));
+    // Should be fetched from different URLs
+    assertFalse(a.getURL().equals(b.getURL()));
+
+    // No image packing
+    assertEquals(0, a.getTop());
+    assertEquals(0, a.getLeft());
+    assertEquals(0, b.getTop());
+    assertEquals(0, b.getLeft());
+  }
 }