chromium/third_party/blink/web_tests/inspector-protocol/resources/device-emulation.html

<html>
<head>
<script>
function setMetaViewport(override)
{
    var VIEWPORTS = {
        "w=320": "width=320",
        "w=dw": "width=device-width",
        "w=980": "width=980",
        "none": "no viewport (desktop site)"
    };

    var viewport = VIEWPORTS["none"];
    for (var key in VIEWPORTS) {
        if (location.search.indexOf(key) !== -1) {
            viewport = VIEWPORTS[key];
            window.__viewport = key;
            break;
        }
    }
    if (override) {
        viewport = VIEWPORTS[override];
        window.__viewport = override;
    }
    if (viewport != VIEWPORTS["none"])
        document.write('<meta name="viewport" content="'+viewport+'">');
}

var results;

function dumpMetrics(full)
{
    results = [];
    writeResult("Device:", "");
    testJS("window.screenX");
    testJS("window.screenY");

    writeResult("Viewport:", "?" + window.__viewport);

    testMQOrientation();
    testJS("window.orientation", "");

    if (full) {
        testMQDimension("resolution", null, "dpi");
        testMQDevicePixelRatio(window.devicePixelRatio);
        testJS("window.devicePixelRatio", "");
    }

    writeResult("Widths:", "");

    if (full) {
        testMQDimension("device-width", screen.width);
        testJS("screen.width");
        testJS("screen.availWidth");
        testJS("window.outerWidth");
        testJS("window.innerWidth");
        testMQDimension("width", document.documentElement.clientWidth);
    }
    testJS("document.documentElement.clientWidth");
    testJS("document.documentElement.offsetWidth");
    testJS("document.documentElement.scrollWidth");
    if (full)
        testJS("document.body.clientWidth");
    testJS("document.body.offsetWidth");
    testJS("document.body.scrollWidth");

    writeResult("Heights:", "");

    if (full) {
        testMQDimension("device-height", screen.height);
        testJS("screen.height");
        testJS("screen.availHeight");
        testJS("window.outerHeight");
        testJS("window.innerHeight");
        testMQDimension("height", document.documentElement.clientHeight);
    }
    testJS("document.documentElement.clientHeight");
    testJS("document.documentElement.offsetHeight");
    testJS("document.documentElement.scrollHeight");
    if (full)
        testJS("document.body.clientHeight");
    testJS("document.body.offsetHeight");
    testJS("document.body.scrollHeight");

    return results.join("\n");
}

function dumpDevicePosture() {
  let output = [];
  output.push("Main frame Posture:");
  output = output.concat(navigator.devicePosture.type);
  output.push("Iframe Posture:");
  output = output.concat(window.frames[0].navigator.devicePosture.type);
  return output.join("\n");
}

function dumpViewportSegments() {
    let output = [];
    output.push("Main frame segments:");
  output = output.concat(dumpViewportSegmentsForWindow(this));
    output.push("Iframe segments:");
  output = output.concat(dumpViewportSegmentsForWindow(window.frames[0]));
    return output.join("\n");
}

function dumpViewportSegmentsForWindow(window_object) {
    let output = [];
    let segments = window_object.viewport.segments;
    output.push(segments ? segments.length : 0);
    if (segments) {
      segments.forEach((segment) => {
          let segmentString = `${segment.x} ${segment.y} ${segment.width} ${segment.height}`;
          output.push(segmentString);
      });
    }
    return output;
}

function testJS(expr, unit)
{
    if (unit === undefined)
        unit = "px";

    var ans = eval(expr);
    if (typeof ans == "number")
        ans += unit;

    // Shorten long properties to make more readable
    expr = expr.replace("documentElement", "docElem").replace("document", "doc");

    writeResult(expr, ans);
}

function testMQOrientation()
{
    if (matchMedia("screen and (orientation: portrait)").matches)
        writeResult("@media orientation", "portrait");
    else if (matchMedia("screen and (orientation: landscape)").matches)
        writeResult("@media orientation", "landscape");
    else
        writeResult("@media orientation", "???");
}

function testMQDevicePixelRatio(guess)
{
    // To save time, try the guess value first; otherwise try common values (TODO: binary search).
    if (matchMedia("screen and (-webkit-device-pixel-ratio: "+guess+"), screen and (device-pixel-ratio: "+guess+")").matches)
        writeResult("@media device-pixel-ratio", guess);
    else if (matchMedia("screen and (-webkit-device-pixel-ratio: 2), screen and (device-pixel-ratio: 2)").matches)
        writeResult("@media device-pixel-ratio", "2");
    else if (matchMedia("screen and (-webkit-device-pixel-ratio: 1.5), screen and (device-pixel-ratio: 1.5)").matches)
        writeResult("@media device-pixel-ratio", "1.5");
    else if (matchMedia("screen and (-webkit-device-pixel-ratio: 1), screen and (device-pixel-ratio: 1)").matches)
        writeResult("@media device-pixel-ratio", "1");
    else if (matchMedia("screen and (-webkit-device-pixel-ratio: 2.25), screen and (device-pixel-ratio: 2.25)").matches)
        writeResult("@media device-pixel-ratio", "2.25");
    else
        writeResult("@media device-pixel-ratio", "???");
}

function testMQDimension(feature, guess, unit)
{
    unit = unit || "px";
    // To save time, try the guess value first; otherwise binary search.
    if (guess && matchMedia("screen and (" + feature + ":" + guess + unit + ")").matches) {
        writeResult("@media " + feature, guess + unit);
    } else {
        var val = mqBinarySearch(feature, 1, 2560, unit);
        writeResult("@media " + feature, val ? val + unit : "???");
    }
}

// Searches the inclusive range [minValue, maxValue].
function mqBinarySearch(feature, minValue, maxValue, unit)
{
    if (minValue == maxValue) {
        if (matchMedia("screen and (" + feature + ":" + minValue + unit + ")").matches)
            return minValue;
        else
            return null;
    }
    var mid = Math.ceil((minValue + maxValue) / 2);
    if (matchMedia("screen and (min-" + feature + ":" + mid + unit + ")").matches)
        return mqBinarySearch(feature, mid, maxValue, unit); // feature is >= mid
    else
        return mqBinarySearch(feature, minValue, mid - 1, unit); // feature is < mid
}

function writeResult(key, val)
{
    results.push(key + (val ? " = " + val : ""));
}
</script>

<script>
  // This test is based on http://jsbin.com/urowoh/latest.
  setMetaViewport();
</script>

<style>
html {
    overflow-x: hidden;
}

body {
    margin: 0;
    min-height: 1000px;
    overflow-x: hidden;
}
body.small {
    min-height: 100px;
}
</style>
</head>

<body>
<iframe src="about:blank"></iframe>
</body>
</html>