Add Bitmap.CompressFormat#WEBP_LOSSY/LOSSLESS

Bug: 135133301
Test: Iadbd8cf3b69a150b9e38ad556392346e1bb27084

WEBP does not give clients explicit control of how to do their WEBP
encode. Add new formats that do. Update the docs for the existing
formats (and the new ones) to explain more precisely how quality is
interpreted.

Change-Id: I9583903c21ab2048fed8e7ed501ee8377ea5ba36
diff --git a/api/current.txt b/api/current.txt
index 8522034..51d93cf 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13732,7 +13732,9 @@
   public enum Bitmap.CompressFormat {
     enum_constant public static final android.graphics.Bitmap.CompressFormat JPEG;
     enum_constant public static final android.graphics.Bitmap.CompressFormat PNG;
-    enum_constant public static final android.graphics.Bitmap.CompressFormat WEBP;
+    enum_constant @Deprecated public static final android.graphics.Bitmap.CompressFormat WEBP;
+    enum_constant public static final android.graphics.Bitmap.CompressFormat WEBP_LOSSLESS;
+    enum_constant public static final android.graphics.Bitmap.CompressFormat WEBP_LOSSY;
   }
 
   public enum Bitmap.Config {
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 18a1b43..d204490 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -9,6 +9,7 @@
 #include "SkColorSpace.h"
 #include "GraphicsJNI.h"
 #include "SkStream.h"
+#include "SkWebpEncoder.h"
 
 #include "android_os_Parcel.h"
 #include "android_util_Binder.h"
@@ -512,27 +513,14 @@
 enum JavaEncodeFormat {
     kJPEG_JavaEncodeFormat = 0,
     kPNG_JavaEncodeFormat = 1,
-    kWEBP_JavaEncodeFormat = 2
+    kWEBP_JavaEncodeFormat = 2,
+    kWEBP_LOSSY_JavaEncodeFormat = 3,
+    kWEBP_LOSSLESS_JavaEncodeFormat = 4,
 };
 
 static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
                                 jint format, jint quality,
                                 jobject jstream, jbyteArray jstorage) {
-    SkEncodedImageFormat fm;
-    switch (format) {
-    case kJPEG_JavaEncodeFormat:
-        fm = SkEncodedImageFormat::kJPEG;
-        break;
-    case kPNG_JavaEncodeFormat:
-        fm = SkEncodedImageFormat::kPNG;
-        break;
-    case kWEBP_JavaEncodeFormat:
-        fm = SkEncodedImageFormat::kWEBP;
-        break;
-    default:
-        return JNI_FALSE;
-    }
-
     LocalScopedBitmap bitmap(bitmapHandle);
     if (!bitmap.valid()) {
         return JNI_FALSE;
@@ -563,6 +551,30 @@
         }
         skbitmap = p3;
     }
+    SkEncodedImageFormat fm;
+    switch (format) {
+        case kJPEG_JavaEncodeFormat:
+            fm = SkEncodedImageFormat::kJPEG;
+            break;
+        case kPNG_JavaEncodeFormat:
+            fm = SkEncodedImageFormat::kPNG;
+            break;
+        case kWEBP_JavaEncodeFormat:
+            fm = SkEncodedImageFormat::kWEBP;
+            break;
+        case kWEBP_LOSSY_JavaEncodeFormat:
+        case kWEBP_LOSSLESS_JavaEncodeFormat: {
+            SkWebpEncoder::Options options;
+            options.fQuality = quality;
+            options.fCompression = format == kWEBP_LOSSY_JavaEncodeFormat ?
+                    SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless;
+            return SkWebpEncoder::Encode(strm.get(), skbitmap.pixmap(), options) ?
+                    JNI_TRUE : JNI_FALSE;
+        }
+        default:
+            return JNI_FALSE;
+    }
+
     return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
 }
 
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 4471017..d900a42 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1359,9 +1359,44 @@
      * Specifies the known formats a bitmap can be compressed into
      */
     public enum CompressFormat {
-        JPEG    (0),
-        PNG     (1),
-        WEBP    (2);
+        /**
+         * Compress to the JPEG format. {@code quality} of {@code 0} means
+         * compress for the smallest size. {@code 100} means compress for max
+         * visual quality.
+         */
+        JPEG          (0),
+        /**
+         * Compress to the PNG format. PNG is lossless, so {@code quality} is
+         * ignored.
+         */
+        PNG           (1),
+        /**
+         * Compress to the WEBP format. {@code quality} of {@code 0} means
+         * compress for the smallest size. {@code 100} means compress for max
+         * visual quality. As of {@link android.os.Build.VERSION_CODES#Q}, a
+         * value of {@code 100} results in a file in the lossless WEBP format.
+         * Otherwise the file will be in the lossy WEBP format.
+         *
+         * @deprecated in favor of the more explicit
+         *             {@link CompressFormat#WEBP_LOSSY} and
+         *             {@link CompressFormat#WEBP_LOSSLESS}.
+         */
+        @Deprecated
+        WEBP          (2),
+        /**
+         * Compress to the WEBP lossy format. {@code quality} of {@code 0} means
+         * compress for the smallest size. {@code 100} means compress for max
+         * visual quality.
+         */
+        WEBP_LOSSY    (3),
+        /**
+         * Compress to the WEBP lossless format. {@code quality} refers to how
+         * much effort to put into compression. A value of {@code 0} means to
+         * compress quickly, resulting in a relatively large file size.
+         * {@code 100} means to spend more time compressing, resulting in a
+         * smaller file.
+         */
+        WEBP_LOSSLESS (4);
 
         CompressFormat(int nativeInt) {
             this.nativeInt = nativeInt;
@@ -1385,10 +1420,8 @@
      * pixels).
      *
      * @param format   The format of the compressed image
-     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
-     *                 small size, 100 meaning compress for max quality. Some
-     *                 formats, like PNG which is lossless, will ignore the
-     *                 quality setting
+     * @param quality  Hint to the compressor, 0-100. The value is interpreted
+     *                 differently depending on the {@link CompressFormat}.
      * @param stream   The outputstream to write the compressed data.
      * @return true if successfully compressed to the specified stream.
      */