Bug 1340484 - Round RGB values when obtaining from HSL instead of flooring; r?dbaron draft
authorManish Goregaokar <manishearth@gmail.com>
Mon, 08 May 2017 16:43:05 -0700
changeset 576536 75a116938bb194966345506e475278ee00806265
parent 576455 6f18b4657a0ca09d75281198ed91f9d1567745d5
child 628227 50092cc90ec3c16453299ce0c1d006305a3f20c0
push id58395
push userbmo:manishearth@gmail.com
push dateThu, 11 May 2017 20:18:59 +0000
reviewersdbaron
bugs1340484
milestone55.0a1
Bug 1340484 - Round RGB values when obtaining from HSL instead of flooring; r?dbaron MozReview-Commit-ID: AFfczBFV00n
gfx/src/nsColor.cpp
image/test/reftest/bmp/bmp-4bpp/reftest.list
image/test/reftest/bmp/bmpsuite/q/reftest.list
image/test/reftest/gif/reftest.list
image/test/reftest/ico/ico-bmp-1bpp/reftest.list
image/test/reftest/ico/ico-bmp-24bpp/reftest.list
image/test/reftest/ico/ico-bmp-32bpp/reftest.list
image/test/reftest/ico/ico-bmp-4bpp/reftest.list
image/test/reftest/ico/ico-bmp-8bpp/reftest.list
image/test/reftest/ico/ico-mixed/reftest.list
image/test/reftest/ico/ico-png/reftest.list
layout/inspector/tests/test_color_to_rgba.html
layout/reftests/bugs/reftest.list
layout/style/test/mochitest.ini
layout/style/test/test_color_rounding.html
toolkit/components/places/tests/browser/browser_colorAnalyzer.js
--- a/gfx/src/nsColor.cpp
+++ b/gfx/src/nsColor.cpp
@@ -337,19 +337,21 @@ NS_HSL2RGB(float h, float s, float l)
   uint8_t r, g, b;
   float m1, m2;
   if (l <= 0.5f) {
     m2 = l*(s+1);
   } else {
     m2 = l + s - l*s;
   }
   m1 = l*2 - m2;
-  r = uint8_t(255 * HSL_HueToRGB(m1, m2, h + 1.0f/3.0f));
-  g = uint8_t(255 * HSL_HueToRGB(m1, m2, h));
-  b = uint8_t(255 * HSL_HueToRGB(m1, m2, h - 1.0f/3.0f));
+  // We round, not floor, because that's how we handle
+  // percentage RGB values.
+  r = ClampColor(255 * HSL_HueToRGB(m1, m2, h + 1.0f/3.0f));
+  g = ClampColor(255 * HSL_HueToRGB(m1, m2, h));
+  b = ClampColor(255 * HSL_HueToRGB(m1, m2, h - 1.0f/3.0f));
   return NS_RGB(r, g, b);  
 }
 
 const char*
 NS_RGBToColorName(nscolor aColor)
 {
   for (size_t idx = 0; idx < ArrayLength(kColors); ++idx) {
     if (kColors[idx] == aColor) {
--- a/image/test/reftest/bmp/bmp-4bpp/reftest.list
+++ b/image/test/reftest/bmp/bmp-4bpp/reftest.list
@@ -16,9 +16,9 @@
 == bmp-size-31x31-4bpp.bmp bmp-size-31x31-4bpp.png
 == bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
 == bmp-size-33x33-4bpp.bmp bmp-size-33x33-4bpp.png
 == bmp-not-square-4bpp.bmp bmp-not-square-4bpp.png
 == os2bmp-size-32x32-4bpp.bmp bmp-size-32x32-4bpp.png
 == top-to-bottom-16x16-4bpp.bmp  bmp-size-16x16-4bpp.png
 # test that delta skips are drawn as transparent
 # taken from http://bmptestsuite.sourceforge.net/
-fails-if(stylo) == rle4-delta-320x240.bmp rle4-delta-320x240.png
+== rle4-delta-320x240.bmp rle4-delta-320x240.png
--- a/image/test/reftest/bmp/bmpsuite/q/reftest.list
+++ b/image/test/reftest/bmp/bmpsuite/q/reftest.list
@@ -16,22 +16,22 @@
 == wrapper.html?pal2.bmp about:blank
 
 # BMP: bihsize=40, 127 x 64, bpp=4, compression=2, colors=13
 # "An RLE-compressed image that used 'delta' codes to skip over some pixels,
 # leaving them undefined. Some viewers make undefined pixels transparent,
 # others make them black, and others assign them palette color 0 (purple, in
 # this case)."
 # [We make the undefined pixels transparent. So does Chromium.]
-fails-if(stylo) == pal4rletrns.bmp pal4rletrns.png
+== pal4rletrns.bmp pal4rletrns.png
 
 # BMP: bihsize=40, 127 x 64, bpp=8, compression=1, colors=253
 # "8-bit version of q/pal4rletrns.bmp."
 # [Ditto.]
-fails-if(stylo) == pal8rletrns.bmp pal8rletrns.png
+== pal8rletrns.bmp pal8rletrns.png
 
 # BMP: bihsize=40, 127 x 64, bpp=8, compression=0, colors=252
 # "A file with some unused bytes between the palette and the image. This is
 # probably valid, but I’m not 100% sure."
 # [We accept it. So does Chromium.]
 fuzzy(1,899) == pal8offs.bmp pal8.png
 
 # BMP: bihsize=40, 127 x 64, bpp=8, compression=0, colors=300
@@ -66,17 +66,17 @@ fuzzy(1,899) == pal8os2v2-16.bmp pal8.pn
 # (possibly including one round of bit replication), instead of proper
 # scaling."
 == rgb16-231.bmp rgb16-231.png
 
 # BMP: bihsize=124, 127 x 64, bpp=16, compression=3, colors=0
 # "A 16-bit image with an alpha channel. There are 4 bits for each color
 # channel, and 4 bits for the alpha channel. It’s not clear if this is valid,
 # but I can’t find anything that suggests it isn’t."
-fails-if(stylo) == rgba16-4444.bmp rgba16-4444.png
+== rgba16-4444.bmp rgba16-4444.png
 
 # BMP: bihsize=40, 127 x 64, bpp=24, compression=0, colors=300
 # "A 24-bit image, with a palette containing 300 colors. The fact that the
 # palette has more than 256 colors may cause some viewers to complain, but the
 # documentation does not mention a size limit."
 # [We accept it. So does Chromium.]
 == rgb24largepal.bmp rgb24.png
 
@@ -114,17 +114,17 @@ fails-if(stylo) == rgba16-4444.bmp rgba1
 # 10 for blue. As far as I know, this is perfectly valid, but it is unusual."
 fuzzy(1,1408) == rgb32-111110.bmp rgb24.png
 
 # BMP: bihsize=124, 127 x 64, bpp=32, compression=3, colors=0
 # "A BMP with an alpha channel. Transparency is barely documented, so it’s
 # possible that this file is not correctly formed. The color channels are in an
 # unusual order, to prevent viewers from passing this test by making a lucky
 # guess."
-fails-if(stylo) == rgba32.bmp rgba32.png
+== rgba32.bmp rgba32.png
 
 # BMP: bihsize=40, 127 x 64, bpp=32, compression=6, colors=0
 # "An image of type BI_ALPHABITFIELDS. Supposedly, this was used on Windows CE.
 # I don’t know whether it is constructed correctly."
 # [We reject it. So does Chromium.]
 == wrapper.html?rgba32abf.bmp about:blank
 
 
--- a/image/test/reftest/gif/reftest.list
+++ b/image/test/reftest/gif/reftest.list
@@ -1,29 +1,29 @@
 # GIF tests
 
 # tests for bug 519589
-fails-if(stylo) == 1bit-255-trans.gif 1bit-255-trans.png
-fails-if(stylo) == in-colormap-trans.gif in-colormap-trans.png
-fails-if(stylo) == out-of-colormap-trans.gif out-of-colormap-trans.png
+== 1bit-255-trans.gif 1bit-255-trans.png
+== in-colormap-trans.gif in-colormap-trans.png
+== out-of-colormap-trans.gif out-of-colormap-trans.png
 
 # a GIF file that uses the comment extension
 == comment.gif comment.png
 
 # a GIF file with a background smaller than the size of the canvas
-fails-if(stylo) == small-background-size.gif small-background-size-ref.gif
-fails-if(stylo) == small-background-size-2.gif small-background-size-2-ref.gif
+== small-background-size.gif small-background-size-ref.gif
+== small-background-size-2.gif small-background-size-2-ref.gif
 
 # a transparent gif that disposes previous frames with clear; we must properly
 # clear each frame to pass.
 random == delaytest.html?transparent-animation.gif transparent-animation-finalframe.gif # incorrect timing dependence (bug 558678)
 
 # test for bug 641198
 skip == test_bug641198.html animation2a-finalframe.gif  # Disabled; see bug 1120144.
 
 # Bug 1062886: a gif with a single color and an offset
-fails-if(stylo) == one-color-offset.gif one-color-offset-ref.gif
+== one-color-offset.gif one-color-offset-ref.gif
 
 # Bug 1068230
 == tile-transform.html tile-transform-ref.html
 
 # Bug 1234077
 == truncated-framerect.html truncated-framerect-ref.html
--- a/image/test/reftest/ico/ico-bmp-1bpp/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-1bpp/reftest.list
@@ -12,12 +12,12 @@
 == ico-size-9x9-1bpp.ico   ico-size-9x9-1bpp.png
 == ico-size-15x15-1bpp.ico ico-size-15x15-1bpp.png
 == ico-size-16x16-1bpp.ico ico-size-16x16-1bpp.png
 == ico-size-17x17-1bpp.ico ico-size-17x17-1bpp.png
 == ico-size-31x31-1bpp.ico ico-size-31x31-1bpp.png
 == ico-size-32x32-1bpp.ico ico-size-32x32-1bpp.png
 == ico-size-33x33-1bpp.ico ico-size-33x33-1bpp.png
 == ico-size-256x256-1bpp.ico ico-size-256x256-1bpp.png
-fails-if(stylo) == ico-partial-transparent-1bpp.ico ico-partial-transparent-1bpp.png
-fails-if(stylo) == ico-transparent-1bpp.ico ico-transparent-1bpp.png
-fails-if(stylo) == ico-not-square-transparent-1bpp.ico ico-not-square-transparent-1bpp.png
+== ico-partial-transparent-1bpp.ico ico-partial-transparent-1bpp.png
+== ico-transparent-1bpp.ico ico-transparent-1bpp.png
+== ico-not-square-transparent-1bpp.ico ico-not-square-transparent-1bpp.png
 
--- a/image/test/reftest/ico/ico-bmp-24bpp/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-24bpp/reftest.list
@@ -12,12 +12,12 @@
 == ico-size-9x9-24bpp.ico   ico-size-9x9-24bpp.png
 == ico-size-15x15-24bpp.ico ico-size-15x15-24bpp.png
 == ico-size-16x16-24bpp.ico ico-size-16x16-24bpp.png
 == ico-size-17x17-24bpp.ico ico-size-17x17-24bpp.png
 == ico-size-31x31-24bpp.ico ico-size-31x31-24bpp.png
 == ico-size-32x32-24bpp.ico ico-size-32x32-24bpp.png
 == ico-size-33x33-24bpp.ico ico-size-33x33-24bpp.png
 == ico-size-256x256-24bpp.ico ico-size-256x256-24bpp.png
-fails-if(stylo) == ico-partial-transparent-24bpp.ico ico-partial-transparent-24bpp.png
-fails-if(stylo) == ico-transparent-24bpp.ico ico-transparent-24bpp.png
-fails-if(stylo) == ico-not-square-transparent-24bpp.ico ico-not-square-transparent-24bpp.png
+== ico-partial-transparent-24bpp.ico ico-partial-transparent-24bpp.png
+== ico-transparent-24bpp.ico ico-transparent-24bpp.png
+== ico-not-square-transparent-24bpp.ico ico-not-square-transparent-24bpp.png
 
--- a/image/test/reftest/ico/ico-bmp-32bpp/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-32bpp/reftest.list
@@ -12,11 +12,11 @@
 == ico-size-9x9-32bpp.ico   ico-size-9x9-32bpp.png
 == ico-size-15x15-32bpp.ico ico-size-15x15-32bpp.png
 == ico-size-16x16-32bpp.ico ico-size-16x16-32bpp.png
 == ico-size-17x17-32bpp.ico ico-size-17x17-32bpp.png
 == ico-size-31x31-32bpp.ico ico-size-31x31-32bpp.png
 == ico-size-32x32-32bpp.ico ico-size-32x32-32bpp.png
 == ico-size-33x33-32bpp.ico ico-size-33x33-32bpp.png
 == ico-size-256x256-32bpp.ico ico-size-256x256-32bpp.png
-fails-if(stylo) == ico-partial-transparent-32bpp.ico ico-partial-transparent-32bpp.png
-fails-if(stylo) == ico-transparent-32bpp.ico ico-transparent-32bpp.png
-fails-if(stylo) == ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png
+== ico-partial-transparent-32bpp.ico ico-partial-transparent-32bpp.png
+== ico-transparent-32bpp.ico ico-transparent-32bpp.png
+== ico-not-square-transparent-32bpp.ico ico-not-square-transparent-32bpp.png
--- a/image/test/reftest/ico/ico-bmp-4bpp/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-4bpp/reftest.list
@@ -12,12 +12,12 @@
 == ico-size-9x9-4bpp.ico   ico-size-9x9-4bpp.png
 == ico-size-15x15-4bpp.ico ico-size-15x15-4bpp.png
 == ico-size-16x16-4bpp.ico ico-size-16x16-4bpp.png
 == ico-size-17x17-4bpp.ico ico-size-17x17-4bpp.png
 == ico-size-31x31-4bpp.ico ico-size-31x31-4bpp.png
 == ico-size-32x32-4bpp.ico ico-size-32x32-4bpp.png
 == ico-size-33x33-4bpp.ico ico-size-33x33-4bpp.png
 == ico-size-256x256-4bpp.ico ico-size-256x256-4bpp.png
-fails-if(stylo) == ico-partial-transparent-4bpp.ico ico-partial-transparent-4bpp.png
-fails-if(stylo) == ico-transparent-4bpp.ico ico-transparent-4bpp.png
-fails-if(stylo) == ico-not-square-transparent-4bpp.ico ico-not-square-transparent-4bpp.png
+== ico-partial-transparent-4bpp.ico ico-partial-transparent-4bpp.png
+== ico-transparent-4bpp.ico ico-transparent-4bpp.png
+== ico-not-square-transparent-4bpp.ico ico-not-square-transparent-4bpp.png
 
--- a/image/test/reftest/ico/ico-bmp-8bpp/reftest.list
+++ b/image/test/reftest/ico/ico-bmp-8bpp/reftest.list
@@ -12,12 +12,12 @@
 == ico-size-9x9-8bpp.ico   ico-size-9x9-8bpp.png
 == ico-size-15x15-8bpp.ico ico-size-15x15-8bpp.png
 == ico-size-16x16-8bpp.ico ico-size-16x16-8bpp.png
 == ico-size-17x17-8bpp.ico ico-size-17x17-8bpp.png
 == ico-size-31x31-8bpp.ico ico-size-31x31-8bpp.png
 == ico-size-32x32-8bpp.ico ico-size-32x32-8bpp.png
 == ico-size-33x33-8bpp.ico ico-size-33x33-8bpp.png
 == ico-size-256x256-8bpp.ico ico-size-256x256-8bpp.png
-fails-if(stylo) == ico-partial-transparent-8bpp.ico ico-partial-transparent-8bpp.png
+== ico-partial-transparent-8bpp.ico ico-partial-transparent-8bpp.png
 fails-if(stylo) == ico-transparent-8bpp.ico ico-transparent-8bpp.png
-fails-if(stylo) == ico-not-square-transparent-8bpp.ico ico-not-square-transparent-8bpp.png
+== ico-not-square-transparent-8bpp.ico ico-not-square-transparent-8bpp.png
 
--- a/image/test/reftest/ico/ico-mixed/reftest.list
+++ b/image/test/reftest/ico/ico-mixed/reftest.list
@@ -1,3 +1,3 @@
 # ICO BMP and PNG mixed tests
 
-fails-if(stylo) == mixed-bmp-png.ico mixed-bmp-png48.png
+== mixed-bmp-png.ico mixed-bmp-png48.png
--- a/image/test/reftest/ico/ico-png/reftest.list
+++ b/image/test/reftest/ico/ico-png/reftest.list
@@ -20,10 +20,10 @@
 
 # Corrupted files so no image should be loaded
 # x00n0g01 - empty 0x0 grayscale file
 == wrapper.html?x00n0g01.ico about:blank
 # xcrn0g04 - added cr bytes
 == wrapper.html?xcrn0g04.ico about:blank
 
 # Test ICO PNG transparency
-fails-if(stylo) == transparent-png.ico transparent-png.png
+== transparent-png.ico transparent-png.png
 
--- a/layout/inspector/tests/test_color_to_rgba.html
+++ b/layout/inspector/tests/test_color_to_rgba.html
@@ -16,20 +16,20 @@
   testColor("rgb(255,0,0)", {r:255, g:0, b:0, a:1});
   testColor("rgba(255,0,0)", {r:255, g:0, b:0, a:1});
   testColor("rgb(255,0,0,0.7)", {r:255, g:0, b:0, a:0.7});
   testColor("rgba(255,0,0,0.7)", {r:255, g:0, b:0, a:0.7});
   testColor("rgb(50%,75%,60%)", {r:128, g:191, b:153, a:1});
   testColor("rgba(50%,75%,60%)", {r:128, g:191, b:153, a:1});
   testColor("rgb(100%,50%,25%,0.7)", {r:255, g:128, b:64, a:0.7});
   testColor("rgba(100%,50%,25%,0.7)", {r:255, g:128, b:64, a:0.7});
-  testColor("hsl(320,30%,10%)", {r:33, g:17, b:28, a:1});
-  testColor("hsla(320,30%,10%)", {r:33, g:17, b:28, a:1});
-  testColor("hsl(170,60%,40%,0.9)", {r:40, g:163, b:142, a:0.9});
-  testColor("hsla(170,60%,40%,0.9)", {r:40, g:163, b:142, a:0.9});
+  testColor("hsl(320,30%,10%)", {r:33, g:18, b:28, a:1});
+  testColor("hsla(320,30%,10%)", {r:33, g:18, b:28, a:1});
+  testColor("hsl(170,60%,40%,0.9)", {r:41, g:163, b:143, a:0.9});
+  testColor("hsla(170,60%,40%,0.9)", {r:41, g:163, b:143, a:0.9});
 
   function testColor(color, expected) {
     let rgb = utils.colorToRGBA(color);
 
     if (rgb === null) {
       ok(expected === null, "color: " + color + " returns null");
       return;
     }
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1196,17 +1196,17 @@ test-pref(dom.use_xbl_scopes_for_remote_
 == 455171-5.html 455171-5-ref.html
 == 455280-1.xhtml 455280-1-ref.xhtml
 == 455826-1.html 455826-1-ref.html
 fails-if(cocoaWidget) fails-if(Android) == 456147.xul 456147-ref.html # bug 458047
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1a.html 456219-1-ref.html # bug 1128229
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1b.html 456219-1-ref.html # bug 1128229
 fuzzy-if(Android,11,41) fuzzy-if(winWidget||gtkWidget,4,6) fuzzy-if(d2d,4,69) == 456219-1c.html 456219-1-ref.html # bug 1128229
 fuzzy-if(skiaContent,1,45) == 456219-2.html 456219-2-ref.html
-fails-if(stylo) == 456330-1.gif 456330-1-ref.png
+== 456330-1.gif 456330-1-ref.png
 == 456484-1.html 456484-1-ref.html
 == 457398-1.html 457398-1-ref.html
 == 457398-2.html 457398-2-ref.html
 == 458296-1a.html 458296-1a-ref.html
 == 458296-1b.html 458296-1-ref.html
 == 458296-1c.html 458296-1-ref.html
 == 458296-1d.html 458296-1-ref.html
 == 458487-1a.html 458487-1-ref.html
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -154,16 +154,17 @@ support-files = file_bug1089417_iframe.h
 [test_bug1112014.html]
 [test_bug1203766.html]
 [test_bug1232829.html]
 [test_bug1292447.html]
 [test_cascade.html]
 [test_ch_ex_no_infloops.html]
 [test_change_hint_optimizations.html]
 [test_clip-path_polygon.html]
+[test_color_rounding.html]
 [test_compute_data_with_start_struct.html]
 skip-if = toolkit == 'android'
 [test_computed_style.html]
 [test_computed_style_min_size_auto.html]
 [test_computed_style_no_pseudo.html]
 [test_computed_style_prefs.html]
 [test_condition_text.html]
 [test_condition_text_assignment.html]
new file mode 100644
--- /dev/null
+++ b/layout/style/test/test_color_rounding.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=utf-8>
+  <title>Test rounding of CSS color valus</title>
+  <link rel="author" title="Manish Goregaokar" href="mailto:mgoregaokar@mozilla.com">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <link rel='stylesheet' href='/resources/testharness.css'>
+</head>
+<body>
+<div id="colordiv"></div>
+<script>
+
+function do_test(color, computed, reason) {
+    test(function() {
+        var element = document.getElementById('colordiv');
+        // assume this works; this way we clear any previous state
+        element.style.color = "red";
+        element.style.color = color;
+        assert_equals(getComputedStyle(element).color, computed);
+    }, `${reason}: ${color}`);
+}
+
+do_test("rgb(10%, 10%, 10%, 10%)", "rgba(26, 26, 26, 0.1)", "rgb percent-to-int should round");
+do_test("rgb(10%, 10%, 10%)", "rgb(26, 26, 26)", "rgb percent-to-int should round");
+do_test("hsl(0, 0%, 90%)", "rgb(230, 230, 230)", "hsl-to rgb should round");
+do_test("hsla(0, 0%, 90%, 10%)", "rgba(230, 230, 230, 0.1)", "hsl-to rgb should round");
+do_test("rgb(100%, 100%, 0%)", "rgb(255, 255, 0)", "handling of extrema");
+do_test("rgba(100%, 100%, 100%, 100%)", "rgb(255, 255, 255)", "handling of extrema");
+do_test("rgba(100%, 100%, 100%, 0%)", "rgba(255, 255, 255, 0)", "handling of extrema");
+do_test("rgb(255.5, 260, 500, 50)", "rgb(255, 255, 255)", "out of bounds should be handled");
+do_test("rgb(254.5, 254.55, 254.45)", "rgb(255, 255, 254)", "number values should be rounded");
+do_test("rgb(99.8%, 99.9%, 99.7%)", "rgb(254, 255, 254)", "percentage values should be rounded");
+
+</script>
+</body>
+</html>
--- a/toolkit/components/places/tests/browser/browser_colorAnalyzer.js
+++ b/toolkit/components/places/tests/browser/browser_colorAnalyzer.js
@@ -195,17 +195,17 @@ add_task(function* test_interestingColor
 // 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");
+  }, 0xAA0909, "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);