// Copyright (c) 2011 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.
cr.define('media', function() {
'use strict';
/**
* This class represents a file cached by net.
*/
function CacheEntry() {
this.read_ = new media.DisjointRangeSet;
this.written_ = new media.DisjointRangeSet;
this.available_ = new media.DisjointRangeSet;
// Set to true when we know the entry is sparse.
this.sparse = false;
this.key = null;
this.size = null;
// The <details> element representing this CacheEntry.
this.details_ = document.createElement('details');
this.details_.className = 'cache-entry';
this.details_.open = false;
// The <details> summary line. It contains a chart of requested file ranges
// and the url if we know it.
var summary = document.createElement('summary');
this.summaryText_ = document.createTextNode('');
summary.appendChild(this.summaryText_);
summary.appendChild(document.createTextNode(' '));
// Controls to modify this CacheEntry.
var controls = document.createElement('span');
controls.className = 'cache-entry-controls';
summary.appendChild(controls);
summary.appendChild(document.createElement('br'));
// A link to clear recorded data from this CacheEntry.
var clearControl = document.createElement('a');
clearControl.href = 'javascript:void(0)';
clearControl.onclick = this.clear.bind(this);
clearControl.textContent = '(clear entry)';
controls.appendChild(clearControl);
this.details_.appendChild(summary);
// The canvas for drawing cache writes.
this.writeCanvas = document.createElement('canvas');
this.writeCanvas.width = media.BAR_WIDTH;
this.writeCanvas.height = media.BAR_HEIGHT;
this.details_.appendChild(this.writeCanvas);
// The canvas for drawing cache reads.
this.readCanvas = document.createElement('canvas');
this.readCanvas.width = media.BAR_WIDTH;
this.readCanvas.height = media.BAR_HEIGHT;
this.details_.appendChild(this.readCanvas);
// A tabular representation of the data in the above canvas.
this.detailTable_ = document.createElement('table');
this.detailTable_.className = 'cache-table';
this.details_.appendChild(this.detailTable_);
}
CacheEntry.prototype = {
/**
* Mark a range of bytes as read from the cache.
* @param {int} start The first byte read.
* @param {int} length The number of bytes read.
*/
readBytes: function(start, length) {
start = parseInt(start);
length = parseInt(length);
this.read_.add(start, start + length);
this.available_.add(start, start + length);
this.sparse = true;
},
/**
* Mark a range of bytes as written to the cache.
* @param {int} start The first byte written.
* @param {int} length The number of bytes written.
*/
writeBytes: function(start, length) {
start = parseInt(start);
length = parseInt(length);
this.written_.add(start, start + length);
this.available_.add(start, start + length);
this.sparse = true;
},
/**
* Merge this CacheEntry with another, merging recorded ranges and flags.
* @param {CacheEntry} other The CacheEntry to merge into this one.
*/
merge: function(other) {
this.read_.merge(other.read_);
this.written_.merge(other.written_);
this.available_.merge(other.available_);
this.sparse = this.sparse || other.sparse;
this.key = this.key || other.key;
this.size = this.size || other.size;
},
/**
* Clear all recorded ranges from this CacheEntry and redraw this.details_.
*/
clear: function() {
this.read_ = new media.DisjointRangeSet;
this.written_ = new media.DisjointRangeSet;
this.available_ = new media.DisjointRangeSet;
this.generateDetails();
},
/**
* Helper for drawCacheReadsToCanvas() and drawCacheWritesToCanvas().
*
* Accepts the entries to draw, a canvas fill style, and the canvas to
* draw on.
*/
drawCacheEntriesToCanvas: function(entries, fillStyle, canvas) {
// Don't bother drawing anything if we don't know the total size.
if (!this.size) {
return;
}
var width = canvas.width;
var height = canvas.height;
var context = canvas.getContext('2d');
var fileSize = this.size;
context.fillStyle = '#aaa';
context.fillRect(0, 0, width, height);
function drawRange(start, end) {
var left = start / fileSize * width;
var right = end / fileSize * width;
context.fillRect(left, 0, right - left, height);
}
context.fillStyle = fillStyle;
entries.map(function(start, end) {
drawRange(start, end);
});
},
/**
* Draw cache writes to the given canvas.
*
* It should consist of a horizontal bar with highlighted sections to
* represent which parts of a file have been written to the cache.
*
* e.g. |xxxxxx----------x|
*/
drawCacheWritesToCanvas: function(canvas) {
this.drawCacheEntriesToCanvas(this.written_, '#00a', canvas);
},
/**
* Draw cache reads to the given canvas.
*
* It should consist of a horizontal bar with highlighted sections to
* represent which parts of a file have been read from the cache.
*
* e.g. |xxxxxx----------x|
*/
drawCacheReadsToCanvas: function(canvas) {
this.drawCacheEntriesToCanvas(this.read_, '#0a0', canvas);
},
/**
* Update this.details_ to contain everything we currently know about
* this file.
*/
generateDetails: function() {
function makeElement(tag, content) {
var toReturn = document.createElement(tag);
toReturn.textContent = content;
return toReturn;
}
this.details_.id = this.key;
this.summaryText_.textContent = this.key || 'Unknown File';
this.detailTable_.textContent = '';
var header = document.createElement('thead');
var footer = document.createElement('tfoot');
var body = document.createElement('tbody');
this.detailTable_.appendChild(header);
this.detailTable_.appendChild(footer);
this.detailTable_.appendChild(body);
var headerRow = document.createElement('tr');
headerRow.appendChild(makeElement('th', 'Read From Cache'));
headerRow.appendChild(makeElement('th', 'Written To Cache'));
header.appendChild(headerRow);
var footerRow = document.createElement('tr');
var footerCell = document.createElement('td');
footerCell.textContent = 'Out of ' + (this.size || 'unkown size');
footerCell.setAttribute('colspan', 2);
footerRow.appendChild(footerCell);
footer.appendChild(footerRow);
var read = this.read_.map(function(start, end) {
return start + ' - ' + end;
});
var written = this.written_.map(function(start, end) {
return start + ' - ' + end;
});
var length = Math.max(read.length, written.length);
for (var i = 0; i < length; i++) {
var row = document.createElement('tr');
row.appendChild(makeElement('td', read[i] || ''));
row.appendChild(makeElement('td', written[i] || ''));
body.appendChild(row);
}
this.drawCacheWritesToCanvas(this.writeCanvas);
this.drawCacheReadsToCanvas(this.readCanvas);
},
/**
* Render this CacheEntry as a <li>.
* @return {HTMLElement} A <li> representing this CacheEntry.
*/
toListItem: function() {
this.generateDetails();
var result = document.createElement('li');
result.appendChild(this.details_);
return result;
}
};
return {
CacheEntry: CacheEntry
};
});