summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/browser/browser_colorAnalyzer.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/tests/browser/browser_colorAnalyzer.js')
-rw-r--r--toolkit/components/places/tests/browser/browser_colorAnalyzer.js259
1 files changed, 259 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/browser/browser_colorAnalyzer.js b/toolkit/components/places/tests/browser/browser_colorAnalyzer.js
new file mode 100644
index 000000000..7b7fe6ec5
--- /dev/null
+++ b/toolkit/components/places/tests/browser/browser_colorAnalyzer.js
@@ -0,0 +1,259 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const CA = Cc["@mozilla.org/places/colorAnalyzer;1"].
+ getService(Ci.mozIColorAnalyzer);
+
+const hiddenWindowDoc = Cc["@mozilla.org/appshell/appShellService;1"].
+ getService(Ci.nsIAppShellService).
+ hiddenDOMWindow.document;
+
+const XHTML_NS = "http://www.w3.org/1999/xhtml";
+
+/**
+ * Passes the given uri to findRepresentativeColor.
+ * If expected is null, you expect it to fail.
+ * If expected is a function, it will call that function.
+ * If expected is a color, you expect that color to be returned.
+ * Message is used in the calls to is().
+ */
+function frcTest(uri, expected, message) {
+ return new Promise(resolve => {
+ CA.findRepresentativeColor(Services.io.newURI(uri, "", null),
+ function(success, color) {
+ if (expected == null) {
+ ok(!success, message);
+ } else if (typeof expected == "function") {
+ expected(color, message);
+ } else {
+ ok(success, "success: " + message);
+ is(color, expected, message);
+ }
+ resolve();
+ });
+ });
+}
+
+/**
+ * Handy function for getting an image into findRepresentativeColor and testing it.
+ * Makes a canvas with the given dimensions, calls paintCanvasFunc with the 2d
+ * context of the canvas, sticks the generated canvas into findRepresentativeColor.
+ * See frcTest.
+ */
+function canvasTest(width, height, paintCanvasFunc, expected, message) {
+ let canvas = hiddenWindowDoc.createElementNS(XHTML_NS, "canvas");
+ canvas.width = width;
+ canvas.height = height;
+ paintCanvasFunc(canvas.getContext("2d"));
+ let uri = canvas.toDataURL();
+ return frcTest(uri, expected, message);
+}
+
+// simple test - draw a red box in the center, make sure we get red back
+add_task(function* test_redSquare() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "red";
+ ctx.fillRect(2, 2, 12, 12);
+ }, 0xFF0000, "redSquare analysis returns red");
+});
+
+
+// draw a blue square in one corner, red in the other, such that blue overlaps
+// red by one pixel, making it the dominant color
+add_task(function* test_blueOverlappingRed() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, 8, 8);
+ ctx.fillStyle = "blue";
+ ctx.fillRect(7, 7, 8, 8);
+ }, 0x0000FF, "blueOverlappingRed analysis returns blue");
+});
+
+// draw a red gradient next to a solid blue rectangle to ensure that a large
+// block of similar colors beats out a smaller block of one color
+add_task(function* test_redGradientBlueSolid() {
+ yield canvasTest(16, 16, function(ctx) {
+ let gradient = ctx.createLinearGradient(0, 0, 1, 15);
+ gradient.addColorStop(0, "#FF0000");
+ gradient.addColorStop(1, "#FF0808");
+
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "blue";
+ ctx.fillRect(9, 0, 7, 16);
+ }, function(actual, message) {
+ ok(actual >= 0xFF0000 && actual <= 0xFF0808, message);
+ }, "redGradientBlueSolid analysis returns redish");
+});
+
+// try a transparent image, should fail
+add_task(function* test_transparent() {
+ yield canvasTest(16, 16, function(ctx) {
+ // do nothing!
+ }, null, "transparent analysis fails");
+});
+
+add_task(function* test_invalidURI() {
+ yield frcTest("data:blah,Imnotavaliddatauri", null, "invalid URI analysis fails");
+});
+
+add_task(function* test_malformedPNGURI() {
+ yield frcTest("data:image/png;base64,iVBORblahblahblah", null,
+ "malformed PNG URI analysis fails");
+});
+
+add_task(function* test_unresolvableURI() {
+ yield frcTest("http://www.example.com/blah/idontexist.png", null,
+ "unresolvable URI analysis fails");
+});
+
+// draw a small blue box on a red background to make sure the algorithm avoids
+// using the background color
+add_task(function* test_blueOnRedBackground() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "blue";
+ ctx.fillRect(4, 4, 8, 8);
+ }, 0x0000FF, "blueOnRedBackground analysis returns blue");
+});
+
+// draw a slightly different color in the corners to make sure the corner colors
+// don't have to be exactly equal to be considered the background color
+add_task(function* test_variableBackground() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "white";
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "#FEFEFE";
+ ctx.fillRect(15, 0, 1, 1);
+ ctx.fillStyle = "#FDFDFD";
+ ctx.fillRect(15, 15, 1, 1);
+ ctx.fillStyle = "#FCFCFC";
+ ctx.fillRect(0, 15, 1, 1);
+ ctx.fillStyle = "black";
+ ctx.fillRect(4, 4, 8, 8);
+ }, 0x000000, "variableBackground analysis returns black");
+});
+
+// like the above test, but make the colors different enough that they aren't
+// considered the background color
+add_task(function* test_tooVariableBackground() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "white";
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "#EEDDCC";
+ ctx.fillRect(15, 0, 1, 1);
+ ctx.fillStyle = "#DDDDDD";
+ ctx.fillRect(15, 15, 1, 1);
+ ctx.fillStyle = "#CCCCCC";
+ ctx.fillRect(0, 15, 1, 1);
+ ctx.fillStyle = "black";
+ ctx.fillRect(4, 4, 8, 8);
+ }, function(actual, message) {
+ isnot(actual, 0x000000, message);
+ }, "tooVariableBackground analysis doesn't return black");
+});
+
+// draw a small black/white box over transparent background to make sure the
+// algorithm doesn't think rgb(0,0,0) == rgba(0,0,0,0)
+add_task(function* test_transparentBackgroundConflation() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "black";
+ ctx.fillRect(2, 2, 12, 12);
+ ctx.fillStyle = "white";
+ ctx.fillRect(5, 5, 6, 6);
+ }, 0x000000, "transparentBackgroundConflation analysis returns black");
+});
+
+
+// make sure we fall back to the background color if we have no other choice
+// (instead of failing as if there were no colors)
+add_task(function* test_backgroundFallback() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "black";
+ ctx.fillRect(0, 0, 16, 16);
+ }, 0x000000, "backgroundFallback analysis returns black");
+});
+
+// draw red rectangle next to a pink one to make sure the algorithm picks the
+// more interesting color
+add_task(function* test_interestingColorPreference() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "#FFDDDD";
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, 3, 16);
+ }, 0xFF0000, "interestingColorPreference analysis returns red");
+});
+
+// draw high saturation but dark red next to slightly less saturated color but
+// much lighter, to make sure the algorithm doesn't pick colors that are
+// nearly black just because of high saturation (in HSL terms)
+add_task(function* test_saturationDependence() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "hsl(0, 100%, 5%)";
+ ctx.fillRect(0, 0, 16, 16);
+ ctx.fillStyle = "hsl(0, 90%, 35%)";
+ ctx.fillRect(0, 0, 8, 16);
+ }, 0xA90808, "saturationDependence analysis returns lighter red");
+});
+
+// make sure the preference for interesting colors won't stupidly pick 1 pixel
+// of red over 169 black pixels
+add_task(function* test_interestingColorPreferenceLenient() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "black";
+ ctx.fillRect(1, 1, 13, 13);
+ ctx.fillStyle = "red";
+ ctx.fillRect(3, 3, 1, 1);
+ }, 0x000000, "interestingColorPreferenceLenient analysis returns black");
+});
+
+// ...but 6 pixels of red is more reasonable
+add_task(function* test_interestingColorPreferenceNotTooLenient() {
+ yield canvasTest(16, 16, function(ctx) {
+ ctx.fillStyle = "black";
+ ctx.fillRect(1, 1, 13, 13);
+ ctx.fillStyle = "red";
+ ctx.fillRect(3, 3, 3, 2);
+ }, 0xFF0000, "interestingColorPreferenceNotTooLenient analysis returns red");
+});
+
+var maxPixels = 144; // see ColorAnalyzer MAXIMUM_PIXELS const
+
+// make sure that images larger than maxPixels*maxPixels fail
+add_task(function* test_imageTooLarge() {
+ yield canvasTest(1+maxPixels, 1+maxPixels, function(ctx) {
+ ctx.fillStyle = "red";
+ ctx.fillRect(0, 0, 1+maxPixels, 1+maxPixels);
+ }, null, "imageTooLarge analysis fails");
+});
+
+// the rest of the tests are for coverage of "real" favicons
+// exact color isn't terribly important, just make sure it's reasonable
+const filePrefix = getRootDirectory(gTestPath) + "colorAnalyzer/";
+
+add_task(function* test_categoryDiscover() {
+ yield frcTest(filePrefix + "category-discover.png", 0xB28D3A,
+ "category-discover analysis returns red");
+});
+
+add_task(function* test_localeGeneric() {
+ yield frcTest(filePrefix + "localeGeneric.png", 0x3EC23E,
+ "localeGeneric analysis returns green");
+});
+
+add_task(function* test_dictionaryGeneric() {
+ yield frcTest(filePrefix + "dictionaryGeneric-16.png", 0x854C30,
+ "dictionaryGeneric-16 analysis returns brown");
+});
+
+add_task(function* test_extensionGeneric() {
+ yield frcTest(filePrefix + "extensionGeneric-16.png", 0x53BA3F,
+ "extensionGeneric-16 analysis returns green");
+});