[androidkit] Add SamplingOptions

Mirroring SkSamplingOptions.

Change-Id: I6c4d21fb3f123e7931271fcc830d82f6b0215c40
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/410786
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
diff --git a/modules/androidkit/src/Canvas.cpp b/modules/androidkit/src/Canvas.cpp
index 3a37f0a..c93c2bc 100644
--- a/modules/androidkit/src/Canvas.cpp
+++ b/modules/androidkit/src/Canvas.cpp
@@ -13,6 +13,19 @@
 
 namespace {
 
+SkSamplingOptions sampling_opts(jint desc, jfloat coeffB, jfloat coeffC) {
+    if (desc & 0x01) {
+        return SkSamplingOptions(SkCubicResampler{coeffB, coeffC});
+    }
+
+    const auto fm = static_cast<SkFilterMode>((desc >> 1) & 0x01);
+    SkASSERT(fm <= SkFilterMode::kLast);
+    const auto mm = static_cast<SkMipmapMode>((desc >> 2) & 0x03);
+    SkASSERT(mm <= SkMipmapMode::kLast);
+
+    return SkSamplingOptions(fm, mm);
+}
+
 jint Canvas_GetWidth(JNIEnv* env, jobject, jlong native_instance) {
     const auto* canvas = reinterpret_cast<const SkCanvas*>(native_instance);
     return canvas ? canvas->imageInfo().width() : 0;
@@ -80,12 +93,13 @@
 }
 
 void Canvas_DrawImage(JNIEnv* env, jobject, jlong native_instance, jlong native_image,
-                      jfloat x, jfloat y) {
+                      jfloat x, jfloat y,
+                      jint sampling_desc, jfloat sampling_b, jfloat sampling_c) {
     auto* canvas = reinterpret_cast<SkCanvas*>(native_instance);
     auto*  image = reinterpret_cast<SkImage *>(native_image);
 
     if (canvas && image) {
-        canvas->drawImage(image, x, y);
+        canvas->drawImage(image, x, y, sampling_opts(sampling_desc, sampling_b, sampling_c));
     }
 }
 
@@ -93,16 +107,16 @@
 
 int register_androidkit_Canvas(JNIEnv* env) {
     static const JNINativeMethod methods[] = {
-        {"nGetWidth"        , "(J)I"     , reinterpret_cast<void*>(Canvas_GetWidth)      },
-        {"nGetHeight"       , "(J)I"     , reinterpret_cast<void*>(Canvas_GetHeight)     },
-        {"nSave"            , "(J)V"     , reinterpret_cast<void*>(Canvas_Save)          },
-        {"nRestore"         , "(J)V"     , reinterpret_cast<void*>(Canvas_Restore)       },
-        {"nGetLocalToDevice", "(J)J"     , reinterpret_cast<void*>(Canvas_LocalToDevice) },
-        {"nConcat"          , "(JJ)V"    , reinterpret_cast<void*>(Canvas_Concat)        },
-        {"nConcat16f"       , "(J[F)V"   , reinterpret_cast<void*>(Canvas_Concat16f)     },
-        {"nDrawColor"       , "(JFFFF)V" , reinterpret_cast<void*>(Canvas_DrawColor)     },
-        {"nDrawRect"        , "(JFFFFJ)V", reinterpret_cast<void*>(Canvas_DrawRect)      },
-        {"nDrawImage"       , "(JJFF)V"  , reinterpret_cast<void*>(Canvas_DrawImage)     },
+        {"nGetWidth"        , "(J)I"      , reinterpret_cast<void*>(Canvas_GetWidth)      },
+        {"nGetHeight"       , "(J)I"      , reinterpret_cast<void*>(Canvas_GetHeight)     },
+        {"nSave"            , "(J)V"      , reinterpret_cast<void*>(Canvas_Save)          },
+        {"nRestore"         , "(J)V"      , reinterpret_cast<void*>(Canvas_Restore)       },
+        {"nGetLocalToDevice", "(J)J"      , reinterpret_cast<void*>(Canvas_LocalToDevice) },
+        {"nConcat"          , "(JJ)V"     , reinterpret_cast<void*>(Canvas_Concat)        },
+        {"nConcat16f"       , "(J[F)V"    , reinterpret_cast<void*>(Canvas_Concat16f)     },
+        {"nDrawColor"       , "(JFFFF)V"  , reinterpret_cast<void*>(Canvas_DrawColor)     },
+        {"nDrawRect"        , "(JFFFFJ)V" , reinterpret_cast<void*>(Canvas_DrawRect)      },
+        {"nDrawImage"       , "(JJFFIFF)V", reinterpret_cast<void*>(Canvas_DrawImage)     },
     };
 
     const auto clazz = env->FindClass("org/skia/androidkit/Canvas");
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
index e427e43..24a6a54 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
@@ -11,6 +11,7 @@
 import org.skia.androidkit.Image;
 import org.skia.androidkit.Matrix;
 import org.skia.androidkit.Paint;
+import org.skia.androidkit.SamplingOptions;
 import org.skia.androidkit.Surface;
 
 public class Canvas {
@@ -71,9 +72,13 @@
         );
     }
 
-    // TODO: sampling options
     public void drawImage(Image image, float x, float y) {
-        nDrawImage(mNativeInstance, image.getNativeInstance(), x, y);
+        drawImage(image, x, y, new SamplingOptions());
+    }
+
+    public void drawImage(Image image, float x, float y, SamplingOptions sampling) {
+        nDrawImage(mNativeInstance, image.getNativeInstance(), x, y,
+                   sampling.getNativeDesc(), sampling.getCubicCoeffB(), sampling.getCubicCoeffC());
     }
 
     // package private
@@ -98,5 +103,7 @@
     private static native void nDrawRect(long nativeInstance,
                                          float left, float right, float top, float bottom,
                                          long nativePaint);
-    private static native void nDrawImage(long nativeInstance, long nativeImage, float x, float y);
+    private static native void nDrawImage(long nativeInstance, long nativeImage, float x, float y,
+                                          int samplingDesc,
+                                          float samplingCoeffB, float samplingCoeffC);
 }
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/SamplingOptions.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/SamplingOptions.java
new file mode 100644
index 0000000..d9e002a
--- /dev/null
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/SamplingOptions.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2021 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+package org.skia.androidkit;
+
+public class SamplingOptions {
+    private FilterMode mFilter;
+    private MipmapMode mMipmap;
+    private float      mCubicCoeffB,
+                       mCubicCoeffC;
+    private boolean    mUseCubic;
+
+    public enum FilterMode {
+        NEAREST,
+        LINEAR,
+    };
+
+    public enum MipmapMode {
+        NONE,
+        NEAREST,
+        LINEAR,
+    }
+
+    public SamplingOptions() {
+        this(FilterMode.NEAREST);
+    }
+
+    public SamplingOptions(FilterMode f) {
+        this(f, MipmapMode.NONE);
+    }
+
+    public SamplingOptions(FilterMode f, MipmapMode m) {
+        mFilter = f;
+        mMipmap = m;
+        mUseCubic = false;
+    }
+
+    public SamplingOptions(float cubicCoeffB, float cubicCoeffC) {
+        mFilter = FilterMode.NEAREST;
+        mMipmap = MipmapMode.NONE;
+        mCubicCoeffB = cubicCoeffB;
+        mCubicCoeffC = cubicCoeffC;
+        mUseCubic = true;
+    }
+
+    public static SamplingOptions MITCHELL() {
+        return new SamplingOptions(1/3.0f, 1/3.0f);
+    }
+
+    public static SamplingOptions CATMULLROM() {
+        return new SamplingOptions(0.0f, 1/2.0f);
+    }
+
+    // package private
+    int getNativeDesc() {
+        // Encode all options except coefficients in a bit field:
+        //
+        //   b0   -> useCubic
+        //   b1   -> filter
+        //   b2,3 -> mipmap
+
+        int desc = mUseCubic ? 0x01 : 0x00;
+
+        switch (mFilter) {
+        case NEAREST:
+            break;
+        case LINEAR:
+            desc |= 0x02;
+            break;
+        }
+
+        switch (mMipmap) {
+        case NONE:
+            break;
+        case NEAREST:
+            desc |= 0x04;
+            break;
+        case LINEAR:
+            desc |= 0x08;
+            break;
+        }
+
+        return desc;
+    }
+
+    float getCubicCoeffB() {
+        return mCubicCoeffB;
+    }
+
+    float getCubicCoeffC() {
+        return mCubicCoeffC;
+    }
+}
\ No newline at end of file
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
index 79fb2b3..abfb479 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
+++ b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
@@ -60,7 +60,9 @@
             is.read(data);
 
             Image image = Image.fromEncoded(data);
-            canvas.drawImage(image, 200, 0);
+            // TODO: Canvas.scale
+            canvas.concat(new Matrix().scale(10, 10));
+            canvas.drawImage(image, 20, 0, SamplingOptions.CATMULLROM());
         } catch (Exception e) {
             Log.e("AndroidKit Demo", "Could not load Image resource: " + R.raw.brickwork_texture);
         }