home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / AvantBrowser / asetup.exe / _data / webkit / chrome.dll / 0 / BINDATA / 551 < prev    next >
Encoding:
Text File  |  2013-04-03  |  34.7 KB  |  1,144 lines

  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4.  
  5. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  6. // Use of this source code is governed by a BSD-style license that can be
  7. // found in the LICENSE file.
  8.  
  9. cr.define('media', function() {
  10.   'use strict';
  11.  
  12.   /**
  13.    * This class represents a file cached by net.
  14.    */
  15.   function CacheEntry() {
  16.     this.read_ = new media.DisjointRangeSet;
  17.     this.written_ = new media.DisjointRangeSet;
  18.     this.available_ = new media.DisjointRangeSet;
  19.  
  20.     // Set to true when we know the entry is sparse.
  21.     this.sparse = false;
  22.     this.key = null;
  23.     this.size = null;
  24.  
  25.     // The <details> element representing this CacheEntry.
  26.     this.details_ = document.createElement('details');
  27.     this.details_.className = 'cache-entry';
  28.     this.details_.open = false;
  29.  
  30.     // The <details> summary line. It contains a chart of requested file ranges
  31.     // and the url if we know it.
  32.     var summary = document.createElement('summary');
  33.  
  34.     this.summaryText_ = document.createTextNode('');
  35.     summary.appendChild(this.summaryText_);
  36.  
  37.     summary.appendChild(document.createTextNode(' '));
  38.  
  39.     // Controls to modify this CacheEntry.
  40.     var controls = document.createElement('span');
  41.     controls.className = 'cache-entry-controls';
  42.     summary.appendChild(controls);
  43.     summary.appendChild(document.createElement('br'));
  44.  
  45.     // A link to clear recorded data from this CacheEntry.
  46.     var clearControl = document.createElement('a');
  47.     clearControl.href = 'javascript:void(0)';
  48.     clearControl.onclick = this.clear.bind(this);
  49.     clearControl.textContent = '(clear entry)';
  50.     controls.appendChild(clearControl);
  51.  
  52.     this.details_.appendChild(summary);
  53.  
  54.     // The canvas for drawing cache writes.
  55.     this.writeCanvas = document.createElement('canvas');
  56.     this.writeCanvas.width = media.BAR_WIDTH;
  57.     this.writeCanvas.height = media.BAR_HEIGHT;
  58.     this.details_.appendChild(this.writeCanvas);
  59.  
  60.     // The canvas for drawing cache reads.
  61.     this.readCanvas = document.createElement('canvas');
  62.     this.readCanvas.width = media.BAR_WIDTH;
  63.     this.readCanvas.height = media.BAR_HEIGHT;
  64.     this.details_.appendChild(this.readCanvas);
  65.  
  66.     // A tabular representation of the data in the above canvas.
  67.     this.detailTable_ = document.createElement('table');
  68.     this.detailTable_.className = 'cache-table';
  69.     this.details_.appendChild(this.detailTable_);
  70.   }
  71.  
  72.   CacheEntry.prototype = {
  73.     /**
  74.      * Mark a range of bytes as read from the cache.
  75.      * @param {int} start The first byte read.
  76.      * @param {int} length The number of bytes read.
  77.      */
  78.     readBytes: function(start, length) {
  79.       start = parseInt(start);
  80.       length = parseInt(length);
  81.       this.read_.add(start, start + length);
  82.       this.available_.add(start, start + length);
  83.       this.sparse = true;
  84.     },
  85.  
  86.     /**
  87.      * Mark a range of bytes as written to the cache.
  88.      * @param {int} start The first byte written.
  89.      * @param {int} length The number of bytes written.
  90.      */
  91.     writeBytes: function(start, length) {
  92.       start = parseInt(start);
  93.       length = parseInt(length);
  94.       this.written_.add(start, start + length);
  95.       this.available_.add(start, start + length);
  96.       this.sparse = true;
  97.     },
  98.  
  99.     /**
  100.      * Merge this CacheEntry with another, merging recorded ranges and flags.
  101.      * @param {CacheEntry} other The CacheEntry to merge into this one.
  102.      */
  103.     merge: function(other) {
  104.       this.read_.merge(other.read_);
  105.       this.written_.merge(other.written_);
  106.       this.available_.merge(other.available_);
  107.       this.sparse = this.sparse || other.sparse;
  108.       this.key = this.key || other.key;
  109.       this.size = this.size || other.size;
  110.     },
  111.  
  112.     /**
  113.      * Clear all recorded ranges from this CacheEntry and redraw this.details_.
  114.      */
  115.     clear: function() {
  116.       this.read_ = new media.DisjointRangeSet;
  117.       this.written_ = new media.DisjointRangeSet;
  118.       this.available_ = new media.DisjointRangeSet;
  119.       this.generateDetails();
  120.     },
  121.  
  122.     /**
  123.      * Helper for drawCacheReadsToCanvas() and drawCacheWritesToCanvas().
  124.      *
  125.      * Accepts the entries to draw, a canvas fill style, and the canvas to
  126.      * draw on.
  127.      */
  128.     drawCacheEntriesToCanvas: function(entries, fillStyle, canvas) {
  129.       // Don't bother drawing anything if we don't know the total size.
  130.       if (!this.size) {
  131.         return;
  132.       }
  133.  
  134.       var width = canvas.width;
  135.       var height = canvas.height;
  136.       var context = canvas.getContext('2d');
  137.       var fileSize = this.size;
  138.  
  139.       context.fillStyle = '#aaa';
  140.       context.fillRect(0, 0, width, height);
  141.  
  142.       function drawRange(start, end) {
  143.         var left = start / fileSize * width;
  144.         var right = end / fileSize * width;
  145.         context.fillRect(left, 0, right - left, height);
  146.       }
  147.  
  148.       context.fillStyle = fillStyle;
  149.       entries.map(function(start, end) {
  150.         drawRange(start, end);
  151.       });
  152.     },
  153.  
  154.     /**
  155.      * Draw cache writes to the given canvas.
  156.      *
  157.      * It should consist of a horizontal bar with highlighted sections to
  158.      * represent which parts of a file have been written to the cache.
  159.      *
  160.      * e.g. |xxxxxx----------x|
  161.      */
  162.     drawCacheWritesToCanvas: function(canvas) {
  163.       this.drawCacheEntriesToCanvas(this.written_, '#00a', canvas);
  164.     },
  165.  
  166.     /**
  167.      * Draw cache reads to the given canvas.
  168.      *
  169.      * It should consist of a horizontal bar with highlighted sections to
  170.      * represent which parts of a file have been read from the cache.
  171.      *
  172.      * e.g. |xxxxxx----------x|
  173.      */
  174.     drawCacheReadsToCanvas: function(canvas) {
  175.       this.drawCacheEntriesToCanvas(this.read_, '#0a0', canvas);
  176.     },
  177.  
  178.     /**
  179.      * Update this.details_ to contain everything we currently know about
  180.      * this file.
  181.      */
  182.     generateDetails: function() {
  183.       this.details_.id = this.key;
  184.       this.summaryText_.textContent = this.key || 'Unknown File';
  185.  
  186.       this.detailTable_.textContent = '';
  187.       var header = document.createElement('thead');
  188.       var footer = document.createElement('tfoot');
  189.       var body = document.createElement('tbody');
  190.       this.detailTable_.appendChild(header);
  191.       this.detailTable_.appendChild(footer);
  192.       this.detailTable_.appendChild(body);
  193.  
  194.       var headerRow = document.createElement('tr');
  195.       headerRow.appendChild(media.makeElement('th', 'Read From Cache'));
  196.       headerRow.appendChild(media.makeElement('th', 'Written To Cache'));
  197.       header.appendChild(headerRow);
  198.  
  199.       var footerRow = document.createElement('tr');
  200.       var footerCell = document.createElement('td');
  201.       footerCell.textContent = 'Out of ' + (this.size || 'unkown size');
  202.       footerCell.setAttribute('colspan', 2);
  203.       footerRow.appendChild(footerCell);
  204.       footer.appendChild(footerRow);
  205.  
  206.       var read = this.read_.map(function(start, end) {
  207.         return start + ' - ' + end;
  208.       });
  209.       var written = this.written_.map(function(start, end) {
  210.         return start + ' - ' + end;
  211.       });
  212.  
  213.       var length = Math.max(read.length, written.length);
  214.       for (var i = 0; i < length; i++) {
  215.         var row = document.createElement('tr');
  216.         row.appendChild(media.makeElement('td', read[i] || ''));
  217.         row.appendChild(media.makeElement('td', written[i] || ''));
  218.         body.appendChild(row);
  219.       }
  220.  
  221.       this.drawCacheWritesToCanvas(this.writeCanvas);
  222.       this.drawCacheReadsToCanvas(this.readCanvas);
  223.     },
  224.  
  225.     /**
  226.      * Render this CacheEntry as a <li>.
  227.      * @return {HTMLElement} A <li> representing this CacheEntry.
  228.      */
  229.     toListItem: function() {
  230.       this.generateDetails();
  231.  
  232.       var result = document.createElement('li');
  233.       result.appendChild(this.details_);
  234.       return result;
  235.     }
  236.   };
  237.  
  238.   return {
  239.     CacheEntry: CacheEntry
  240.   };
  241. });
  242.  
  243. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  244. // Use of this source code is governed by a BSD-style license that can be
  245. // found in the LICENSE file.
  246.  
  247. cr.define('media', function() {
  248.  
  249.   /**
  250.    * This class represents a collection of non-intersecting ranges. Ranges
  251.    * specified by (start, end) can be added and removed at will. It is used to
  252.    * record which sections of a media file have been cached, e.g. the first and
  253.    * last few kB plus several MB in the middle.
  254.    *
  255.    * Example usage:
  256.    * someRange.add(0, 100);     // Contains 0-100.
  257.    * someRange.add(150, 200);   // Contains 0-100, 150-200.
  258.    * someRange.remove(25, 75);  // Contains 0-24, 76-100, 150-200.
  259.    * someRange.add(25, 149);    // Contains 0-200.
  260.    */
  261.   function DisjointRangeSet() {
  262.     this.ranges_ = {};
  263.   }
  264.  
  265.   DisjointRangeSet.prototype = {
  266.     /**
  267.      * Deletes all ranges intersecting with (start ... end) and returns the
  268.      * extents of the cleared area.
  269.      * @param {int} start The start of the range to remove.
  270.      * @param {int} end The end of the range to remove.
  271.      * @param {int} sloppiness 0 removes only strictly overlapping ranges, and
  272.      *                         1 removes adjacent ones.
  273.      * @return {Object} The start and end of the newly cleared range.
  274.      */
  275.     clearRange: function(start, end, sloppiness) {
  276.       var ranges = this.ranges_;
  277.       var result = {start: start, end: end};
  278.  
  279.       for (var rangeStart in this.ranges_) {
  280.         rangeEnd = this.ranges_[rangeStart];
  281.         // A range intersects another if its start lies within the other range
  282.         // or vice versa.
  283.         if ((rangeStart >= start && rangeStart <= (end + sloppiness)) ||
  284.             (start >= rangeStart && start <= (rangeEnd + sloppiness))) {
  285.           delete ranges[rangeStart];
  286.           result.start = Math.min(result.start, rangeStart);
  287.           result.end = Math.max(result.end, rangeEnd);
  288.         }
  289.       }
  290.  
  291.       return result;
  292.     },
  293.  
  294.     /**
  295.      * Adds a range to this DisjointRangeSet.
  296.      * Joins adjacent and overlapping ranges together.
  297.      * @param {int} start The beginning of the range to add, inclusive.
  298.      * @param {int} end The end of the range to add, inclusive.
  299.      */
  300.     add: function(start, end) {
  301.       if (end < start)
  302.         return;
  303.  
  304.       // Remove all touching ranges.
  305.       result = this.clearRange(start, end, 1);
  306.       // Add back a single contiguous range.
  307.       this.ranges_[Math.min(start, result.start)] = Math.max(end, result.end);
  308.     },
  309.  
  310.     /**
  311.      * Combines a DisjointRangeSet with this one.
  312.      * @param {DisjointRangeSet} ranges A DisjointRangeSet to be squished into
  313.      * this one.
  314.      */
  315.     merge: function(other) {
  316.       var ranges = this;
  317.       other.forEach(function(start, end) { ranges.add(start, end); });
  318.     },
  319.  
  320.     /**
  321.      * Removes a range from this DisjointRangeSet.
  322.      * Will split existing ranges if necessary.
  323.      * @param {int} start The beginning of the range to remove, inclusive.
  324.      * @param {int} end The end of the range to remove, inclusive.
  325.      */
  326.     remove: function(start, end) {
  327.       if (end < start)
  328.         return;
  329.  
  330.       // Remove instersecting ranges.
  331.       result = this.clearRange(start, end, 0);
  332.  
  333.       // Add back non-overlapping ranges.
  334.       if (result.start < start)
  335.         this.ranges_[result.start] = start - 1;
  336.       if (result.end > end)
  337.         this.ranges_[end + 1] = result.end;
  338.     },
  339.  
  340.     /**
  341.      * Iterates over every contiguous range in this DisjointRangeSet, calling a
  342.      * function for each (start, end).
  343.      * @param {function(int, int)} iterator The function to call on each range.
  344.      */
  345.     forEach: function(iterator) {
  346.       for (var start in this.ranges_)
  347.         iterator(start, this.ranges_[start]);
  348.     },
  349.  
  350.     /**
  351.      * Maps this DisjointRangeSet to an array by calling a given function on the
  352.      * start and end of each contiguous range, sorted by start.
  353.      * @param {function(int, int)} mapper Maps a range to an array element.
  354.      * @return {Array} An array of each mapper(range).
  355.      */
  356.     map: function(mapper) {
  357.       var starts = [];
  358.       for (var start in this.ranges_)
  359.         starts.push(parseInt(start));
  360.       starts.sort(function(a, b) {
  361.         return a - b;
  362.       });
  363.  
  364.       var ranges = this.ranges_;
  365.       var results = starts.map(function(s) {
  366.         return mapper(s, ranges[s]);
  367.       });
  368.  
  369.       return results;
  370.     },
  371.  
  372.     /**
  373.      * Finds the maximum value present in any of the contained ranges.
  374.      * @return {int} The maximum value contained by this DisjointRangeSet.
  375.      */
  376.     max: function() {
  377.       var max = -Infinity;
  378.       for (var start in this.ranges_)
  379.         max = Math.max(max, this.ranges_[start]);
  380.       return max;
  381.     },
  382.   };
  383.  
  384.   return {
  385.     DisjointRangeSet: DisjointRangeSet
  386.   };
  387. });
  388.  
  389. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  390. // Use of this source code is governed by a BSD-style license that can be
  391. // found in the LICENSE file.
  392.  
  393. cr.define('media', function() {
  394.   'use strict';
  395.  
  396.   /**
  397.    * This class holds a list of MediaLogEvents.
  398.    * It inherits from <li> and contains a tabular list of said events,
  399.    * the time at which they occurred, and their parameters.
  400.    */
  401.   var EventList = cr.ui.define('li');
  402.  
  403.   EventList.prototype = {
  404.     __proto__: HTMLLIElement.prototype,
  405.     startTime_: null,
  406.  
  407.     /**
  408.      * Decorate this list item as an EventList.
  409.      */
  410.     decorate: function() {
  411.       this.table_ = document.createElement('table');
  412.       var details = document.createElement('details');
  413.       var summary = media.makeElement('summary', 'Log:');
  414.       details.appendChild(summary);
  415.       details.appendChild(this.table_);
  416.       this.appendChild(details);
  417.  
  418.       var hRow = document.createElement('tr');
  419.       hRow.appendChild(media.makeElement('th', 'Time:'));
  420.       hRow.appendChild(media.makeElement('th', 'Event:'));
  421.       hRow.appendChild(media.makeElement('th', 'Parameters:'));
  422.       var header = document.createElement('thead');
  423.       header.appendChild(hRow);
  424.       this.table_.appendChild(header);
  425.     },
  426.  
  427.     /**
  428.      * Add an event to the list. It is stored as a new row in this.table_.
  429.      * @param {Object} event The MediaLogEvent that has occurred.
  430.      */
  431.     addEvent: function(event) {
  432.       var timeInMs = event.time * 1000;  // Work with milliseconds.
  433.       this.startTime_ = this.startTime_ || timeInMs;
  434.       timeInMs -= this.startTime_;
  435.  
  436.       var row = document.createElement('tr');
  437.       row.appendChild(media.makeElement('td', timeInMs.toFixed(1)));
  438.       row.appendChild(media.makeElement('td', event.type));
  439.       var params = [];
  440.       for (var key in event.params) {
  441.         params.push(key + ': ' + event.params[key]);
  442.       }
  443.  
  444.       row.appendChild(media.makeElement('td', params.join(', ')));
  445.       this.table_.appendChild(row);
  446.     }
  447.   };
  448.  
  449.   return {
  450.     EventList: EventList
  451.   };
  452. });
  453.  
  454. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  455. // Use of this source code is governed by a BSD-style license that can be
  456. // found in the LICENSE file.
  457.  
  458. cr.define('media', function() {
  459.  
  460.   /**
  461.    * This class stores hashes by their id field and provides basic methods for
  462.    * iterating over the collection.
  463.    * @constructor
  464.    */
  465.   function ItemStore() {
  466.     this.items_ = {};
  467.   }
  468.  
  469.   ItemStore.prototype = {
  470.     /**
  471.      * Get a sorted list of item ids.
  472.      * @return {Array} A sorted array of ids.
  473.      */
  474.     ids: function() {
  475.       var ids = [];
  476.       for (var i in this.items_)
  477.         ids.push(i);
  478.       return ids.sort();
  479.     },
  480.  
  481.     /**
  482.      * Add an item to the store.
  483.      * @param {Object} item The item to be added.
  484.      * @param {string} item.id The id of the item.
  485.      */
  486.     addItem: function(item) {
  487.       this.items_[item.id] = item;
  488.     },
  489.  
  490.     /**
  491.      * Add a dictionary of items to the store.
  492.      * @param {Object} items A dictionary of individual items. The keys are
  493.      *    irrelevant but each must have an id field.
  494.      */
  495.     addItems: function(items) {
  496.       for (id in items)
  497.         this.addItem(items[id]);
  498.     },
  499.  
  500.     /**
  501.      * Remove an item from the store.
  502.      * @param {string} id The id of the item to be removed.
  503.      */
  504.     removeItem: function(id) {
  505.       delete this.items_[id];
  506.     },
  507.  
  508.     /**
  509.      * Map this itemStore to an Array. Items are sorted by id.
  510.      * @param {function(*)} mapper The mapping function applied to each item.
  511.      * @return {Array} An array of mapped items.
  512.      */
  513.     map: function(mapper) {
  514.       var items = this.items_;
  515.       var ids = this.ids();
  516.       return ids.map(function(id) { return mapper(items[id]); });
  517.     }
  518.   };
  519.  
  520.   return {
  521.     ItemStore: ItemStore
  522.   };
  523. });
  524.  
  525. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  526. // Use of this source code is governed by a BSD-style license that can be
  527. // found in the LICENSE file.
  528.  
  529. cr.define('media', function() {
  530.   'use strict';
  531.  
  532.   /**
  533.    * This class inherits from <li> and is designed to store and display
  534.    * information about an open media player.
  535.    */
  536.   var MediaPlayer = cr.ui.define('li');
  537.  
  538.   MediaPlayer.prototype = {
  539.     __proto__: HTMLLIElement.prototype,
  540.     renderer: null,
  541.     id: null,
  542.  
  543.     /**
  544.      * Decorate this <li> as a MediaPlayer.
  545.      */
  546.     decorate: function() {
  547.       this.properties = {};
  548.  
  549.       this.url_ = document.createElement('span');
  550.       this.url_.textContent = 'URL Unknown';
  551.  
  552.       this.summary_ = document.createElement('summary');
  553.       this.summary_.appendChild(this.url_);
  554.  
  555.       var bufferedDiv = document.createElement('div');
  556.       bufferedDiv.className = 'buffered';
  557.       this.summary_.appendChild(bufferedDiv);
  558.  
  559.       // Create our canvii.
  560.       function createCanvas(label) {
  561.         var canvas = document.createElement('canvas');
  562.         canvas.width = media.BAR_WIDTH;
  563.         canvas.height = media.BAR_HEIGHT;
  564.         return canvas;
  565.       }
  566.       this.bufferedCanvas_ = createCanvas();
  567.       this.cacheReadsCanvas_ = createCanvas();
  568.       this.cacheWritesCanvas_ = createCanvas();
  569.  
  570.       // Create our per-canvas entry divs that are initially hidden.
  571.       function addEntry(label, canvas) {
  572.         var labelDiv = document.createElement('div');
  573.         labelDiv.textContent = label;
  574.         var canvasDiv = document.createElement('div');
  575.         canvasDiv.appendChild(canvas);
  576.         var entryDiv = document.createElement('div');
  577.         entryDiv.appendChild(labelDiv);
  578.         entryDiv.appendChild(canvasDiv);
  579.         entryDiv.hidden = true;
  580.         bufferedDiv.appendChild(entryDiv);
  581.         return entryDiv;
  582.       }
  583.       this.bufferedEntry_ = addEntry('Buffered', this.bufferedCanvas_);
  584.       this.cacheReadsEntry_ = addEntry('Cache Reads', this.cacheReadsCanvas_);
  585.       this.cacheWritesEntry_ = addEntry(
  586.           'Cache Writes', this.cacheWritesCanvas_);
  587.  
  588.       this.details_ = document.createElement('details');
  589.       this.details_.appendChild(this.summary_);
  590.  
  591.       this.propertyTable_ = document.createElement('table');
  592.       this.events_ = new media.EventList;
  593.       this.metrics_ = new media.Metrics;
  594.  
  595.       var properties = media.createDetailsLi();
  596.       properties.summary.textContent = 'Properties:';
  597.       properties.details.appendChild(this.propertyTable_);
  598.  
  599.       var ul = document.createElement('ul');
  600.       ul.appendChild(properties);
  601.       ul.appendChild(this.metrics_);
  602.       ul.appendChild(this.events_);
  603.       this.details_.appendChild(ul);
  604.  
  605.       this.appendChild(this.details_);
  606.       $('media-players').appendChild(this);
  607.     },
  608.  
  609.     /**
  610.      * Record an event and update statistics etc.
  611.      * @param {Object} event The event that occurred.
  612.      */
  613.     addEvent: function(event) {
  614.       for (var key in event.params) {
  615.         this.properties[key] = event.params[key];
  616.       }
  617.  
  618.       if (event.type == 'LOAD' && event.params['url']) {
  619.         this.url_.textContent = event.params['url'];
  620.       }
  621.  
  622.       if (event.type == 'BUFFERED_EXTENTS_CHANGED') {
  623.         return;
  624.       }
  625.       this.events_.addEvent(event);
  626.       this.metrics_.addEvent(event);
  627.     },
  628.  
  629.     /**
  630.      * Update the summary line and properties table and redraw the canvas.
  631.      * @return {HTMLElement} A <li> representing this MediaPlayer.
  632.      */
  633.     redraw: function() {
  634.       media.appendDictionaryToTable(this.properties, this.propertyTable_);
  635.  
  636.       this.setAttribute('status', this.properties.state);
  637.  
  638.       // Don't bother drawing anything if we don't know the total size.
  639.       var size = this.properties.total_bytes;
  640.       if (!size) {
  641.         return;
  642.       }
  643.  
  644.       // Draw the state of BufferedResourceLoader.
  645.       this.bufferedEntry_.hidden = false;
  646.       var canvas = this.bufferedCanvas_;
  647.       var context = canvas.getContext('2d');
  648.       context.fillStyle = '#aaa';
  649.       context.fillRect(0, 0, canvas.width, canvas.height);
  650.  
  651.       var left = this.properties.buffer_start / size * canvas.width;
  652.       var middle = this.properties.buffer_current / size * canvas.width;
  653.       var right = this.properties.buffer_end / size * canvas.width;
  654.       context.fillStyle = '#a0a';
  655.       context.fillRect(left, 0, middle - left, canvas.height);
  656.       context.fillStyle = '#aa0';
  657.       context.fillRect(middle, 0, right - middle, canvas.height);
  658.  
  659.       // Only show cached file information if we have something.
  660.       var cacheEntry = media.cacheEntriesByKey[this.properties.url];
  661.       if (!cacheEntry) {
  662.         return;
  663.       }
  664.  
  665.       // Draw cache reads.
  666.       this.cacheReadsEntry_.hidden = false;
  667.       cacheEntry.drawCacheReadsToCanvas(this.cacheReadsCanvas_);
  668.  
  669.       // Draw cache writes.
  670.       this.cacheWritesEntry_.hidden = false;
  671.       cacheEntry.drawCacheWritesToCanvas(this.cacheWritesCanvas_);
  672.     },
  673.   };
  674.  
  675.   return {
  676.     MediaPlayer: MediaPlayer
  677.   };
  678. });
  679.  
  680. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  681. // Use of this source code is governed by a BSD-style license that can be
  682. // found in the LICENSE file.
  683.  
  684. cr.define('media', function() {
  685.   'use strict';
  686.  
  687.   // A set of parameter names. An entry of 'abc' allows metrics to specify
  688.   // events with specific values of 'abc'.
  689.   var metricProperties = {
  690.     'pipeline_state': true,
  691.   };
  692.  
  693.   // A set of metrics to measure. The user will see the most recent and average
  694.   // measurement of the time between each metric's start and end events.
  695.   var metrics = {
  696.     'seek': {
  697.       'start': 'SEEK',
  698.       'end': 'pipeline_state=started'
  699.     },
  700.     'first frame': {
  701.       'start': 'WEBMEDIAPLAYER_CREATED',
  702.       'end': 'pipeline_state=started'
  703.     },
  704.   };
  705.  
  706.   /**
  707.    * This class measures times between the events specified above. It inherits
  708.    * <li> and contains a table that displays the measurements.
  709.    */
  710.   var Metrics = cr.ui.define('li');
  711.  
  712.   Metrics.prototype = {
  713.     __proto__: HTMLLIElement.prototype,
  714.  
  715.     /**
  716.      * Decorate this <li> as a Metrics.
  717.      */
  718.     decorate: function() {
  719.       this.table_ = document.createElement('table');
  720.       var details = document.createElement('details');
  721.       var summary = media.makeElement('summary', 'Metrics:');
  722.       details.appendChild(summary);
  723.       details.appendChild(this.table_);
  724.       this.appendChild(details);
  725.  
  726.       var hRow = document.createElement('tr');
  727.       hRow.appendChild(media.makeElement('th', 'Metric:'));
  728.       hRow.appendChild(media.makeElement('th', 'Last Measure:'));
  729.       hRow.appendChild(media.makeElement('th', 'Average:'));
  730.       var header = document.createElement('thead');
  731.       header.appendChild(hRow);
  732.       this.table_.appendChild(header);
  733.  
  734.       for (var metric in metrics) {
  735.         var last = document.createElement('td');
  736.         var avg = document.createElement('td');
  737.         this[metric] = {
  738.           count: 0,
  739.           total: 0,
  740.           start: null,
  741.           last: last,
  742.           avg: avg
  743.         };
  744.         var row = document.createElement('tr');
  745.         row.appendChild(media.makeElement('td', metric + ':'));
  746.         row.appendChild(last);
  747.         row.appendChild(avg);
  748.         this.table_.appendChild(row);
  749.       }
  750.     },
  751.  
  752.     /**
  753.      * An event has occurred. Update any metrics that refer to this type
  754.      * of event. Can be called multiple times by addEvent below if the metrics
  755.      * refer to specific parameters.
  756.      * @param {Object} event The MediaLogEvent that has occurred.
  757.      * @param {string} type The type of event.
  758.      */
  759.     addEventInternal: function(event, type) {
  760.       var timeInMs = event.time * 1000;  // Work with milliseconds.
  761.  
  762.       for (var metric in metrics) {
  763.         var m = this[metric];
  764.         if (type == metrics[metric].start && !m.start) {
  765.           m.start = timeInMs;
  766.         } else if (type == metrics[metric].end && m.start != null) {
  767.           var last = timeInMs - m.start;
  768.           m.last.textContent = last.toFixed(1);
  769.           m.total += last;
  770.           m.count++;
  771.           if (m.count > 1)
  772.             m.avg.textContent = (m.total / m.count).toFixed(1);
  773.           m.start = null;
  774.         }
  775.       }
  776.     },
  777.  
  778.     /**
  779.      * An event has occurred. Update any metrics that refer to events of this
  780.      * type or with this event's parameters.
  781.      * @param {Object} event The MediaLogEvent that has occurred.
  782.      */
  783.     addEvent: function(event) {
  784.       this.addEventInternal(event, event.type);
  785.       for (var p in event.params) {
  786.         if (p in metricProperties) {
  787.           var type = p + '=' + event.params[p];
  788.           this.addEventInternal(event, type);
  789.         }
  790.       }
  791.     },
  792.   };
  793.  
  794.   return {
  795.       Metrics: Metrics,
  796.   };
  797. });
  798.  
  799. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  800. // Use of this source code is governed by a BSD-style license that can be
  801. // found in the LICENSE file.
  802.  
  803. cr.define('media', function() {
  804.   'use strict';
  805.  
  806.   /**
  807.    * The width and height of a bar drawn on a file canvas in pixels.
  808.    */
  809.   var BAR_WIDTH = 500;
  810.   var BAR_HEIGHT = 16;
  811.  
  812.   /**
  813.    * Draws a 1px white horizontal line across |context|.
  814.    */
  815.   function drawLine(context, top) {
  816.     context.moveTo(0, top);
  817.     context.lineTo(BAR_WIDTH, top);
  818.     context.strokeStyle = '#fff';
  819.     context.stroke();
  820.   }
  821.  
  822.   /**
  823.    * Creates an HTMLElement of type |type| with textContent |content|.
  824.    * @param {string} type The type of element to create.
  825.    * @param {string} content The content to place in the element.
  826.    * @return {HTMLElement} A newly initialized element.
  827.    */
  828.   function makeElement(type, content) {
  829.     var element = document.createElement(type);
  830.     element.textContent = content;
  831.     return element;
  832.   }
  833.  
  834.   /**
  835.    * Creates a new <li> containing a <details> with a <summary> and sets
  836.    * properties to reference them.
  837.    * @return {Object} The new <li>.
  838.    */
  839.   function createDetailsLi() {
  840.     var li = document.createElement('li');
  841.     li.details = document.createElement('details');
  842.     li.summary = document.createElement('summary');
  843.     li.appendChild(li.details);
  844.     li.details.appendChild(li.summary);
  845.     return li
  846.   }
  847.  
  848.   /**
  849.    * Appends each key-value pair in a dictionary to a row in a table.
  850.    * @param {Object} dict The dictionary to append.
  851.    * @param {HTMLElement} table The <table> element to append to.
  852.    */
  853.   function appendDictionaryToTable(dict, table) {
  854.     table.textContent = '';
  855.     for (var key in dict) {
  856.       var tr = document.createElement('tr');
  857.       tr.appendChild(makeElement('td', key + ':'));
  858.       tr.appendChild(makeElement('td', dict[key]));
  859.       table.appendChild(tr);
  860.     }
  861.     return table;
  862.   }
  863.  
  864.   return {
  865.     BAR_WIDTH: BAR_WIDTH,
  866.     BAR_HEIGHT: BAR_HEIGHT,
  867.     drawLine: drawLine,
  868.     makeElement: makeElement,
  869.     createDetailsLi: createDetailsLi,
  870.     appendDictionaryToTable: appendDictionaryToTable
  871.   };
  872. });
  873.  
  874.  
  875. cr.define('media', function() {
  876.   'use strict';
  877.  
  878.   // Stores information on open audio streams, referenced by id.
  879.   var audioStreams = new media.ItemStore;
  880.  
  881.   // Active media players, indexed by 'render_id:player_id'.
  882.   var mediaPlayers = {};
  883.  
  884.   // Cached files indexed by key and source id.
  885.   var cacheEntriesByKey = {};
  886.   var cacheEntries = {};
  887.  
  888.   // Map of event source -> url.
  889.   var requestURLs = {};
  890.  
  891.   // Constants passed to us from Chrome.
  892.   var eventTypes = {};
  893.   var eventPhases = {};
  894.  
  895.   // The <div>s on the page in which to display information.
  896.   var audioStreamDiv;
  897.   var cacheDiv;
  898.  
  899.   // A timer used to limit the rate of redrawing the Media Players section.
  900.   var redrawTimer = null;
  901.  
  902.   /**
  903.    * Initialize variables and ask MediaInternals for all its data.
  904.    */
  905.   function initialize() {
  906.     audioStreamDiv = $('audio-streams');
  907.     cacheDiv = $('cache-entries');
  908.  
  909.     // Get information about all currently active media.
  910.     chrome.send('getEverything');
  911.   }
  912.  
  913.   /**
  914.    * Write the set of audio streams to the DOM.
  915.    */
  916.   function printAudioStreams() {
  917.  
  918.     /**
  919.      * Render a single stream as a <li>.
  920.      * @param {Object} stream The stream to render.
  921.      * @return {HTMLElement} A <li> containing the stream information.
  922.      */
  923.     function printStream(stream) {
  924.       var out = document.createElement('li');
  925.       out.id = stream.id;
  926.       out.className = 'audio-stream';
  927.       out.setAttribute('status', stream.status);
  928.  
  929.       out.textContent += 'Audio stream ' + stream.id.split('.')[1];
  930.       out.textContent += ' is ' + (stream.playing ? 'playing' : 'paused');
  931.       if (typeof stream.volume != 'undefined') {
  932.         out.textContent += ' at ' + (stream.volume * 100).toFixed(0);
  933.         out.textContent += '% volume.';
  934.       }
  935.       return out;
  936.     }
  937.  
  938.     var out = document.createElement('ul');
  939.     audioStreams.map(printStream).forEach(function(s) {
  940.       out.appendChild(s);
  941.     });
  942.  
  943.     audioStreamDiv.textContent = '';
  944.     audioStreamDiv.appendChild(out);
  945.   }
  946.  
  947.   /**
  948.    * Redraw each MediaPlayer.
  949.    */
  950.   function printMediaPlayers() {
  951.     for (var key in mediaPlayers) {
  952.       mediaPlayers[key].redraw();
  953.     }
  954.     redrawTimer = null;
  955.   }
  956.  
  957.   /**
  958.    * Write the set of sparse CacheEntries to the DOM.
  959.    */
  960.   function printSparseCacheEntries() {
  961.     var out = document.createElement('ul');
  962.     for (var key in cacheEntriesByKey) {
  963.       if (cacheEntriesByKey[key].sparse)
  964.         out.appendChild(cacheEntriesByKey[key].toListItem());
  965.     }
  966.  
  967.     cacheDiv.textContent = '';
  968.     cacheDiv.appendChild(out);
  969.   }
  970.  
  971.   /**
  972.    * Receiving data for an audio stream.
  973.    * Add it to audioStreams and update the page.
  974.    * @param {Object} stream JSON representation of an audio stream.
  975.    */
  976.   function addAudioStream(stream) {
  977.     audioStreams.addItem(stream);
  978.     printAudioStreams();
  979.   }
  980.  
  981.   /**
  982.    * Receiving all data.
  983.    * Add it all to the appropriate stores and update the page.
  984.    * @param {Object} stuff JSON containing lists of data.
  985.    * @param {Object} stuff.audio_streams A dictionary of audio streams.
  986.    */
  987.   function onReceiveEverything(stuff) {
  988.     audioStreams.addItems(stuff.audio_streams);
  989.     printAudioStreams();
  990.   }
  991.  
  992.   /**
  993.    * Removing an item from the appropriate store.
  994.    * @param {string} id The id of the item to be removed, in the format
  995.    *    "item_type.identifying_info".
  996.    */
  997.   function onItemDeleted(id) {
  998.     var type = id.split('.')[0];
  999.     switch (type) {
  1000.       case 'audio_streams':
  1001.         audioStreams.removeItem(id);
  1002.         printAudioStreams();
  1003.         break;
  1004.     }
  1005.   }
  1006.  
  1007.   /**
  1008.    * A render process has ended, delete any media players associated with it.
  1009.    * @param {number} renderer The id of the render process.
  1010.    */
  1011.   function onRendererTerminated(renderer) {
  1012.     for (var key in mediaPlayers) {
  1013.       if (mediaPlayers[key].renderer == renderer) {
  1014.         $('media-players').removeChild(mediaPlayers[key]);
  1015.         delete mediaPlayers[key];
  1016.         break;
  1017.       }
  1018.     }
  1019.     printMediaPlayers();
  1020.   }
  1021.  
  1022.   /**
  1023.    * Receiving net events.
  1024.    * Update cache information and update that section of the page.
  1025.    * @param {Array} updates A list of net events that have occurred.
  1026.    */
  1027.   function onNetUpdate(updates) {
  1028.     updates.forEach(function(update) {
  1029.       var id = update.source.id;
  1030.       if (!cacheEntries[id])
  1031.         cacheEntries[id] = new media.CacheEntry;
  1032.  
  1033.       switch (eventPhases[update.phase] + '.' + eventTypes[update.type]) {
  1034.       case 'PHASE_BEGIN.DISK_CACHE_ENTRY_IMPL':
  1035.         var key = update.params.key;
  1036.  
  1037.         // Merge this source with anything we already know about this key.
  1038.         if (cacheEntriesByKey[key]) {
  1039.           cacheEntriesByKey[key].merge(cacheEntries[id]);
  1040.           cacheEntries[id] = cacheEntriesByKey[key];
  1041.         } else {
  1042.           cacheEntriesByKey[key] = cacheEntries[id];
  1043.         }
  1044.         cacheEntriesByKey[key].key = key;
  1045.         break;
  1046.  
  1047.       case 'PHASE_BEGIN.SPARSE_READ':
  1048.         cacheEntries[id].readBytes(update.params.offset,
  1049.                                    update.params.buff_len);
  1050.         cacheEntries[id].sparse = true;
  1051.         break;
  1052.  
  1053.       case 'PHASE_BEGIN.SPARSE_WRITE':
  1054.         cacheEntries[id].writeBytes(update.params.offset,
  1055.                                     update.params.buff_len);
  1056.         cacheEntries[id].sparse = true;
  1057.         break;
  1058.  
  1059.       case 'PHASE_BEGIN.URL_REQUEST_START_JOB':
  1060.         requestURLs[update.source.id] = update.params.url;
  1061.         break;
  1062.  
  1063.       case 'PHASE_NONE.HTTP_TRANSACTION_READ_RESPONSE_HEADERS':
  1064.         // Record the total size of the file if this was a range request.
  1065.         var range = /content-range:\s*bytes\s*\d+-\d+\/(\d+)/i.exec(
  1066.             update.params.headers);
  1067.         var key = requestURLs[update.source.id];
  1068.         delete requestURLs[update.source.id];
  1069.         if (range && key) {
  1070.           if (!cacheEntriesByKey[key]) {
  1071.             cacheEntriesByKey[key] = new media.CacheEntry;
  1072.             cacheEntriesByKey[key].key = key;
  1073.           }
  1074.           cacheEntriesByKey[key].size = range[1];
  1075.         }
  1076.         break;
  1077.       }
  1078.     });
  1079.  
  1080.     printSparseCacheEntries();
  1081.   }
  1082.  
  1083.   /**
  1084.    * Receiving values for constants. Store them for later use.
  1085.    * @param {Object} constants A dictionary of constants.
  1086.    * @param {Object} constants.eventTypes A dictionary of event name -> int.
  1087.    * @param {Object} constants.eventPhases A dictionary of event phase -> int.
  1088.    */
  1089.   function onReceiveConstants(constants) {
  1090.     var events = constants.eventTypes;
  1091.     for (var e in events) {
  1092.       eventTypes[events[e]] = e;
  1093.     }
  1094.  
  1095.     var phases = constants.eventPhases;
  1096.     for (var p in phases) {
  1097.       eventPhases[phases[p]] = p;
  1098.     }
  1099.   }
  1100.  
  1101.   /**
  1102.    * Receiving notification of a media event.
  1103.    * @param {Object} event The json representation of a MediaLogEvent.
  1104.    */
  1105.   function onMediaEvent(event) {
  1106.     var source = event.renderer + ':' + event.player;
  1107.     var item = mediaPlayers[source] ||
  1108.         new media.MediaPlayer({id: source, renderer: event.renderer});
  1109.     mediaPlayers[source] = item;
  1110.     item.addEvent(event);
  1111.  
  1112.     // Both media and net events could provide the size of the file.
  1113.     // Media takes priority, but keep the size in both places synchronized.
  1114.     if (cacheEntriesByKey[item.properties.url]) {
  1115.       item.properties.total_bytes = item.properties.total_bytes ||
  1116.                                     cacheEntriesByKey[item.properties.url].size;
  1117.       cacheEntriesByKey[item.properties.url].size = item.properties.total_bytes;
  1118.     }
  1119.  
  1120.     // Events tend to arrive in groups; don't redraw the page too often.
  1121.     if (!redrawTimer)
  1122.       redrawTimer = setTimeout(printMediaPlayers, 50);
  1123.   }
  1124.  
  1125.   return {
  1126.     initialize: initialize,
  1127.     addAudioStream: addAudioStream,
  1128.     cacheEntriesByKey: cacheEntriesByKey,
  1129.     onReceiveEverything: onReceiveEverything,
  1130.     onItemDeleted: onItemDeleted,
  1131.     onRendererTerminated: onRendererTerminated,
  1132.     onNetUpdate: onNetUpdate,
  1133.     onReceiveConstants: onReceiveConstants,
  1134.     onMediaEvent: onMediaEvent
  1135.   };
  1136. });
  1137.  
  1138. /**
  1139.  * Initialize everything once we have access to the DOM.
  1140.  */
  1141. document.addEventListener('DOMContentLoaded', function() {
  1142.   media.initialize();
  1143. });
  1144.