Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / tools / binary_size / template / index.html
1 <!--
2   Copyright 2014 The Chromium Authors. All rights reserved.
3   Use of this source code is governed by a BSD-style license that can be
4   found in the LICENSE file.
5 -->
6 <html>
7 <head>
8 <title>Binary Size Analysis</title>
9 <script src="d3/d3.js" charset="utf-8"></script>
10 <script src="D3SymbolTreeMap.js" charset="utf-8"></script>
11 <script src="data.js" charset="utf-8"></script>
12 <style>
13 body {
14     margin: 0px;
15     padding: 5px;
16 }
17 .swatch {
18     border: 1px solid rgb(100,100,100);
19     -webkit-user-select: none;
20     cursor: default;
21 }
22 </style>
23 <script>
24 var treemap;
25 var filterChanging = false;
26 var savedSettings = {};
27
28 function init() {
29     if (window.metadata !== undefined && window.metadata.subtitle) {
30         document.getElementById('subtitle').innerHTML = ': ' + escape(metadata.subtitle);
31     }
32     initFilterOptions();
33     treemap = new D3SymbolTreeMap(
34         savedSettings.width,
35         savedSettings.height,
36         savedSettings.maxLevels);
37     treemap.init();
38 }
39
40 function getIdealSizes() {
41     var width = window.innerWidth - 20;
42     var height = window.innerHeight - 70;
43     return {'width': width, 'height': height};
44 }
45
46 function showReport(title, data, headers, dataFunction, styleFunction) {
47     var div =  d3.select('body').append('div')
48         .style('margin', '0')
49         .style('padding', '5px')
50         .style('position', 'absolute')
51         .style('top', '10%')
52         .style('left', '10%')
53         .style('background-color', 'rgba(255,255,255,0.9)')
54         .style('width', '80%')
55         .style('height', '80%')
56         .style('z-index', '2147483647')
57         .style('border', '3px ridge grey')
58         .style('box-shadow', '10px 10px 5px rgba(80,80,80,0.7)')
59         .style('text-align', 'center')
60         .style('border-radius', '10px');
61     var titlebar = div.append('div')
62         .style('margin', '0')
63         .style('padding', '5px')
64         .style('position', 'absolute')
65         .style('top', '0%')
66         .style('left', '0%')
67         .style('width', '100%')
68         .style('height', '10%')
69         .style('font-size', 'x-large');
70     titlebar.text(title);
71     var controls = div.append('div')
72         .style('margin', '0')
73         .style('padding', '5px')
74         .style('position', 'absolute')
75         .style('top', '90%')
76         .style('left', '0%')
77         .style('width', '100%')
78         .style('height', '10%');
79     controls.append('input').attr('type', 'button')
80         .attr('value', 'Dismiss')
81         .on('click', function(){div.remove();});
82
83     var tableDiv = div.append('div')
84         .style('overflow', 'auto')
85         .style('position', 'absolute')
86         .style('top', '10%')
87         .style('left', '0%')
88         .style('width', '100%')
89         .style('height', '80%')
90         .style('border-top', '1px solid rgb(230,230,230)')
91         .style('border-bottom', '1px solid rgb(230,230,230)');
92     var table = tableDiv.append('table')
93         .attr('border', '1')
94         .attr('cellspacing', '0')
95         .attr('cellpadding', '2')
96         .style('margin-left', 'auto')
97         .style('margin-right', 'auto');
98     var header = table.append('tr');
99     for (var i = 0; i < headers.length; i++) {
100         header.append('th').text(headers[i]);
101     }
102
103     for (var i = 0; i < data.length; i++) {
104         var row = table.append('tr');
105         for (j = 0; j < headers.length; j++) {
106             var td = row.append('td');
107             if (styleFunction) {
108                 styleFunction.call(this, td, j);
109             }
110             dataFunction.call(this, data[i], j, td);
111         }
112     }
113 }
114
115 function bigSymbolsReport() {
116     var list = treemap.biggestSymbols(100);
117     var headers = ['Rank', 'Size (Bytes)', 'Type', 'Location'];
118     var styleFunction = function(selection, index) {
119         if (index === 3) {
120             selection.style('font-family', 'monospace');
121         }
122     };
123     var recordIndex = 1;
124     var dataFunction = function(record, index, cell) {
125         if (index === 0) {
126             cell.text(recordIndex++);
127         } else if (index === 1) {
128             cell.text(D3SymbolTreeMap._pretty(record.value));
129         } else if (index === 2) {
130             cell.text(record.t);
131         } else {
132             if (treemap.pathFor(record).indexOf('/out') == 0) {
133                 cell.append('span').text(treemap.pathFor(record));
134                 cell.append('br');
135                 cell.append('span').text('Symbol: ');
136                 cell.append('span').text(record.n);
137             } else {
138                 var href = 'https://code.google.com/p/chromium/codesearch#chromium/src'
139                     + treemap.pathFor(record)
140                     + '&q='
141                     + record.n;
142                 cell.append('a')
143                     .attr('href', href)
144                     .attr('target', '_blank')
145                     .text(treemap.pathFor(record));
146                 cell.append('br');
147                 cell.append('span').text('Symbol: ');
148                 cell.append('span').text(record.n);
149             }
150         }
151     };
152     showReport('100 Largest Symbols', list, headers, dataFunction, styleFunction);
153 }
154
155 function bigPathsReport() {
156     var list = treemap.biggestPaths(100);
157     var headers = ['Rank', 'Size (Bytes)', 'Location'];
158     var styleFunction = function(selection, index) {
159         if (index === 2) {
160             selection.style('font-family', 'monospace');
161         }
162     };
163     var recordIndex = 1;
164     var dataFunction = function(record, index, cell) {
165         if (index === 0) {
166             cell.text(recordIndex++);
167         } else if (index === 1) {
168             cell.text(D3SymbolTreeMap._pretty(record.value));
169         } else if (index === 2) {
170             if (treemap.pathFor(record).indexOf('/out') == 0) {
171                 cell.text(treemap.pathFor(record));
172             } else {
173                 var href = 'https://code.google.com/p/chromium/codesearch#chromium/src' + treemap.pathFor(record);
174                 cell.append('a')
175                     .attr('href', href)
176                     .attr('target', '_blank')
177                     .text(treemap.pathFor(record));
178             }
179
180         }
181     };
182     showReport('100 Largest Paths', list, headers, dataFunction, styleFunction);
183 }
184
185 function symbolFilterTextChanged() {
186     if (filterChanging) return true;
187     filterChanging = true;
188     var enabled = document.getElementById('symbol_types_filter').value;
189     for (var x=0; x<=25; x++) {
190         var checkBox = document.getElementById('check_' + x);
191         checkBox.checked = (enabled.indexOf(checkBox.value) != -1);
192     }
193     filterChanging = false;
194 }
195
196 function updateFilterText() {
197     if (filterChanging) return true;
198     filterChanging = true;
199     var text = '';
200     for (var x=0; x<=25; x++) {
201         var checkBox = document.getElementById('check_' + x);
202         if (checkBox.checked) {
203             text += checkBox.value;
204         }
205     }
206     document.getElementById('symbol_types_filter').value=text;
207     filterChanging = false;
208 }
209
210 function initFilterOptions() {
211     updateFilterText();
212     for (var x=0; x<=25; x++) {
213         var checkBox = document.getElementById('check_' + x);
214         checkBox.onchange=updateFilterText;
215         var swatch = document.getElementById('swatch_' + x);
216         swatch.style.backgroundColor = D3SymbolTreeMap.getColorForType(checkBox.value).toString();
217     }
218     var gteCheckbox = document.getElementById('check_gte');
219     gteCheckbox.onchange = function() {
220         document.getElementById('symbol_filter_gte').disabled = !gteCheckbox.checked;
221     }
222     var regexCheckbox = document.getElementById('check_regex');
223     regexCheckbox.onchange = function() {
224         document.getElementById('symbol_filter_regex').disabled = !regexCheckbox.checked;
225     }
226     var excludeRegexCheckbox = document.getElementById('check_exclude_regex');
227     excludeRegexCheckbox.onchange = function() {
228         document.getElementById('symbol_filter_exclude_regex').disabled = !excludeRegexCheckbox.checked;
229     }
230     var idealSizes = getIdealSizes();
231     document.getElementById('width').value = idealSizes.width;
232     document.getElementById('height').value = idealSizes.height;
233     saveFilterSettings();
234 }
235
236 function filterSetAll(enabled) {
237     for (var x=0; x<=25; x++) {
238         var checkBox = document.getElementById('check_' + x);
239         checkBox.checked = enabled;
240     }
241     updateFilterText();
242 }
243
244 function showOptions() {
245     loadFilterSettings();
246     var container = document.getElementById('options_container');
247     var w = container.offsetWidth;
248     var h = container.offsetHeight;
249     container.style.margin = '-' + (h/2) + 'px 0 0 -' + (w/2) + 'px';
250     container.style.visibility = 'visible';
251 }
252
253 function hideOptions() {
254     var container = document.getElementById('options_container');
255     container.style.visibility = 'hidden';
256 }
257
258 function applySettings() {
259     hideOptions();
260     var oldWidth = savedSettings.width;
261     var oldHeight = savedSettings.height;
262     var oldSymbols = savedSettings.symbolTypes;
263     var oldRegex = savedSettings.regex;
264     var oldExcludeRegex = savedSettings.excludeRegex;
265     var oldGte = savedSettings.gte;
266     var oldMaxLevels = savedSettings.maxLevels;
267     saveFilterSettings();
268     var resizeNeeded = oldWidth !== savedSettings.width || oldHeight !== savedSettings.height;
269     var regexChanged = oldRegex !== savedSettings.regex;
270     var excludeRegexChanged = oldExcludeRegex !== savedSettings.excludeRegex;
271     var symbolsChanged = oldSymbols !== savedSettings.symbolTypes;
272     var gteChanged = oldGte !== savedSettings.gte;
273     var filterChanged = regexChanged || excludeRegexChanged || symbolsChanged || gteChanged;
274     var maxLevelsChanged = oldMaxLevels !== savedSettings.maxLevels;
275
276     if (filterChanged) {
277         // Type filters
278         typeFilter = function(datum) {
279             if (datum.depth === 0) return true; // root node
280             if (datum.t === undefined) return true;
281             return savedSettings.symbolTypes !== undefined &&
282                 savedSettings.symbolTypes.indexOf(datum.t) !== -1;
283         }
284
285         // Regex filter
286         var regexFilter = undefined;
287         if (savedSettings.regex !== undefined && savedSettings.regex.length > 0) {
288             console.log('filter: regex is "' + savedSettings.regex + '"');
289             var regex = new RegExp(savedSettings.regex);
290             regexFilter = function(datum) {
291                 if (datum.depth === 0) return true; // root node
292                 var fullName = this.pathFor(datum);
293                 if (datum.children === undefined) { // it is a leaf node (symbol)
294                     fullName += ':' + datum.n;
295                 }
296                 return regex.test(fullName);
297             }
298         }
299
300         // Exclude regex filter
301         var excludeRegexFilter = undefined;
302         if (savedSettings.excludeRegex !== undefined && savedSettings.excludeRegex.length > 0) {
303             console.log('filter: exclude-regex is "' + savedSettings.excludeRegex + '"');
304             var excludeRegex = new RegExp(savedSettings.excludeRegex);
305             excludeRegexFilter = function(datum) {
306                 if (datum.depth === 0) return true; // root node
307                 var fullName = this.pathFor(datum);
308                 if (datum.children === undefined) { // it is a leaf node (symbol)
309                     fullName += ':' + datum.n;
310                 }
311                 return !excludeRegex.test(fullName);
312             }
313         }
314
315         // Size filter
316         var sizeFilter = undefined;
317         if (savedSettings.gte !== undefined) {
318             console.log('filter: minimum size is ' + savedSettings.gte + ' bytes');
319             sizeFilter = function(datum) {
320                 if (datum.children !== undefined) return true; // non-leaf
321                 if (datum.value === undefined) console.log('whoops');
322                 return datum.value >= savedSettings.gte;
323             }
324         }
325
326         // Make a filter to apply to the tree
327         var filter = function(datum) {
328             if (typeFilter && !typeFilter.call(this, datum)) return false;
329             if (regexFilter && !regexFilter.call(this, datum)) return false;
330             if (excludeRegexFilter && !excludeRegexFilter.call(this, datum)) return false;
331             if (sizeFilter && !sizeFilter.call(this, datum)) return false;
332             return true;
333         };
334         treemap.filter(filter);
335     }
336
337     // Adjust levels if needed.
338     if (maxLevelsChanged) {
339         treemap.setMaxLevels(savedSettings.maxLevels);
340     }
341
342     // Resize map if necessary.
343     if (resizeNeeded) {
344         console.log('desired treemap dimensions have changed, requesting resize');
345         treemap.resize(savedSettings.width, savedSettings.height);
346     }
347 }
348
349 function cancelSettings() {
350     hideOptions();
351     loadFilterSettings();
352 }
353
354 function saveFilterSettings() {
355     savedSettings.symbolTypes = document.getElementById('symbol_types_filter').value;
356     if (document.getElementById('check_regex').checked) {
357         savedSettings.regex = document.getElementById('symbol_filter_regex').value;
358     } else {
359         savedSettings.regex = undefined;
360     }
361     if (document.getElementById('check_exclude_regex').checked) {
362         savedSettings.excludeRegex = document.getElementById('symbol_filter_exclude_regex').value;
363     } else {
364         savedSettings.excludeRegex = undefined;
365     }
366     if (document.getElementById('check_gte').checked) {
367         savedSettings.gte = parseInt(document.getElementById('symbol_filter_gte').value);
368     } else {
369         savedSettings.gte = undefined;
370     }
371     savedSettings.width = parseInt(document.getElementById('width').value);
372     savedSettings.height = parseInt(document.getElementById('height').value);
373     savedSettings.maxLevels = parseInt(document.getElementById('max_levels').value);
374 }
375
376 function loadFilterSettings() {
377     document.getElementById('symbol_types_filter').value = savedSettings.symbolTypes;
378     symbolFilterTextChanged();
379     if (savedSettings.regex !== undefined) {
380         document.getElementById('check_regex').checked = true;
381         document.getElementById('symbol_filter_regex').value = savedSettings.regex;
382     } else {
383         document.getElementById('check_regex').checked = false;
384     }
385     if (savedSettings.excludeRegex !== undefined) {
386         document.getElementById('check_exclude_regex').checked = true;
387         document.getElementById('symbol_filter_exclude_regex').value = savedSettings.excludeRegex;
388     } else {
389         document.getElementById('check_exclude_regex').checked = false;
390     }
391     if (savedSettings.gte !== undefined) {
392         document.getElementById('check_gte').checked = true;
393         document.getElementById('symbol_filter_gte').value = savedSettings.gte;
394     } else {
395         document.getElementById('check_gte').checked = false;
396     }
397     document.getElementById('width').value = savedSettings.width;
398     document.getElementById('height').value = savedSettings.height;
399     document.getElementById('max_levels').value = savedSettings.maxLevels;
400 }
401
402 function escape(str) {
403     return str.replace(/&/g, '&amp;')
404               .replace(/"/g, '&quot;')
405               .replace(/</g, '&lt;')
406               .replace(/>/g, '&gt;');
407 }
408 </script>
409 </head>
410 <body onload='init()'>
411 <div style='position: absolute; top: 5px; left: 5px;'>
412   <input type='button' onclick='showOptions()' value='Options &amp; Legend...'>
413   <span style='-webkit-user-select: none; cursor: help;' title='Click to view the symbol legend or to configure filters and options for the treemap'>[?]</span>
414 </div>
415 <div style='position: absolute; right: 5px; top: 5px; white-space: nowrap;'>
416     Reports:
417     <input type='button' onclick='bigSymbolsReport()' value='Large Symbols' title='Click to view a report of the largest 100 symbols that are with the bounds of the treemap that is currently displayed.'>
418     <input type='button' onclick='bigPathsReport()' value='Large Files' title='Click to view a report of the largest 100 source files that are with the bounds of the treemap that is currently displayed.'>
419 </div>
420 <div style='text-align: center; margin-bottom: 5px;'>
421     <span style='font-size: x-large; font-weight: bold; font-variant: small-caps'>Binary Size Analysis<span id='subtitle'></span></span>
422     <br><span style='font-size: small; font-style: italic;'>Double-click a box to zoom in, double-click outermost title to zoom out.</span>
423 </div>
424 <table id='options_container' style='visibility: hidden; border: 3px ridge grey; padding: 0px; top: 50%; left: 50%; position: fixed; z-index: 2147483646; overflow: auto; background-color: rgba(255,255,255,0.9); border-radius: 10px; box-shadow: 10px 10px 5px rgba(80,80,80,0.7);'><tr><td style='vertical-align: top'>
425     <table cellspacing=0 cellborder=0 style='width:100%'>
426         <tr><th colspan=3 style='padding-bottom: .25em; text-decoration: underline;'>Symbol Types To Show</th></tr>
427         <tr>
428             <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
429                     <span class='swatch' id='swatch_0'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_0' value='A'>Global absolute (A)
430                 <br><span class='swatch' id='swatch_1'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_1' value='B'>Global uninitialized data (B)
431                 <br><span class='swatch' id='swatch_2'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_2' value='b'>Local uninitialized data (b)
432                 <br><span class='swatch' id='swatch_3'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_3' value='C'>Global uninitialized common (C)
433                 <br><span class='swatch' id='swatch_4'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_4' value='D'>Global initialized data (D)
434                 <br><span class='swatch' id='swatch_5'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_5' value='d'>Local initialized data (d)
435                 <br><span class='swatch' id='swatch_6'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_6' value='G'>Global small initialized data (G)
436                 <br><span class='swatch' id='swatch_7'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_7' value='g'>Local small initialized data (g)
437                 <br><span class='swatch' id='swatch_8'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_8' value='i'>Indirect function (i)
438             </td>
439             <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
440                     <span class='swatch' id='swatch_9'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_9' value='N'>Debugging (N)
441                 <br><span class='swatch' id='swatch_10'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_10' value='p'>Stack unwind (p)
442                 <br><span class='swatch' id='swatch_11'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_11' value='R'>Global read-only data (R)
443                 <br><span class='swatch' id='swatch_12'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_12' value='r'>Local read-only data (r)
444                 <br><span class='swatch' id='swatch_13'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_13' value='S'>Global small uninitialized data (S)
445                 <br><span class='swatch' id='swatch_14'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_14' value='s'>Local small uninitialized data (s)
446                 <br><span class='swatch' id='swatch_15'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_15' value='T'>Global code (T)
447                 <br><span class='swatch' id='swatch_16'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_16' value='t'>Local code (t)
448                 <br><span class='swatch' id='swatch_17'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_17' value='U'>Undefined (U)
449             </td>
450             <td style='width: 33%; white-space: nowrap; vertical-align: top;'>
451                     <span class='swatch' id='swatch_18'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_18' value='u'>Unique (u)
452                 <br><span class='swatch' id='swatch_19'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_19' value='V'>Global weak object (V)
453                 <br><span class='swatch' id='swatch_20'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_20' value='v'>Local weak object (v)
454                 <br><span class='swatch' id='swatch_21'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_21' value='W'>Global weak symbol (W)
455                 <br><span class='swatch' id='swatch_22'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_22' value='w'>Local weak symbol (w)
456                 <br><span class='swatch' id='swatch_23'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_23' value='@'>Vtable entry (@)
457                 <br><span class='swatch' id='swatch_24'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_24' value='-'>STABS debugging (-)
458                 <br><span class='swatch' id='swatch_25'>&nbsp;&nbsp;&nbsp;</span><input checked type='checkbox' id='check_25' value='?'>Unrecognized (?)
459             </td>
460         </tr>
461         <tr><td colspan=3 style='text-align: center; white-space: nowrap; padding-top: 1em;'>
462             Select <input type='button' onclick='filterSetAll(true)' value='All'>,
463             <input type='button' onclick='filterSetAll(false)' value='None'>,
464             or type a string: <input id='symbol_types_filter' size=30 value='' onkeyup='symbolFilterTextChanged()' onblur='updateFilterText()'>
465             <span style='-webkit-user-select: none; cursor: help;' title='Enter codes from the list above for the symbols you want to see. The checkboxes will update automatically to match the string that you enter.'>[?]</span>
466         </td></tr>
467    </table>
468 </td></tr><tr><td style='vertical-align: top; padding-top: 10px; border-top: 1px solid grey;'>
469     <table cellspacing=0 cellborder=0 style='width: 100%'>
470         <tr><th colspan=2 style='padding-bottom: .25em; text-decoration: underline;'>Advanced Options</th></tr>
471         <tr>
472             <td style='white-space: nowrap; vertical-align: top;'>
473                 <input type='checkbox' id='check_regex'>
474                 Only include symbols matching this regex:
475             </td>
476             <td style='text-align: right; vertical-align: top;'>
477                 <input disabled id='symbol_filter_regex' size=30 value='' style='text-align: right;'>
478                 <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Only symbols that match this regex will be shown. This filter applies before any exclusion regex specified below. The format of each symbol is [path]:[symbol_name]'>[?]</span>
479             </td>
480         </tr>
481         <tr>
482             <td style='white-space: nowrap; vertical-align: top;'>
483                 <input type='checkbox' id='check_exclude_regex'>
484                 Exclude all symbols matching this regex:
485             </td>
486             <td style='text-align: right; vertical-align: top;'>
487                 <input disabled id='symbol_filter_exclude_regex' size=30 value='' style='text-align: right;'>
488                 <span style='-webkit-user-select: none; cursor: help;' title='Enter a javascript regex. Symbols that match this tegex will not be shown. This filter applies after any inclusion filter specified above. The format of each symbol is [path]:[symbol_name]'>[?]</span>
489             </td>
490         </tr>
491         <tr>
492             <td style='white-space: nowrap; vertical-align: top;'>
493                 <input type='checkbox' id='check_gte'>
494                 Only include symbols that are at least <span style='font-style: italic;'>n</span> bytes:
495             </td>
496             <td style='text-align: right; vertical-align: top;'>
497                 <input disabled id='symbol_filter_gte' size=8 value='' style='text-align: right;'>
498                 <span style='-webkit-user-select: none; cursor: help;' title='Symbols whose size is less than this value will be hidden.'>[?]</span>
499             </td>
500         </tr>
501         <tr>
502             <td style='white-space: nowrap vertical-align: top;;'>
503                 Show at most <span style='font-style: italic;'>n</span> levels of detail at a time:
504             </td>
505             <td style='text-align: right; vertical-align: top;'>
506                 <input id='max_levels' size=4 value='2' style='text-align: right;'><span style='-webkit-user-select: none; cursor: help;' title='Increasing this value shows more detail without the need to zoom, but uses more computing power.'>[?]</span>
507             </td>
508         </tr>
509         <tr>
510             <td style='white-space: nowrap vertical-align: top;;'>
511                 Set the size of the treemap to <span style='font-style: italic;'>W x H</span> pixels:
512             </td>
513             <td style='text-align: right; vertical-align: top;'>
514                 <input id='width' size=4 value='' style='text-align: right;'>
515                 &nbsp;x&nbsp;<input id='height' size=4 value='' style='text-align: right;'>
516             </td>
517         </tr>
518     </table>
519 </td></tr>
520 <tr><td style='padding-top: 10px; text-align: right; border-top: 1px solid grey'>
521     <input type='button' value='Apply' onclick='applySettings()'>
522     <input type='button' value='Cancel' onclick='cancelSettings()'>
523 </td></tr></table>
524 </body>
525 </html>