<!DOCTYPE html>
<html>
<head>
  <title>CSS Values and Units Test: Checks viewport units against CSS 2.1 properties and the CSSOM</title>
  <meta charset="UTF-8">
  <meta name="assert" content="Testing what happens when one applies and rereads viewport unit lengths to CSS 2.1 properties that accept length values" />
  <link rel="author" title="Christian Schaefer" href="mailto:schaepp@gmx.de">
  <link rel="help" href="http://www.w3.org/TR/css3-values/#viewport-relative-lengths">
  <script src="/resources/testharness.js"></script>
  <script src="/resources/testharnessreport.js"></script>
  <style>
    #div {
      position: relative;
      width: 50vw;
      height: 10vw;
      background: green;
      border: 0 green solid;
      font-size: 4vw;
    }

    #table td {
      border: 1px solid green;
    }
  </style>
</head>
<body>
  <div id="log"></div>

  <p>
    Checks viewport units. Also re-check with zoom in/out.
  </p>

  <div id="div">
    Test the Web Forward!
  </div>

  <table id="table">
    <tbody>
      <tr>
        <td id="td">Test</td>
        <td>T</td>
        <td>W</td>
        <td>F</td>
      </tr>
    </tbody>
  </table>

  <script>

  /* Boilerplate code */

  var camelize = function (str) {
    return str.replace(/\-(\w)/g, function(str, letter){
      return letter.toUpperCase();
    });
  };

  var retrieveComputedStyle = function(element,property){
    var result =
      document
      .defaultView
      .getComputedStyle(element,null)
      .getPropertyValue(property);

    // If there are multiple values, cut down to the first
    result = result.split(' ')[0];

    if(window.console) console.log('Retrieving ' + property + ' property. Result: ' + result);

    return result;
  }

  var testit = function(element,vunit,property,expectedResult){

    element.style[camelize(property)] = '0px';
    element.style[camelize(property)] = lengthAmount + vunit;

    if(window.console) console.log(element.nodeName.toLowerCase() + '.style.' + camelize(property) + ' = ' + lengthAmount + vunit);

    var result = retrieveComputedStyle(element,property);

    // Test against WebKit's getComputedStyle bug, where it does not return absolute values
    // As required here: http://www.w3.org/TR/1998/REC-CSS2-19980512/cascade.html#computed-value
    // If it returns a pixel value, but this value is 0px then it is considered a fail, too.
    var px_result = result.search(/^[-\d\.]+px$/) !== -1 && result !== '0px' ? 'non-zero px-based value' : result;

    // If browser returns pixel value, we compare against our expected pixel value
    if(px_result === 'non-zero px-based value'){
      test(function(){
        assert_equals(Math.round(parseFloat(result.replace(/[^-\d\.]+/g,''))),expectedResult);
      },vunit + ' length applied to ' + property);
    }
    // If not, we compare against the value we set initially
    else {
      test(function(){
        assert_equals(result,lengthAmount + vunit);
      },vunit + ' length applied to ' + property);
    }

    // Does the browser have a bug in getComputedStyle or not?
    test(function(){
      assert_equals(px_result,'non-zero px-based value');
    },vunit + ' length applied to ' + property + ': getComputedStyle returns a non-zero px-based value');

    element.style[camelize(property)] = '';
  }

  var lengthAmount = 10;
  var layoutViewportWidth = document.documentElement.clientWidth;
  var layoutViewportHeight = document.documentElement.clientHeight;

  var viewportUnits = [
     {
       ident: 'vw',
       expectedResult: Math.round(layoutViewportWidth * (lengthAmount / 100))
    }
    ,{
       ident: 'vh',
       expectedResult: Math.round(layoutViewportHeight * (lengthAmount / 100))
    }
    ,{
       ident: 'vmin',
       expectedResult: layoutViewportWidth < layoutViewportHeight ? Math.round(layoutViewportWidth * (lengthAmount / 100)) : Math.round(layoutViewportHeight * (lengthAmount / 100))
    }
    ,{
       ident: 'vmax',
       expectedResult: layoutViewportWidth > layoutViewportHeight ? Math.round(layoutViewportWidth * (lengthAmount / 100)) : Math.round(layoutViewportHeight * (lengthAmount / 100))
    }
  ]

  // List of length accepting properties and which element they map to
  // http://www.w3.org/TR/CSS21/propidx.html
  var lengthAcceptingProperties = [
     {
      name: 'width',
      element: 'div'
    }
    ,{
      name: 'height',
      element: 'div'
    }
    ,{
      name: 'min-width',
      element: 'div'
    }
    ,{
      name: 'min-height',
      element: 'div'
    }
    ,{
      name: 'max-width',
      element: 'div'
    }
    ,{
      name: 'max-height',
      element: 'div'
    }
    ,{
      name: 'margin-top',
      element: 'div'
    }
    ,{
      name: 'padding-top',
      element: 'div'
    }
    ,{
      name: 'border-top-width',
      element: 'div'
    }
    ,{
      name: 'font-size',
      element: 'div'
    }
    ,{
      name: 'line-height',
      element: 'div'
    }
    ,{
      name: 'border-spacing',
      element: 'table'
    }
    ,{
      name: 'top',
      element: 'div'
    }
    ,{
      name: 'right',
      element: 'div'
    }
    ,{
      name: 'bottom',
      element: 'div'
    }
    ,{
      name: 'left',
      element: 'div'
    }
    ,{
      name: 'letter-spacing',
      element: 'div'
    }
    ,{
      name: 'text-indent',
      element: 'div'
    }
    ,{
      name: 'vertical-align',
      element: 'td'
    }
    ,{
      name: 'word-spacing',
      element: 'div'
    }
  ];

  var div = document.getElementById('div');
  var table = document.getElementById('table');
  var td = document.getElementById('td');

  for(unitEntry in viewportUnits){
    for(propertyEntry in lengthAcceptingProperties){

      var vunit = viewportUnits[unitEntry].ident;
      var expectedResult = viewportUnits[unitEntry].expectedResult;
      var property = lengthAcceptingProperties[propertyEntry].name;
      var element = window[lengthAcceptingProperties[propertyEntry].element];

      testit(element,vunit,property,expectedResult);
    }
  }

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