Merge "Remove ImageCache from PhotoProvider in favor of MediaCache." into gb-ub-photos-bryce
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 409f1e3..8c5d7a4 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -18,10 +18,12 @@
 
 import android.app.ActionBar;
 import android.app.Activity;
+import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.app.WallpaperManager;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -94,6 +96,8 @@
     private String mAction = "";
     MasterImage mMasterImage = null;
 
+    private static final long LIMIT_SUPPORTS_HIGHRES = 134217728; // 128Mb
+
     public static final String TINY_PLANET_ACTION = "com.android.camera.action.TINY_PLANET";
     public static final String LAUNCH_FULLSCREEN = "launch-fullscreen";
     public static final int MAX_BMAP_IN_INTENT = 990000;
@@ -487,7 +491,11 @@
             pipeline.setOriginal(largeBitmap);
             float previewScale = (float) largeBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
             pipeline.setPreviewScaleFactor(previewScale);
-
+            Bitmap highresBitmap = mImageLoader.getOriginalBitmapHighres();
+            if (highresBitmap != null) {
+                float highResPreviewScale = (float) highresBitmap.getWidth() / (float) mImageLoader.getOriginalBounds().width();
+                pipeline.setHighResPreviewScaleFactor(highResPreviewScale);
+            }
             pipeline.turnOnPipeline(true);
             MasterImage.getImage().setOriginalGeometry(largeBitmap);
             mLoadBitmapTask = null;
@@ -879,6 +887,12 @@
         mMasterImage.setStateAdapter(mImageStateAdapter);
         mMasterImage.setActivity(this);
         mMasterImage.setImageLoader(mImageLoader);
+
+        if (Runtime.getRuntime().maxMemory() > LIMIT_SUPPORTS_HIGHRES) {
+            mMasterImage.setSupportsHighRes(true);
+        } else {
+            mMasterImage.setSupportsHighRes(false);
+        }
     }
 
     // //////////////////////////////////////////////////////////////////////////////
@@ -972,7 +986,30 @@
     @Override
     public void onBackPressed() {
         if (mPanelController.onBackPressed()) {
-            saveImage();
+            if (detectSpecialExitCases()) {
+                saveImage();
+            } else if(!mImageShow.hasModifications()) {
+                done();
+            } else {
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setMessage(R.string.unsaved).setTitle(R.string.save_before_exit);
+                builder.setPositiveButton(R.string.save_and_exit, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        saveImage();
+                    }
+                });
+                builder.setNeutralButton(R.string.exit, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        done();
+                    }
+                });
+                builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                    }
+                });
+
+                AlertDialog dialog = builder.show();
+            }
         }
     }
 
@@ -1026,27 +1063,7 @@
     private boolean mOutputted = false;
 
     public void saveImage() {
-        if (mCropExtras != null) {
-            if (mCropExtras.getExtraOutput() != null) {
-                mSaveToExtraUri = true;
-                mOutputted = true;
-            }
-            if (mCropExtras.getSetAsWallpaper()) {
-                mSaveAsWallpaper = true;
-                mOutputted = true;
-            }
-            if (mCropExtras.getReturnData()) {
-
-                mReturnAsExtra = true;
-                mOutputted = true;
-            }
-
-            if (mOutputted) {
-                mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
-                showSavingProgress(null);
-                mImageShow.returnFilteredResult(this);
-            }
-        }
+        handleSpecialExitCases();
         if (!mOutputted) {
             if (mImageShow.hasModifications()) {
                 // Get the name of the album, to which the image will be saved
@@ -1061,6 +1078,33 @@
         }
     }
 
+    public boolean detectSpecialExitCases() {
+        return mCropExtras != null && (mCropExtras.getExtraOutput() != null
+                || mCropExtras.getSetAsWallpaper() || mCropExtras.getReturnData());
+    }
+
+    public void handleSpecialExitCases() {
+        if (mCropExtras != null) {
+            if (mCropExtras.getExtraOutput() != null) {
+                mSaveToExtraUri = true;
+                mOutputted = true;
+            }
+            if (mCropExtras.getSetAsWallpaper()) {
+                mSaveAsWallpaper = true;
+                mOutputted = true;
+            }
+            if (mCropExtras.getReturnData()) {
+                mReturnAsExtra = true;
+                mOutputted = true;
+            }
+            if (mOutputted) {
+                mImageShow.getImagePreset().mGeoData.setUseCropExtrasFlag(true);
+                showSavingProgress(null);
+                mImageShow.returnFilteredResult(this);
+            }
+        }
+    }
+
     public void onFilteredResult(Bitmap filtered) {
         Intent intent = new Intent();
         intent.putExtra(CropExtras.KEY_CROPPED_RECT, mImageShow.getImageCropBounds());
diff --git a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java
index bc1d450..ecfdaba 100644
--- a/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java
+++ b/src/com/android/gallery3d/filtershow/cache/CachingPipeline.java
@@ -54,6 +54,7 @@
 
     private volatile GeometryMetadata mPreviousGeometry = null;
     private volatile float mPreviewScaleFactor = 1.0f;
+    private volatile float mHighResPreviewScaleFactor = 1.0f;
     private volatile String mName = "";
 
     public CachingPipeline(FiltersManager filtersManager, String name) {
@@ -112,6 +113,7 @@
             }
             mPreviousGeometry = null;
             mPreviewScaleFactor = 1.0f;
+            mHighResPreviewScaleFactor = 1.0f;
 
             destroyPixelAllocations();
         }
@@ -149,13 +151,20 @@
         if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
             return "PARTIAL_RENDERING";
         }
+        if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
+            return "HIGHRES_RENDERING";
+        }
         return "UNKNOWN TYPE!";
     }
 
-    private void setupEnvironment(ImagePreset preset) {
+    private void setupEnvironment(ImagePreset preset, boolean highResPreview) {
         mEnvironment.setCachingPipeline(this);
         mEnvironment.setFiltersManager(mFiltersManager);
-        mEnvironment.setScaleFactor(mPreviewScaleFactor);
+        if (highResPreview) {
+            mEnvironment.setScaleFactor(mHighResPreviewScaleFactor);
+        } else {
+            mEnvironment.setScaleFactor(mPreviewScaleFactor);
+        }
         mEnvironment.setQuality(ImagePreset.QUALITY_PREVIEW);
         mEnvironment.setImagePreset(preset);
     }
@@ -164,7 +173,7 @@
         mOriginalBitmap = bitmap;
         Log.v(LOGTAG,"setOriginal, size " + bitmap.getWidth() + " x " + bitmap.getHeight());
         ImagePreset preset = MasterImage.getImage().getPreset();
-        setupEnvironment(preset);
+        setupEnvironment(preset, false);
         updateOriginalAllocation(preset);
     }
 
@@ -210,7 +219,8 @@
             if (getRenderScriptContext() == null) {
                 return;
             }
-            if ((request.getType() != RenderingRequest.PARTIAL_RENDERING
+            if (((request.getType() != RenderingRequest.PARTIAL_RENDERING
+                    && request.getType() != RenderingRequest.HIGHRES_RENDERING)
                     && request.getBitmap() == null)
                     || request.getImagePreset() == null) {
                 return;
@@ -222,7 +232,8 @@
 
             Bitmap bitmap = request.getBitmap();
             ImagePreset preset = request.getImagePreset();
-            setupEnvironment(preset);
+            setupEnvironment(preset,
+                    request.getType() != RenderingRequest.HIGHRES_RENDERING);
             mFiltersManager.freeFilterResources(preset);
 
             if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
@@ -239,6 +250,12 @@
                 }
             }
 
+            if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
+                ImageLoader loader = MasterImage.getImage().getImageLoader();
+                bitmap = loader.getOriginalBitmapHighres();
+                bitmap = preset.applyGeometry(bitmap, mEnvironment);
+            }
+
             if (request.getType() == RenderingRequest.FULL_RENDERING
                     || request.getType() == RenderingRequest.GEOMETRY_RENDERING
                     || request.getType() == RenderingRequest.FILTERS_RENDERING) {
@@ -261,7 +278,8 @@
             if (request.getType() == RenderingRequest.FULL_RENDERING
                     || request.getType() == RenderingRequest.FILTERS_RENDERING
                     || request.getType() == RenderingRequest.ICON_RENDERING
-                    || request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+                    || request.getType() == RenderingRequest.PARTIAL_RENDERING
+                    || request.getType() == RenderingRequest.HIGHRES_RENDERING) {
                 Bitmap bmp = preset.apply(bitmap, mEnvironment);
                 request.setBitmap(bmp);
                 mFiltersManager.freeFilterResources(preset);
@@ -274,7 +292,7 @@
             if (getRenderScriptContext() == null) {
                 return bitmap;
             }
-            setupEnvironment(preset);
+            setupEnvironment(preset, false);
             mEnvironment.setQuality(ImagePreset.QUALITY_FINAL);
             mEnvironment.setScaleFactor(1.0f);
             mFiltersManager.freeFilterResources(preset);
@@ -289,7 +307,7 @@
             if (getRenderScriptContext() == null) {
                 return bitmap;
             }
-            setupEnvironment(preset);
+            setupEnvironment(preset, false);
             mEnvironment.setQuality(ImagePreset.QUALITY_PREVIEW);
             mFiltersManager.freeFilterResources(preset);
             bitmap = preset.applyGeometry(bitmap, mEnvironment);
@@ -309,7 +327,7 @@
 
             String thread = Thread.currentThread().getName();
             long time = System.currentTimeMillis();
-            setupEnvironment(preset);
+            setupEnvironment(preset, false);
             mFiltersManager.freeFilterResources(preset);
 
             Bitmap resizedOriginalBitmap = mResizedOriginalBitmap;
@@ -346,11 +364,14 @@
         return buffer.checkRepaintNeeded();
     }
 
-
     public void setPreviewScaleFactor(float previewScaleFactor) {
         mPreviewScaleFactor = previewScaleFactor;
     }
 
+    public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
+        mHighResPreviewScaleFactor = highResPreviewScaleFactor;
+    }
+
     public synchronized boolean isInitialized() {
         return getRenderScriptContext() != null && mOriginalBitmap != null;
     }
diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
index 1ba6e95..a8c8d7b 100644
--- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
+++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
@@ -47,9 +47,23 @@
     private final static int COMPUTE_PRESET = 2;
     private final static int COMPUTE_RENDERING_REQUEST = 3;
     private final static int COMPUTE_PARTIAL_RENDERING_REQUEST = 4;
+    private final static int COMPUTE_HIGHRES_RENDERING_REQUEST = 5;
 
     private volatile boolean mHasUnhandledPreviewRequest = false;
 
+    private String getType(int value) {
+        if (value == COMPUTE_RENDERING_REQUEST) {
+            return "COMPUTE_RENDERING_REQUEST";
+        }
+        if (value == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+            return "COMPUTE_PARTIAL_RENDERING_REQUEST";
+        }
+        if (value == COMPUTE_HIGHRES_RENDERING_REQUEST) {
+            return "COMPUTE_HIGHRES_RENDERING_REQUEST";
+        }
+        return "UNKNOWN TYPE";
+    }
+
     private Handler mProcessingHandler = null;
     private final Handler mUIHandler = new Handler() {
         @Override
@@ -89,12 +103,13 @@
                 break;
             }
             case COMPUTE_RENDERING_REQUEST:
-            case COMPUTE_PARTIAL_RENDERING_REQUEST: {
-                if (msg.what == COMPUTE_PARTIAL_RENDERING_REQUEST) {
-                    if (mProcessingHandler.hasMessages(COMPUTE_PARTIAL_RENDERING_REQUEST)) {
-                        return false;
-                    }
+            case COMPUTE_PARTIAL_RENDERING_REQUEST:
+            case COMPUTE_HIGHRES_RENDERING_REQUEST: {
+
+                if (DEBUG) {
+                    Log.v(LOGTAG, "Compute Request: " + getType(msg.what));
                 }
+
                 RenderingRequest request = (RenderingRequest) msg.obj;
                 mAccessoryPipeline.render(request);
                 Message uimsg = mUIHandler.obtainMessage(NEW_RENDERING_REQUEST);
@@ -140,9 +155,16 @@
         if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
             type = COMPUTE_PARTIAL_RENDERING_REQUEST;
         }
+        if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
+            type = COMPUTE_HIGHRES_RENDERING_REQUEST;
+        }
         Message msg = mProcessingHandler.obtainMessage(type);
         msg.obj = request;
-        if (type == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+        if (type == COMPUTE_PARTIAL_RENDERING_REQUEST
+                || type == COMPUTE_HIGHRES_RENDERING_REQUEST) {
+            if (mProcessingHandler.hasMessages(msg.what)) {
+                mProcessingHandler.removeMessages(msg.what);
+            }
             mProcessingHandler.sendMessageDelayed(msg, HIRES_DELAY);
         } else {
             mProcessingHandler.sendMessage(msg);
@@ -174,6 +196,11 @@
         mPreviewPipeline.setPreviewScaleFactor(previewScaleFactor);
     }
 
+    public void setHighResPreviewScaleFactor(float highResPreviewScaleFactor) {
+        mAccessoryPipeline.setHighResPreviewScaleFactor(highResPreviewScaleFactor);
+        mPreviewPipeline.setHighResPreviewScaleFactor(highResPreviewScaleFactor);
+    }
+
     public static synchronized void reset() {
         sPipeline.mAccessoryPipeline.reset();
         sPipeline.mPreviewPipeline.reset();
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index a6a0bcf..b4e98e1 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -42,6 +42,7 @@
 import com.android.gallery3d.filtershow.HistoryAdapter;
 import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.imageshow.ImageShow;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 import com.android.gallery3d.filtershow.tools.BitmapTask;
 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
@@ -67,6 +68,7 @@
     private final Vector<ImageShow> mListeners = new Vector<ImageShow>();
     private Bitmap mOriginalBitmapSmall = null;
     private Bitmap mOriginalBitmapLarge = null;
+    private Bitmap mOriginalBitmapHighres = null;
     private Bitmap mBackgroundBitmap = null;
 
     private final ZoomCache mZoomCache = new ZoomCache();
@@ -97,6 +99,8 @@
     private Rect mOriginalBounds = null;
     private static int mZoomOrientation = ORI_NORMAL;
 
+    static final int MAX_BITMAP_DIM = 900;
+
     private ReentrantLock mLoadingLock = new ReentrantLock();
 
     public ImageLoader(FilterShowActivity activity, Context context) {
@@ -127,6 +131,13 @@
             mLoadingLock.unlock();
             return false;
         }
+        if (MasterImage.getImage().supportsHighRes()) {
+            int highresPreviewSize = mOriginalBitmapLarge.getWidth() * 2;
+            if (highresPreviewSize > mOriginalBounds.width()) {
+                highresPreviewSize = mOriginalBounds.width();
+            }
+            mOriginalBitmapHighres = loadScaledBitmap(uri, highresPreviewSize, false);
+        }
         updateBitmaps();
         mLoadingLock.unlock();
         return true;
@@ -197,6 +208,9 @@
         if (mOrientation > 1) {
             mOriginalBitmapSmall = rotateToPortrait(mOriginalBitmapSmall, mOrientation);
             mOriginalBitmapLarge = rotateToPortrait(mOriginalBitmapLarge, mOrientation);
+            if (mOriginalBitmapHighres != null) {
+                mOriginalBitmapHighres = rotateToPortrait(mOriginalBitmapHighres, mOrientation);
+            }
         }
         mZoomOrientation = mOrientation;
         warnListeners();
@@ -272,9 +286,11 @@
         return null;
     }
 
-    static final int MAX_BITMAP_DIM = 900;
-
     private Bitmap loadScaledBitmap(Uri uri, int size) {
+        return loadScaledBitmap(uri, size, true);
+    }
+
+    private Bitmap loadScaledBitmap(Uri uri, int size, boolean enforceSize) {
         InputStream is = null;
         try {
             is = mContext.getContentResolver().openInputStream(uri);
@@ -291,7 +307,12 @@
 
             int scale = 1;
             while (true) {
-                if (width_tmp <= MAX_BITMAP_DIM && height_tmp <= MAX_BITMAP_DIM) {
+                if (width_tmp <= 2 || height_tmp <= 2) {
+                    break;
+                }
+                if (!enforceSize
+                        || (width_tmp <= MAX_BITMAP_DIM
+                        && height_tmp <= MAX_BITMAP_DIM)) {
                     if (width_tmp / 2 < size || height_tmp / 2 < size) {
                         break;
                     }
@@ -336,6 +357,10 @@
         return mOriginalBitmapLarge;
     }
 
+    public Bitmap getOriginalBitmapHighres() {
+        return mOriginalBitmapHighres;
+    }
+
     public void addListener(ImageShow imageShow) {
         mLoadingLock.lock();
         if (!mListeners.contains(imageShow)) {
diff --git a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
index 138abb0..3416ddf 100644
--- a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
+++ b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
@@ -31,6 +31,7 @@
     private ImagePreset mImagePreset = null;
     private ImagePreset mOriginalImagePreset = null;
     private RenderingRequestCaller mCaller = null;
+    private float mScaleFactor = 1.0f;
     private Rect mBounds = null;
     private Rect mDestination = null;
     private int mType = FULL_RENDERING;
@@ -39,6 +40,7 @@
     public static final int GEOMETRY_RENDERING = 2;
     public static final int ICON_RENDERING = 3;
     public static final int PARTIAL_RENDERING = 4;
+    public static final int HIGHRES_RENDERING = 5;
     private static final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
 
     public static void post(Bitmap source, ImagePreset preset, int type, RenderingRequestCaller caller) {
@@ -47,8 +49,10 @@
 
     public static void post(Bitmap source, ImagePreset preset, int type,
                             RenderingRequestCaller caller, Rect bounds, Rect destination) {
-        if ((type != PARTIAL_RENDERING && source == null) || preset == null || caller == null) {
-            Log.v(LOGTAG, "something null: source: " + source + " or preset: " + preset + " or caller: " + caller);
+        if (((type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) && source == null)
+                || preset == null || caller == null) {
+            Log.v(LOGTAG, "something null: source: " + source
+                    + " or preset: " + preset + " or caller: " + caller);
             return;
         }
         RenderingRequest request = new RenderingRequest();
@@ -59,7 +63,7 @@
             CachingPipeline pipeline = new CachingPipeline(
                     FiltersManager.getManager(), "Icon");
             bitmap = pipeline.renderGeometryIcon(source, preset);
-        } else if (type != PARTIAL_RENDERING) {
+        } else if (type != PARTIAL_RENDERING && type != HIGHRES_RENDERING) {
             bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig);
         }
 
@@ -67,6 +71,7 @@
         ImagePreset passedPreset = new ImagePreset(preset);
         passedPreset.setImageLoader(MasterImage.getImage().getImageLoader());
         request.setOriginalImagePreset(preset);
+        request.setScaleFactor(MasterImage.getImage().getScaleFactor());
 
         if (type == PARTIAL_RENDERING) {
             request.setBounds(bounds);
@@ -136,6 +141,14 @@
         mBounds = bounds;
     }
 
+    public void setScaleFactor(float scaleFactor) {
+        mScaleFactor = scaleFactor;
+    }
+
+    public float getScaleFactor() {
+        return mScaleFactor;
+    }
+
     public Rect getDestination() {
         return mDestination;
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index b92460d..7e0e25d 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -63,7 +63,8 @@
         representation.setShowEditingControls(showEditingControls());
         representation.setShowParameterValue(showParameterValue());
         representation.setShowUtilityPanel(showUtilityPanel());
-        representation.mTempRepresentation = null;
+        representation.mTempRepresentation =
+                mTempRepresentation != null ? mTempRepresentation.clone() : null;
         if (DEBUG) {
             Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">");
         }
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 38dc177..1ab9e54 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -323,7 +323,11 @@
         canvas.scale(scaleFactor, scaleFactor, cx, cy);
         canvas.translate(translation.x, translation.y);
         drawBackground(canvas);
-        drawImage(canvas, getFilteredImage());
+        drawImage(canvas, getFilteredImage(), true);
+        Bitmap highresPreview = MasterImage.getImage().getHighresImage();
+        if (highresPreview != null) {
+            drawImage(canvas, highresPreview, false);
+        }
         canvas.restore();
 
         if (showTitle() && getImagePreset() != null) {
@@ -374,7 +378,7 @@
         return MasterImage.getImage().getFilteredImage();
     }
 
-    public void drawImage(Canvas canvas, Bitmap image) {
+    public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) {
         if (image != null) {
             Rect s = new Rect(0, 0, image.getWidth(),
                     image.getHeight());
@@ -389,7 +393,9 @@
 
             Rect d = new Rect((int) tx, (int) ty, (int) (w + tx),
                     (int) (h + ty));
-            mImageBounds = d;
+            if (updateBounds) {
+                mImageBounds = d;
+            }
             canvas.drawBitmap(image, s, d, mPaint);
         }
     }
@@ -420,7 +426,7 @@
             Rect d = new Rect(mImageBounds.left, mImageBounds.top,
                     mImageBounds.left + px, mImageBounds.top + py);
             canvas.clipRect(d);
-            drawImage(canvas, image);
+            drawImage(canvas, image, false);
             Paint paint = new Paint();
             paint.setColor(Color.BLACK);
             paint.setStrokeWidth(3);
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 993f5d5..94573bc 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -19,15 +19,12 @@
 import android.graphics.*;
 import android.os.Handler;
 import android.os.Message;
-import android.util.Log;
 
-import android.util.Log;
 import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.HistoryAdapter;
 import com.android.gallery3d.filtershow.ImageStateAdapter;
 import com.android.gallery3d.filtershow.cache.*;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
-import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 
@@ -42,6 +39,8 @@
     private static int sIconSeedSize = 128;
     private static float sHistoryPreviewSize = 128.0f;
 
+    private boolean mSupportsHighRes = false;
+
     private ImageFilter mCurrentFilter = null;
     private ImagePreset mPreset = null;
     private ImagePreset mGeometryOnlyPreset = null;
@@ -52,6 +51,7 @@
     private Bitmap mGeometryOnlyBitmap = null;
     private Bitmap mFiltersOnlyBitmap = null;
     private Bitmap mPartialBitmap = null;
+    private Bitmap mHighresBitmap = null;
 
     private ImageLoader mLoader = null;
     private HistoryAdapter mHistory = null;
@@ -96,6 +96,10 @@
         return sMasterImage;
     }
 
+    public void setSupportsHighRes(boolean value) {
+        mSupportsHighRes = value;
+    }
+
     public static void setIconSeedSize(int iconSeedSize) {
         sIconSeedSize = iconSeedSize;
     }
@@ -253,6 +257,10 @@
         return mPartialBitmap;
     }
 
+    public Bitmap getHighresImage() {
+        return mHighresBitmap;
+    }
+
     public void notifyObservers() {
         for (ImageShow observer : mObservers) {
             observer.invalidate();
@@ -283,7 +291,6 @@
             }
         }
         invalidatePreview();
-        needsUpdateFullResPreview();
         mActivity.enableSave(hasModifications());
     }
 
@@ -307,17 +314,27 @@
         }
     }
 
+    public void invalidateHighresPreview() {
+        if (mHighresBitmap != null) {
+            mHighresBitmap = null;
+            notifyObservers();
+        }
+    }
+
     public void invalidatePreview() {
         mFilteredPreview.invalidate();
         invalidatePartialPreview();
-        needsUpdateFullResPreview();
+        invalidateHighresPreview();
+        needsUpdatePartialPreview();
+        needsUpdateHighResPreview();
         FilteringPipeline.getPipeline().updatePreviewBuffer();
     }
 
     public void setImageShowSize(int w, int h) {
         if (mImageShowSize.x != w || mImageShowSize.y != h) {
             mImageShowSize.set(w, h);
-            needsUpdateFullResPreview();
+            needsUpdatePartialPreview();
+            needsUpdateHighResPreview();
         }
     }
 
@@ -345,7 +362,15 @@
         return invert;
     }
 
-    public void needsUpdateFullResPreview() {
+    public void needsUpdateHighResPreview() {
+        if (!mSupportsHighRes) {
+            return;
+        }
+        RenderingRequest.post(null, mPreset, RenderingRequest.HIGHRES_RENDERING, this);
+        invalidateHighresPreview();
+    }
+
+    public void needsUpdatePartialPreview() {
         if (!mPreset.canDoPartialRendering()) {
             invalidatePartialPreview();
             return;
@@ -372,10 +397,16 @@
         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
             mFiltersOnlyBitmap = request.getBitmap();
         }
-        if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+        if (request.getType() == RenderingRequest.PARTIAL_RENDERING
+                && request.getScaleFactor() == getScaleFactor()) {
             mPartialBitmap = request.getBitmap();
             notifyObservers();
         }
+        if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
+            mHighresBitmap = request.getBitmap();
+            notifyObservers();
+        }
+
         if (request.getType() == RenderingRequest.ICON_RENDERING) {
             // History preview images
             ImagePreset preset = request.getOriginalImagePreset();
@@ -426,7 +457,7 @@
     public void setTranslation(Point translation) {
         mTranslation.x = translation.x;
         mTranslation.y = translation.y;
-        needsUpdateFullResPreview();
+        needsUpdatePartialPreview();
     }
 
     public Point getOriginalTranslation() {
@@ -441,7 +472,7 @@
     public void resetTranslation() {
         mTranslation.x = 0;
         mTranslation.y = 0;
-        needsUpdateFullResPreview();
+        needsUpdatePartialPreview();
     }
 
     public Bitmap getThumbnailBitmap() {
@@ -455,4 +486,8 @@
     public void setMaxScaleFactor(float maxScaleFactor) {
         mMaxScaleFactor = maxScaleFactor;
     }
+
+    public boolean supportsHighRes() {
+        return mSupportsHighRes;
+    }
 }