<!DOCTYPE HTML>
<html>
<head>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script>

let gl, ext;

function getStrings() {
  const ret = {
    renderer: gl.getParameter(gl.RENDERER),
    vendor: gl.getParameter(gl.VENDOR),
  };
  if (ext) {
    ret.unmasked_renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
    ret.unmasked_vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);
  }
  return ret;
}

const RTX3070_R = 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11-27.21.14.5751)';
const RTX3070_V = 'Google Inc.';
const RTX3070_R_SANITIZED = 'ANGLE (NVIDIA, NVIDIA GeForce GTX 980 Direct3D11 vs_5_0 ps_5_0)';

function expectJsonEqual(was, expected, when) {
  if (when) {
    when = when + ': ';
  } else {
    when = '';
  }
  const wasStr = JSON.stringify(was);
  const expectedStr = JSON.stringify(expected);
  let str = `${when}Was ${wasStr}`;
  const matches = (wasStr == expectedStr);
  if (!matches) {
    str += `, expected ${expectedStr}`;
  }
  ok(matches, str);
}

async function testKnownCiStrings() {
  gl = document.createElement('canvas').getContext('webgl');
  if (!gl) return;

  await SpecialPowers.pushPrefEnv({'set': [
    ['webgl.sanitize-unmasked-renderer', false],
  ]});
  ext = gl.getExtension('WEBGL_debug_renderer_info');
  const was = getStrings();

  const KNOWN_ON_CI = {
    renderer: [
      'Adreno (TM) 540', // Android
      'Adreno (TM) 650', // Android pixel5
      'llvmpipe', // Linux
      'Intel(R) HD Graphics 400', // Mac
      'Apple M1', // Mac
      'ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0)', // Windows
    ],
    vendor: [
      'Mozilla',
    ],
    unmasked_renderer: [
      'Adreno (TM) 540', // Android
      'Adreno (TM) 620', // Android pixel5
      'llvmpipe (LLVM 10.0.0, 256 bits)', // Linux
      'Intel(R) UHD Graphics 630', // Mac
      'Apple M1', // Mac
      'ANGLE (NVIDIA, NVIDIA Tesla M60 Direct3D11 vs_5_0 ps_5_0, D3D11-23.21.13.9181)', // Windows
      'ANGLE (NVIDIA, NVIDIA Tesla M60 Direct3D11 vs_5_0 ps_5_0, D3D11-30.0.14.7239)', // Windows 11
    ],
    unmasked_vendor: [
      'Qualcomm', // Android
      'VMware, Inc.', // Linux
      'Intel Inc.', // Mac
      'Apple', // Mac
      'Google Inc. (NVIDIA)', // Windows
    ],
  };
  for (const k in was) {
    const wasVal = was[k];
    const knownList = KNOWN_ON_CI[k];
    ok(knownList.includes(wasVal),
       `[ignore if not on CI] getParameter(${k}) -> ${wasVal} must be in KNOWN_ON_CI`);
  }
  await SpecialPowers.popPrefEnv();
}

// -

async function testPrefBehavior() {
  const canvas = document.createElement('canvas');
  gl = canvas.getContext('webgl');
  ext = null;
  if (!gl) {
    todo(gl, 'Get WebGL working here first.');
    return;
  }

  // -
  // Assuming that we're on CI, test against known-good strings.
  // If we add machine configs, we'll need to add to these lists.
  // This is to avoid situations like bug 1743734, where ANGLE added
  // detailed driver version/date to its RENDERER strings, which
  // we want to prevent.

  const KNOWN_CI_VENDORS = [
    'Mozilla',
  ];
  const KNOWN_CI_RENDERERS = [
    'Adreno (TM) 540', // Android
    'Adreno (TM) 650', // Android
    'Intel(R) HD Graphics 400', // Mac
    'Apple M1', // Mac
    'llvmpipe', // Linux
    'ANGLE (NVIDIA, NVIDIA GeForce 8800 GTX Direct3D11 vs_5_0 ps_5_0)', // Windows
  ];
  function assertKnownValid(key, knownList) {
    const val = gl.getParameter(gl[key]);
    ok(knownList.includes(val),
       `[ignore if not on CI] getParameter(${key}) -> ${val} not known-valid!`);
  }
  assertKnownValid('VENDOR', KNOWN_CI_VENDORS);
  assertKnownValid('RENDERER', KNOWN_CI_RENDERERS);

  // -

  await SpecialPowers.pushPrefEnv({'set': [
    ['webgl.override-unmasked-renderer', RTX3070_R],
    ['webgl.override-unmasked-vendor', RTX3070_V],
  ]});

  // -
  // Test disabled

  await SpecialPowers.pushPrefEnv({'set': [
    ['webgl.enable-debug-renderer-info', false],
  ]});

  ext = gl.getExtension('WEBGL_debug_renderer_info');
  ok(!ext,
     'When pref disabled: Should not have access to \'WEBGL_debug_renderer_info\'.');

  {
    const EXPECTED = {
      renderer: RTX3070_R_SANITIZED,
      vendor: 'Mozilla',
    };
    const was = getStrings();
    expectJsonEqual(was, EXPECTED, 'v92 behavior w/o ext');
  }

  await SpecialPowers.popPrefEnv();

  // -
  // Test RFP

  await SpecialPowers.pushPrefEnv({'set': [
    ['privacy.resistFingerprinting', true],
  ]});

  ext = gl.getExtension('WEBGL_debug_renderer_info');
  ok(!ext,
     'With RFP: Should not have access to \'WEBGL_debug_renderer_info\'.');

  {
    const EXPECTED = {
      renderer: 'Mozilla',
      vendor: 'Mozilla',
    };
    const was = getStrings();
    expectJsonEqual(was, EXPECTED, 'RFP behavior');
  }

  await SpecialPowers.popPrefEnv();

  // -
  // Test default state (v92+)

  ext = gl.getExtension('WEBGL_debug_renderer_info');
  ok(ext,
     'By default: Should have access to \'WEBGL_debug_renderer_info\'.');

  {
    const EXPECTED = {
      renderer: RTX3070_R_SANITIZED,
      vendor: 'Mozilla',
      unmasked_renderer: RTX3070_R_SANITIZED,
      unmasked_vendor: RTX3070_V,
    };
    const was = getStrings();
    expectJsonEqual(was, EXPECTED, 'v92 behavior');
  }

  // -
  // Test v91 behavior

  await SpecialPowers.pushPrefEnv({'set': [
    ['webgl.enable-renderer-query', false],
  ]});

  {
    const EXPECTED = {
      renderer: 'Mozilla',
      vendor: 'Mozilla',
      unmasked_renderer: RTX3070_R_SANITIZED,
      unmasked_vendor: RTX3070_V,
    };
    const was = getStrings();
    expectJsonEqual(was, EXPECTED, 'v91 behavior');
  }

  // -
  // Test v90 behavior

  await SpecialPowers.pushPrefEnv({'set': [
    ['webgl.sanitize-unmasked-renderer', false],
  ]});

  {
    const EXPECTED = {
      renderer: 'Mozilla',
      vendor: 'Mozilla',
      unmasked_renderer: RTX3070_R,
      unmasked_vendor: RTX3070_V,
    };
    const was = getStrings();
    expectJsonEqual(was, EXPECTED, 'v90 behavior');
  }
}

// -

SimpleTest.waitForExplicitFinish();
(async function() {
  await testKnownCiStrings();
  await testPrefBehavior();

  ok(true, 'Test complete.');
  SimpleTest.finish();
})();

</script>
</body>
</html>
