summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/shape-detection
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/shape-detection
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--testing/web-platform/tests/shape-detection/META.yml3
-rw-r--r--testing/web-platform/tests/shape-detection/README.md63
-rw-r--r--testing/web-platform/tests/shape-detection/detected-boundingBox-read-only.https.html56
-rw-r--r--testing/web-platform/tests/shape-detection/detected-postMessage.https.html90
-rw-r--r--testing/web-platform/tests/shape-detection/detection-Blob.https.window.js19
-rw-r--r--testing/web-platform/tests/shape-detection/detection-HTMLCanvasElement.https.html125
-rw-r--r--testing/web-platform/tests/shape-detection/detection-HTMLImageElement-empty-src.https.html33
-rw-r--r--testing/web-platform/tests/shape-detection/detection-HTMLImageElement-zero-dimension-image.https.html34
-rw-r--r--testing/web-platform/tests/shape-detection/detection-HTMLImageElement.https.html86
-rw-r--r--testing/web-platform/tests/shape-detection/detection-HTMLVideoElement.https.html67
-rw-r--r--testing/web-platform/tests/shape-detection/detection-ImageBitmap-closed.https.window.js44
-rw-r--r--testing/web-platform/tests/shape-detection/detection-ImageBitmap.https.html66
-rw-r--r--testing/web-platform/tests/shape-detection/detection-ImageData-detached.https.html46
-rw-r--r--testing/web-platform/tests/shape-detection/detection-ImageData.https.html68
-rw-r--r--testing/web-platform/tests/shape-detection/detection-ImageDataUint16StorageFormat.https.window.js41
-rw-r--r--testing/web-platform/tests/shape-detection/detection-SVGImageElement.https.window.js19
-rw-r--r--testing/web-platform/tests/shape-detection/detection-VideoFrame.https.window.js24
-rw-r--r--testing/web-platform/tests/shape-detection/detection-getSupportedFormats.https.html25
-rw-r--r--testing/web-platform/tests/shape-detection/detection-on-worker.https.worker.js54
-rw-r--r--testing/web-platform/tests/shape-detection/detection-options.https.html54
-rw-r--r--testing/web-platform/tests/shape-detection/detection-security-test.https.html82
-rw-r--r--testing/web-platform/tests/shape-detection/detector-same-object.https.html67
-rw-r--r--testing/web-platform/tests/shape-detection/idlharness.https.any.js19
-rw-r--r--testing/web-platform/tests/shape-detection/resources/shapedetection-helpers.js75
-rw-r--r--testing/web-platform/tests/shape-detection/shapedetection-cross-origin.sub.https.html66
25 files changed, 1326 insertions, 0 deletions
diff --git a/testing/web-platform/tests/shape-detection/META.yml b/testing/web-platform/tests/shape-detection/META.yml
new file mode 100644
index 0000000000..7754624047
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/META.yml
@@ -0,0 +1,3 @@
+spec: https://wicg.github.io/shape-detection-api/
+suggested_reviewers:
+ - yellowdoge
diff --git a/testing/web-platform/tests/shape-detection/README.md b/testing/web-platform/tests/shape-detection/README.md
new file mode 100644
index 0000000000..624b021336
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/README.md
@@ -0,0 +1,63 @@
+The `shapedetection-helpers.js` tests require implementations of
+the `FaceDetectionTest`, `BarcodeDetectionTest` and `TextDetectionTest`
+interfaces, which should emulate platform shape detection backends.
+
+The `FaceDetectionTest` interface is defined as:
+
+```
+ class FaceDetectionTest {
+ async initialize(); // Sets up the testing environment.
+ async reset(); // Frees the resources.
+ MockFaceDetectionProvider(); //Returns `MockFaceDetectionProvider` interface.
+ };
+
+ class MockFaceDetectionProvider {
+ getFrameData(); //Gets frame data of detection result.
+ getMaxDetectedFaces(); //Gets value of `maxDetectedFaces` in `FaceDetector` constructor
+ getFastMode(); //Gets value of `fastMode` in `FaceDetector` constructor
+ };
+```
+
+The Chromium implementation of the `FaceDetectionTest` interface is located in
+[mock-facedetection.js](../resources/chromium/mock-facedetection.js).
+
+The `BarcodeDetectionTest` interface is defined as:
+
+```
+ class BarcodeDetectionTest {
+ async initialize(); // Sets up the testing environment.
+ async reset(); // Frees the resources.
+ MockBarcodeDetectionProvider(); //Returns `MockBarcodeDetectionProvider` interface.
+ };
+
+ class MockBarcodeDetectionProvider {
+ async enumerateSupportedFormats(); //Enumerates supported formats
+ getFrameData(); //Gets frame data of detection result.
+ getFormats(); //Gets value of `formats` in `BarcodeDetector` constructor
+ simulateNoImplementation(); // simulate a 'no implementation available' case
+ };
+```
+
+The Chromium implementation of the `BarcodeDetectionTest` interface is located in
+[mock-barcodedetection.js](../resources/chromium/mock-barcodedetection.js).
+
+The `TextDetectionTest` interface is defined as:
+
+```
+ class TextDetectionTest {
+ async initialize(); // Sets up the testing environment.
+ async reset(); // Frees the resources.
+ MockTextDetection(); //Returns `MockTextDetection` interface.
+ };
+
+ class MockTextDetection {
+ getFrameData(); //Gets frame data of detection result.
+ };
+```
+
+The Chromium implementation of the `TextDetectionTest` interface is located in
+[mock-textdetection.js](../resources/chromium/mock-textdetection.js).
+
+Other browser vendors should provide their own implementations of
+the `FaceDetectionTest`, `BarcodeDetectionTest` and `TextDetectionTest`
+interfaces.
diff --git a/testing/web-platform/tests/shape-detection/detected-boundingBox-read-only.https.html b/testing/web-platform/tests/shape-detection/detected-boundingBox-read-only.https.html
new file mode 100644
index 0000000000..dcf379b97a
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detected-boundingBox-read-only.https.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that detected{Face, Barcode, Text}'s boundingBox
+// should be DOMRectReadOnly.
+const imageDataTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ name: "Face - detectedFace.boundingBox should be DOMRectReadOnly"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ name: "Barcode - detectedBarcode.boundingBox should be DOMRectReadOnly"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ name: "Text - detectedText.boundingBox should be DOMRectReadOnly"
+ }
+ ];
+
+for (let imageDataTest of imageDataTests) {
+ detection_test(imageDataTest.mockTestName, async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+
+ const canvas = document.createElement("canvas");
+ canvas.getContext("2d").drawImage(img, 0, 0);
+
+ const detector = imageDataTest.createDetector();
+ const detectionResult = await detector.detect(canvas.getContext("2d")
+ .getImageData(0, 0, canvas.width, canvas.height));
+ CheckDetectedReadOnlyBoundingBoxes(detectionResult);
+ }, imageDataTest.name);
+}
+
+function CheckDetectedReadOnlyBoundingBoxes(detectedObjects) {
+ const properties =
+ ['x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left'];
+
+ detectedObjects.forEach(detectedObject => {
+ properties.forEach(property => {
+ assert_readonly(detectedObject.boundingBox, property);
+ });
+ });
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detected-postMessage.https.html b/testing/web-platform/tests/shape-detection/detected-postMessage.https.html
new file mode 100644
index 0000000000..8066984b26
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detected-postMessage.https.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that Detected{Face, Barcode, Text} can be passed to
+// postMessage().
+const postMessageTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - DetectedFace can be passed to postMessage()"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - DetectedBarcode can be passed to postMessage()"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - DetectedText can be passed to postMessage()",
+ },
+ ];
+
+for (let postMessageTest of postMessageTests) {
+ detection_test(postMessageTest.mockTestName, async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+
+ const canvas = document.createElement("canvas");
+ canvas.getContext("2d").drawImage(img, 0, 0);
+
+ const detector = postMessageTest.createDetector();
+ const detectionResult = await detector.detect(canvas.getContext("2d")
+ .getImageData(0, 0, canvas.width, canvas.height));
+
+ const msgWatcher = new EventWatcher(t, window, ['message']);
+ window.postMessage(detectionResult);
+ const evt = await msgWatcher.wait_for('message');
+ postMessageTest.detectionResultTest(evt.data)
+ }, postMessageTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult) {
+ assert_equals(detectionResult.length, 3, "Number of faces");
+ assert_equals(detectionResult[0].landmarks.length, 2, "Number of landmarks");
+ assert_object_equals(detectionResult[0].landmarks[0],
+ {type : 'eye', locations : [{x : 4.0, y : 5.0}]},
+ "landmark #1");
+ assert_equals(detectionResult[0].landmarks[1].locations.length, 8,
+ "Number of locations along eye");
+ assert_object_equals(detectionResult[1].landmarks[0],
+ {type : 'nose', locations : [{x : 100.0, y : 50.0}]},
+ "landmark #2");
+ assert_equals(detectionResult[1].landmarks[1].locations.length, 9,
+ "Number of locations along nose");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+ for (let i = 0; i < detectionResult.length; i++) {
+ assert_equals(detectionResult[i].boundingBox.x, detectionResult[i].cornerPoints[0].x);
+ assert_equals(detectionResult[i].boundingBox.y, detectionResult[i].cornerPoints[0].y);
+ assert_equals(detectionResult[i].boundingBox.width,
+ detectionResult[i].cornerPoints[2].x - detectionResult[i].cornerPoints[3].x);
+ assert_equals(detectionResult[i].boundingBox.height,
+ detectionResult[i].cornerPoints[2].y - detectionResult[i].cornerPoints[1].y);
+ }
+
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-Blob.https.window.js b/testing/web-platform/tests/shape-detection/detection-Blob.https.window.js
new file mode 100644
index 0000000000..401a9cc72d
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-Blob.https.window.js
@@ -0,0 +1,19 @@
+'use strict';
+
+promise_test(async (t) => {
+ const blob = new Blob(['not really a png'], {type: 'image/png'});
+ const detector = new FaceDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(blob));
+}, 'FaceDetector.detect() rejects on a Blob');
+
+promise_test(async (t) => {
+ const blob = new Blob(['not really a png'], {type: 'image/png'});
+ const detector = new BarcodeDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(blob));
+}, 'BarcodeDetector.detect() rejects on a Blob');
+
+promise_test(async (t) => {
+ const blob = new Blob(['not really a png'], {type: 'image/png'});
+ const detector = new TextDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(blob));
+}, 'TextDetector.detect() rejects on a Blob');
diff --git a/testing/web-platform/tests/shape-detection/detection-HTMLCanvasElement.https.html b/testing/web-platform/tests/shape-detection/detection-HTMLCanvasElement.https.html
new file mode 100644
index 0000000000..4773bc8a66
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-HTMLCanvasElement.https.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that a Detector's detect() works on an HTMLCanvasElement
+// and on an OffscreenCanvas.
+const canvasElementTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "uint8",
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(HTMLCanvasElement)"
+ },
+ {
+ createDetector: () => { return new FaceDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "float16",
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(HTMLCanvasElementF16Format)"
+ },
+ {
+ createDetector: () => { return new FaceDetector(); },
+ createCanvas: () => { return new OffscreenCanvas(300, 150); },
+ pixelFormat: "uint8",
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(OffscreenCanvas)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "uint8",
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(HTMLCanvasElement)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "float16",
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(HTMLCanvasElementF16Format)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ createCanvas: () => { return new OffscreenCanvas(300, 150); },
+ pixelFormat: "uint8",
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(OffscreenCanvas)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "uint8",
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(HTMLCanvasElement)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ createCanvas: () => { return document.createElement("canvas"); },
+ pixelFormat: "float16",
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(HTMLCanvasElementF16Format)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ createCanvas: () => { return new OffscreenCanvas(300, 150); },
+ pixelFormat: "uint8",
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(OffscreenCanvas)"
+ }
+ ];
+
+for (let canvasElementTest of canvasElementTests) {
+ detection_test(canvasElementTest.mockTestName, async (t, detectionTest) => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+ const canvas = canvasElementTest.createCanvas();
+ canvas.getContext(
+ "2d", { pixelFormat: canvasElementTest.pixelFormat }).drawImage(
+ img, 0, 0);
+
+ const detector = canvasElementTest.createDetector();
+ const detectionResult = await detector.detect(canvas);
+ canvasElementTest.detectionResultTest(detectionResult, detectionTest);
+ }, canvasElementTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult, mockTest) {
+ const imageReceivedByMock =
+ mockTest.MockFaceDetectionProvider().getFrameData();
+ assert_equals(imageReceivedByMock.byteLength, 180000, "Image length");
+ const GREEN_PIXEL = 0xFF00FF00;
+ assert_equals(imageReceivedByMock[0], GREEN_PIXEL, "Pixel color");
+ assert_equals(detectionResult.length, 3, "Number of faces");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-empty-src.https.html b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-empty-src.https.html
new file mode 100644
index 0000000000..40eee24494
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-empty-src.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// This test verifies *Detector.detect() rejects the promise when fed with
+// an HTMLImageElement with an empty 'src'.
+const emptyInputTests = [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ name: "Face - detect(empty src)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ name: "Barcode - detect(empty src)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ name: "Text - detect(empty src)"
+ }
+];
+
+for (let emptyInputTest of emptyInputTests) {
+ promise_test(async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "";
+ await imgWatcher.wait_for("error");
+
+ const detector = emptyInputTest.createDetector();
+ promise_rejects_dom(t, "InvalidStateError", detector.detect(img));
+ }, emptyInputTest.name);
+}
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-zero-dimension-image.https.html b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-zero-dimension-image.https.html
new file mode 100644
index 0000000000..621dd4e23f
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement-zero-dimension-image.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// This test verifies *Detector.detect() returns an empty list when fed with
+// an HTMLImageElement with an image with 0x0 dimensions.
+const zeroDimensionsTests = [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ name: "Face - detect(0x0)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ name: "Barcode - detect(0x0)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ name: "Text - detect(0x0)"
+ }
+];
+
+for (let zeroDimensionsTest of zeroDimensionsTests) {
+ promise_test(async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/red-zerosize.svg";
+ await imgWatcher.wait_for("load");
+
+ const detector = zeroDimensionsTest.createDetector();
+ const detectionResult = await detector.detect(img);
+ assert_equals(detectionResult.length, 0);
+ }, zeroDimensionsTest.name);
+}
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-HTMLImageElement.https.html b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement.https.html
new file mode 100644
index 0000000000..f3b994c258
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-HTMLImageElement.https.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<body>
+<img id="img" src="/images/green-16x16.png"/>
+</body>
+<script>
+
+// These tests verify that a Detector's detect() works on an HTMLImageElement.
+const imageElementTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(HTMLImageElement)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(HTMLImageElement)",
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(HTMLImageElement)"
+ }
+ ];
+
+for (let imageElementTest of imageElementTests) {
+ detection_test(imageElementTest.mockTestName, async (t, detectionTest) => {
+ const img = document.getElementById("img");
+
+ const detector = imageElementTest.createDetector();
+ const detectionResult = await detector.detect(img);
+ imageElementTest.detectionResultTest(detectionResult, detectionTest);
+ }, imageElementTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult, mockTest) {
+ const imageReceivedByMock =
+ mockTest.MockFaceDetectionProvider().getFrameData();
+ assert_equals(imageReceivedByMock.byteLength, 1024, "Image length");
+ const GREEN_PIXEL = 0xFF00FF00;
+ assert_equals(imageReceivedByMock[0], GREEN_PIXEL, "Pixel color");
+ assert_equals(detectionResult.length, 3, "Number of faces");
+ assert_equals(detectionResult[0].landmarks.length, 2, "Number of landmarks");
+ assert_object_equals(detectionResult[0].landmarks[0],
+ {type : 'eye', locations : [{x : 4.0, y : 5.0}]},
+ "landmark #1");
+ assert_equals(detectionResult[0].landmarks[1].locations.length, 8,
+ "Number of locations along eye");
+ assert_object_equals(detectionResult[1].landmarks[0],
+ {type : 'nose', locations : [{x : 100.0, y : 50.0}]},
+ "landmark #2");
+ assert_equals(detectionResult[1].landmarks[1].locations.length, 9,
+ "Number of locations along nose");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+ for (let i = 0; i < detectionResult.length; i++) {
+ assert_equals(detectionResult[i].boundingBox.x, detectionResult[i].cornerPoints[0].x);
+ assert_equals(detectionResult[i].boundingBox.y, detectionResult[i].cornerPoints[0].y);
+ assert_equals(detectionResult[i].boundingBox.width,
+ detectionResult[i].cornerPoints[2].x - detectionResult[i].cornerPoints[3].x);
+ assert_equals(detectionResult[i].boundingBox.height,
+ detectionResult[i].cornerPoints[2].y - detectionResult[i].cornerPoints[1].y);
+ }
+
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-HTMLVideoElement.https.html b/testing/web-platform/tests/shape-detection/detection-HTMLVideoElement.https.html
new file mode 100644
index 0000000000..2ce379bafc
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-HTMLVideoElement.https.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that a Detector's detect() works on an HTMLVideoElement.
+const videoElementTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(HTMLVideoElement)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(HTMLVideoElement)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(HTMLVideoElement)"
+ }
+ ];
+
+for (let videoElementTest of videoElementTests) {
+ detection_test(videoElementTest.mockTestName, async (t, detectionTest) => {
+ const video = document.createElement("video");
+ video.src = "/media/white.webm";
+ video.loop = true;
+ video.autoplay = true;
+ const videoWatcher = new EventWatcher(t, video, ["play", "error"]);
+ video.load();
+ await videoWatcher.wait_for("play");
+
+ const detector = videoElementTest.createDetector();
+ const detectionResult = await detector.detect(video);
+ videoElementTest.detectionResultTest(detectionResult, detectionTest);
+ }, videoElementTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult, mockTest) {
+ const imageReceivedByMock =
+ mockTest.MockFaceDetectionProvider().getFrameData();
+ assert_equals(imageReceivedByMock.byteLength, 307200, "Image length");
+ assert_equals(detectionResult.length, 3, "Number of faces");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-ImageBitmap-closed.https.window.js b/testing/web-platform/tests/shape-detection/detection-ImageBitmap-closed.https.window.js
new file mode 100644
index 0000000000..80cb373f33
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-ImageBitmap-closed.https.window.js
@@ -0,0 +1,44 @@
+'use strict';
+
+async function createClosedImageBitmap(t) {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ['load', 'error']);
+ img.src = '/images/green-16x16.png';
+ await imgWatcher.wait_for('load');
+ const imageBitmap = await createImageBitmap(img);
+ imageBitmap.close();
+ return imageBitmap;
+}
+
+promise_test(async (t) => {
+ const imageBitmap = await createClosedImageBitmap(t);
+ const detector = new FaceDetector();
+ try {
+ await detector.detect(imageBitmap);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'FaceDetector.detect() rejects on a closed ImageBitmap');
+
+promise_test(async (t) => {
+ const imageBitmap = await createClosedImageBitmap(t);
+ const detector = new BarcodeDetector();
+ try {
+ await detector.detect(imageBitmap);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'BarcodeDetector.detect() rejects on a closed ImageBitmap');
+
+promise_test(async (t) => {
+ const imageBitmap = await createClosedImageBitmap(t);
+ const detector = new TextDetector();
+ try {
+ await detector.detect(imageBitmap);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'TextDetector.detect() rejects on a closed ImageBitmap');
diff --git a/testing/web-platform/tests/shape-detection/detection-ImageBitmap.https.html b/testing/web-platform/tests/shape-detection/detection-ImageBitmap.https.html
new file mode 100644
index 0000000000..b4302c4a51
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-ImageBitmap.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that a Detector's detect() works on an ImageBitmap.
+const imageBitmapTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(ImageBitmap)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(ImageBitmap)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(ImageBitmap)",
+ }
+ ];
+
+for (let imageBitmapTest of imageBitmapTests) {
+ detection_test(imageBitmapTest.mockTestName, async (t, detectionTest) => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+ const imageBitmap = await createImageBitmap(img);
+
+ const detector = imageBitmapTest.createDetector();
+ const detectionResult = await detector.detect(imageBitmap);
+ imageBitmapTest.detectionResultTest(detectionResult, detectionTest);
+ }, imageBitmapTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult, mockTest) {
+ const imageReceivedByMock = mockTest.MockFaceDetectionProvider().getFrameData();
+ assert_equals(imageReceivedByMock.byteLength, 1024, "Image length");
+ const GREEN_PIXEL = 0xFF00FF00;
+ assert_equals(imageReceivedByMock[0], GREEN_PIXEL, "Pixel color");
+ assert_equals(detectionResult.length, 3, "Number of faces");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-ImageData-detached.https.html b/testing/web-platform/tests/shape-detection/detection-ImageData-detached.https.html
new file mode 100644
index 0000000000..b4e31c8656
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-ImageData-detached.https.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+function detachBuffer(buffer) {
+ window.postMessage('', '*', [buffer]);
+}
+
+promise_test(async () => {
+ let data = new ImageData(1024, 1024);
+ detachBuffer(data.data.buffer);
+ let detector = new FaceDetector();
+ try {
+ await detector.detect(data);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'FaceDetector.detect() rejects on a detached buffer');
+
+promise_test(async () => {
+ let data = new ImageData(1024, 1024);
+ detachBuffer(data.data.buffer);
+ let detector = new BarcodeDetector();
+ try {
+ await detector.detect(data);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'BarcodeDetector.detect() rejects on a detached buffer');
+
+promise_test(async () => {
+ let data = new ImageData(1024, 1024);
+ detachBuffer(data.data.buffer);
+ let detector = new TextDetector();
+ try {
+ await detector.detect(data);
+ assert_unreached();
+ } catch (e) {
+ assert_equals(e.code, DOMException.INVALID_STATE_ERR);
+ }
+}, 'TextDetector.detect() rejects on a detached buffer');
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-ImageData.https.html b/testing/web-platform/tests/shape-detection/detection-ImageData.https.html
new file mode 100644
index 0000000000..330239fdf0
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-ImageData.https.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that a Detector's detect() works on an ImageBitmap.
+const imageDataTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: FaceDetectorDetectionResultTest,
+ name: "Face - detect(ImageData)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: BarcodeDetectorDetectionResultTest,
+ name: "Barcode - detect(ImageData)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: TextDetectorDetectionResultTest,
+ name: "Text - detect(ImageData)",
+ }
+ ];
+
+for (let imageDataTest of imageDataTests) {
+ detection_test(imageDataTest.mockTestName, async (t, detectionTest) => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+ const canvas = document.createElement("canvas");
+ canvas.getContext("2d").drawImage(img, 0, 0);
+
+ const detector = imageDataTest.createDetector();
+ const detectionResult = await detector.detect(canvas.getContext("2d")
+ .getImageData(0, 0, canvas.width, canvas.height));
+ imageDataTest.detectionResultTest(detectionResult, detectionTest);
+ }, imageDataTest.name);
+}
+
+function FaceDetectorDetectionResultTest(detectionResult, mockTest) {
+ const imageReceivedByMock = mockTest.MockFaceDetectionProvider().getFrameData();
+ assert_equals(imageReceivedByMock.byteLength, 180000,"Image length");
+ const GREEN_PIXEL = 0xFF00FF00;
+ assert_equals(imageReceivedByMock[0], GREEN_PIXEL, "Pixel color");
+ assert_equals(detectionResult.length, 3, "Number of faces");
+}
+
+function BarcodeDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of barcodes");
+ assert_equals(detectionResult[0].rawValue, "cats", "barcode 1");
+ assert_equals(detectionResult[0].format, "qr_code", "barcode 1 format");
+ assert_equals(detectionResult[1].rawValue, "dogs", "barcode 2");
+ assert_equals(detectionResult[1].format, "code_128", "barcode 2 format");
+}
+
+function TextDetectorDetectionResultTest(detectionResult, mockTest) {
+ assert_equals(detectionResult.length, 2, "Number of textBlocks");
+ assert_equals(detectionResult[0].rawValue, "cats", "textBlock 1");
+ assert_equals(detectionResult[1].rawValue, "dogs", "textBlock 2");
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-ImageDataUint16StorageFormat.https.window.js b/testing/web-platform/tests/shape-detection/detection-ImageDataUint16StorageFormat.https.window.js
new file mode 100644
index 0000000000..24dd3e597c
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-ImageDataUint16StorageFormat.https.window.js
@@ -0,0 +1,41 @@
+// META: script=/resources/testharness.js
+// META: script=/resources/testharnessreport.js
+// META: script=/shape-detection/resources/shapedetection-helpers.js
+
+const imgUint16 = new ImageData(1024, 1024, {storageFormat: 'uint16'});
+
+// These tests verify that a Detector's detect() can process ImageData with
+// uint16 storage format.
+const imageDataTests = [
+ {
+ createDetector: () => {
+ return new FaceDetector();
+ },
+ mockTestName: 'FaceDetectionTest',
+ name:
+ 'FaceDetector.detect() can process uint16 storage format ImageData'
+ },
+ {
+ createDetector: () => {
+ return new BarcodeDetector();
+ },
+ mockTestName: 'BarcodeDetectionTest',
+ name:
+ 'BarcodeDetector.detect() can process uint16 storage format ImageData'
+ },
+ {
+ createDetector: () => {
+ return new TextDetector();
+ },
+ mockTestName: 'TextDetectionTest',
+ name:
+ 'TextDetector.detect() can process uint16 storage format ImageData'
+ }
+];
+
+for (let imageDataTest of imageDataTests) {
+ detection_test(imageDataTest.mockTestName, async () => {
+ let detector = imageDataTest.createDetector();
+ await detector.detect(imgUint16);
+ }, imageDataTest.name);
+}
diff --git a/testing/web-platform/tests/shape-detection/detection-SVGImageElement.https.window.js b/testing/web-platform/tests/shape-detection/detection-SVGImageElement.https.window.js
new file mode 100644
index 0000000000..22f1629ecc
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-SVGImageElement.https.window.js
@@ -0,0 +1,19 @@
+'use strict';
+
+promise_test(async (t) => {
+ const image = document.createElementNS("http://www.w3.org/2000/svg", "image");
+ const detector = new FaceDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(image));
+}, 'FaceDetector.detect() rejects on an SVGImageElement');
+
+promise_test(async (t) => {
+ const image = document.createElementNS("http://www.w3.org/2000/svg", "image");
+ const detector = new BarcodeDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(image));
+}, 'BarcodeDetector.detect() rejects on an SVGImageElement');
+
+promise_test(async (t) => {
+ const image = document.createElementNS("http://www.w3.org/2000/svg", "image");
+ const detector = new TextDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(image));
+}, 'TextDetector.detect() rejects on an SVGImageElement');
diff --git a/testing/web-platform/tests/shape-detection/detection-VideoFrame.https.window.js b/testing/web-platform/tests/shape-detection/detection-VideoFrame.https.window.js
new file mode 100644
index 0000000000..601c60bcaf
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-VideoFrame.https.window.js
@@ -0,0 +1,24 @@
+'use strict';
+
+function createVideoFrame() {
+ const canvas = document.createElement('canvas');
+ return new VideoFrame(canvas, {timestamp: 0});
+}
+
+promise_test(async (t) => {
+ const frame = createVideoFrame();
+ const detector = new FaceDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(frame));
+}, 'FaceDetector.detect() rejects on a VideoFrame');
+
+promise_test(async (t) => {
+ const frame = createVideoFrame();
+ const detector = new BarcodeDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(frame));
+}, 'BarcodeDetector.detect() rejects on a VideoFrame');
+
+promise_test(async (t) => {
+ const frame = createVideoFrame();
+ const detector = new TextDetector();
+ await promise_rejects_dom(t, 'NotSupportedError', detector.detect(frame));
+}, 'TextDetector.detect() rejects on a VideoFrame');
diff --git a/testing/web-platform/tests/shape-detection/detection-getSupportedFormats.https.html b/testing/web-platform/tests/shape-detection/detection-getSupportedFormats.https.html
new file mode 100644
index 0000000000..0b4b223369
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-getSupportedFormats.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<link rel="help" href="https://wicg.github.io/shape-detection-api/#dom-barcodedetector-getsupportedformats">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+detection_test('BarcodeDetectionTest', async t => {
+ const result = await BarcodeDetector.getSupportedFormats();
+ assert_equals(result.length, 3, 'Number of supported formats');
+ assert_equals(result[0], 'aztec', 'format 1');
+ assert_equals(result[1], 'data_matrix', 'format 2');
+ assert_equals(result[2], 'qr_code', 'format 3');
+}, 'get supported barcode formats');
+
+detection_test('BarcodeDetectionTest', async (t, detectionTest) => {
+ // Disable built-in support for barcode detection to test fallback handling.
+ detectionTest.MockBarcodeDetectionProvider().simulateNoImplementation();
+
+ const result = await BarcodeDetector.getSupportedFormats();
+ assert_equals(result.length, 0, 'result.length');
+
+}, 'getSupportedFormats() resolves with empty list when unsupported');
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-on-worker.https.worker.js b/testing/web-platform/tests/shape-detection/detection-on-worker.https.worker.js
new file mode 100644
index 0000000000..3981c6fdc8
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-on-worker.https.worker.js
@@ -0,0 +1,54 @@
+importScripts("/resources/testharness.js");
+importScripts("/resources/test-only-api.js");
+importScripts("resources/shapedetection-helpers.js");
+
+'use strict';
+
+// These tests verify that a Detector's detect() works on an
+// ImageBitmap on workers.
+const imageBitmapTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ resultSize: 3, // Number of faces
+ detectorType: "Face"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ resultSize: 2, // Number of barcodes
+ detectorType: "Barcode"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ resultSize: 2, // Number of text blocks
+ detectorType: "Text"
+ }
+ ];
+
+for (let imageBitmapTest of imageBitmapTests) {
+ // ImageBitmap is of transferable type and can be sent to and
+ // tested on worker.
+ detection_test(imageBitmapTest.mockTestName, async (t, detectionTest) => {
+ const img = createTestImage();
+ const theImageBitmap = await createImageBitmap(img);
+ const detector = imageBitmapTest.createDetector();
+ const detectionResult = await detector.detect(theImageBitmap);
+ assert_equals(detectionResult.length, imageBitmapTest.resultSize,
+ `Number of ${imageBitmapTest.detectorType}`);
+ }, `${imageBitmapTest.detectorType} Detector detect(ImageBitmap) on worker`);
+}
+
+function createTestImage() {
+ const image = new OffscreenCanvas(100, 50);
+ const imgctx = image.getContext('2d');
+ imgctx.fillStyle = "#F00";
+ imgctx.fillRect(0, 0, 2, 2);
+ imgctx.fillStyle = "#0F0";
+ imgctx.fillRect(0, 0, 1, 1);
+ return image;
+}
+
+done();
diff --git a/testing/web-platform/tests/shape-detection/detection-options.https.html b/testing/web-platform/tests/shape-detection/detection-options.https.html
new file mode 100644
index 0000000000..4b79da2a6e
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-options.https.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<body>
+<img id="img" src="/images/green-16x16.png"/>
+</body>
+<script>
+
+detection_test("FaceDetectionTest", async (t, detectionTest) => {
+ const img = document.getElementById("img");
+ const mock = detectionTest.MockFaceDetectionProvider();
+
+ const detectorWithDefault = new FaceDetector();
+ let faceDetectionResult = await detectorWithDefault.detect(img);
+ assert_equals(mock.getMaxDetectedFaces(), 10, "default maxDetectedFaces");
+ assert_equals(mock.getFastMode(), false, "default maxDetectedFaces");
+
+ const detectorWithOptions =
+ new FaceDetector({maxDetectedFaces: 7, fastMode: true});
+ faceDetectionResult = await detectorWithOptions.detect(img);
+ assert_equals(mock.getMaxDetectedFaces(), 7, "maxDetectedFaces");
+ assert_equals(mock.getFastMode(), true, "maxDetectedFaces");
+}, "Test that FaceDetectionOptions are correctly propagated");
+
+detection_test("BarcodeDetectionTest", async (t, detectionTest) => {
+ const img = document.getElementById("img");
+ const mock = detectionTest.MockBarcodeDetectionProvider();
+
+ const detectorWithNoOptions = new BarcodeDetector();
+ let barcodeDetectionResult = await detectorWithNoOptions.detect(img);
+ assert_array_equals(mock.getFormats(), [], "formats");
+
+ const detectorWithOptions = new BarcodeDetector({
+ formats: ["code_128", "qr_code"]});
+ barcodeDetectionResult = await detectorWithOptions.detect(img);
+ assert_array_equals(
+ mock.getFormats(),
+ [BarcodeFormat.CODE_128, BarcodeFormat.QR_CODE],
+ "formats");
+
+ const invalidFormats = [
+ [],
+ ["unknown"],
+ ["foo", "bar"]
+ ];
+
+ invalidFormats.forEach(invalidFormat => {
+ assert_throws_js(TypeError, () => new BarcodeDetector({formats: invalidFormat}));
+ });
+
+}, "Test that BarcodeDetectorOptions are correctly propagated");
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detection-security-test.https.html b/testing/web-platform/tests/shape-detection/detection-security-test.https.html
new file mode 100644
index 0000000000..4d87238dad
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detection-security-test.https.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// Detectors should reject undecodable images with an InvalidStateError.
+const badImageTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ name: "Face - detect(broken image)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ name: "Barcode - detect(broken image)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ name: "Text - detect(broken image)"
+ }
+ ];
+
+for (let badImageTest of badImageTests) {
+ // This test verifies that a Detector will reject an undecodable image.
+ promise_test(async t => {
+ const img = new Image();
+ const error =
+ await detectOnElementAndExpectError(badImageTest.createDetector,
+ img, "/images/broken.png");
+ assert_equals(error.name, "InvalidStateError");
+ }, badImageTest.name);
+}
+
+// Detectors should reject undecodable videos with an InvalidStateError.
+const badVideoTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ name: "Face - detect(broken video)"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ name: "Barcode - detect(broken video)"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ name: "Text - detect(broken video)"
+ }
+ ];
+
+for (let badVideoTest of badVideoTests) {
+ // This test verifies that a Detector will reject a broken video.
+ promise_test(async t => {
+ const video = document.createElement('video');
+ const error =
+ await detectOnElementAndExpectError(badVideoTest.createDetector,
+ video, "garbage.webm");
+ assert_equals(error.name, "InvalidStateError");
+ }, badVideoTest.name);
+}
+
+// Returns a Promise that is resolve()d if detect() is rejected. Needs an input
+// |element| (e.g. an HTMLImageElement or HTMLVideoElement) and a |url| to load.
+function detectOnElementAndExpectError(createDetector, element, url) {
+ return new Promise((resolve, reject) => {
+ const tryDetection = async () => {
+ const detector = createDetector();
+ try {
+ const detectionResult = await detector.detect(element);
+ reject("Promise should have been rejected.");
+ } catch (error) {
+ resolve(error);
+ }
+ };
+ element.onload = tryDetection;
+ element.onerror = tryDetection;
+ element.src = url;
+ });
+};
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/detector-same-object.https.html b/testing/web-platform/tests/shape-detection/detector-same-object.https.html
new file mode 100644
index 0000000000..bf7c068041
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/detector-same-object.https.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/shapedetection-helpers.js"></script>
+<script>
+
+// These tests verify that detect()ed Detected{Barcode,Face, Text}'s individual
+// fields are [SameObject].
+const imageDataTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ mockTestName: "FaceDetectionTest",
+ detectionResultTest: CheckDetectedFaceSameObjects,
+ name: "Face - detect(ImageData), [SameObject]"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ mockTestName: "BarcodeDetectionTest",
+ detectionResultTest: CheckDetectedBarcodesSameObjects,
+ name: "Barcode - detect(ImageData), [SameObject]"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ mockTestName: "TextDetectionTest",
+ detectionResultTest: CheckDetectedTextBlocksSameObjects,
+ name: "Text - detect(ImageData), [SameObject]",
+ }
+ ];
+
+for (let imageDataTest of imageDataTests) {
+ detection_test(imageDataTest.mockTestName, async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = "/images/green-16x16.png";
+ await imgWatcher.wait_for("load");
+ const canvas = document.createElement("canvas");
+ canvas.getContext("2d").drawImage(img, 0, 0);
+
+ const detector = imageDataTest.createDetector();
+ const detectionResult = await detector.detect(canvas.getContext("2d")
+ .getImageData(0, 0, canvas.width, canvas.height));
+ imageDataTest.detectionResultTest(detectionResult);
+ }, imageDataTest.name);
+}
+
+function CheckDetectedFaceSameObjects(detectedFaces) {
+ assert_greater_than(detectedFaces.length, 0, "Number of faces");
+ assert_equals(detectedFaces[0].boundingBox, detectedFaces[0].boundingBox);
+ assert_equals(detectedFaces[0].landmarks, detectedFaces[0].landmarks);
+}
+
+function CheckDetectedBarcodesSameObjects(detectedBarcodes) {
+ assert_greater_than(detectedBarcodes.length, 0, "Number of barcodes");
+ assert_equals(detectedBarcodes[0].rawValue, detectedBarcodes[0].rawValue);
+ assert_equals(detectedBarcodes[0].boundingBox, detectedBarcodes[0].boundingBox);
+ assert_equals(detectedBarcodes[0].format, detectedBarcodes[0].format);
+ assert_equals(detectedBarcodes[0].cornerPoints, detectedBarcodes[0].cornerPoints);
+}
+
+function CheckDetectedTextBlocksSameObjects(detectedTextBlocks) {
+ assert_greater_than(detectedTextBlocks.length, 0, "Number of textBlocks");
+ assert_equals(detectedTextBlocks[0].rawValue, detectedTextBlocks[0].rawValue);
+ assert_equals(detectedTextBlocks[0].boundingBox, detectedTextBlocks[0].boundingBox);
+}
+
+</script>
diff --git a/testing/web-platform/tests/shape-detection/idlharness.https.any.js b/testing/web-platform/tests/shape-detection/idlharness.https.any.js
new file mode 100644
index 0000000000..33b5f88f75
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/idlharness.https.any.js
@@ -0,0 +1,19 @@
+// META: global=window,worker
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// See: https://wicg.github.io/shape-detection-api/
+
+'use strict';
+
+idl_test(
+ ['shape-detection-api', 'text-detection-api'],
+ ['dom', 'geometry'],
+ async idl_array => {
+ idl_array.add_objects({
+ FaceDetector: ['new FaceDetector()'],
+ BarcodeDetector: ['new BarcodeDetector()'],
+ TextDetector: ['new TextDetector()'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/shape-detection/resources/shapedetection-helpers.js b/testing/web-platform/tests/shape-detection/resources/shapedetection-helpers.js
new file mode 100644
index 0000000000..1b4949b8f6
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/resources/shapedetection-helpers.js
@@ -0,0 +1,75 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of
+// platform shape detection backends.
+//
+// In Chromium-based browsers this implementation is provided by a polyfill
+// in order to reduce the amount of test-only code shipped to users. To enable
+// these tests the browser must be run with these options:
+//
+// --enable-blink-features=MojoJS,MojoJSTest
+
+async function loadChromiumResources() {
+ await import('/resources/chromium/mock-barcodedetection.js');
+ await import('/resources/chromium/mock-facedetection.js');
+ await import('/resources/chromium/mock-textdetection.js');
+}
+
+/**
+ * @param {String} detectionTestName
+ * name of mock shape detection test interface,
+ * must be the item of ["FaceDetectionTest", "BarcodeDetectionTest",
+ * "TextDetectionTest"]
+*/
+async function initialize_detection_tests(detectionTestName) {
+ let detectionTest;
+ if (typeof document === 'undefined') {
+ // Use 'self' for workers.
+ if (typeof self[detectionTestName] === 'undefined') {
+ // test-only-api.js is already loaded in worker.js
+ if (isChromiumBased) {
+ await loadChromiumResources();
+ }
+ }
+ detectionTest = new self[detectionTestName]();
+ } else {
+ if (typeof window[detectionTestName] === 'undefined') {
+ const script = document.createElement('script');
+ script.src = '/resources/test-only-api.js';
+ script.async = false;
+ const p = new Promise((resolve, reject) => {
+ script.onload = () => { resolve(); };
+ script.onerror = e => { reject(e); };
+ })
+ document.head.appendChild(script);
+ await p;
+
+ if (isChromiumBased) {
+ await loadChromiumResources();
+ }
+
+ }
+ detectionTest = new window[detectionTestName]();
+ }
+ await detectionTest.initialize();
+ return detectionTest;
+}
+
+function detection_test(detectionTestName, func, name, properties) {
+ promise_test(async t => {
+ let detectionTest = await initialize_detection_tests(detectionTestName);
+ try {
+ await func(t, detectionTest);
+ } finally {
+ await detectionTest.reset();
+ };
+ }, name, properties);
+}
+
+function getArrayBufferFromBigBuffer(bigBuffer) {
+ if (bigBuffer.bytes !== undefined) {
+ return new Uint8Array(bigBuffer.bytes).buffer;
+ }
+ return bigBuffer.sharedMemory.bufferHandle.mapBuffer(0,
+ bigBuffer.sharedMemory.size).buffer;
+}
diff --git a/testing/web-platform/tests/shape-detection/shapedetection-cross-origin.sub.https.html b/testing/web-platform/tests/shape-detection/shapedetection-cross-origin.sub.https.html
new file mode 100644
index 0000000000..c4e3c3fec7
--- /dev/null
+++ b/testing/web-platform/tests/shape-detection/shapedetection-cross-origin.sub.https.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+// cross-origin resources
+const IMAGE_URL =
+ "https://{{domains[www1]}}:{{ports[https][0]}}/images/green.png";
+const VIDEO_URL =
+ "https://{{domains[www1]}}:{{ports[https][0]}}/media/white.webm";
+
+const crossOriginTests =
+ [
+ {
+ createDetector: () => { return new FaceDetector(); },
+ detectorType: "FaceDetector"
+ },
+ {
+ createDetector: () => { return new BarcodeDetector(); },
+ detectorType: "BarcodeDetector"
+ },
+ {
+ createDetector: () => { return new TextDetector(); },
+ detectorType: "TextDetector"
+ }
+ ];
+
+for (let crossOriginTest of crossOriginTests) {
+
+ // Verifies that Detector rejects a cross-origin HTMLImageElement.
+ promise_test(async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = IMAGE_URL;
+ await imgWatcher.wait_for("load");
+ const detector = crossOriginTest.createDetector();
+ promise_rejects_dom(t, "SecurityError", detector.detect(img));
+ }, crossOriginTest.detectorType
+ + " should reject cross-origin HTMLImageElements with a SecurityError.");
+
+ // Verifies that Detector rejects a cross-origin ImageBitmap.
+ promise_test(async t => {
+ const img = new Image();
+ const imgWatcher = new EventWatcher(t, img, ["load", "error"]);
+ img.src = IMAGE_URL;
+ await imgWatcher.wait_for("load");
+ const imgBitmap = await createImageBitmap(img);
+ const detector = crossOriginTest.createDetector();
+ promise_rejects_dom(t, "SecurityError", detector.detect(imgBitmap));
+ }, crossOriginTest.detectorType
+ + " should reject cross-origin ImageBitmaps with a SecurityError.");
+
+ // Verifies that Detector rejects a cross-origin HTMLVideoElement.
+ promise_test(async t => {
+ const video = document.createElement('video');
+ const videoWatcher = new EventWatcher(t, video, ["loadeddata", "error"]);
+ video.src = VIDEO_URL;
+ await videoWatcher.wait_for("loadeddata");
+ const detector = crossOriginTest.createDetector();
+ promise_rejects_dom(t, "SecurityError", detector.detect(video));
+ }, crossOriginTest.detectorType
+ + " should reject cross-origin HTMLVideoElements with a SecurityError.");
+
+}
+
+</script> \ No newline at end of file