Merge pull request #2427 from yurydelendik/features-2

pdf.js features testing
This commit is contained in:
Yury Delendik 2012-12-03 13:49:33 -08:00
commit 3c7ef79487
4 changed files with 693 additions and 0 deletions

View File

@ -123,6 +123,7 @@ target.web = function() {
cp(CHROME_BUILD_DIR + '/*.crx', FIREFOX_BUILD_DIR + '/*.rdf',
GH_PAGES_DIR + EXTENSION_SRC_DIR + 'chrome/');
cp('web/index.html.template', GH_PAGES_DIR + '/index.html');
cp('-R', 'test/features', GH_PAGES_DIR);
cd(GH_PAGES_DIR);
exec('git init');

116
test/features/index.html Normal file
View File

@ -0,0 +1,116 @@
<!DOCTYPE html>
<!--
Copyright 2012 Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<meta charset="utf-8">
<title>Required features testing for PDF.js</title>
<style>
body { font-family: sans-serif; }
#tests { width: 920px; border-collapse:collapse; margin: 20px 0; }
#tests td, #tests th { border: 1px solid black; }
.name { text-align: left; }
.test, .emu, .impact, .area { text-align: center; }
.test-Skipped { background-color: #C0C0C0; }
.test-Success { background-color: #C0FFC0; }
.test-Failed { background-color: #FFC0C0; }
.test-Failed.emu-Yes { background-color: #FFFFC0; }
</style>
<style id="fontFaces">
@font-face { font-family: 'plus'; src: url(data:font/opentype;base64,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); }
</style>
<script src="tests.js"></script>
</head>
<body>
<h1>Required Features for PDF.js</h1>
<div>User Agent: <span id="userAgent"></span></div>
<script>
document.getElementById('userAgent').innerHTML = navigator.userAgent;
</script>
<table id="tests">
<caption>Tests Results</caption>
<thead>
<tr><th class="name">Name</th><th class="test">Test</th><th class="impact">Impact</th><th class="area">Area</th><th class="emu">Emulated</th><th></th></tr>
</thead>
<tbody id="output">
</tbody>
</table>
<div id="canvasHolder" style="display: none;">
</div>
<div id="plusfontusage" style="font-family: plus; visibility: hidden;">`</div>
<script>
var wikiPageBase = 'https://github.com/mozilla/pdf.js/wiki/Required-Browser-Features#wiki-';
var output = document.getElementById('output');
// for some browser textContent is absent using innerHTML :/
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
var row = document.createElement('tr');
row.id = test.id;
var nameTd = document.createElement('td');
nameTd.className = 'name';
nameTd.innerHTML = test.name;
row.appendChild(nameTd);
var testTd = document.createElement('td');
testTd.className = 'test';
testTd.innerHTML = 'Running...';
row.appendChild(testTd);
var impactTd = document.createElement('td');
impactTd.className = 'impact';
impactTd.innerHTML = test.impact;
row.appendChild(impactTd);
var areaTd = document.createElement('td');
areaTd.className = 'area';
areaTd.innerHTML = test.area;
row.appendChild(areaTd);
var emulatedTd = document.createElement('td');
emulatedTd.className = 'emu';
row.appendChild(emulatedTd);
output.appendChild(row);
var infoTd = document.createElement('td');
infoTd.className = 'emu';
var infoA = document.createElement('a');
infoA.href = wikiPageBase + test.id;
infoA.innerHTML = 'info';
infoTd.appendChild(infoA);
row.appendChild(infoTd);
output.appendChild(row);
var publish = (function(row, testTd, emulatedTd) {
return function (result) {
row.className = 'test-' + result.output + ' emu-' + result.emulated;
testTd.innerHTML = result.output;
emulatedTd.innerHTML = result.emulated;
};
})(row, testTd, emulatedTd);
var result;
try {
result = test.run();
} catch (e) {
console.error('test run failed: ' + e);
result = { output: 'Failed', emulated: '?' };
}
if (result.then)
result.then(publish);
else
publish(result);
}
</script>
</body>
</html>

553
test/features/tests.js Normal file
View File

@ -0,0 +1,553 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// simple and incomplete implementation of promises
function Promise() {}
Promise.prototype = {
then: function (callback) {
this.callback = callback;
if ('result' in this) callback(this.result);
},
resolve: function (result) {
if ('result' in this) return;
this.result = result;
if ('callback' in this) this.callback(result);
}
};
var isCanvasSupported = (function () {
try {
document.createElement('canvas').getContext('2d').fillStyle = '#FFFFFF';
return true;
} catch (e) {
return false;
}
})();
var tests = [
{
id: 'canvas',
name: 'CANVAS element is present',
run: function () {
if (isCanvasSupported) {
return { output: 'Success', emulated: '' };
} else {
return { output: 'Failed', emulated: 'No' };
}
},
impact: 'Critical',
area: 'Core'
},
{
id: 'get-literal',
name: 'get-literal properties',
run: function () {
try {
var Test = eval('var Test = { get t() { return {}; } }; Test');
Test.t.test = true;
return { output: 'Success', emulated: '' };
} catch (e) {
return { output: 'Failed', emulated: 'No' };
}
},
impact: 'Critical',
area: 'Core'
},
{
id: 'addEventListener',
name: 'addEventListener() is present',
run: function () {
var div = document.createElement('div');
if (div.addEventListener)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'No' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Uint8Array',
name: 'Uint8Array is present',
run: function () {
if (typeof Uint8Array !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Uint16Array',
name: 'Uint16Array is present',
run: function () {
if (typeof Uint16Array !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Int32Array',
name: 'Int32Array is present',
run: function () {
if (typeof Int32Array !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Float32Array',
name: 'Float32Array is present',
run: function () {
if (typeof Float32Array !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Float64Array',
name: 'Float64Array is present',
run: function () {
if (typeof Float64Array !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Object-create',
name: 'Object.create() is present',
run: function () {
if (Object.create instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Object-defineProperty',
name: 'Object.defineProperty() is present',
run: function () {
if (Object.defineProperty instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Object-defineProperty-DOM',
name: 'Object.defineProperty() can be used on DOM objects',
run: function () {
if (!(Object.defineProperty instanceof Function))
return { output: 'Skipped', emulated: '' };
try {
// some browsers (e.g. safari) cannot use defineProperty() on DOM objects
// and thus the native version is not sufficient
Object.defineProperty(new Image(), 'id', { value: 'test' });
return { output: 'Success', emulated: '' };
} catch (e) {
return { output: 'Failed', emulated: 'Yes' };
}
},
impact: 'Important',
area: 'Viewer'
},
{
id: 'get-literal-redefine',
name: 'Defined via get-literal properties can be redefined',
run: function () {
if (!(Object.defineProperty instanceof Function))
return { output: 'Skipped', emulated: '' };
try {
var TestGetter = eval('var Test = function () {}; Test.prototype = { get id() { } }; Test');
Object.defineProperty(new TestGetter(), 'id',
{ value: '', configurable: true, enumerable: true, writable: false });
return { output: 'Success', emulated: '' };
} catch (e) {
return { output: 'Failed', emulated: 'Yes' };
}
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Object-keys',
name: 'Object.keys() is present',
run: function () {
if (Object.keys instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'FileReader',
name: 'FileReader is present',
run: function () {
if (typeof FileReader !== 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'No' };
},
impact: 'Normal',
area: 'Demo'
},
{
id: 'FileReader-readAsArrayBuffer',
name: 'FileReader.prototype.readAsArrayBuffer() is present',
run: function () {
if (typeof FileReader === 'undefined')
return { output: 'Skipped', emulated: '' };
if (FileReader.prototype.readAsArrayBuffer instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Normal',
area: 'Demo'
},
{
id: 'XMLHttpRequest-overrideMimeType',
name: 'XMLHttpRequest.prototype.overrideMimeType() is present',
run: function () {
if (XMLHttpRequest.prototype.overrideMimeType instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Important',
area: 'Viewer'
},
{
id: 'XMLHttpRequest-response',
name: 'XMLHttpRequest.prototype.response is present',
run: function () {
var xhr = new XMLHttpRequest();
if ('response' in xhr)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'bota',
name: 'btoa() is present',
run: function () {
if ('btoa' in window)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'Function-bind',
name: 'Function.prototype.bind is present',
run: function () {
if (Function.prototype.bind instanceof Function)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'dataset',
name: 'dataset is present for HTML element',
run: function () {
var div = document.createElement('div');
if ('dataset' in div)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Important',
area: 'Viewer'
},
{
id: 'classList',
name: 'classList is present for HTML element',
run: function () {
var div = document.createElement('div');
if ('classList' in div)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Important',
area: 'Viewer'
},
{
id: 'console',
name: 'console object is present',
run: function () {
if ('console' in window)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'console-log-bind',
name: 'console.log is a bind-able function',
run: function () {
if (!('console' in window))
return { output: 'Skipped', emulated: '' };
if ('bind' in console.log)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Critical',
area: 'Core'
},
{
id: 'navigator-language',
name: 'navigator.language is present',
run: function () {
if ('language' in navigator)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'Yes' };
},
impact: 'Important',
area: 'Viewer'
},
{
id: 'fillRule-evenodd',
name: 'evenodd fill rule is supported',
run: function () {
if (!isCanvasSupported)
return { output: 'Skipped', emulated: '' };
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.rect(1, 1, 50, 50);
ctx.rect(5, 5, 41, 41);
['fillRule', 'mozFillRule', 'webkitFillRule'].forEach(function (name) {
if (name in ctx) ctx[name] = 'evenodd';
});
ctx.fill();
var data = ctx.getImageData(0, 0, 50, 50).data;
var isEvenOddFill = data[20 * 4 + 20 * 200 + 3] == 0 &&
data[2 * 4 + 2 * 200 + 3] != 0;
if (isEvenOddFill)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'No' };
},
impact: 'Important',
area: 'Core'
},
{
id: 'dash-array',
name: 'dashed lined is supported',
run: function () {
if (!isCanvasSupported)
return { output: 'Skipped', emulated: '' };
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.moveTo(0,5);
ctx.lineTo(50, 5);
ctx.lineWidth = 10;
ctx.mozDash = [10, 10];
ctx.mozDashOffset = 0;
ctx.webkitLineDash = [10, 10];
ctx.webkitLineDashOffset = 0;
ctx.stroke();
var data = ctx.getImageData(0, 0, 50, 50).data;
var isDashed = data[5 * 4 + 5 * 200 + 3] != 0 &&
data[15 * 4 + 5 * 200 + 3] == 0;
if (isDashed)
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'No' };
},
impact: 'Important',
area: 'Core'
},
{
id: 'font-face',
name: '@font-face is supported/enabled',
run: function () {
if (!isCanvasSupported)
return { output: 'Skipped', emulated: '' };
var promise = new Promise();
setTimeout(function() {
if (checkCanvas('plus'))
promise.resolve({ output: 'Success', emulated: '' });
else
promise.resolve({ output: 'Failed', emulated: 'No' });
}, 2000);
return promise;
},
impact: 'Important',
area: 'Core'
},
{
id: 'font-face-sync',
name: '@font-face data urls are loaded synchronously',
run: function () {
if (!isCanvasSupported)
return { output: 'Skipped', emulated: '' };
// Add the font-face rule to the document
var rule = '@font-face { font-family: \'plus-loaded\'; src: url(data:font/opentype;base64,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); }';
var styleElement = document.getElementById('fontFaces');
var styleSheet = styleElement.sheet;
styleSheet.insertRule(rule, styleSheet.cssRules.length);
if (checkCanvas('plus-loaded'))
return { output: 'Success', emulated: '' };
var usageElement = document.createElement('div');
usageElement.setAttribute('style', 'font-family: plus-loaded; visibility: hidden;');
usageElement.textContent = '`';
document.body.appendChild(usageElement);
var promise = new Promise();
setTimeout(function() {
if (checkCanvas('plus-loaded'))
promise.resolve({ output: 'Failed', emulated: 'Yes' });
else
promise.resolve({ output: 'Failed', emulated: 'No' });
}, 2000);
return promise;
},
impact: 'Important',
area: 'Core'
},
{
id: 'Worker',
name: 'Worker is present',
run: function () {
if (typeof Worker != 'undefined')
return { output: 'Success', emulated: '' };
else
return { output: 'Failed', emulated: 'No' };
},
impact: 'Important',
area: 'Core'
},
{
id: 'Worker-Uint8Array',
name: 'Worker can receive/send typed arrays',
run: function () {
if (typeof Worker == 'undefined')
return { output: 'Skipped', emulated: '' };
try {
var worker = new Worker('worker-stub.js');
var promise = new Promise();
var timeout = setTimeout(function () {
promise.resolve({ output: 'Failed', emulated: '?' });
}, 5000);
worker.addEventListener('message', function (e) {
var data = e.data;
if (data.action == 'test' && data.result)
promise.resolve({ output: 'Success', emulated: '' });
else
promise.resolve({ output: 'Failed', emulated: 'Yes' });
});
worker.postMessage({action: 'test',
data: new Uint8Array(60000000)}); // 60MB
return promise;
} catch (e) {
return { output: 'Failed', emulated: 'Yes' };
}
},
impact: 'Important',
area: 'Core'
}
];
function checkCanvas(font) {
var canvas = document.createElement('canvas');
var canvasHolder = document.getElementById('canvasHolder');
canvasHolder.appendChild(canvas);
var ctx = canvas.getContext('2d');
ctx.font = '40px \'' + font + '\'';
ctx.fillText('\u0060', 0, 40);
var data = ctx.getImageData(0, 0, 40, 40).data;
canvasHolder.removeChild(canvas);
// detects plus figure
var minx = 40, maxx = 0, miny = 40, maxy = 0;
for (var y = 0; y < 40; y++) {
for (var x = 0; x < 40; x++) {
if (data[x * 4 + y * 160 + 3] == 0) continue; // no color
minx = Math.min(minx, x); miny = Math.min(miny, y);
maxx = Math.max(maxx, x); maxy = Math.max(maxy, y);
}
}
var colors = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
var counts = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
for (var y = miny; y <= maxy; y++) {
for (var x = minx; x <= maxx; x++) {
var i = Math.floor((x - minx) * 3 / (maxx - minx + 1));
var j = Math.floor((y - miny) * 3 / (maxy - miny + 1));
counts[i][j]++;
if (data[x * 4 + y * 160 + 3] != 0)
colors[i][j]++;
}
}
var isPlus =
colors[0][0] * 3 < counts[0][0] &&
colors[0][1] * 3 > counts[0][1] &&
colors[0][2] * 3 < counts[0][2] &&
colors[1][0] * 3 > counts[1][0] &&
colors[1][1] * 3 > counts[1][1] &&
colors[1][2] * 3 > counts[1][2] &&
colors[2][0] * 3 < counts[2][0] &&
colors[2][1] * 3 > counts[2][1] &&
colors[2][2] * 3 < counts[2][2];
return isPlus;
}

View File

@ -0,0 +1,23 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
onmessage = function (e) {
var data = e.data;
postMessage({action: 'test', result: data.action == 'test' &&
data.data instanceof Uint8Array});
};