Add inPreferQualityOverSpeed into BitmapFactory.Options.

The new field allows a developer to use a more accurate by
slightly slower IDCT method in JPEG decode. This in turns improves the
quality of the reconstructed image.

The field by default is not set and thus does not affect existing
applications.

Bug: 3238925
Change-Id: I93d55b7226e47a43e639325cd1a677694d6f2ee4
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 3b2406c..e72e2b6f 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -27,6 +27,7 @@
 jfieldID gOptions_purgeableFieldID;
 jfieldID gOptions_shareableFieldID;
 jfieldID gOptions_nativeAllocFieldID;
+jfieldID gOptions_preferQualityOverSpeedFieldID;
 jfieldID gOptions_widthFieldID;
 jfieldID gOptions_heightFieldID;
 jfieldID gOptions_mimeFieldID;
@@ -185,6 +186,7 @@
     bool isPurgeable = forcePurgeable ||
                         (allowPurgeable && optionsPurgeable(env, options));
     bool reportSizeToVM = optionsReportSizeToVM(env, options);
+    bool preferQualityOverSpeed = false;
     
     if (NULL != options) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
@@ -199,6 +201,8 @@
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+        preferQualityOverSpeed = env->GetBooleanField(options,
+                gOptions_preferQualityOverSpeedFieldID);
     }
 
     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
@@ -208,6 +212,7 @@
     
     decoder->setSampleSize(sampleSize);
     decoder->setDitherImage(doDither);
+    decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
 
     NinePatchPeeker     peeker(decoder);
     JavaPixelAllocator  javaAllocator(env, reportSizeToVM);
@@ -557,6 +562,8 @@
     gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
     gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
     gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z");
+    gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, gOptions_class,
+            "inPreferQualityOverSpeed", "Z");
     gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
     gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
     gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index f868434..9ae61bc 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -11,6 +11,7 @@
 extern jfieldID gOptions_purgeableFieldID;
 extern jfieldID gOptions_shareableFieldID;
 extern jfieldID gOptions_nativeAllocFieldID;
+extern jfieldID gOptions_preferQualityOverSpeedFieldID;
 extern jfieldID gOptions_widthFieldID;
 extern jfieldID gOptions_heightFieldID;
 extern jfieldID gOptions_mimeFieldID;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index bf18d55..91a8202 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -191,6 +191,7 @@
     int sampleSize = 1;
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
     bool doDither = true;
+    bool preferQualityOverSpeed = false;
 
     if (NULL != options) {
         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
@@ -202,9 +203,12 @@
         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+        preferQualityOverSpeed = env->GetBooleanField(options,
+                gOptions_preferQualityOverSpeedFieldID);
     }
 
     decoder->setDitherImage(doDither);
+    decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
     SkBitmap*           bitmap = new SkBitmap;
     SkAutoTDelete<SkBitmap>       adb(bitmap);
     AutoDecoderCancel   adc(options, decoder);
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index ea5ed6b..8450c3a 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -205,10 +205,21 @@
         public boolean inNativeAlloc;
 
         /**
+         * If inPreferQualityOverSpeed is set to true, the decoder will try to
+         * decode the reconstructed image to a higher quality even at the
+         * expense of the decoding speed. Currently the field only affects JPEG
+         * decode, in the case of which a more accurate, but slightly slower,
+         * IDCT method will be used instead.
+         * @hide
+         */
+        public boolean inPreferQualityOverSpeed;
+
+        /**
          * The resulting width of the bitmap, set independent of the state of
          * inJustDecodeBounds. However, if there is an error trying to decode,
          * outWidth will be set to -1.
          */
+
         public int outWidth;
 
         /**