Demo different sampling options

Requested by blink team

Change-Id: I5b93c330341e8582bfc479bd830bb6dfa3489847
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/396198
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
diff --git a/demos.skia.org/demos/sampling_types/index.html b/demos.skia.org/demos/sampling_types/index.html
new file mode 100644
index 0000000..c9f35c7
--- /dev/null
+++ b/demos.skia.org/demos/sampling_types/index.html
@@ -0,0 +1,195 @@
+<!DOCTYPE html>
+<title>Image sampling techniques</title>
+<meta charset="utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<script type="text/javascript" src="https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/canvaskit.js"></script>
+
+<style>
+    figcaption {
+        max-width: 800px;
+    }
+</style>
+
+<body>
+  <h1>Image sampling techniques</h1>
+
+  <div class="slidecontainer">
+      <input style="width:400px;" type="range" min="-10" max="10" value="0" step="0.01"
+             class="slider" id="scale_slider" title="Scale">
+  </div>
+
+  <figure>
+      <div ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
+          <canvas id="draw" width=2048 height=1600></canvas>
+      </div>
+    <figcaption>
+        Drop an Image onto the page (above)
+    </figcaption>
+  </figure>
+
+</body>
+
+<script type="text/javascript" charset="utf-8">
+    function preventScrolling(elem) {
+        elem.addEventListener('touchmove', (e) => {
+        // Prevents touch events in the element from scrolling.
+        e.preventDefault();
+        e.stopPropagation();
+      });
+    }
+
+    function dragOverHandler(ev) { ev.preventDefault(); }
+
+    // these can be changed with click/drag on the primary rectangle
+    let cell_width = 256,
+        cell_height = 256;
+
+    let image = null;
+    let CK = null;
+    let surface = null;
+    let drawFrame = null;
+
+    function dropHandler(ev) {
+      ev.preventDefault();
+
+      let file = null;
+      if (ev.dataTransfer.items) {
+        // Use DataTransferItemList interface to access the file(s)
+        for (item of ev.dataTransfer.items) {
+          // If dropped items aren't files, reject them
+          if (item.kind === 'file') {
+            file = item.getAsFile();
+            break;
+          }
+        }
+      } else {
+        // Use DataTransfer interface to access the file(s)
+        for (f of ev.dataTransfer.files) {
+          file = f;
+          break;
+        }
+      }
+      if (file) {
+          file.arrayBuffer().then(buffer => {
+              image = CK.MakeImageFromEncoded(buffer);
+              surface.requestAnimationFrame(drawFrame);
+          });
+      }
+    }
+
+  const ckLoaded = CanvasKitInit({ locateFile: (file) => 'https://unpkg.com/canvaskit-wasm@0.25.0/bin/full/' + file });
+
+  ckLoaded.then((_CK) => {
+    CK = _CK;
+    surface = CK.MakeCanvasSurface('draw');
+    if (!surface) {
+      throw 'Could not make surface';
+    }
+
+    const font = new CK.Font(null, 15);
+    const paint = new CK.Paint();
+    const textPaint = new CK.Paint();
+    const TX = 20,
+          TY = 30;  // where we start the first rectangle
+
+    scale_slider.oninput = () => { surface.requestAnimationFrame(drawFrame); };
+
+    m33_scaled = function(sx, sy) {
+        if (!sy) sy = sx;
+        let m = new Float32Array(9);
+        m[0] = sx; m[4] = sy; m[8] = 1;
+        return m;
+    }
+
+    drawFrame = function(canvas) {
+        if (!image) return;
+
+        const scale = scale_slider.valueAsNumber < 0 ? 1 / (1 - scale_slider.valueAsNumber)
+                                                     : (1 + scale_slider.valueAsNumber);
+
+        const bounds = [0, 0, cell_width, cell_height];
+
+        const lm = m33_scaled(scale, scale);
+
+       const samplings = [
+            [CK.FilterMode.Nearest, CK.MipmapMode.None,   0, 0, "Nearest"],
+            [CK.FilterMode.Linear,  CK.MipmapMode.None,   0, 0, "Bilerp"],
+            [CK.FilterMode.Linear,  CK.MipmapMode.Linear, 0, 0, "Trilerp"],
+            [null, null,     0,   0.5, "CatmullRom"],
+            [null, null, 1/3.0, 1/3.0, "Mitchell"],
+        ];
+
+        const tile = CK.TileMode.Repeat;
+
+        canvas.save();
+        canvas.translate(TX, TY);
+        canvas.save();
+        for (i in samplings) {
+            if (i == 3) {
+                canvas.restore();
+                canvas.translate(0, bounds[3] - bounds[1] + 30);
+                canvas.save();
+            }
+
+            const s = samplings[i];
+            const shader = s[0] ? image.makeShaderOptions(tile, tile, s[0], s[1], lm)
+                                : image.makeShaderCubic(  tile, tile, s[2], s[3], lm);
+            paint.setShader(shader);
+            canvas.drawRect(bounds, paint);
+            shader.delete();
+
+            canvas.drawText(s[4], 20, -8, textPaint, font);
+
+            canvas.translate(bounds[2] - bounds[0] + 30, 0);
+        }
+        canvas.restore();
+        canvas.restore();
+        // draw the drag handle
+        if (true) {
+            canvas.save();
+            paint.setShader(null);
+            paint.setColor(CK.Color4f(1, 0, 0));
+            paint.setStrokeWidth(2);
+            canvas.translate(TX + cell_width + 4, TY + cell_height + 4);
+            canvas.drawLine(-12,   0, 0, 0, paint);
+            canvas.drawLine(  0, -12, 0, 0, paint);
+            canvas.restore()
+        }
+    };
+
+    // register our mouse handler
+    {
+        function len2(x, y) {
+            return x*x + y*y;
+        }
+        function hit_test(x,y, x1,y1) {
+            return len2(x-x1, y-y1) <= 10*10;
+        }
+
+        let do_drag = false;
+        function pointer_up(e) {
+            do_drag = false;
+         }
+        function pointer_down(e) {
+            do_drag = hit_test(TX+cell_width, TY+cell_height, e.offsetX, e.offsetY);
+         }
+        function pointer_move(e) {
+          if (e.pressure && do_drag) {
+              cell_width  = Math.max(e.offsetX - TX, 32);
+              cell_height = Math.max(e.offsetY - TY, 32);
+              surface.requestAnimationFrame(drawFrame);
+           }
+        }
+
+        const elem = document.getElementById('draw');
+        elem.addEventListener('pointermove', pointer_move);
+        elem.addEventListener('pointerdown', pointer_down);
+        elem.addEventListener('pointerup', pointer_up);
+        preventScrolling(elem);
+    }
+
+    surface.requestAnimationFrame(drawFrame);
+  });
+
+</script>