Merge "Remove FilteringPipeline" into gb-ub-photos-carlsbad
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cb4bc18..c110e79 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -492,9 +492,6 @@
     <!-- The title of the menu item which display online help in browser. [CHAR LIMIT=20]-->
     <string name="help">Help</string>
 
-    <!-- Web address for gallery help.  DO NOT TRANSLATE -->
-    <string name="help_url_gallery_main" translatable="false"></string>
-
     <!-- The tilte of a dialog showing there is no external storage. [CHAR LIMIT=20] -->
     <string name="no_external_storage_title">No Storage</string>
 
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java
index 368e5c0..1eebdb5 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java
@@ -48,18 +48,19 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterBasicRepresentation representation = (FilterBasicRepresentation) super.clone();
-        representation.setMinimum(getMinimum());
-        representation.setMaximum(getMaximum());
-        representation.setValue(getValue());
-        if (mLogVerbose) {
-            Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">");
-        }
+    public FilterRepresentation copy() {
+        FilterBasicRepresentation representation = new FilterBasicRepresentation(getName(),0,0,0);
+        copyAllParameters(representation);
         return representation;
     }
 
     @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
     public void useParametersFrom(FilterRepresentation a) {
         if (a instanceof FilterBasicRepresentation) {
             FilterBasicRepresentation representation = (FilterBasicRepresentation) a;
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java
index d9e2117..94eb206 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java
@@ -40,16 +40,18 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        setFilterClass(ImageFilterParametricBorder.class);
-        FilterColorBorderRepresentation representation = (FilterColorBorderRepresentation) super.clone();
-        representation.setName(getName());
-        representation.setColor(getColor());
-        representation.setBorderSize(getBorderSize());
-        representation.setBorderRadius(getBorderRadius());
+    public FilterRepresentation copy() {
+        FilterColorBorderRepresentation representation = new FilterColorBorderRepresentation(0,0,0);
+        copyAllParameters(representation);
         return representation;
     }
 
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
     public void useParametersFrom(FilterRepresentation a) {
         if (a instanceof FilterColorBorderRepresentation) {
             FilterColorBorderRepresentation representation = (FilterColorBorderRepresentation) a;
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java
new file mode 100644
index 0000000..345c2f1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.RectF;
+import android.util.JsonReader;
+import android.util.JsonWriter;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorCrop;
+
+import java.io.IOException;
+
+public class FilterCropRepresentation extends FilterRepresentation {
+    public static final String SERIALIZATION_NAME = "CROP";
+    public static final String[] BOUNDS = {
+            "C0", "C1", "C2", "C3", "I0", "I1", "I2", "I3"
+    };
+    private static final String TAG = FilterCropRepresentation.class.getSimpleName();
+
+    RectF mCrop = new RectF();
+    RectF mImage = new RectF();
+
+    public FilterCropRepresentation(RectF crop, RectF image) {
+        super(FilterCropRepresentation.class.getSimpleName());
+        setSerializationName(SERIALIZATION_NAME);
+        setShowParameterValue(true);
+        setFilterClass(FilterCropRepresentation.class);
+        setFilterType(FilterRepresentation.TYPE_GEOMETRY);
+        setTextId(R.string.crop);
+        setEditorId(EditorCrop.ID);
+        setCrop(crop);
+        setImage(image);
+    }
+
+    public FilterCropRepresentation(FilterCropRepresentation m) {
+        this(m.getCrop(), m.getImage());
+    }
+
+    public FilterCropRepresentation() {
+        this(new RectF(), new RectF());
+    }
+
+    public void set(FilterCropRepresentation r) {
+        mCrop.set(r.mCrop);
+        mImage.set(r.mImage);
+    }
+
+    public RectF getCrop() {
+        return new RectF(mCrop);
+    }
+
+    public void getCrop(RectF r) {
+        r.set(mCrop);
+    }
+
+    public void setCrop(RectF crop) {
+        if (crop == null) {
+            throw new IllegalArgumentException("Argument to setCrop is null");
+        }
+        mCrop.set(crop);
+    }
+
+    public RectF getImage() {
+        return new RectF(mImage);
+    }
+
+    public void getImage(RectF r) {
+        r.set(mImage);
+    }
+
+    public void setImage(RectF image) {
+        if (image == null) {
+            throw new IllegalArgumentException("Argument to setImage is null");
+        }
+        mImage.set(image);
+    }
+
+    @Override
+    public boolean allowsSingleInstanceOnly() {
+        return true;
+    }
+
+    @Override
+    public FilterRepresentation copy(){
+        return new FilterCropRepresentation(this);
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        if (!(representation instanceof FilterCropRepresentation)) {
+            throw new IllegalArgumentException("calling copyAllParameters with incompatible types!");
+        }
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        if (!(a instanceof FilterCropRepresentation)) {
+            throw new IllegalArgumentException("calling useParametersFrom with incompatible types!");
+        }
+        setCrop(((FilterCropRepresentation) a).mCrop);
+        setImage(((FilterCropRepresentation) a).mImage);
+    }
+
+    @Override
+    public boolean isNil() {
+        return mCrop.equals(mImage);
+    }
+
+    @Override
+    public void serializeRepresentation(JsonWriter writer) throws IOException {
+        writer.beginObject();
+        writer.name(BOUNDS[0]).value(mCrop.left);
+        writer.name(BOUNDS[1]).value(mCrop.top);
+        writer.name(BOUNDS[2]).value(mCrop.right);
+        writer.name(BOUNDS[3]).value(mCrop.bottom);
+        writer.name(BOUNDS[4]).value(mImage.left);
+        writer.name(BOUNDS[5]).value(mImage.top);
+        writer.name(BOUNDS[6]).value(mImage.right);
+        writer.name(BOUNDS[7]).value(mImage.bottom);
+        writer.endObject();
+    }
+
+    @Override
+    public void deSerializeRepresentation(JsonReader reader) throws IOException {
+        reader.beginObject();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            if (BOUNDS[0].equals(name)) {
+                mCrop.left = (float) reader.nextDouble();
+            } else if (BOUNDS[1].equals(name)) {
+                mCrop.top = (float) reader.nextDouble();
+            } else if (BOUNDS[2].equals(name)) {
+                mCrop.right = (float) reader.nextDouble();
+            } else if (BOUNDS[3].equals(name)) {
+                mCrop.bottom = (float) reader.nextDouble();
+            } else if (BOUNDS[4].equals(name)) {
+                mImage.left = (float) reader.nextDouble();
+            } else if (BOUNDS[5].equals(name)) {
+                mImage.top = (float) reader.nextDouble();
+            } else if (BOUNDS[6].equals(name)) {
+                mImage.right = (float) reader.nextDouble();
+            } else if (BOUNDS[7].equals(name)) {
+                mImage.bottom = (float) reader.nextDouble();
+            } else {
+                reader.skipValue();
+            }
+        }
+        reader.endObject();
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
index 569ead9..a264f44 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
@@ -33,10 +33,16 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterCurvesRepresentation rep = new FilterCurvesRepresentation();
-        rep.useParametersFrom(this);
-        return rep;
+    public FilterRepresentation copy() {
+        FilterCurvesRepresentation representation = new FilterCurvesRepresentation();
+        copyAllParameters(representation);
+        return representation;
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
     }
 
     @Override
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java
index 9c986a6..ac0cb74 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java
@@ -18,6 +18,19 @@
 
 public class FilterDirectRepresentation extends FilterRepresentation {
 
+    @Override
+    public FilterRepresentation copy() {
+        FilterDirectRepresentation representation = new FilterDirectRepresentation(getName());
+        copyAllParameters(representation);
+        return representation;
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
     public FilterDirectRepresentation(String name) {
         super(name);
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
index dcc325d..977dbea 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
@@ -74,12 +74,19 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterDrawRepresentation representation = (FilterDrawRepresentation) super.clone();
+    public FilterRepresentation copy() {
+        FilterDrawRepresentation representation = new FilterDrawRepresentation();
+        copyAllParameters(representation);
         return representation;
     }
 
     @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
     public boolean isNil() {
         return getDrawing().isEmpty();
     }
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
index a7efbca..e5a6fdd 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
@@ -43,15 +43,19 @@
     }
 
     @Override
-    public synchronized FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterFxRepresentation representation = (FilterFxRepresentation) super.clone();
-        representation.setName(getName());
-        representation.setBitmapResource(getBitmapResource());
-        representation.setNameResource(getNameResource());
+    public FilterRepresentation copy() {
+        FilterFxRepresentation representation = new FilterFxRepresentation(getName(),0,0);
+        copyAllParameters(representation);
         return representation;
     }
 
     @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
     public synchronized void useParametersFrom(FilterRepresentation a) {
         if (a instanceof FilterFxRepresentation) {
             FilterFxRepresentation representation = (FilterFxRepresentation) a;
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java
index c32f7cc..f310a2b 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java
@@ -37,13 +37,19 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterImageBorderRepresentation representation = (FilterImageBorderRepresentation) super.clone();
-        representation.setName(getName());
-        representation.setDrawableResource(getDrawableResource());
+    public FilterRepresentation copy() {
+        FilterImageBorderRepresentation representation =
+                new FilterImageBorderRepresentation(mDrawableResource);
+        copyAllParameters(representation);
         return representation;
     }
 
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
     public void useParametersFrom(FilterRepresentation a) {
         if (a instanceof FilterImageBorderRepresentation) {
             FilterImageBorderRepresentation representation = (FilterImageBorderRepresentation) a;
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
new file mode 100644
index 0000000..0acf70e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.util.JsonReader;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorFlip;
+
+import java.io.IOException;
+
+public class FilterMirrorRepresentation extends FilterRepresentation {
+    public static final String SERIALIZATION_NAME = "MIRROR";
+    private static final String SERIALIZATION_MIRROR_VALUE = "value";
+    private static final String TAG = FilterMirrorRepresentation.class.getSimpleName();
+
+    Mirror mMirror = Mirror.NONE;
+
+    public enum Mirror {
+        NONE('N'), VERTICAL('V'), HORIZONTAL('H'), BOTH('B');
+        char mValue;
+
+        private Mirror(char value) {
+            mValue = value;
+        }
+
+        public char value() {
+            return mValue;
+        }
+
+        public static Mirror fromValue(char value) {
+            switch (value) {
+                case 'N':
+                    return NONE;
+                case 'V':
+                    return VERTICAL;
+                case 'H':
+                    return HORIZONTAL;
+                case 'B':
+                    return BOTH;
+                default:
+                    return null;
+            }
+        }
+    }
+
+    public FilterMirrorRepresentation(Mirror mirror) {
+        super(FilterMirrorRepresentation.class.getSimpleName());
+        setSerializationName(SERIALIZATION_NAME);
+        setShowParameterValue(true);
+        setFilterClass(FilterMirrorRepresentation.class);
+        setFilterType(FilterRepresentation.TYPE_GEOMETRY);
+        setTextId(R.string.mirror);
+        setEditorId(EditorFlip.ID);
+        setMirror(mirror);
+    }
+
+    public FilterMirrorRepresentation(FilterMirrorRepresentation m) {
+        this(m.getMirror());
+    }
+
+    public FilterMirrorRepresentation() {
+        this(Mirror.NONE);
+    }
+
+    public Mirror getMirror() {
+        return mMirror;
+    }
+
+    public void set(FilterMirrorRepresentation r) {
+        mMirror = r.mMirror;
+    }
+
+    public void setMirror(Mirror mirror) {
+        if (mirror == null) {
+            throw new IllegalArgumentException("Argument to setMirror is null");
+        }
+        mMirror = mirror;
+    }
+
+    @Override
+    public boolean allowsSingleInstanceOnly() {
+        return true;
+    }
+
+    @Override
+    public FilterRepresentation copy() {
+        return new FilterMirrorRepresentation(this);
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        if (!(representation instanceof FilterMirrorRepresentation)) {
+            throw new IllegalArgumentException("calling copyAllParameters with incompatible types!");
+        }
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        if (!(a instanceof FilterMirrorRepresentation)) {
+            throw new IllegalArgumentException("calling useParametersFrom with incompatible types!");
+        }
+        setMirror(((FilterMirrorRepresentation) a).getMirror());
+    }
+
+    @Override
+    public boolean isNil() {
+        return mMirror == Mirror.NONE;
+    }
+
+    @Override
+    public void serializeRepresentation(JsonWriter writer) throws IOException {
+        writer.beginObject();
+        writer.name(SERIALIZATION_MIRROR_VALUE).value(mMirror.value());
+        writer.endObject();
+    }
+
+    @Override
+    public void deSerializeRepresentation(JsonReader reader) throws IOException {
+        boolean unset = true;
+        reader.beginObject();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            if (SERIALIZATION_MIRROR_VALUE.equals(name)) {
+                Mirror r = Mirror.fromValue((char) reader.nextInt());
+                if (r != null) {
+                    setMirror(r);
+                    unset = false;
+                }
+            } else {
+                reader.skipValue();
+            }
+        }
+        if (unset) {
+            Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME);
+        }
+        reader.endObject();
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java
index aa52893..9bd1699 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java
@@ -31,11 +31,12 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterPointRepresentation representation = (FilterPointRepresentation) super
-                .clone();
-        representation.mCandidates = (Vector<FilterPoint>) mCandidates.clone();
-        return representation;
+    public abstract FilterRepresentation copy();
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
     }
 
     public boolean hasCandidates() {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
index 8a87841..dd06a97 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java
@@ -34,6 +34,19 @@
         setOverlayOnly(true);
     }
 
+    @Override
+    public FilterRepresentation copy() {
+        FilterRedEyeRepresentation representation = new FilterRedEyeRepresentation();
+        copyAllParameters(representation);
+        return representation;
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
     public void addRect(RectF rect, RectF bounds) {
         Vector<RedEyeCandidate> intersects = new Vector<RedEyeCandidate>();
         for (int i = 0; i < getCandidates().size(); i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index e6018bb..5b33ffb 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -25,7 +25,7 @@
 import java.io.IOException;
 import java.util.ArrayList;
 
-public class FilterRepresentation implements Cloneable {
+public class FilterRepresentation {
     private static final String LOGTAG = "FilterRepresentation";
     private static final boolean DEBUG = false;
     private String mName;
@@ -45,15 +45,20 @@
     public static final byte TYPE_VIGNETTE = 4;
     public static final byte TYPE_NORMAL = 5;
     public static final byte TYPE_TINYPLANET = 6;
+    public static final byte TYPE_GEOMETRY = 7;
     protected static final String NAME_TAG = "Name";
 
     public FilterRepresentation(String name) {
         mName = name;
     }
 
-    @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterRepresentation representation = (FilterRepresentation) super.clone();
+    public FilterRepresentation copy(){
+        FilterRepresentation representation = new FilterRepresentation(mName);
+        representation.useParametersFrom(this);
+        return representation;
+    }
+
+    protected void copyAllParameters(FilterRepresentation representation) {
         representation.setName(getName());
         representation.setFilterClass(getFilterClass());
         representation.setFilterType(getFilterType());
@@ -65,10 +70,6 @@
         representation.setShowParameterValue(showParameterValue());
         representation.mSerializationName = mSerializationName;
 
-        if (DEBUG) {
-            Log.v(LOGTAG, "cloning from <" + this + "> to <" + representation + ">");
-        }
-        return representation;
     }
 
     public boolean equals(FilterRepresentation representation) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java
new file mode 100644
index 0000000..8f7d8eb
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.util.JsonReader;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorRotate;
+
+import java.io.IOException;
+
+public class FilterRotateRepresentation extends FilterRepresentation {
+    public static final String SERIALIZATION_NAME = "ROTATION";
+    public static final String SERIALIZATION_ROTATE_VALUE = "value";
+    private static final String TAG = FilterRotateRepresentation.class.getSimpleName();
+
+    Rotation mRotation = Rotation.ZERO;
+
+    public enum Rotation {
+        ZERO(0), NINETY(90), ONE_EIGHTY(180), TWO_SEVENTY(270);
+        private final int mValue;
+
+        private Rotation(int value) {
+            mValue = value;
+        }
+
+        public int value() {
+            return mValue;
+        }
+
+        public static Rotation fromValue(int value) {
+            switch (value) {
+                case 0:
+                    return ZERO;
+                case 90:
+                    return NINETY;
+                case 180:
+                    return ONE_EIGHTY;
+                case 270:
+                    return TWO_SEVENTY;
+                default:
+                    return null;
+            }
+        }
+    }
+
+    public FilterRotateRepresentation(Rotation rotation) {
+        super(FilterRotateRepresentation.class.getSimpleName());
+        setSerializationName(SERIALIZATION_NAME);
+        setShowParameterValue(true);
+        setFilterClass(FilterRotateRepresentation.class);
+        setFilterType(FilterRepresentation.TYPE_GEOMETRY);
+        setTextId(R.string.rotate);
+        setEditorId(EditorRotate.ID);
+        setRotation(rotation);
+    }
+
+    public FilterRotateRepresentation(FilterRotateRepresentation r) {
+        this(r.getRotation());
+    }
+
+    public FilterRotateRepresentation() {
+        this(Rotation.ZERO);
+    }
+
+    public Rotation getRotation() {
+        return mRotation;
+    }
+
+    public void set(FilterRotateRepresentation r) {
+        mRotation = r.mRotation;
+    }
+
+    public void setRotation(Rotation rotation) {
+        if (rotation == null) {
+            throw new IllegalArgumentException("Argument to setRotation is null");
+        }
+        mRotation = rotation;
+    }
+
+    @Override
+    public boolean allowsSingleInstanceOnly() {
+        return true;
+    }
+
+    @Override
+    public FilterRepresentation copy() {
+        return new FilterRotateRepresentation(this);
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        if (!(representation instanceof FilterRotateRepresentation)) {
+            throw new IllegalArgumentException("calling copyAllParameters with incompatible types!");
+        }
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        if (!(a instanceof FilterRotateRepresentation)) {
+            throw new IllegalArgumentException("calling useParametersFrom with incompatible types!");
+        }
+        setRotation(((FilterRotateRepresentation) a).getRotation());
+    }
+
+    @Override
+    public boolean isNil() {
+        return mRotation == Rotation.ZERO;
+    }
+
+    @Override
+    public void serializeRepresentation(JsonWriter writer) throws IOException {
+        writer.beginObject();
+        writer.name(SERIALIZATION_ROTATE_VALUE).value(mRotation.value());
+        writer.endObject();
+    }
+
+    @Override
+    public void deSerializeRepresentation(JsonReader reader) throws IOException {
+        boolean unset = true;
+        reader.beginObject();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            if (SERIALIZATION_ROTATE_VALUE.equals(name)) {
+                Rotation r = Rotation.fromValue(reader.nextInt());
+                if (r != null) {
+                    setRotation(r);
+                    unset = false;
+                }
+            } else {
+                reader.skipValue();
+            }
+        }
+        if (unset) {
+            Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME);
+        }
+        reader.endObject();
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java
new file mode 100644
index 0000000..a06216e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.util.JsonReader;
+import android.util.JsonWriter;
+import android.util.Log;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorStraighten;
+
+import java.io.IOException;
+
+public class FilterStraightenRepresentation extends FilterRepresentation {
+    public static final String SERIALIZATION_NAME = "STRAIGHTEN";
+    public static final String SERIALIZATION_STRAIGHTEN_VALUE = "value";
+    private static final String TAG = FilterStraightenRepresentation.class.getSimpleName();
+
+    float mStraighten;
+
+    public FilterStraightenRepresentation(float straighten) {
+        super(FilterStraightenRepresentation.class.getSimpleName());
+        setSerializationName(SERIALIZATION_NAME);
+        setShowParameterValue(true);
+        setFilterClass(FilterStraightenRepresentation.class);
+        setFilterType(FilterRepresentation.TYPE_GEOMETRY);
+        setTextId(R.string.straighten);
+        setEditorId(EditorStraighten.ID);
+        setStraighten(straighten);
+    }
+
+    public FilterStraightenRepresentation(FilterStraightenRepresentation s) {
+        this(s.getStraighten());
+    }
+
+    public FilterStraightenRepresentation() {
+        this(0);
+    }
+
+    public void set(FilterStraightenRepresentation r) {
+        mStraighten = r.mStraighten;
+    }
+
+    public float getStraighten() {
+        return mStraighten;
+    }
+
+    public void setStraighten(float straighten) {
+        if (!rangeCheck(straighten)) {
+            straighten = Math.min(Math.max(straighten, -45), 45);
+        }
+        mStraighten = straighten;
+    }
+
+    @Override
+    public boolean allowsSingleInstanceOnly() {
+        return true;
+    }
+
+    @Override
+    public FilterRepresentation copy() {
+        return new FilterStraightenRepresentation(this);
+    }
+
+    @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        if (!(representation instanceof FilterStraightenRepresentation)) {
+            throw new IllegalArgumentException("calling copyAllParameters with incompatible types!");
+        }
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        if (!(a instanceof FilterStraightenRepresentation)) {
+            throw new IllegalArgumentException("calling useParametersFrom with incompatible types!");
+        }
+        setStraighten(((FilterStraightenRepresentation) a).getStraighten());
+    }
+
+    @Override
+    public boolean isNil() {
+        return mStraighten == 0;
+    }
+
+    @Override
+    public void serializeRepresentation(JsonWriter writer) throws IOException {
+        writer.beginObject();
+        writer.name(SERIALIZATION_STRAIGHTEN_VALUE).value(mStraighten);
+        writer.endObject();
+    }
+
+    @Override
+    public void deSerializeRepresentation(JsonReader reader) throws IOException {
+        boolean unset = true;
+        reader.beginObject();
+        while (reader.hasNext()) {
+            String name = reader.nextName();
+            if (SERIALIZATION_STRAIGHTEN_VALUE.equals(name)) {
+                int s = reader.nextInt();
+                if (rangeCheck(s)) {
+                    setStraighten(s);
+                    unset = false;
+                }
+            } else {
+                reader.skipValue();
+            }
+        }
+        if (unset) {
+            Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME);
+        }
+        reader.endObject();
+    }
+
+    private boolean rangeCheck(float s) {
+        if (s < -45 || s > 45) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java
index b03751e..be18129 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java
@@ -37,15 +37,19 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterTinyPlanetRepresentation representation = (FilterTinyPlanetRepresentation) super
-                .clone();
-        representation.mAngle = mAngle;
-        representation.setZoom(getZoom());
+    public FilterRepresentation copy() {
+        FilterTinyPlanetRepresentation representation = new FilterTinyPlanetRepresentation();
+        copyAllParameters(representation);
         return representation;
     }
 
     @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
     public void useParametersFrom(FilterRepresentation a) {
         FilterTinyPlanetRepresentation representation = (FilterTinyPlanetRepresentation) a;
         super.useParametersFrom(a);
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
index 06a9953..b666e63 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java
@@ -51,16 +51,19 @@
     }
 
     @Override
-    public FilterRepresentation clone() throws CloneNotSupportedException {
-        FilterVignetteRepresentation representation = (FilterVignetteRepresentation) super
-                .clone();
-        representation.mCenterX = mCenterX;
-        representation.mCenterY = mCenterY;
-
+    public FilterRepresentation copy() {
+        FilterVignetteRepresentation representation = new FilterVignetteRepresentation();
+        copyAllParameters(representation);
         return representation;
     }
 
     @Override
+    protected void copyAllParameters(FilterRepresentation representation) {
+        super.copyAllParameters(representation);
+        representation.useParametersFrom(this);
+    }
+
+    @Override
     public void setCenter(float centerX, float centerY) {
         mCenterX = centerX;
         mCenterY = centerY;
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
index 2b9e370..26dce37 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
@@ -26,9 +26,13 @@
 import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
+import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterFxRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
 import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
@@ -61,33 +65,28 @@
     }
 
     public ImagePreset(ImagePreset source) {
-        try {
-            for (int i = 0; i < source.mFilters.size(); i++) {
-                FilterRepresentation representation = null;
-                FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i);
-                if (sourceRepresentation instanceof GeometryMetadata) {
-                    GeometryMetadata geoData = new GeometryMetadata();
-                    GeometryMetadata srcGeo = (GeometryMetadata) sourceRepresentation;
-                    geoData.set(srcGeo);
-                    representation = geoData;
-                } else {
-                    // TODO: get rid of clone()...
-                    representation = sourceRepresentation.clone();
-                }
-                addFilter(representation);
+
+        for (int i = 0; i < source.mFilters.size(); i++) {
+            FilterRepresentation representation = null;
+            FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i);
+            if (sourceRepresentation instanceof GeometryMetadata) {
+                GeometryMetadata geoData = new GeometryMetadata();
+                GeometryMetadata srcGeo = (GeometryMetadata) sourceRepresentation;
+                geoData.set(srcGeo);
+                representation = geoData;
+            } else {
+                representation = sourceRepresentation.copy();
             }
-        } catch (java.lang.CloneNotSupportedException e) {
-            Log.v(LOGTAG, "Exception trying to clone: " + e);
+            addFilter(representation);
         }
+
     }
 
     public FilterRepresentation getFilterRepresentation(int position) {
         FilterRepresentation representation = null;
-        try {
-            representation = mFilters.elementAt(position).clone();
-        } catch (CloneNotSupportedException e) {
-            e.printStackTrace();
-        }
+
+        representation = mFilters.elementAt(position).copy();
+
         return representation;
     }
 
@@ -129,11 +128,7 @@
         }
         FilterRepresentation representation = mFilters.elementAt(position);
         if (representation != null) {
-            try {
-                representation = representation.clone();
-            } catch (CloneNotSupportedException e) {
-                e.printStackTrace();
-            }
+            representation = representation.copy();
         }
         return representation;
     }
@@ -668,8 +663,17 @@
     }
 
     FilterRepresentation creatFilterFromName(String name) {
+        // TODO: move these to FiltersManager pattern.
         if (GeometryMetadata.SERIALIZATION_NAME.equalsIgnoreCase(name)) {
             return new GeometryMetadata();
+        } else if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
+            return new FilterRotateRepresentation();
+        } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) {
+            return new FilterMirrorRepresentation();
+        } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) {
+            return new FilterStraightenRepresentation();
+        } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) {
+            return new FilterCropRepresentation();
         }
         FiltersManager filtersManager = FiltersManager.getManager();
         return filtersManager.createFilterFromName(name);