graphics_HwOverlays: Fix kukui canvas* test cases

kukui/krane etc have a fractional deviceAspectRatio and have a nonzero
rotation (screen.orientation.angle) when set in its 0 UI rotation (i.e.
landscape). This breaks all of our graphics_HwOverlays.canvas* tests.

This CL prerrotates the canvas via a scaleZ() CSS transforms, and fixes
the devicePixelRatio by making the canvas itself of integer dimensions,
while having sub-pixel accuracy (see crbug.com/1042110 for why).

It also adds a CSS left offset to allow for canvases to be entirely
inside the screen, which happens somwhoe in krane. (And this needs the
div with "position:relative" style to wrap up the canvas with
"position:absolute").

TEST=test_that  -b ${BOARD} $IP graphics_HwOverlays.canvas* on krane,
and kohaku
BUG=chromium:1046109, chromium:1046445

Change-Id: I2140ab7b2ac59bf5c7e33a5cc9dfda9cc9d4c00d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2024167
Tested-by: Miguel Casas <mcasas@chromium.org>
Reviewed-by: Ilja H. Friedel <ihf@chromium.org>
diff --git a/client/site_tests/graphics_HwOverlays/canvas_2d_low_latency.html b/client/site_tests/graphics_HwOverlays/canvas_2d_low_latency.html
index 956ff21..707a09e 100644
--- a/client/site_tests/graphics_HwOverlays/canvas_2d_low_latency.html
+++ b/client/site_tests/graphics_HwOverlays/canvas_2d_low_latency.html
@@ -3,32 +3,53 @@
   <title>Canvas 2D Low Latency</title>
 </head>
 <body>
-  <canvas id='canvas1' style="border: 1px solid black;"></canvas>
+  <div style="position:relative; padding: 25px">
+    <canvas id='canvas1' style="position:absolute;"></canvas>
+  </div>
 </body>
 <script type="text/javascript">
   let canvas = document.getElementById('canvas1');
-  // Make the canvas very large but still falling inside the viewport; |height|
+  let ctx = canvas.getContext('2d', { desynchronized: true, alpha: false});
+
+  // Some devices, e.g. krane, have a non-zero rotation in landscape mode. We
+  // precompensate this via the rotateZ CSS transform. See crbug.com/1046109.
+  const angle = screen.orientation.angle % 360;
+  canvas.style.transform = `rotateZ(${angle}deg)`;
+
+  // Make the canvas large but still falling inside the viewport; |height|
   // also has to account for the Shelf (taskbar) at the bottom.
+  const integerWidth = Math.min(500, Math.floor(window.innerWidth * 0.9));
+  const integerHeight = Math.min(300, Math.floor(window.innerHeight * 0.9));
+
+  // We need subpixel accuracy for non-integer aspect ratios crbug.com/1042110.
   const dpr = window.devicePixelRatio || 1;
-  const width = (window.innerWidth / dpr) * 0.9 / dpr;
-  const height = (window.innerHeight / dpr) * 0.9 / dpr;
-  canvas.width = width;
-  canvas.height = height;
+  canvas.style.border = `${1 / dpr}px solid black`;
+  if (angle % 180 == 90) {
+    canvas.width = integerHeight;
+    canvas.height = integerWidth;
+    canvas.style.width = `${integerHeight / dpr}px`;
+    canvas.style.height = `${integerWidth / dpr}px`;
 
-  let ctx = canvas.getContext('2d', {
-    desynchronized: true,
-    alpha: false
-  });
+    // On krane, the canvas needs to be shifted "rightwards" when the screen is
+    // rotated 90 or 270 degrees, to bring it in view, see crbug.com/1046445/
+    const offset = ((integerWidth / dpr) - (integerHeight / dpr)) / 2;
+    canvas.style.left = `${offset}px`;
+  } else {
+    canvas.width = integerWidth;
+    canvas.height = integerHeight;
+    canvas.style.width = `${integerWidth / dpr}px`;
+    canvas.style.height = `${integerHeight / dpr}px`;
+  }
+
   let draw_passes_count = 0;
-
   function draw_pass() {
     ctx.beginPath();
     ctx.lineWidth = '5';
     // Consider a seeded random number generator if there are reproducibility
     // problems.
     ctx.strokeStyle = 'rgb(' + 0 + ',' + Math.random() * 255 + ',0)';
-    ctx.moveTo(Math.random() * width, Math.random() * height);
-    ctx.lineTo(Math.random() * width, Math.random() * height);
+    ctx.moveTo(Math.random() * integerWidth, Math.random() * integerHeight);
+    ctx.lineTo(Math.random() * integerWidth, Math.random() * integerHeight);
     ctx.stroke(); // Draw it
     draw_passes_count++;
   }
diff --git a/client/site_tests/graphics_HwOverlays/canvas_3d.html b/client/site_tests/graphics_HwOverlays/canvas_3d.html
index 007c3d1..a2206ed 100644
--- a/client/site_tests/graphics_HwOverlays/canvas_3d.html
+++ b/client/site_tests/graphics_HwOverlays/canvas_3d.html
@@ -3,19 +3,46 @@
   <title>Canvas 3D</title>
 </head>
 <body>
-  <canvas id='canvas1' style="border: 1px solid black;"></canvas>
+  <div style="position:relative; padding: 25px">
+    <canvas id='canvas1' style="position:absolute;"></canvas>
+  </div>
 </body>
 <script type="text/javascript">
   var canvas = document.getElementById('canvas1');
   var ctx = canvas.getContext('webgl');
-  // Make the canvas very large but still falling inside the viewport; |height|
+
+  // Some devices, e.g. krane, have a non-zero rotation in landscape mode. We
+  // precompensate this via the rotateZ CSS transform. See crbug.com/1046109.
+  const angle = screen.orientation.angle % 360;
+  canvas.style.transform = `rotateZ(${angle}deg)`;
+
+  // Make the canvas large but still falling inside the viewport; |height|
   // also has to account for the Shelf (taskbar) at the bottom.
+  const integerWidth = Math.min(500, Math.floor(window.innerWidth * 0.9));
+  const integerHeight = Math.min(300, Math.floor(window.innerHeight * 0.9));
+
+  // We need subpixel accuracy for non-integer aspect ratios crbug.com/1042110.
   const dpr = window.devicePixelRatio || 1;
-  canvas.width = (window.innerWidth / dpr) * 0.9 / dpr;
-  canvas.height = (window.innerHeight / dpr) * 0.9 / dpr;
+  canvas.style.border = `${1 / dpr}px solid black`;
+  if (angle % 180 == 90) {
+    canvas.width = integerHeight;
+    canvas.height = integerWidth;
+    canvas.style.width = `${integerHeight / dpr}px`;
+    canvas.style.height = `${integerWidth / dpr}px`;
+
+    // On krane, the canvas needs to be shifted "rightwards" when the screen is
+    // rotated 90 or 270 degrees, to bring it in view, see crbug.com/1046445/
+    const offset = ((integerWidth / dpr) - (integerHeight / dpr)) / 2;
+    canvas.style.left = `${offset}px`;
+    //canvas.style.top = `-${offset}px`;
+  } else {
+    canvas.width = integerWidth;
+    canvas.height = integerHeight;
+    canvas.style.width = `${integerWidth / dpr}px`;
+    canvas.style.height = `${integerHeight / dpr}px`;
+  }
 
   var draw_passes_count = 0;
-
   function draw_pass() {
     // Consider a seeded random number generator if there are reproducibility
     // problems.