Merge "Fix the filtershow activity to portrait" into gb-ub-photos-arches
diff --git a/jni/Android.mk b/jni/Android.mk
index 213663c..92789c1 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -34,7 +34,9 @@
                    filters/hsv.c \
                    filters/vibrance.c \
                    filters/geometry.c \
-                   filters/vignette.c
+                   filters/vignette.c \
+                   filters/redEyeMath.c \
+                   filters/redeye.c
 
 LOCAL_CFLAGS    += -ffast-math -O3 -funroll-loops
 LOCAL_ARM_MODE := arm
diff --git a/jni/filters/filters.h b/jni/filters/filters.h
index 954d02d..d8728f0 100644
--- a/jni/filters/filters.h
+++ b/jni/filters/filters.h
@@ -47,5 +47,6 @@
 
 extern void rgb2hsv( unsigned char *rgb,int rgbOff,unsigned short *hsv,int hsvOff);
 extern void hsv2rgb(unsigned short *hsv,int hsvOff,unsigned char  *rgb,int rgbOff);
-
+extern void filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect);
+extern double fastevalPoly(double *poly,int n, double x);
 #endif // FILTERS_H
diff --git a/jni/filters/hsv.c b/jni/filters/hsv.c
index af438f8..aabd053 100644
--- a/jni/filters/hsv.c
+++ b/jni/filters/hsv.c
@@ -17,128 +17,140 @@
 #include <math.h>
 #include "filters.h"
 
+double fastevalPoly(double *poly,int n, double x){
+
+    double f =x;
+    double sum = poly[0]+poly[1]*f;
+    int i;
+    for (i = 2; i < n; i++) {
+        f*=x;
+        sum += poly[i]*f;
+    }
+    return sum;
+}
+
 void rgb2hsv( unsigned char *rgb,int rgbOff,unsigned short *hsv,int hsvOff)
 {
-      int iMin,iMax,chroma;
-      int ABITS = 4;
-      int HSCALE = 256;
+    int iMin,iMax,chroma;
+    int ABITS = 4;
+    int HSCALE = 256;
 
-      int k1=255 << ABITS;
-      int k2=HSCALE << ABITS;
+    int k1=255 << ABITS;
+    int k2=HSCALE << ABITS;
 
-      int ri = rgb[rgbOff+0];
-      int gi = rgb[rgbOff+1];
-      int bi = rgb[rgbOff+2];
-      short rv,rs,rh;
+    int ri = rgb[rgbOff+0];
+    int gi = rgb[rgbOff+1];
+    int bi = rgb[rgbOff+2];
+    short rv,rs,rh;
 
-      if (ri > gi) {
-          iMax = MAX (ri, bi);
-          iMin = MIN (gi, bi);
-      } else {
-          iMax = MAX (gi, bi);
-          iMin = MIN (ri, bi);
-      }
-
-      chroma = iMax - iMin;
-      // set value
-      rv = (short)( iMax << ABITS);
-
-      // set saturation
-      if (rv == 0)
-        rs = 0;
-      else
-        rs = (short)((k1*chroma)/iMax);
-
-      // set hue
-      if (rs == 0)
-          rh = 0;
-      else {
-          if ( ri == iMax ) {
-            rh  = (short)( (k2*(6*chroma+gi - bi))/(6*chroma));
-            if (rh >= k2) rh -= k2;
-          } else if (gi  == iMax)
-            rh  = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma));
-          else // (bi == iMax )
-            rh  = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma));
-      }
-      hsv[hsvOff+0] = rv;
-      hsv[hsvOff+1] = rs;
-      hsv[hsvOff+2] = rh;
+    if (ri > gi) {
+        iMax = MAX (ri, bi);
+        iMin = MIN (gi, bi);
+    } else {
+        iMax = MAX (gi, bi);
+        iMin = MIN (ri, bi);
     }
 
- void hsv2rgb(unsigned short *hsv,int hsvOff, unsigned char *rgb,int rgbOff)
- {
-   int ABITS = 4;
-   int HSCALE = 256;
-   int m;
-   int H,X,ih,is,iv;
-   int k1=255<<ABITS;
-   int k2=HSCALE<<ABITS;
-   int k3=1<<(ABITS-1);
-   int rr=0;
-   int rg=0;
-   int rb=0;
-   short cv = hsv[hsvOff+0];
-   short cs = hsv[hsvOff+1];
-   short ch = hsv[hsvOff+2];
+    chroma = iMax - iMin;
+    // set value
+    rv = (short)( iMax << ABITS);
 
-   // set chroma and min component value m
-   //chroma = ( cv * cs )/k1;
-   //m = cv - chroma;
-   m = ((int)cv*(k1 - (int)cs ))/k1;
+    // set saturation
+    if (rv == 0)
+        rs = 0;
+    else
+        rs = (short)((k1*chroma)/iMax);
 
-   // chroma  == 0 <-> cs == 0 --> m=cv
-   if (cs == 0) {
-       rb = ( rg = ( rr =( cv >> ABITS) ));
-   } else {
-     ih=(int)ch;
-     is=(int)cs;
-     iv=(int)cv;
+    // set hue
+    if (rs == 0)
+        rh = 0;
+    else {
+        if ( ri == iMax ) {
+            rh  = (short)( (k2*(6*chroma+gi - bi))/(6*chroma));
+            if (rh >= k2) rh -= k2;
+        } else if (gi  == iMax)
+            rh  = (short)( (k2*(2*chroma+bi - ri ))/(6*chroma));
+        else // (bi == iMax )
+                    rh  = (short)( (k2*(4*chroma+ri - gi ))/(6*chroma));
+    }
+    hsv[hsvOff+0] = rv;
+    hsv[hsvOff+1] = rs;
+    hsv[hsvOff+2] = rh;
+}
 
-     H = (6*ih)/k2;
-     X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ;
+void hsv2rgb(unsigned short *hsv,int hsvOff, unsigned char *rgb,int rgbOff)
+{
+    int ABITS = 4;
+    int HSCALE = 256;
+    int m;
+    int H,X,ih,is,iv;
+    int k1=255<<ABITS;
+    int k2=HSCALE<<ABITS;
+    int k3=1<<(ABITS-1);
+    int rr=0;
+    int rg=0;
+    int rb=0;
+    short cv = hsv[hsvOff+0];
+    short cs = hsv[hsvOff+1];
+    short ch = hsv[hsvOff+2];
 
-     // removing additional bits --> unit8
-     X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS;
-     m=m >> ABITS;
+    // set chroma and min component value m
+    //chroma = ( cv * cs )/k1;
+    //m = cv - chroma;
+    m = ((int)cv*(k1 - (int)cs ))/k1;
 
-     // ( chroma + m ) --> cv ;
-     cv=(short) (cv >> ABITS);
-     switch (H) {
-         case 0:
-           rr = cv;
-           rg = X;
-           rb = m;
-           break;
-         case 1:
-           rr = X;
-           rg = cv;
-           rb = m;
-           break;
-         case 2:
-           rr = m;
-           rg = cv;
-           rb = X;
-           break;
-         case 3:
-           rr = m;
-           rg = X;
-           rb = cv;
-           break;
-         case 4:
-           rr = X;
-           rg = m;
-           rb = cv;
-           break;
-         case 5:
-           rr = cv;
-           rg = m ;
-           rb = X;
-           break;
-     }
-   }
-   rgb[rgbOff+0] =  rr;
-   rgb[rgbOff+1] =  rg;
-   rgb[rgbOff+2] =  rb;
- }
+    // chroma  == 0 <-> cs == 0 --> m=cv
+    if (cs == 0) {
+        rb = ( rg = ( rr =( cv >> ABITS) ));
+    } else {
+        ih=(int)ch;
+        is=(int)cs;
+        iv=(int)cv;
+
+        H = (6*ih)/k2;
+        X = ((iv*is)/k2)*(k2- abs(6*ih- 2*(H>>1)*k2 - k2)) ;
+
+        // removing additional bits --> unit8
+        X=( (X+iv*(k1 - is ))/k1 + k3 ) >> ABITS;
+        m=m >> ABITS;
+
+        // ( chroma + m ) --> cv ;
+        cv=(short) (cv >> ABITS);
+        switch (H) {
+        case 0:
+            rr = cv;
+            rg = X;
+            rb = m;
+            break;
+        case 1:
+            rr = X;
+            rg = cv;
+            rb = m;
+            break;
+        case 2:
+            rr = m;
+            rg = cv;
+            rb = X;
+            break;
+        case 3:
+            rr = m;
+            rg = X;
+            rb = cv;
+            break;
+        case 4:
+            rr = X;
+            rg = m;
+            rb = cv;
+            break;
+        case 5:
+            rr = cv;
+            rg = m ;
+            rb = X;
+            break;
+        }
+    }
+    rgb[rgbOff+0] =  rr;
+    rgb[rgbOff+1] =  rg;
+    rgb[rgbOff+2] =  rb;
+}
 
diff --git a/jni/filters/redEyeMath.c b/jni/filters/redEyeMath.c
new file mode 100644
index 0000000..26f3f76
--- /dev/null
+++ b/jni/filters/redEyeMath.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+int value(int r, int g, int b) {
+    return MAX(r, MAX(g, b));
+}
+
+int isRed(unsigned char *src, int p) {
+    int b = src[p + 2];
+    int g = src[p + 1];
+    int r = src[p];
+    int max = MAX(g, b);
+
+    return ((r * 100 / (max + 2) > 160) & (max < 80));
+}
+
+void findPossible(unsigned char *src, unsigned char *mask, int iw, int ih,
+        short *rect) {
+    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
+    int y, x;
+
+    for (y = 0; y < recH; y++) {
+        int sy = (recY + y) * iw;
+        for (x = 0; x < recW; x++) {
+            int p = (recX + x + sy) * 4;
+
+            int b = src[p + 2];
+            int g = src[p + 1];
+            int r = src[p];
+            mask[x + y * recW] = (
+                    mask[x + y * recW] > 0 && (value(r, g, b) > 240) ? 1 : 0);
+
+        }
+
+    }
+}
+
+void findReds(unsigned char *src, unsigned char *mask, int iw, int ih,
+        short *rect) {
+    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
+    int y, x;
+
+    for (y = 0; y < recH; y++) {
+        int sy = (recY + y) * iw;
+        for (x = 0; x < recW; x++) {
+            int p = (recX + x + sy) * 4;
+
+            mask[x + y * recW] = ((isRed(src, p)) ? 1 : 0);
+
+        }
+
+    }
+}
+
+void dialateMaskIfRed(unsigned char *src, int iw, int ih, unsigned char *mask,
+        unsigned char *out, short *rect) {
+    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
+    int y, x;
+
+    for (y = 1; y < recH - 1; y++) {
+        int row = recW * y;
+        int sy = (recY + y) * iw;
+        for (x = 1; x < recW - 1; x++) {
+            int p = (recX + x + sy) * 4;
+
+            char b = (mask[row + x] | mask[row + x + 1] | mask[row + x - 1]
+                    | mask[row + x - recW] | mask[row + x + recW]);
+            if (b != 0 && isRed(src, p))
+                out[row + x] = 1;
+            else
+                out[row + x] = mask[row + x];
+        }
+    }
+}
+
+void dialateMask(unsigned char *mask, unsigned char *out, int mw, int mh) {
+    int y, x;
+    for (y = 1; y < mh - 1; y++) {
+        int row = mw * y;
+        for (x = 1; x < mw - 1; x++) {
+            out[row + x] = (mask[row + x] | mask[row + x + 1]
+                    | mask[row + x - 1] | mask[row + x - mw]
+                    | mask[row + x + mw]);
+        }
+    }
+}
+
+void stuff(int r, int g, int b, unsigned char *img, int off) {
+    img[off + 2] = b;
+    img[off + 1] = g;
+    img[off] = r;
+}
+
+void filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect) {
+    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
+    unsigned char *mask1 = (unsigned char *) malloc(recW * recH);
+    unsigned char *mask2 = (unsigned char *)malloc(recW*recH);
+    int QUE_LEN = 100;
+    int y, x, i;
+
+    rect[0] = MAX(rect[0],0);
+    rect[1] = MAX(rect[1],0);
+    rect[2] = MIN(rect[2]+rect[0],iw)-rect[0];
+    rect[3] = MIN(rect[3]+rect[1],ih)-rect[1];
+
+    findReds(src, mask2, iw, ih, rect);
+    dialateMask(mask2, mask1, recW, recH);
+    dialateMask(mask1, mask2, recW, recH);
+    dialateMask(mask2, mask1, recW, recH);
+    dialateMask(mask1, mask2, recW, recH);
+    findPossible(src, mask2, iw, ih, rect);
+    dialateMask(mask2, mask1, recW, recH);
+
+    for (i = 0; i < 12; i++) {
+        dialateMaskIfRed(src, iw, ih, mask1, mask2, rect);
+        dialateMaskIfRed(src, iw, ih, mask2, mask1, rect);
+    }
+    dialateMask(mask1, mask2, recW, recH);
+    dialateMask(mask2, mask1, recW, recH);
+
+    for (y = 3; y < recH-3; y++) {
+        int sy = (recY + y) * iw;
+        for (x = 3; x < recW-3; x++) {
+            int p = (recX + x + sy) * 4;
+
+            int b = src[p + 2];
+            int g = src[p + 1];
+            int r = src[p];
+
+            if (mask1[x + y * recW] != 0) {
+                int m = MAX(g,b);
+                float rr = (r - m) / (float) m;
+                if (rr > .7f && g < 60 && b < 60) {
+                    dest[p + 2] = (0);
+                    dest[p + 1] = (0);
+                    dest[p] = (0);
+                } else {
+                    if (mask2[x + y * recW] != 0) {
+                        stuff(r / 2, g / 2, b / 2, dest, p);
+                    } else
+                        stuff((2 * r) / 3, (2 * g) / 3, (2 * b) / 3, dest, p);
+                }
+
+            } else
+                stuff(r, g, b, dest, p);
+
+            //dest[p + 2] = dest[p + 1] =dest[p]=src[p];
+        }
+
+    }
+
+    free(mask1);
+    free(mask2);
+}
+
+
diff --git a/jni/filters/redeye.c b/jni/filters/redeye.c
new file mode 100644
index 0000000..9a358dd
--- /dev/null
+++ b/jni/filters/redeye.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+ void JNIFUNCF(ImageFilterRedEye, nativeApplyFilter, jobject bitmap, jint width, jint height, jshortArray vrect)
+ {
+     char* destination = 0;
+     AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+     unsigned char * rgb = (unsigned char * )destination;
+     short* rect = (*env)->GetShortArrayElements(env, vrect,0);
+
+     filterRedEye(rgb,rgb,width,height,rect);
+
+     (*env)->ReleaseShortArrayElements(env, vrect, rect, 0);
+     AndroidBitmap_unlockPixels(env, bitmap);
+ }
diff --git a/jni/filters/shadows.c b/jni/filters/shadows.c
index f812b93..38d64c8 100644
--- a/jni/filters/shadows.c
+++ b/jni/filters/shadows.c
@@ -17,23 +17,41 @@
 #include <math.h>
 #include "filters.h"
 
- void JNIFUNCF(ImageFilterShadows, nativeApplyFilter, jobject bitmap, jint width, jint height, jshortArray vlut)
- {
-     char* destination = 0;
-     AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
-     unsigned char * rgb = (unsigned char * )destination;
-     int i;
-     int len = width * height * 4;
-     short* lut = (*env)->GetShortArrayElements(env, vlut,0);
-     unsigned short * hsv = (unsigned short *)malloc(3*sizeof(short));
-     for (i = 0; i < len; i+=4)
-     {
-       rgb2hsv(rgb,i,hsv,0);
-       hsv[0] = lut[hsv[0]];
-       hsv2rgb(hsv,0, rgb,i);
-     }
+void JNIFUNCF(ImageFilterShadows, nativeApplyFilter, jobject bitmap, jint width, jint height, float scale){
+    double shadowFilterMap[] = {
+            -0.00591,  0.0001,
+             1.16488,  0.01668,
+            -0.18027, -0.06791,
+            -0.12625,  0.09001,
+             0.15065, -0.03897
+    };
 
-     (*env)->ReleaseShortArrayElements(env, vlut, lut, 0);
-     free(hsv);
-     AndroidBitmap_unlockPixels(env, bitmap);
- }
+    char* destination = 0;
+    AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+    unsigned char * rgb = (unsigned char * )destination;
+    int i;
+    double s = (scale>=0)?scale:scale/5;
+    int len = width * height * 4;
+
+    double *poly = (double *) malloc(5*sizeof(double));
+    for (i = 0; i < 5; i++) {
+        poly[i] = fastevalPoly(shadowFilterMap+i*2,2 , s);
+    }
+
+    unsigned short * hsv = (unsigned short *)malloc(3*sizeof(short));
+
+    for (i = 0; i < len; i+=4)
+    {
+        rgb2hsv(rgb,i,hsv,0);
+
+        double v = (fastevalPoly(poly,5,hsv[0]/4080.)*4080);
+        if (v>4080) v = 4080;
+        hsv[0] = (unsigned short) ((v>0)?v:0);
+
+        hsv2rgb(hsv,0, rgb,i);
+    }
+
+    free(poly);
+    free(hsv);
+    AndroidBitmap_unlockPixels(env, bitmap);
+}
diff --git a/res/layout/filtershow_activity.xml b/res/layout/filtershow_activity.xml
index a3e4023..7915371 100644
--- a/res/layout/filtershow_activity.xml
+++ b/res/layout/filtershow_activity.xml
@@ -271,6 +271,12 @@
                         style="@style/FilterShowBottomButton"
                         android:src="@drawable/filtershow_button_geometry_flip"
                         android:text="@string/flip" />
+
+                    <com.android.gallery3d.filtershow.ui.ImageButtonTitle
+                        android:id="@+id/redEyeButton"
+                        style="@style/FilterShowBottomButton"
+                        android:src="@drawable/photoeditor_effect_redeye"
+                        android:text="@string/redeye" />
                 </LinearLayout>
             </HorizontalScrollView>
 
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml
index 9fd5b92..5023566 100644
--- a/res/values/filtershow_strings.xml
+++ b/res/values/filtershow_strings.xml
@@ -81,6 +81,8 @@
     <string name="curvesRGB">Curves</string>
     <!--  Label for the vignette filter button [CHAR LIMIT=15] -->
     <string name="vignette">Vignette</string>
+    <!-- Name for the photo effect that removes redeye. [CHAR LIMIT=15] -->
+    <string name="redeye">Red Eye</string>
 
     <!--  Labels for the curves tool -->
 
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
index 7ded725..3a97c53 100644
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -303,7 +303,7 @@
                                 mMediaSet.getMediaItemCount() > 1) {
                             mPhotoView.switchToImage(1);
                         } else {
-                            mPhotoView.setFilmMode(false);
+                            mPhotoView.setFilmMode(mPhotoView.canUndo());
                             stayedOnCamera = true;
                         }
 
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 664b67f..6d61441 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -202,6 +202,7 @@
         mPanelController.addComponent(mColorsButton, findViewById(R.id.tintButton));
         mPanelController.addComponent(mColorsButton, findViewById(R.id.exposureButton));
         mPanelController.addComponent(mColorsButton, findViewById(R.id.shadowRecoveryButton));
+        mPanelController.addComponent(mColorsButton, findViewById(R.id.redEyeButton));
 
         mPanelController.addView(findViewById(R.id.resetEffect));
         mPanelController.addView(findViewById(R.id.applyEffect));
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index dbb6f27..0c50046 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -13,6 +13,7 @@
 import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
 import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
 import com.android.gallery3d.filtershow.filters.ImageFilterHue;
+import com.android.gallery3d.filtershow.filters.ImageFilterRedEye;
 import com.android.gallery3d.filtershow.filters.ImageFilterSaturated;
 import com.android.gallery3d.filtershow.filters.ImageFilterShadows;
 import com.android.gallery3d.filtershow.filters.ImageFilterSharpen;
@@ -368,6 +369,9 @@
         if (filter == null && name.equalsIgnoreCase("Shadows")) {
             filter = setImagePreset(new ImageFilterShadows(), name);
         }
+        if (filter == null && name.equalsIgnoreCase("Redeye")) {
+            filter = setImagePreset(new ImageFilterRedEye(), name);
+        }
         mMasterImage.setCurrentFilter(filter);
     }
 
@@ -480,6 +484,13 @@
                 ensureFilter("Shadows");
                 break;
             }
+            case R.id.redEyeButton: {
+                mCurrentImage = showImageView(R.id.imageShow).setShowControls(true);
+                mUtilityPanel.setEffectName("Redeye");
+                mUtilityPanel.setGeometryEffect(false);
+                ensureFilter("Redeye");
+                break;
+            }
             case R.id.resetEffect: {
                 mCurrentImage.resetParameter();
                 break;
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
new file mode 100644
index 0000000..c990c18
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java
@@ -0,0 +1,42 @@
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class ImageFilterRedEye extends ImageFilter {
+    private static final String TAG = "ImageFilterRedEye";
+
+
+    public ImageFilterRedEye() {
+        mName = "Redeye";
+
+    }
+
+    @Override
+    public ImageFilter clone() throws CloneNotSupportedException {
+        ImageFilterRedEye filter = (ImageFilterRedEye) super.clone();
+
+        return filter;
+    }
+
+    native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short []matrix);
+
+    public void apply(Bitmap bitmap) {
+        int w = bitmap.getWidth();
+        int h = bitmap.getHeight();
+        float p = mParameter;
+        float value = p;
+        int box = Math.min(w, h);
+        int sizex = Math.min((int)((p+100)*box/400),w/2);
+        int sizey = Math.min((int)((p+100)*box/800),h/2);
+
+        short [] rect = new short[]{
+                (short) (w/2-sizex),(short) (w/2-sizey),
+                (short) (2*sizex),(short) (2*sizey)};
+
+        nativeApplyFilter(bitmap, w, h, rect);
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
index 9b379a1..ee62196 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
@@ -3,61 +3,28 @@
 
 import android.graphics.Bitmap;
 
-import com.android.gallery3d.filtershow.ui.ControlPoint;
-import com.android.gallery3d.filtershow.ui.Spline;
-
 public class ImageFilterShadows extends ImageFilter {
-    private final float SHADOW = .1f;
-    private final float MID = .5f;
-    private final float HIGHLIGHT = .9f;
-
-    private final float []baseX = {0f,SHADOW,MID,HIGHLIGHT,1f};
-    private final float []baseY = {0f,SHADOW,MID,HIGHLIGHT,1f};
 
     public ImageFilterShadows() {
         mName = "Shadows";
 
     }
-    short [] calcMap(){
-        Spline sp = new Spline();
-        for (int i = 0; i < baseX.length; i++) {
-            sp.addPoint(baseX[i], baseY[i]);
-        }
-        int max = 4080;
-        int w = 40800;
-        float []px = new float[w+1];
-        float []py = new float[w+1];
-        short []vlut = new short[4080+1];
-        for (int i = 0; i < px.length; i++) {
-            float t = i/(float)(w);
 
-            ControlPoint p = sp.getPoint(t);
-            px[i] = p.x;
-            py[i] = p.y;
-        }
-        for (int i = 0; i < py.length; i++) {
-            short x = (short)Math.min(4080,Math.max(0,((int)(px[i]*max))));
-            short y = (short)Math.min(4082,Math.max(0,((int)(py[i]*max))));
-            vlut[x] = y;
-        }
-        return vlut;
-    }
     @Override
     public ImageFilter clone() throws CloneNotSupportedException {
         ImageFilterShadows filter = (ImageFilterShadows) super.clone();
         return filter;
     }
 
-    native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short []valMap);
+    native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float  factor);
 
     @Override
     public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
         float p = mParameter;
-        baseY[1] = (float)(SHADOW*Math.pow(4, mParameter/100.));
 
-        nativeApplyFilter(bitmap, w, h, calcMap());
+        nativeApplyFilter(bitmap, w, h, p);
         return bitmap;
     }
 }
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index 3fa13cf..7097dff 100644
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -630,7 +630,7 @@
             if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return;
 
             if (mWantPictureCenterCallbacks && mPositionController.isCenter()) {
-                mListener.onPictureCenter(mIsCamera && !canUndoLastPicture());
+                mListener.onPictureCenter(mIsCamera);
             }
         }
 
@@ -1375,13 +1375,8 @@
         }
     }
 
-    // Returns true if the user can still undo the deletion of the last
-    // remaining picture in the album. We need to check this and delay making
-    // the camera preview full screen, otherwise the user won't have a chance to
-    // undo it.
-    private boolean canUndoLastPicture() {
-        if ((mUndoBarState & UNDO_BAR_SHOW) == 0) return false;
-        return (mUndoBarState & UNDO_BAR_DELETE_LAST) != 0;
+    public boolean canUndo() {
+        return (mUndoBarState & UNDO_BAR_SHOW) != 0;
     }
 
     ////////////////////////////////////////////////////////////////////////////