chromium/third_party/blink/perf_tests/shadow_dom/resources/declarative.js

(function() {
  const lightDomElementName = 'x-elemnt'; // Must have the same length as 'template'
  function getSnippet(useShadowDom,innerContent,lightDomDuplicates) {
    innerContent = innerContent ?? '<span><!--This is the leaf node--></span>';
    lightDomDuplicates = lightDomDuplicates ?? 1;
    PerfTestRunner.assert_true(!useShadowDom || lightDomDuplicates === 1,'Only light dom content can use duplicates');
    let openTag = useShadowDom ? '<template shadowrootmode=open>' : `<${lightDomElementName} shadowrootmode=open>`;
    let closeTag = useShadowDom ? '</template>' : `</${lightDomElementName}>`;
    let hiddenLightDomContent = useShadowDom ? '<span>Some non-slotted light dom content</span>' : '<!--   Some hidden light-dom content here   -->';
    let extraCopies = '';
    while (lightDomDuplicates>1) {
      extraCopies += `${openTag}${closeTag}`;
      --lightDomDuplicates;
    }
    return `<div class="host">${extraCopies}${openTag}${innerContent}<span><!--Shadow content here--></span>${closeTag}${hiddenLightDomContent}</div>`;
  }

  function getShadowMarkup(useShadowDom, depth, copies, lightDomDuplicates) {
    let snippet = undefined;
    for (let d=0;d<depth;++d) {
      snippet = getSnippet(useShadowDom, snippet, lightDomDuplicates);
    }
    let html = '<!DOCTYPE html><body>';
    for(let i=0;i<copies;++i) {
      html += snippet;
    }
    return html;
  }

  function getPolyfillMarkup(escapeClosingTag) {
    escapeClosingTag = escapeClosingTag ?? true;
    return `<script>
      document.querySelectorAll('${lightDomElementName}').forEach(element => {
        const shadowRoot = element.parentNode.attachShadow({ mode: 'open' });
        shadowRoot.replaceChildren(...Array.from(element.childNodes));
        element.remove();
      });
      <${escapeClosingTag ? '\/' : '/'}script>
    }`
  }

  const domParser = new DOMParser();
  function parseHtml(html) {
    return Document.parseHTMLUnsafe(html);
  }

  function measureParse(html) {
    let start = PerfTestRunner.now();
    parseHtml(html);
    return PerfTestRunner.now() - start;
  }

  function parseAndAppend(parent, html) {
    const fragment = Document.parseHTMLUnsafe(html);
    parent.replaceChildren(...fragment.body.childNodes);
  }

  function measureParseAndAppend(parent, html) {
    parent.replaceChildren(); // Ensure empty
    let start = PerfTestRunner.now();
    parseAndAppend(parent, html);
    return PerfTestRunner.now() - start;
  }

  async function measureLoadTimeIframe(html) {
    return new Promise((resolve, reject) => {
      const iframe = document.createElement('iframe');
      iframe.style.display = 'none';
      iframe.srcdoc = html;
      iframe.onload = () => {
        resolve(PerfTestRunner.now() - start);
        iframe.remove();
      };
      let start = PerfTestRunner.now();
      document.body.appendChild(iframe);
    });
  }

  function median(data) {
    data.sort();
    const middle = Math.floor(data.length / 2);
    return data.length % 2 ? data[middle] : (data[middle - 1] + data[middle]) / 2;
  }

  // Do some double-checks that things are working:
  function testParse(html) {
    const test_div = document.createElement('div');
    measureParseAndAppend(test_div, html);
    return test_div;
  }
  PerfTestRunner.assert_true(HTMLTemplateElement.prototype.hasOwnProperty("shadowRootMode"),'Declarative Shadow DOM not enabled/supported');
  PerfTestRunner.assert_true(testParse(getShadowMarkup(true, 1, 1)).firstChild.shadowRoot,'Declarative Shadow DOM not detected');
  PerfTestRunner.assert_true(getShadowMarkup(true, 5, 6).length === getShadowMarkup(false, 5, 6).length,'Shadow and light DOM content should have identical length');
  const light1 = testParse(getShadowMarkup(false, 5, 6, /*lightDomDuplicates=*/1)).querySelectorAll(lightDomElementName).length;
  const light2 = testParse(getShadowMarkup(false, 5, 6, /*lightDomDuplicates=*/2)).querySelectorAll(lightDomElementName).length;
  PerfTestRunner.assert_true(light1*2 === light2,"The lightDomDuplicates parameter isn't working");

  window.parseHtml = parseHtml;
  window.measureParse = measureParse;
  window.parseAndAppend = parseAndAppend;
  window.measureParseAndAppend = measureParseAndAppend;
  window.measureLoadTimeIframe = measureLoadTimeIframe;
  window.getShadowMarkup = getShadowMarkup;
  window.getPolyfillMarkup = getPolyfillMarkup;
  window.median = median;
})();