chromium/third_party/blink/renderer/core/css/scripts/style_perftest_snap_page

#!/usr/bin/env python3
# Copyright (c) 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Create a JSON bundle containing a snapshot of any webpage
(HTML and stylesheets), suitable for the style perftest
(style_perftest.cc).

Use e.g. as:

  third_party/blink/renderer/core/css/scripts/style_perftest_snap_page
      --browser=content-shell-default \
      --url=https://www.sesse.net/ \
      --snapshot-path=whatever.json

The file can then be put in third_party/blink/renderer/core/css/perftest_data/
and/or be uploaded to the cloud buckets.

User stylesheets are not included due to JavaScript limitations.

Note that some pages with CORS profiles will deny getting stylesheets;
if so, you may need to hack CSSStyleSheet::CanAccessRules()
in your local build.
"""

import os
import sys
import codecs

TELEMETRY_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), '../../../../../catapult/telemetry')
sys.path.append(TELEMETRY_DIR)

from telemetry.util import wpr_modes
from telemetry.internal.browser import browser_options
from telemetry.internal.browser import browser_finder
from telemetry.internal.util import binary_manager

JSON_SUFFIX = '.json'
EXPENSIVE_JS_TIMEOUT_SECONDS = 240

def _CreateBrowser(finder_options):
  possible_browser = browser_finder.FindBrowser(finder_options)
  return possible_browser.BrowserSession(finder_options.browser_options)

def SnapPageToFile(finder_options, url, snapshot_path):
  """ Save the HTML snapshot of the page whose address is |url| to
  |snapshot_file|. If there are multiple iframes, only the first
  (numerically lowest ID) will be saved.
  """
  with _CreateBrowser(finder_options) as browser:
    tab = browser.tabs[0]
    tab.Navigate(url)

    print('Snapshotting content of %s. This could take a while...' % url)
    tab.WaitForDocumentReadyStateToBeComplete()
    tab.action_runner.WaitForNetworkQuiescence(
        timeout_in_seconds=EXPENSIVE_JS_TIMEOUT_SECONDS)

    context_id = list(tab.EnableAllContexts())[0]
    tab.ExecuteJavaScript(
       '''
       var serializedDom = {
         "html": document.documentElement.outerHTML,
         "stylesheets": [],
       };
       for (let i = 0; i < document.styleSheets.length; ++i) {
         let sheet = document.styleSheets[i];
         let text = "";
         for (let j = 0; j < sheet.rules.length; ++j) {
           text += sheet.rules[j].cssText + '\\n';
         }
         serializedDom.stylesheets.push({
           "type": "author",
           "text": text
         });
       }
       ''', context_id=context_id,
       timeout=EXPENSIVE_JS_TIMEOUT_SECONDS)

    page_snapshot = tab.EvaluateJavaScript('JSON.stringify(serializedDom)',
                                           context_id=context_id)

    print('Writing page snapshot [path=%s].' % snapshot_path)
    with codecs.open(snapshot_path, 'w', 'utf-8') as f:
      f.write(page_snapshot)

def main(args):
  options = browser_options.BrowserFinderOptions()
  parser = options.CreateParser(
      usage='Create a snapshot of the page, suitable for the style perftest')
  parser.add_option('--url', help='URL of the web page to record')
  parser.add_option('--snapshot-path', help='Where to save the snapshot',
      default='snapshot.json')
  parser.parse_args(args)

  binary_manager.InitDependencyManager([])

  if not options.snapshot_path.endswith(JSON_SUFFIX):
    raise ValueError('Snapshot path should end with \'%s\' [value=\'%s\'].' % (
        JSON_SUFFIX, options.snapshot_path))

  SnapPageToFile(options, options.url, options.snapshot_path)

if __name__ == '__main__':
  sys.exit(main(sys.argv[1:]))