4 changed files with 693 additions and 0 deletions
@ -0,0 +1,116 @@
@@ -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> |
@ -0,0 +1,553 @@
@@ -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; |
||||
} |
||||
|
@ -0,0 +1,23 @@
@@ -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}); |
||||
}; |
||||
|
Loading…
Reference in new issue