Thursday, 13 November 2014

Programming Aphorisms

There are some simple saying that I like that help me write better code. They may not be true in all cases but are generally true. I'll probably update this over time.


Development Qualities: Readability > Duplication > Performance
Product Qualities: Usability > Redundancy > Performance
  • Code is as much a product to developers and the product itself is to users.
  • Always true unless it will be discarded immediately.
  • If you can't explain it you can't do it right.
  • If someone else can't understand it then they can use it. (Could be yourself in a few months.)
  • If the code has to be optimized heavily for performance then that optimized code needs to be written especially better so it can be easily understood and it must say what optimizations have been implemented and why.
  • Redundancy and duplication can be a good thing is it improves overall usability and readability. I say overall because you have to judge the specific case against the added complexity.

Use smart objects and dumb code.
  • Related to don't repeat yourself principle.
Programs must be written for people to read, and only incidentally for machines to execute.
  • Just remember how fun it is to read code you're not familiar with, and how long it takes.
  • Few people even remember their own code after a while.
Code tells you how; comments tell you why.
  • The code should be descriptive and make it very clear what is happening, but code itself cannot explain why it is needed.
Premature optimization is the root of all evil.
  • It's better to write easy to understand code and optimize if later if possible.
  • Optimization is not possible without profiling.
  • It is okay to do simple obvious optimization when it doesn't hurt readability.
If you don't know how to do something, you don't know how to do it on a computer.

Trust, but verify.
  • A Russian proverb made famous by in the west by Ronald Reagan concerning nuclear disarmament.
  • A belief without evidence is not sufficient for knowledge.
  • For programming it means testing.
  • For requirement gathering it mean include features in plans but check if necessary before implementation.
  • For people "It's not that I don't believe you, it's that I need to know you're right."
  • Closely related to the cover your ass principle.
Don't repeat yourself.
  • Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
Later equals never.
  • LeBlanc's Law
  • Technical debt
  • Addressing problems as they are found and fixing them properly results in higher efficiency and higher quality.
  • Quick fixes are the same as doing it later but often worse.
  • Maximizing output maximizes output required (effort, time, and cost).
  • It is easy to put something off, difficult to do it now, and nearly impossible to start doing something that has been put off.
 The only way to go fast -- is to keep the code as clean as possible at all times.
  • Slow and steady wins the race.
  • It takes more time to read bad code then to clean it up.
Master programmers think of systems as stories to be told rather than programs to be written.
  • No jumps in logic.
  • Set things up then resolve them.
The first rule of functions is that they should be small.
  • This include length and width. Try to minimize the area not including blank lines.
  • A lot of nesting results in triangle code.
Don't write in triangles.
  • Nesting of code blocks results in triangle shaped code.
  • This usually results in logical jumps when a long if block is followed by a short else block. 
  • This indents a lot of code making the code bigger and more difficult to read.

http://c2.com/cgi/wiki?DontRepeatYourself
http://alvinalexander.com/programming/clean-code-quotes-robert-c-martin

Friday, 19 April 2013

WebVTT Reftest Bug

For the bug 855633 in Mozilla's bug tracker.

https://bugzilla.mozilla.org/show_bug.cgi?id=855633

I've written many reftests for WebVTT. Outstanding tests include positioning cues with right-to-left test. There appears to be a bug in the specification. Overlapping cue tests need to be written. Tests for the tags ruby, class, and voice are not done. In addition, there are no tests for new CSS properties such as ::cue.

I've had to make a number of basic test changes. The first is that the height of the first line in a cue should be found using the css property height instead of line-height. Line-height returns "normal" on some browsers but height is always a number. Also, the specification wants the height of the first line not the line-height of the first line.

Another issue was that the height may not always be an integer. Decimal pixel values are valid (eg. 27.6px) so parseFloat should be used instead of parseInt.

The following tests are written.


Test the default behaviour. No particular rule. (April 17, 2013)
basic

Make sure cues do not render for the audio element. (April 17, 2013)
audio

Make sure control interface and cue do not overlap. (April 17, 2013)
controls

Ensure cues display in the correct order for multiple cues and tracks. (April 17, 2013)
2tracks-start-time-a
2tracks-start-time-b
1track-start-time-a
1track-start-time-b
2tracks-track-order-a
2tracks-track-order-b
2tracks-end-time-a
2tracks-end-time-b
1track-end-time-a
1track-end-time-b
1track-cue-order-a
1track-cue-order-b

Right to left writing direction test (April 17, 2013)
writing-direction-rtl

Writing mode vertical test (April 17, 2013)
writing-mode-vertical-lr
writing-mode-vertical-rl

Cue writing direction, alignment, and writting mode tests. (April 17, 2013)
The rules for direction, alignment, and mode depend on each other
so tests for each individually would be the identical.
There is a specification bug for positioning cues with right-to-left text. Those tests need to be done.
setting-horizontal-end-ltr
setting-horizontal-left-ltr
setting-horizontal-middle49-ltr
setting-horizontal-middle50-ltr
setting-horizontal-middle51-ltr
setting-horizontal-right-ltr
setting-horizontal-start-ltr
setting-vertical-lr-end
setting-vertical-lr-left
setting-vertical-lr-middle49
setting-vertical-lr-middle50
setting-vertical-lr-middle51
setting-vertical-lr-right
setting-vertical-lr-start
setting-vertical-rl-end
setting-vertical-rl-left
setting-vertical-rl-middle49
setting-vertical-rl-middle50
setting-vertical-rl-middle51
setting-vertical-rl-right
setting-vertical-rl-start

Snap-to-line tests
snap-to-lines-false-horizontal
snap-to-lines-false-vertical-lr
snap-to-lines-false-vertical-rl
snap-to-lines-true-horizontal
snap-to-lines-true-vertical-lr
snap-to-lines-true-vertical-rl

Text wrapping tests
wrap-balance
wrap-break-word

Cue test payload tag tests
tag-bold
tag-italic
tag-underline.vtt

Thursday, 18 April 2013

WebVTT Cue Display Order


I was working on the order that cues are displayed for a WebVTT file and I came across some interesting things. I was looking to test the following render rule which is a little hard to figure out but the HTML5 specification was very specific on the order.

"8. For each track track in tracks, append to cues all the cues from track's list of cues that have their text track cue active flag set."


http://dev.w3.org/html5/webvtt/#cues-with-video (April, 17, 2013)


This means that cues from different tracks should display the same as cues for the same track.

"13. Sort the tasks in events in ascending time order (tasks with earlier times first).
Further sort tasks in events that have the same time by the relative text track cue order of the text track cues associated with these tasks."


http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#list-of-newly-introduced-cues (April, 17, 2013)


The event time is the start time for entering cues, and later of the start and end time for exiting cues.

"text track cue order, which is determined as follows: first group the cues by their text track, with the groups being sorted in the same order as their text tracks appear in the media element's list of text tracks; then, within each group, cues must be sorted by their start time, earliest first; then, any cues with the same start time must be sorted by their end time, latest first; and finally, any cues with identical end times must be sorted in the order they were last added to their respective text track list of cues, oldest first"


http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#text-track-cue-order (April, 17, 2013)


Therefore the correct cue order is:
  1. start time (ascending)
  2. track order (top to bottom)
  3. end time (descending)
  4. cue order (top to bottom)
There are a few important things to take away from this. First, the start time is more important than anything else and the cues from multiple tracks will be mixed together. Also, end times are descending. If the cue ending soonest were under the longer lasting cue, the lasting cue would drop when the other exits. This may make it look like another cue, so it's better to have the lasting one stay in the same place on the bottom.

With the starting time being most important, one would think the ending time would be second. Instead the track order is second. This at first seems odd, but because the tracks are likely for different purposes, separating them is useful. Start time trumps track order because cues could appear in between other cues instead of at the top.

There are 12 reftests to test all possible cases with 1 track and 2 tracks.

Wednesday, 17 April 2013

WebVTT Cue Layout Reference

The purpose of this post is to describe how a WebVTT file should render. I will reference rules from the rendering cues for video section.


3. Let output be an empty list of absolutely positioned CSS block boxes.


This is a div element with the the CSS property position set to absolute.

4. If the user agent is exposing a user interface for video, add to output one or more completely transparent positioned CSS block boxes that cover the same region as the user interface.


If the video has controls visible, add a empty div over the control area.

9. For each track track in tracks, append to cues all the cues from track's list of cues that have their text track cue active flag set.
10. If reset is false, then, for each text track cue cue in cues: if cue's text track cue display state has a set of CSS boxes, then add those boxes to output, and remove cue from cues.
10. 17. Add the CSS boxes in boxes to output.


For every cue to be displayed in all tracks, add a div. If the cue has already been rendered, use the existing div.

10. 12. - The children of the nodes must be wrapped in an anonymous box whose 'display' property has the value 'inline'. This is the WebVTT cue background box.


The cue contents should be rendered into a signle <div style="display:inline"> inside the cue div.

10. 12. - Text runs must be wrapped according to the CSS line-wrapping rules, with the following additional constraints:
10. 12. - * Regardless of the value of the 'white-space' property, lines must be wrapped at the edge of their containing blocks, even if doing so requires splitting a word where there is no line breaking opportunity. (Thus, normally text wraps as needed, but if there is a particularly long word, it does not overflow as it normally would in CSS, it is instead forcibly wrapped at the box's edge.)
10. 12. - * Regardless of the value of the 'white-space' property, any line breaks inserted by the user agent for the purposes of line wrapping must be placed so as to minimize Δ across each run of consecutive lines between preserved newlines in the source. Δ for a set of lines is defined as the sum over each line of the absolute of the difference between the line's length and the mean line length of the set.


If a word is longer than the allowed width break the work with a hyphen. Don't use the CSS property word-wrap to break-word, this needs to be determined dynamically. After the number of lines is know and words broken, minimize the cue width without creating new lines.

For example

This is a really long sentence that needs to be displayed on
two lines.


should be

This is a really long sentence that
needs to be displayed on two lines.


Viewport

The specification uses the CSS viewport units vw and vh. I cannot get these to work properly with video, so I've calculated the values based on the video.


Layout

This is what the layout should be for a basic webvtt cue.

Test Video CSS



#testVideo {
 position: absolute;
 left: 0px;
 top: 0px;
 width: 640px;
 height: 480px;
}


Basic Cue Reference CSS



/* cue constants, same for every cue */
.cueBox {
 position: absolute;
 unicode-bidi: plaintext;
 font: 24px sans-serif;    /* 5vh = 24px */
 color: rgba(255,255,255,1);
 white-space: pre-line;
 
}
.cueBackgroundBox {
 display:inline;
 background: rgba(0,0,0,0.8);
}

/* cue variables, depends on cue */
#testCue {
 direction: ltr;
 writing-mode: horizontal-tb;
 left: 0px;    /* 0vw = 0px */
 top: 0px;    /* 0vh = 0px */
 width: 640px;    /* 100vw = 640px */
 text-align: center;
}

Thursday, 28 March 2013

WebVTT reftests

A reftest is a pass or fail test which checks that two web pages look identical. It does this by producing two bitmap images and verifying if they are identical or not. HTML content can be rendered the same way using different methods, such as an image and a specific frame of video. Reftests are useful to ensure that something is rendered correctly by comparing to what is ought to look like. Specifically, this is done by creating two web pages and comparing them.

Further information

Importance

This is tremendously important for WebVTT because it is the only way to ensure consistency to the specification, and therefore consistency between implementations. This means that a WebVTT file will look the same anywhere it is used, and thus enables content developers to use advanced features. WebVTT is a web standard after all.

The goal of web standards is to make implementation interoperable. (W3C) This means "the situation in which all implementations process particular content in a reliable and identical or equivalent way." (W3C) Historically when format implementations were not consistent with each other, developers only used a limited subset of the format features, had multiple versions for each implementation, or used a third-party solution. Recall the browser wars and the push for browsers to comply with web standards. (Web Standards Project)

Reftest Format

A reftest consists of three files:
  • Test page with feature to be tested
  • Reference page that show have the feature should look
  • A reftest.list file that lists the assertions

Example

The following test should pass and serves to demonstrate the basic format.

spaces1.html
<html><body>
X X
</body></html>

spaces2.html
<html><body>
X&nbsp;X
</body></html>

reftests.list
== spaces1.html spaces2.html

Details

There are two main types of assertions, expect pass (==) or expect fail (!=).

The two tests will be processed as soon as the page finished loading. Sometimes the test needs to be delayed for asynchronous content. This can be accomplished by adding the class "reftest-wait" to the HTML element and removing it at the appropriate time. This is required for WebVTT test because the video and text tracks are loaded  asynchronously.

Basic WebVTT Test

basic.html
<html class="reftest-wait">
<head>
 <meta charset="UTF-8">
 
 <style>
  #testVideo {
   position: absolute;
   left: 0px;
   top: 0px;
   width: 640px;
   height: 480px;
   margin: 0px;
   padding: 0px;
  }
 </style>
 
 <title>WebVTT</title>
</head>
<body>
 <video id="testVideo">
  <source src="grey320x240.ogv" type="video/ogg">
  <track src="basic.vtt">
 </video>
 
 <script src="testScript.js"></script>
</body>
</html>

basic-ref.html
<html class="reftest-wait">
<head>
 <meta charset="UTF-8">
 
 <style>
  #testVideo {
   position: absolute;
   left: 0px;
   top: 0px;
   width: 640px;
   height: 480px;
   margin: 0px;
   padding: 0px;
  }
  #testDiv {
   position: absolute;
   left: 0px;
   top: 250px;
   width: 640px;
   margin: 0px;
   padding: 0px;
  }
 </style>
 
 <title>WebVTT</title>
</head>
<body>
 <video id="testVideo">
  <source src="grey320x240.ogv" type="video/ogg">
 </video>
 <div id="testDiv">WebVTT Test</div>

 <script src="testScript.js"></script>
</body>
</html>

testScript.js
/*
   Make sure video is loaded,
   and that it is always at the same frame.
*/
document.getElementById('testVideo');

// Need to play to load video
testVideo.onplay = function() {
 
 // Stop video and seek to 5 seconds
 testVideo.onpause = function() {
 
  // When video is loaded, preform test
  testVideo.oncanplaythrough = function() {
   document.documentElement.className = "";
  };
  testVideo.currentTime = 5;
 };
 testVideo.pause();
};
testVideo.play();

Breakdown

CSS
The style is to make sure margins, padding, and positions are not a factor. We are not testing that, and by knowing the exact properties of the video we can create precisely what the caption should look for. It is important to only test one thing in each test.

Javascript
In order to make sure the test is correct, the bitmap must be created on exactly the same frame in the video. The following steps are performed to ensure that.

  • The video must be loaded and is not loaded until the video has been instructed to play.
  • The test must be performed on the same frame so the video must be paused on that frame.
  • To set the video to the correct frame for the test the video must be set to a predetermined frame.
    • currentTime is a decimal number in seconds
    • 1/24 is a second represents one frame in a 24 frame per second (fps) video
  • It may take time for the video to load the frame so it must wait until the video is loaded
    • A loading overlay may be shown while the video is loading. It must be gone before the test is performed.
  • Remove the "reftest-wait" class to perform the test.

Video

I created the video for the WebVTT tests. To do this I created a completely grey image. I chose grey so that white and black will be easily seen and not blend into the background. I used VirtualDub to create a raw video AVI using an AviSynth file with the ImageSource function and a silent audio file I created. I then converted the AVI to the Theora video format (OGV). Theora was chose because it is a free and open format, is specified by the HTML5 standard, and works in most browsers including Mozilla Firefox and Google Chrome.

File size is 30 kilobytes.

video
Created by Kyle Barnhart (me)
Released to public domain under Unlicense

Running Tests

Test are easily run in a Mozilla build. Just used "./mach reftest" to run all tests. You can also specify a particular set of tests. For WebVTT I used the following.

./mach reftest layout/reftests/webvtt/reftest.list

This also shows the standard location for reftests in mozilla-central.

After you have built the code, running the tests only takes a few seconds or more depending on the number of tests and the time it takes to clear the "reftest-wait" class in each test that must be delayed.

Saturday, 9 March 2013

WebVTT Parser Rules

In some recent discussion the nature of the specification has come up again. Since this has never been dealt with, I was told to ignore and leave the issue, an update seems in order.

There is a new bug that has been posted where the following is stated.
"Also add a notice at syntax specification that implementers need to read the parsing section."
- Bug 21230 - [WebVTT] specify extension points in syntax spec

This comes from a discussion on the mailing list. I'll add the following relevant sections.

[Discussion of conflict between syntax and parser rules in WebVTT specification]

No, there is no conflict. The first one is the current spec, the second is the requirement on how to parse it so that the current spec can be extended in the future.

- Silvia Pfeiffer


Ralph Giles wrote:
"If you do want to do something application-specific here, at least try to follow the syntax rules implied by Silvia's draft. Then when you have some implementation experience, we should try to spec what those rules actually are."

Please don't do that, either. Don't put anything in there at all until we're sure of what the format should be.

- Glenn Maynard


Just to clarify (at least to my understanding): The first is the file format, and the second is the parser.  Both are part of the spec.  The file format tells you what's valid--what authors should be writing.  The parser tells you how to deal with every possible input, which includes error handling (inputs that don't follow the file format) and--as you said--forwards-compatibility.

I've seen a couple people confused by this, leading to people trying to write implementations by looking at the file format, which is bad.  Browser vendors understand it, since that's how the HTML spec works, but since non-browser people without experience with that spec may be implementing this (more than most other parts of the web), maybe there should be a brief note at the top of the file format section explaining this.  ("If you're implementing WebVTT, you're in the wrong place!")

- Glenn Maynard


Agreed, we need to clarify this. I want to make sure to specify extension points in the syntax specification to make sure that implementers are made aware of this.

- Silvia Pfeiffer

Tuesday, 5 March 2013

WebVTT Mozilla Reftest

I'm working on what needs to be done for testing the WebVTT rendering rules. The best way to go looks like using reftest. Mozilla MDN has a page on it. Full documentation for Mozilla is here.

It is very straightforward. Make two HTML pages that are identical except for the thing you want to test. For example, webvtt-basic.html will have a <track> in a <video>. webvtt-basic-ref.html will have <div> in <video>. The results must look exactly the same to pass the test.

Reftest works be taking a screenshot of the windows immediately after the document is loaded and comparing. However, since this is a video that might take a second to load, adding the class reftest-wait and removing it when the time is right with document.documentElement.className = "".

Here is a basic test.
<!DOCTYPE html>
<html class="reftest-wait">
<title>WebVTT</title>
<body>
<video id="testVideo" autoplay>
    <source src="test.ogv" type="video/ogg">
    <track src="test.vtt">
</video>
</body>
<script>
    document.getElementById('testVideo').onplay = function(e) {
  document.documentElement.className = "";
    };
</script>
</html>


I found a nice public domain video to use.

video