cache_entry.js revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright (c) 2011 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
5cr.define('media', function() {
6  'use strict';
7
8  /**
9   * This class represents a file cached by net.
10   */
11  function CacheEntry() {
12    this.read_ = new media.DisjointRangeSet;
13    this.written_ = new media.DisjointRangeSet;
14    this.available_ = new media.DisjointRangeSet;
15
16    // Set to true when we know the entry is sparse.
17    this.sparse = false;
18    this.key = null;
19    this.size = null;
20
21    // The <details> element representing this CacheEntry.
22    this.details_ = document.createElement('details');
23    this.details_.className = 'cache-entry';
24    this.details_.open = false;
25
26    // The <details> summary line. It contains a chart of requested file ranges
27    // and the url if we know it.
28    var summary = document.createElement('summary');
29
30    this.summaryText_ = document.createTextNode('');
31    summary.appendChild(this.summaryText_);
32
33    summary.appendChild(document.createTextNode(' '));
34
35    // Controls to modify this CacheEntry.
36    var controls = document.createElement('span');
37    controls.className = 'cache-entry-controls';
38    summary.appendChild(controls);
39    summary.appendChild(document.createElement('br'));
40
41    // A link to clear recorded data from this CacheEntry.
42    var clearControl = document.createElement('a');
43    clearControl.href = 'javascript:void(0)';
44    clearControl.onclick = this.clear.bind(this);
45    clearControl.textContent = '(clear entry)';
46    controls.appendChild(clearControl);
47
48    this.details_.appendChild(summary);
49
50    // The canvas for drawing cache writes.
51    this.writeCanvas = document.createElement('canvas');
52    this.writeCanvas.width = media.BAR_WIDTH;
53    this.writeCanvas.height = media.BAR_HEIGHT;
54    this.details_.appendChild(this.writeCanvas);
55
56    // The canvas for drawing cache reads.
57    this.readCanvas = document.createElement('canvas');
58    this.readCanvas.width = media.BAR_WIDTH;
59    this.readCanvas.height = media.BAR_HEIGHT;
60    this.details_.appendChild(this.readCanvas);
61
62    // A tabular representation of the data in the above canvas.
63    this.detailTable_ = document.createElement('table');
64    this.detailTable_.className = 'cache-table';
65    this.details_.appendChild(this.detailTable_);
66  }
67
68  CacheEntry.prototype = {
69    /**
70     * Mark a range of bytes as read from the cache.
71     * @param {int} start The first byte read.
72     * @param {int} length The number of bytes read.
73     */
74    readBytes: function(start, length) {
75      start = parseInt(start);
76      length = parseInt(length);
77      this.read_.add(start, start + length);
78      this.available_.add(start, start + length);
79      this.sparse = true;
80    },
81
82    /**
83     * Mark a range of bytes as written to the cache.
84     * @param {int} start The first byte written.
85     * @param {int} length The number of bytes written.
86     */
87    writeBytes: function(start, length) {
88      start = parseInt(start);
89      length = parseInt(length);
90      this.written_.add(start, start + length);
91      this.available_.add(start, start + length);
92      this.sparse = true;
93    },
94
95    /**
96     * Merge this CacheEntry with another, merging recorded ranges and flags.
97     * @param {CacheEntry} other The CacheEntry to merge into this one.
98     */
99    merge: function(other) {
100      this.read_.merge(other.read_);
101      this.written_.merge(other.written_);
102      this.available_.merge(other.available_);
103      this.sparse = this.sparse || other.sparse;
104      this.key = this.key || other.key;
105      this.size = this.size || other.size;
106    },
107
108    /**
109     * Clear all recorded ranges from this CacheEntry and redraw this.details_.
110     */
111    clear: function() {
112      this.read_ = new media.DisjointRangeSet;
113      this.written_ = new media.DisjointRangeSet;
114      this.available_ = new media.DisjointRangeSet;
115      this.generateDetails();
116    },
117
118    /**
119     * Helper for drawCacheReadsToCanvas() and drawCacheWritesToCanvas().
120     *
121     * Accepts the entries to draw, a canvas fill style, and the canvas to
122     * draw on.
123     */
124    drawCacheEntriesToCanvas: function(entries, fillStyle, canvas) {
125      // Don't bother drawing anything if we don't know the total size.
126      if (!this.size) {
127        return;
128      }
129
130      var width = canvas.width;
131      var height = canvas.height;
132      var context = canvas.getContext('2d');
133      var fileSize = this.size;
134
135      context.fillStyle = '#aaa';
136      context.fillRect(0, 0, width, height);
137
138      function drawRange(start, end) {
139        var left = start / fileSize * width;
140        var right = end / fileSize * width;
141        context.fillRect(left, 0, right - left, height);
142      }
143
144      context.fillStyle = fillStyle;
145      entries.map(function(start, end) {
146        drawRange(start, end);
147      });
148    },
149
150    /**
151     * Draw cache writes to the given canvas.
152     *
153     * It should consist of a horizontal bar with highlighted sections to
154     * represent which parts of a file have been written to the cache.
155     *
156     * e.g. |xxxxxx----------x|
157     */
158    drawCacheWritesToCanvas: function(canvas) {
159      this.drawCacheEntriesToCanvas(this.written_, '#00a', canvas);
160    },
161
162    /**
163     * Draw cache reads to the given canvas.
164     *
165     * It should consist of a horizontal bar with highlighted sections to
166     * represent which parts of a file have been read from the cache.
167     *
168     * e.g. |xxxxxx----------x|
169     */
170    drawCacheReadsToCanvas: function(canvas) {
171      this.drawCacheEntriesToCanvas(this.read_, '#0a0', canvas);
172    },
173
174    /**
175     * Update this.details_ to contain everything we currently know about
176     * this file.
177     */
178    generateDetails: function() {
179      function makeElement(tag, content) {
180        var toReturn = document.createElement(tag);
181        toReturn.textContent = content;
182        return toReturn;
183      }
184
185      this.details_.id = this.key;
186      this.summaryText_.textContent = this.key || 'Unknown File';
187
188      this.detailTable_.textContent = '';
189      var header = document.createElement('thead');
190      var footer = document.createElement('tfoot');
191      var body = document.createElement('tbody');
192      this.detailTable_.appendChild(header);
193      this.detailTable_.appendChild(footer);
194      this.detailTable_.appendChild(body);
195
196      var headerRow = document.createElement('tr');
197      headerRow.appendChild(makeElement('th', 'Read From Cache'));
198      headerRow.appendChild(makeElement('th', 'Written To Cache'));
199      header.appendChild(headerRow);
200
201      var footerRow = document.createElement('tr');
202      var footerCell = document.createElement('td');
203      footerCell.textContent = 'Out of ' + (this.size || 'unkown size');
204      footerCell.setAttribute('colspan', 2);
205      footerRow.appendChild(footerCell);
206      footer.appendChild(footerRow);
207
208      var read = this.read_.map(function(start, end) {
209        return start + ' - ' + end;
210      });
211      var written = this.written_.map(function(start, end) {
212        return start + ' - ' + end;
213      });
214
215      var length = Math.max(read.length, written.length);
216      for (var i = 0; i < length; i++) {
217        var row = document.createElement('tr');
218        row.appendChild(makeElement('td', read[i] || ''));
219        row.appendChild(makeElement('td', written[i] || ''));
220        body.appendChild(row);
221      }
222
223      this.drawCacheWritesToCanvas(this.writeCanvas);
224      this.drawCacheReadsToCanvas(this.readCanvas);
225    },
226
227    /**
228     * Render this CacheEntry as a <li>.
229     * @return {HTMLElement} A <li> representing this CacheEntry.
230     */
231    toListItem: function() {
232      this.generateDetails();
233
234      var result = document.createElement('li');
235      result.appendChild(this.details_);
236      return result;
237    }
238  };
239
240  return {
241    CacheEntry: CacheEntry
242  };
243});
244