chromium/chrome/test/data/pdf/viewer_thumbnail_test.ts

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import type {ViewerThumbnailElement} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js';
import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';

function createThumbnail() {
  document.body.innerHTML = '';
  const thumbnail = document.createElement('viewer-thumbnail');
  document.body.appendChild(thumbnail);
  return thumbnail;
}

function testThumbnailSize(
    thumbnail: ViewerThumbnailElement, imageSize: number[],
    canvasSize: number[]) {
  const imageData = new ImageData(imageSize[0]!, imageSize[1]!);
  thumbnail.image = imageData;

  const canvas = thumbnail.shadowRoot!.querySelector('canvas')!;
  chrome.test.assertEq(`${canvasSize[0]}px`, canvas.style.width);
  chrome.test.assertEq(`${canvasSize[1]}px`, canvas.style.height);

  // The div containing the canvas should be resized to fit.
  const div = canvas.parentElement!;
  chrome.test.assertEq(canvasSize[0], div.offsetWidth);
  chrome.test.assertEq(canvasSize[1], div.offsetHeight);
}

async function testThumbnailRotation(
    thumbnail: ViewerThumbnailElement, clockwiseRotations: number,
    divSize: number[]) {
  thumbnail.clockwiseRotations = clockwiseRotations;
  await microtasksFinished();

  const canvas = thumbnail.shadowRoot!.querySelector('canvas')!;
  const halfTurn = clockwiseRotations % 2 === 0;
  chrome.test.assertEq(
      `${halfTurn ? divSize[0] : divSize[1]}px`, canvas.style.width);
  chrome.test.assertEq(
      `${halfTurn ? divSize[1] : divSize[0]}px`, canvas.style.height);

  // The div containing the rotated canvas should be resized to fit.
  const div = canvas.parentElement!;
  chrome.test.assertEq(divSize[0], div.offsetWidth);
  chrome.test.assertEq(divSize[1], div.offsetHeight);

  chrome.test.assertEq(
      `rotate(${clockwiseRotations * 90}deg)`, canvas.style.transform);
}

async function testThumbnailRotations(
    imageSize: number[], rotatedDivSizes: number[][]) {
  const thumbnail = createThumbnail();
  const imageData = new ImageData(imageSize[0]!, imageSize[1]!);
  thumbnail.image = imageData;

  chrome.test.assertEq(4, rotatedDivSizes.length);
  for (let rotations = 0; rotations < rotatedDivSizes.length; rotations++) {
    await testThumbnailRotation(
        thumbnail, rotations, rotatedDivSizes[rotations]!);
  }
}

const tests = [
  function testSetNormalImageLowRes() {
    window.devicePixelRatio = 1;
    const thumbnail = createThumbnail();

    [
        // Letter portrait
        {imageSize: [108, 140], canvasSize: [108, 140]},
        // Letter landscape
        {imageSize: [140, 108], canvasSize: [140, 108]},
        // A4 portrait
        {imageSize: [108, 152], canvasSize: [108, 152]},
        // A4 portrait
        {imageSize: [152, 108], canvasSize: [140, 99]},
    ].forEach(({
                imageSize,
                canvasSize,
              }) => testThumbnailSize(thumbnail, imageSize, canvasSize));

    chrome.test.succeed();
  },
  function testSetNormalImageHighRes() {
    window.devicePixelRatio = 2;
    const thumbnail = createThumbnail();

    [
        // Letter portrait
        {imageSize: [216, 280], canvasSize: [108, 140]},
        // Letter landscape
        {imageSize: [280, 216], canvasSize: [140, 108]},
        // A4 portrait
        {imageSize: [216, 304], canvasSize: [108, 152]},
        // A4 portrait
        {imageSize: [304, 216], canvasSize: [140, 99]},
    ].forEach(({
                imageSize,
                canvasSize,
              }) => testThumbnailSize(thumbnail, imageSize, canvasSize));

    chrome.test.succeed();
  },
  function testSetExtremeImageLowRes() {
    window.devicePixelRatio = 1;
    const thumbnail = createThumbnail();

    [
        // The image should not scale to preserve its resolution.
        {imageSize: [50, 1500], canvasSize: [50, 1500]},
        // The image should scale down to fit in the sidenav.
        {imageSize: [1500, 50], canvasSize: [140, 4]},
    ].forEach(({
                imageSize,
                canvasSize,
              }) => testThumbnailSize(thumbnail, imageSize, canvasSize));

    chrome.test.succeed();
  },
  function testSetExtremeImageHighRes() {
    window.devicePixelRatio = 2;
    const thumbnail = createThumbnail();

    [
        // The image should scale down to preserve its resolution.
        {imageSize: [50, 1500], canvasSize: [25, 750]},
        // The image should scale down to fit in the sidenav.
        {imageSize: [1500, 50], canvasSize: [140, 4]},
    ].forEach(({
                imageSize,
                canvasSize,
              }) => testThumbnailSize(thumbnail, imageSize, canvasSize));

    chrome.test.succeed();
  },
  async function testRotateNormalLowRes() {
    window.devicePixelRatio = 1;

    // Letter
    await testThumbnailRotations(
        [108, 140], [[108, 140], [140, 108], [108, 140], [140, 108]]);

    // A4
    await testThumbnailRotations(
        [108, 152], [[108, 152], [140, 99], [108, 152], [140, 99]]);

    chrome.test.succeed();
  },
  async function testRotateNormalHighRes() {
    window.devicePixelRatio = 2;

    // Letter
    await testThumbnailRotations(
        [216, 280], [[108, 140], [140, 108], [108, 140], [140, 108]]);

    // A4
    await testThumbnailRotations(
        [216, 304], [[108, 152], [140, 99], [108, 152], [140, 99]]);

    chrome.test.succeed();
  },
  async function testRotateNormalHighRes() {
    window.devicePixelRatio = 1;

    await testThumbnailRotations(
        [50, 1500], [[50, 1500], [140, 4], [50, 1500], [140, 4]]);

    chrome.test.succeed();
  },
  async function testRotateNormalHighRes() {
    window.devicePixelRatio = 2;

    await testThumbnailRotations(
        [50, 1500], [[25, 750], [140, 4], [25, 750], [140, 4]]);

    chrome.test.succeed();
  },
  async function testContextMenuDisabled() {
    // Set some image data so a canvas is created inside the thumbnail.
    const thumbnail = createThumbnail();
    thumbnail.image = new ImageData(108, 140);
    const canvas = thumbnail.shadowRoot!.querySelector('canvas')!;

    const whenContextMenu = eventToPromise('contextmenu', canvas);
    canvas.dispatchEvent(new CustomEvent('contextmenu', {cancelable: true}));
    const e = await whenContextMenu;

    chrome.test.assertTrue(e.defaultPrevented);
    chrome.test.succeed();
  },
];

chrome.test.runTests(tests);