Merge branch 'master' of https://github.com/mozilla/pdf.js into title-mods
This commit is contained in:
commit
211c63f587
1
LICENSE
1
LICENSE
@ -12,6 +12,7 @@
|
||||
Jakob Miland <saebekassebil@gmail.com>
|
||||
Artur Adib <aadib@mozilla.com>
|
||||
Brendan Dahl <bdahl@mozilla.com>
|
||||
David Quintana <gigaherz@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
|
1
Makefile
1
Makefile
@ -39,6 +39,7 @@ PDF_JS_FILES = \
|
||||
../external/jpgjs/jpg.js \
|
||||
jpx.js \
|
||||
bidi.js \
|
||||
metadata.js \
|
||||
$(NULL)
|
||||
|
||||
# make server
|
||||
|
@ -1,5 +1,5 @@
|
||||
# PDF.JS
|
||||
|
||||
|
||||
|
||||
pdf.js is an HTML5 technology experiment that explores building a faithful
|
||||
and efficient Portable Document Format (PDF) renderer without native code
|
||||
|
@ -30,23 +30,11 @@ function log(aMsg) {
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
function getWindow(top, id) {
|
||||
return top.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.getOuterWindowWithId(id);
|
||||
}
|
||||
function windowID(win) {
|
||||
return win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.outerWindowID;
|
||||
}
|
||||
function topWindow(win) {
|
||||
return win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
|
||||
function getDOMWindow(aChannel) {
|
||||
var requestor = aChannel.notificationCallbacks;
|
||||
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
|
||||
return win;
|
||||
}
|
||||
|
||||
// All the priviledged actions.
|
||||
@ -75,6 +63,7 @@ ChromeActions.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Event listener to trigger chrome privedged code.
|
||||
function RequestListener(actions) {
|
||||
this.actions = actions;
|
||||
@ -163,38 +152,32 @@ PdfStreamConverter.prototype = {
|
||||
var channel = ioService.newChannel(
|
||||
'resource://pdf.js/web/viewer.html', null, null);
|
||||
|
||||
var listener = this.listener;
|
||||
// Proxy all the requst observer calls, when it gets to onStopRequst
|
||||
// we can get the dom window.
|
||||
var proxy = {
|
||||
onStartRequest: function() {
|
||||
listener.onStartRequest.apply(listener, arguments);
|
||||
},
|
||||
onDataAvailable: function() {
|
||||
listener.onDataAvailable.apply(listener, arguments);
|
||||
},
|
||||
onStopRequest: function() {
|
||||
var domWindow = getDOMWindow(channel);
|
||||
// Double check the url is still the correct one.
|
||||
if (domWindow.document.documentURIObject.equals(aRequest.URI)) {
|
||||
let requestListener = new RequestListener(new ChromeActions);
|
||||
domWindow.addEventListener(PDFJS_EVENT_ID, function(event) {
|
||||
requestListener.receive(event);
|
||||
}, false, true);
|
||||
}
|
||||
listener.onStopRequest.apply(listener, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
// Keep the URL the same so the browser sees it as the same.
|
||||
channel.originalURI = aRequest.URI;
|
||||
channel.asyncOpen(this.listener, aContext);
|
||||
|
||||
// Setup a global listener waiting for the next DOM to be created and verfiy
|
||||
// that its the one we want by its URL. When the correct DOM is found create
|
||||
// an event listener on that window for the pdf.js events that require
|
||||
// chrome priviledges. Code snippet from John Galt.
|
||||
let window = aRequest.loadGroup.groupObserver
|
||||
.QueryInterface(Ci.nsIWebProgress)
|
||||
.DOMWindow;
|
||||
let top = topWindow(window);
|
||||
let id = windowID(window);
|
||||
window = null;
|
||||
|
||||
top.addEventListener('DOMWindowCreated', function onDOMWinCreated(event) {
|
||||
let doc = event.originalTarget;
|
||||
let win = doc.defaultView;
|
||||
|
||||
if (id == windowID(win)) {
|
||||
top.removeEventListener('DOMWindowCreated', onDOMWinCreated, true);
|
||||
if (!doc.documentURIObject.equals(aRequest.URI))
|
||||
return;
|
||||
|
||||
let requestListener = new RequestListener(new ChromeActions);
|
||||
win.addEventListener(PDFJS_EVENT_ID, function(event) {
|
||||
requestListener.receive(event);
|
||||
}, false, true);
|
||||
} else if (!getWindow(top, id)) {
|
||||
top.removeEventListener('DOMWindowCreated', onDOMWinCreated, true);
|
||||
}
|
||||
}, true);
|
||||
channel.asyncOpen(proxy, aContext);
|
||||
},
|
||||
|
||||
// nsIRequestObserver::onStopRequest
|
||||
|
22
external/shelljs/ChangeLog
vendored
Normal file
22
external/shelljs/ChangeLog
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
2012.03.22, Version 0.0.4
|
||||
|
||||
* ls() and find() return arrays instead of hashes (Artur Adib)
|
||||
* exec({silent:...}) overrides global silent() state (Artur Adib)
|
||||
|
||||
|
||||
2012.03.21, Version 0.0.3
|
||||
|
||||
* Wildcard bug fix (Artur Adib)
|
||||
* execSync() now uses dummy file I/O op to reduce CPU usage (Artur Adib)
|
||||
* Minor fixes
|
||||
|
||||
|
||||
2012.03.15, Version 0.0.2
|
||||
|
||||
* New methods: find(), test() (Artur Adib)
|
||||
* Deprecated non-Unix methods: exists(), verbose()
|
||||
|
||||
|
||||
2012.03.03, Version 0.0.2pre1
|
||||
|
||||
* First public release
|
66
external/shelljs/README.md
vendored
66
external/shelljs/README.md
vendored
@ -1,6 +1,7 @@
|
||||
# ShellJS - Unix shell commands for Node.js [![Build Status](https://secure.travis-ci.org/arturadib/shelljs.png)](http://travis-ci.org/arturadib/shelljs)
|
||||
|
||||
_This project is young and experimental. Use at your own risk._
|
||||
+ _This project is young and experimental. Use at your own risk._
|
||||
+ _Major API change as of v0.0.4: `ls()` and `find()` now return arrays._
|
||||
|
||||
ShellJS is a **portable** (Windows included) implementation of Unix shell commands on top of the Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping its familiar and powerful commands.
|
||||
|
||||
@ -18,11 +19,11 @@ cp('-R', 'stuff/*', 'out/Release');
|
||||
|
||||
// Replace macros in each .js file
|
||||
cd('lib');
|
||||
for (file in ls('*.js')) {
|
||||
ls('*.js').forEach(function(file) {
|
||||
sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
|
||||
sed('-i', /.*REMOVE_THIS_LINE.*\n/, '', file);
|
||||
sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, cat('macro.js'), file);
|
||||
}
|
||||
});
|
||||
cd('..');
|
||||
|
||||
// Run external tool synchronously
|
||||
@ -73,11 +74,11 @@ target.docs = function() {
|
||||
cd(__dirname);
|
||||
mkdir('docs');
|
||||
cd('lib');
|
||||
for (file in ls('*.js')) {
|
||||
ls('*.js').forEach(function(file){
|
||||
var text = grep('//@', file); // extract special comments
|
||||
text.replace('//@', ''); // remove comment tags
|
||||
text.to('docs/my_docs.md');
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
@ -128,9 +129,7 @@ ls('-R', '/users/me', '/tmp');
|
||||
ls('-R', ['/users/me', '/tmp']); // same as above
|
||||
```
|
||||
|
||||
Returns list of files in the given path, or in current directory if no path provided.
|
||||
For convenient iteration via `for (file in ls())`, the format returned is a hash object:
|
||||
`{ 'file1':null, 'dir1/file2':null, ...}`.
|
||||
Returns array of files in the given path, or in current directory if no path provided.
|
||||
|
||||
#### find(path [,path ...])
|
||||
#### find(path_array)
|
||||
@ -139,18 +138,12 @@ Examples:
|
||||
```javascript
|
||||
find('src', 'lib');
|
||||
find(['src', 'lib']); // same as above
|
||||
for (file in find('.')) {
|
||||
if (!file.match(/\.js$/))
|
||||
continue;
|
||||
// all files at this point end in '.js'
|
||||
}
|
||||
find('.').filter(function(file) { return file.match(/\.js$/); });
|
||||
```
|
||||
|
||||
Returns list of all files (however deep) in the given paths. For convenient iteration
|
||||
via `for (file in find(...))`, the format returned is a hash object:
|
||||
`{ 'file1':null, 'dir1/file2':null, ...}`.
|
||||
Returns array of all files (however deep) in the given paths.
|
||||
|
||||
The main difference with respect to `ls('-R', path)` is that the resulting file names
|
||||
The main difference from `ls('-R', path)` is that the resulting file names
|
||||
include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
|
||||
|
||||
#### cp('[options ,] source [,source ...], dest')
|
||||
@ -332,6 +325,10 @@ When in synchronous mode returns the object `{ code:..., output:... }`, containi
|
||||
`output` (stdout + stderr) and its exit `code`. Otherwise the `callback` gets the
|
||||
arguments `(code, output)`.
|
||||
|
||||
**Note:** For long-lived processes, it's best to run `exec()` asynchronously as
|
||||
the current synchronous implementation uses a lot of CPU. This should be getting
|
||||
fixed soon.
|
||||
|
||||
## Non-Unix commands
|
||||
|
||||
|
||||
@ -339,16 +336,35 @@ arguments `(code, output)`.
|
||||
Searches and returns string containing a writeable, platform-dependent temporary directory.
|
||||
Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).
|
||||
|
||||
#### exists(path [, path ...])
|
||||
#### exists(path_array)
|
||||
Returns true if all the given paths exist.
|
||||
|
||||
#### error()
|
||||
Tests if error occurred in the last command. Returns `null` if no error occurred,
|
||||
otherwise returns string explaining the error
|
||||
|
||||
#### verbose()
|
||||
Enables all output (default)
|
||||
#### silent([state])
|
||||
Example:
|
||||
|
||||
#### silent()
|
||||
Suppresses all output, except for explict `echo()` calls
|
||||
```javascript
|
||||
var silentState = silent();
|
||||
silent(true);
|
||||
/* ... */
|
||||
silent(silentState); // restore old silent state
|
||||
```
|
||||
|
||||
Suppresses all command output if `state = true`, except for `echo()` calls.
|
||||
Returns state if no arguments given.
|
||||
|
||||
## Deprecated
|
||||
|
||||
|
||||
#### exists(path [, path ...])
|
||||
#### exists(path_array)
|
||||
|
||||
_This function is being deprecated. Use `test()` instead._
|
||||
|
||||
Returns true if all the given paths exist.
|
||||
|
||||
#### verbose()
|
||||
|
||||
_This function is being deprecated. Use `silent(false) instead.`_
|
||||
|
||||
Enables all output (default)
|
||||
|
2
external/shelljs/make.js
vendored
2
external/shelljs/make.js
vendored
@ -23,7 +23,7 @@ setTimeout(function() {
|
||||
if (oldTarget.done && !force)
|
||||
return;
|
||||
oldTarget.done = true;
|
||||
return oldTarget(arguments);
|
||||
return oldTarget.apply(oldTarget, arguments);
|
||||
}
|
||||
|
||||
})(t, target[t]);
|
||||
|
35
external/shelljs/package.json
vendored
35
external/shelljs/package.json
vendored
@ -1,12 +1,29 @@
|
||||
{ "name": "shelljs"
|
||||
, "version": "0.0.2pre1"
|
||||
, "author": "Artur Adib <aadib@mozilla.com>"
|
||||
, "description": "Portable Unix shell commands for Node.js"
|
||||
, "keywords": ["unix", "shell", "makefile", "make", "jake", "synchronous"]
|
||||
, "repository": "git://github.com/arturadib/shelljs"
|
||||
, "homepage": "http://github.com/arturadib/shelljs"
|
||||
, "main": "./shell.js"
|
||||
, "scripts": {
|
||||
{
|
||||
"name": "shelljs",
|
||||
"version": "0.0.5pre4",
|
||||
"author": "Artur Adib <aadib@mozilla.com>",
|
||||
"description": "Portable Unix shell commands for Node.js",
|
||||
"keywords": [
|
||||
"unix",
|
||||
"shell",
|
||||
"makefile",
|
||||
"make",
|
||||
"jake",
|
||||
"synchronous"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/arturadib/shelljs.git"
|
||||
},
|
||||
"homepage": "http://github.com/arturadib/shelljs",
|
||||
"main": "./shell.js",
|
||||
"scripts": {
|
||||
"test": "node scripts/run-tests"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"optionalDependencies": {},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
}
|
||||
|
313
external/shelljs/shell.js
vendored
313
external/shelljs/shell.js
vendored
@ -74,9 +74,7 @@ exports.pwd = wrap('pwd', _pwd);
|
||||
//@ ls('-R', ['/users/me', '/tmp']); // same as above
|
||||
//@ ```
|
||||
//@
|
||||
//@ Returns list of files in the given path, or in current directory if no path provided.
|
||||
//@ For convenient iteration via `for (file in ls())`, the format returned is a hash object:
|
||||
//@ `{ 'file1':null, 'dir1/file2':null, ...}`.
|
||||
//@ Returns array of files in the given path, or in current directory if no path provided.
|
||||
function _ls(options, paths) {
|
||||
options = parseOptions(options, {
|
||||
'R': 'recursive',
|
||||
@ -90,24 +88,30 @@ function _ls(options, paths) {
|
||||
else if (typeof paths === 'string')
|
||||
paths = [].slice.call(arguments, 1);
|
||||
|
||||
var hash = {};
|
||||
var list = [];
|
||||
|
||||
function pushHash(file, query) {
|
||||
// Conditionally pushes file to list - returns true if pushed, false otherwise
|
||||
// (e.g. prevents hidden files to be included unless explicitly told so)
|
||||
function pushFile(file, query) {
|
||||
// hidden file?
|
||||
if (path.basename(file)[0] === '.') {
|
||||
// not explicitly asking for hidden files?
|
||||
if (!options.all && !(path.basename(query)[0] === '.' && path.basename(query).length > 1))
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
hash[file] = null;
|
||||
if (platform === 'win')
|
||||
file = file.replace(/\\/g, '/');
|
||||
|
||||
list.push(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
paths.forEach(function(p) {
|
||||
if (fs.existsSync(p)) {
|
||||
// Simple file?
|
||||
if (fs.statSync(p).isFile()) {
|
||||
pushHash(p, p);
|
||||
pushFile(p, p);
|
||||
return; // continue
|
||||
}
|
||||
|
||||
@ -115,14 +119,17 @@ function _ls(options, paths) {
|
||||
if (fs.statSync(p).isDirectory()) {
|
||||
// Iterate over p contents
|
||||
fs.readdirSync(p).forEach(function(file) {
|
||||
pushHash(file, p);
|
||||
if (!pushFile(file, p))
|
||||
return;
|
||||
|
||||
// Recursive
|
||||
var oldDir = _pwd();
|
||||
_cd('', p);
|
||||
if (fs.statSync(file).isDirectory() && options.recursive)
|
||||
hash = extend(hash, _ls('-R', file+'/*'));
|
||||
_cd('', oldDir);
|
||||
// Recursive?
|
||||
if (options.recursive) {
|
||||
var oldDir = _pwd();
|
||||
_cd('', p);
|
||||
if (fs.statSync(file).isDirectory())
|
||||
list = list.concat(_ls('-R'+(options.all?'a':''), file+'/*'));
|
||||
_cd('', oldDir);
|
||||
}
|
||||
});
|
||||
return; // continue
|
||||
}
|
||||
@ -137,17 +144,20 @@ function _ls(options, paths) {
|
||||
// Escape special regular expression chars
|
||||
var regexp = basename.replace(/(\^|\$|\(|\)|\<|\>|\[|\]|\{|\}|\.|\+|\?)/g, '\\$1');
|
||||
// Translates wildcard into regex
|
||||
regexp = '^' + regexp.replace(/\*/g, '.*');
|
||||
regexp = '^' + regexp.replace(/\*/g, '.*') + '$';
|
||||
// Iterate over directory contents
|
||||
fs.readdirSync(dirname).forEach(function(file) {
|
||||
if (file.match(new RegExp(regexp))) {
|
||||
pushHash(path.normalize(dirname+'/'+file), basename);
|
||||
if (!pushFile(path.normalize(dirname+'/'+file), basename))
|
||||
return;
|
||||
|
||||
// Recursive
|
||||
var pp = dirname + '/' + file;
|
||||
if (fs.statSync(pp).isDirectory() && options.recursive)
|
||||
hash = extend(hash, _ls('-R', pp+'/*'));
|
||||
}
|
||||
// Recursive?
|
||||
if (options.recursive) {
|
||||
var pp = dirname + '/' + file;
|
||||
if (fs.statSync(pp).isDirectory())
|
||||
list = list.concat(_ls('-R'+(options.all?'a':''), pp+'/*'));
|
||||
} // recursive
|
||||
} // if file matches
|
||||
}); // forEach
|
||||
return;
|
||||
}
|
||||
@ -155,7 +165,7 @@ function _ls(options, paths) {
|
||||
error('no such file or directory: ' + p, true);
|
||||
});
|
||||
|
||||
return hash;
|
||||
return list;
|
||||
};
|
||||
exports.ls = wrap('ls', _ls);
|
||||
|
||||
@ -168,16 +178,10 @@ exports.ls = wrap('ls', _ls);
|
||||
//@ ```javascript
|
||||
//@ find('src', 'lib');
|
||||
//@ find(['src', 'lib']); // same as above
|
||||
//@ for (file in find('.')) {
|
||||
//@ if (!file.match(/\.js$/))
|
||||
//@ continue;
|
||||
//@ // all files at this point end in '.js'
|
||||
//@ }
|
||||
//@ find('.').filter(function(file) { return file.match(/\.js$/); });
|
||||
//@ ```
|
||||
//@
|
||||
//@ Returns list of all files (however deep) in the given paths. For convenient iteration
|
||||
//@ via `for (file in find(...))`, the format returned is a hash object:
|
||||
//@ `{ 'file1':null, 'dir1/file2':null, ...}`.
|
||||
//@ Returns array of all files (however deep) in the given paths.
|
||||
//@
|
||||
//@ The main difference from `ls('-R', path)` is that the resulting file names
|
||||
//@ include the base directories, e.g. `lib/resources/file1` instead of just `file1`.
|
||||
@ -189,21 +193,28 @@ function _find(options, paths) {
|
||||
else if (typeof paths === 'string')
|
||||
paths = [].slice.call(arguments, 1);
|
||||
|
||||
var hash = {};
|
||||
var list = [];
|
||||
|
||||
function pushFile(file) {
|
||||
if (platform === 'win')
|
||||
file = file.replace(/\\/g, '/');
|
||||
list.push(file);
|
||||
}
|
||||
|
||||
// why not simply do ls('-R', paths)? because the output wouldn't give the base dirs
|
||||
// to get the base dir in the output, we need instead ls('-R', 'dir/*') for every directory
|
||||
|
||||
paths.forEach(function(file){
|
||||
hash[file] = null;
|
||||
paths.forEach(function(file) {
|
||||
pushFile(file);
|
||||
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
for (subfile in _ls('-Ra', file+'/*'))
|
||||
hash[subfile] = null;
|
||||
_ls('-Ra', file+'/*').forEach(function(subfile) {
|
||||
pushFile(subfile);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return hash;
|
||||
return list;
|
||||
}
|
||||
exports.find = wrap('find', _find);
|
||||
|
||||
@ -347,9 +358,20 @@ function _rm(options, files) {
|
||||
|
||||
// Remove simple file
|
||||
if (fs.statSync(file).isFile()) {
|
||||
fs.unlinkSync(file);
|
||||
|
||||
// Do not check for file writing permissions
|
||||
if (options.force) {
|
||||
_unlinkSync(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isWriteable(file))
|
||||
_unlinkSync(file);
|
||||
else
|
||||
error('permission denied: '+file, true);
|
||||
|
||||
return;
|
||||
}
|
||||
} // simple file
|
||||
|
||||
// Path is an existing directory, but no -r flag given
|
||||
if (fs.statSync(file).isDirectory() && !options.recursive) {
|
||||
@ -359,7 +381,7 @@ function _rm(options, files) {
|
||||
|
||||
// Recursively remove existing directory
|
||||
if (fs.statSync(file).isDirectory() && options.recursive) {
|
||||
rmdirSyncRecursive(file);
|
||||
rmdirSyncRecursive(file, options.force);
|
||||
}
|
||||
}); // forEach(file)
|
||||
}; // rm
|
||||
@ -582,7 +604,11 @@ function _to(options, file) {
|
||||
if (!fs.existsSync( path.dirname(file) ))
|
||||
error('no such file or directory: ' + path.dirname(file));
|
||||
|
||||
fs.writeFileSync(file, this.toString(), 'utf8');
|
||||
try {
|
||||
fs.writeFileSync(file, this.toString(), 'utf8');
|
||||
} catch(e) {
|
||||
error('could not write to file (code '+e.code+'): '+file, true);
|
||||
}
|
||||
};
|
||||
// In the future, when Proxies are default, we can add methods like `.to()` to primitive strings.
|
||||
// For now, this is a dummy function to bookmark places we need such strings
|
||||
@ -751,7 +777,7 @@ exports.which = wrap('which', _which);
|
||||
//@ like `.to()`.
|
||||
function _echo(options) {
|
||||
var messages = [].slice.call(arguments, 1);
|
||||
log.apply(this, messages);
|
||||
console.log.apply(this, messages);
|
||||
return ShellString(messages.join(' '));
|
||||
};
|
||||
exports.echo = wrap('echo', _echo);
|
||||
@ -783,6 +809,10 @@ exports.env = process.env;
|
||||
//@ When in synchronous mode returns the object `{ code:..., output:... }`, containing the program's
|
||||
//@ `output` (stdout + stderr) and its exit `code`. Otherwise the `callback` gets the
|
||||
//@ arguments `(code, output)`.
|
||||
//@
|
||||
//@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as
|
||||
//@ the current synchronous implementation uses a lot of CPU. This should be getting
|
||||
//@ fixed soon.
|
||||
function _exec(command, options, callback) {
|
||||
if (!command)
|
||||
error('must specify command');
|
||||
@ -793,7 +823,7 @@ function _exec(command, options, callback) {
|
||||
}
|
||||
|
||||
options = extend({
|
||||
silent: false,
|
||||
silent: state.silent,
|
||||
async: false
|
||||
}, options);
|
||||
|
||||
@ -822,11 +852,53 @@ exports.exec = wrap('exec', _exec, {notUnix:true});
|
||||
//@ Follows Python's [tempfile algorithm](http://docs.python.org/library/tempfile.html#tempfile.tempdir).
|
||||
exports.tempdir = wrap('tempdir', tempDir);
|
||||
|
||||
|
||||
//@
|
||||
//@ #### error()
|
||||
//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
|
||||
//@ otherwise returns string explaining the error
|
||||
exports.error = function() {
|
||||
return state.error;
|
||||
}
|
||||
|
||||
//@
|
||||
//@ #### silent([state])
|
||||
//@ Example:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var silentState = silent();
|
||||
//@ silent(true);
|
||||
//@ /* ... */
|
||||
//@ silent(silentState); // restore old silent state
|
||||
//@ ```
|
||||
//@
|
||||
//@ Suppresses all command output if `state = true`, except for `echo()` calls.
|
||||
//@ Returns state if no arguments given.
|
||||
exports.silent = function(_state) {
|
||||
if (typeof _state !== 'boolean')
|
||||
return state.silent;
|
||||
|
||||
state.silent = _state;
|
||||
}
|
||||
|
||||
|
||||
//@
|
||||
//@ ## Deprecated
|
||||
//@
|
||||
|
||||
|
||||
|
||||
|
||||
//@
|
||||
//@ #### exists(path [, path ...])
|
||||
//@ #### exists(path_array)
|
||||
//@
|
||||
//@ _This function is being deprecated. Use `test()` instead._
|
||||
//@
|
||||
//@ Returns true if all the given paths exist.
|
||||
function _exists(options, paths) {
|
||||
deprecate('exists', 'Use test() instead.');
|
||||
|
||||
if (!paths)
|
||||
error('no paths given');
|
||||
|
||||
@ -844,32 +916,19 @@ function _exists(options, paths) {
|
||||
};
|
||||
exports.exists = wrap('exists', _exists);
|
||||
|
||||
//@
|
||||
//@ #### error()
|
||||
//@ Tests if error occurred in the last command. Returns `null` if no error occurred,
|
||||
//@ otherwise returns string explaining the error
|
||||
exports.error = function() {
|
||||
return state.error;
|
||||
}
|
||||
|
||||
//@
|
||||
//@ #### verbose()
|
||||
//@
|
||||
//@ _This function is being deprecated. Use `silent(false) instead.`_
|
||||
//@
|
||||
//@ Enables all output (default)
|
||||
exports.verbose = function() {
|
||||
deprecate('verbose', 'Use silent(false) instead.');
|
||||
|
||||
state.silent = false;
|
||||
}
|
||||
|
||||
//@
|
||||
//@ #### silent()
|
||||
//@ Suppresses all output, except for explict `echo()` calls
|
||||
exports.silent = function() {
|
||||
state.silent = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -889,6 +948,10 @@ function log() {
|
||||
console.log.apply(this, arguments);
|
||||
}
|
||||
|
||||
function deprecate(what, msg) {
|
||||
console.log('*** ShellJS.'+what+': This function is deprecated.', msg);
|
||||
}
|
||||
|
||||
function write(msg) {
|
||||
if (!state.silent)
|
||||
process.stdout.write(msg);
|
||||
@ -962,7 +1025,7 @@ function wrap(cmd, fn, options) {
|
||||
} catch (e) {
|
||||
if (!state.error) {
|
||||
// If state.error hasn't been set it's an error thrown by Node, not us - probably a bug...
|
||||
console.log('maker.js: internal error');
|
||||
console.log('shell.js: internal error');
|
||||
console.log(e.stack || e);
|
||||
process.exit(1);
|
||||
}
|
||||
@ -970,7 +1033,7 @@ function wrap(cmd, fn, options) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
state.currentCmd = 'maker.js';
|
||||
state.currentCmd = 'shell.js';
|
||||
return retValue;
|
||||
}
|
||||
} // wrap
|
||||
@ -984,10 +1047,22 @@ function copyFileSync(srcFile, destFile) {
|
||||
|
||||
var BUF_LENGTH = 64*1024,
|
||||
buf = new Buffer(BUF_LENGTH),
|
||||
fdr = fs.openSync(srcFile, 'r'),
|
||||
fdw = fs.openSync(destFile, 'w'),
|
||||
bytesRead = BUF_LENGTH,
|
||||
pos = 0;
|
||||
pos = 0,
|
||||
fdr = null,
|
||||
fdw = null;
|
||||
|
||||
try {
|
||||
fdr = fs.openSync(srcFile, 'r');
|
||||
} catch(e) {
|
||||
error('copyFileSync: could not read src file ('+srcFile+')');
|
||||
}
|
||||
|
||||
try {
|
||||
fdw = fs.openSync(destFile, 'w');
|
||||
} catch(e) {
|
||||
error('copyFileSync: could not write to dest file (code='+e.code+'):'+destFile);
|
||||
}
|
||||
|
||||
while (bytesRead === BUF_LENGTH) {
|
||||
bytesRead = fs.readSync(fdr, buf, 0, BUF_LENGTH, pos);
|
||||
@ -1050,28 +1125,41 @@ function cpdirSyncRecursive(sourceDir, destDir, opts) {
|
||||
//
|
||||
// Licensed under the MIT License
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
function rmdirSyncRecursive(dir) {
|
||||
function rmdirSyncRecursive(dir, force) {
|
||||
var files;
|
||||
|
||||
files = fs.readdirSync(dir);
|
||||
|
||||
// Loop through and delete everything in the sub-tree after checking it
|
||||
for(var i = 0; i < files.length; i++) {
|
||||
var currFile = fs.lstatSync(dir + "/" + files[i]);
|
||||
var file = dir + "/" + files[i],
|
||||
currFile = fs.lstatSync(file);
|
||||
|
||||
if(currFile.isDirectory()) // Recursive function back to the beginning
|
||||
rmdirSyncRecursive(dir + "/" + files[i]);
|
||||
if(currFile.isDirectory()) { // Recursive function back to the beginning
|
||||
rmdirSyncRecursive(file, force);
|
||||
}
|
||||
|
||||
else if(currFile.isSymbolicLink()) // Unlink symlinks
|
||||
fs.unlinkSync(dir + "/" + files[i]);
|
||||
else if(currFile.isSymbolicLink()) { // Unlink symlinks
|
||||
if (force || isWriteable(file))
|
||||
_unlinkSync(file);
|
||||
}
|
||||
|
||||
else // Assume it's a file - perhaps a try/catch belongs here?
|
||||
fs.unlinkSync(dir + "/" + files[i]);
|
||||
if (force || isWriteable(file))
|
||||
_unlinkSync(file);
|
||||
}
|
||||
|
||||
// Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
|
||||
// Huzzah for the shopkeep.
|
||||
return fs.rmdirSync(dir);
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = fs.rmdirSync(dir);
|
||||
} catch(e) {
|
||||
error('could not remove directory (code '+e.code+'): ' + dir, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}; // rmdirSyncRecursive
|
||||
|
||||
// Recursively creates 'dir'
|
||||
@ -1118,7 +1206,7 @@ function writeableDir(dir) {
|
||||
var testFile = dir+'/'+randomFileName();
|
||||
try {
|
||||
fs.writeFileSync(testFile, ' ');
|
||||
fs.unlinkSync(testFile);
|
||||
_unlinkSync(testFile);
|
||||
return dir;
|
||||
} catch (e) {
|
||||
return false;
|
||||
@ -1151,6 +1239,10 @@ function tempDir() {
|
||||
// Wrapper around exec() to enable echoing output to console in real time
|
||||
function execAsync(cmd, opts, callback) {
|
||||
var output = '';
|
||||
|
||||
var options = extend({
|
||||
silent: state.silent
|
||||
}, opts);
|
||||
|
||||
var c = child.exec(cmd, {env: process.env}, function(err) {
|
||||
if (callback)
|
||||
@ -1159,14 +1251,14 @@ function execAsync(cmd, opts, callback) {
|
||||
|
||||
c.stdout.on('data', function(data) {
|
||||
output += data;
|
||||
if (!opts.silent)
|
||||
write(data);
|
||||
if (!options.silent)
|
||||
process.stdout.write(data);
|
||||
});
|
||||
|
||||
c.stderr.on('data', function(data) {
|
||||
output += data;
|
||||
if (!opts.silent)
|
||||
write(data);
|
||||
if (!options.silent)
|
||||
process.stdout.write(data);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1178,16 +1270,17 @@ function execAsync(cmd, opts, callback) {
|
||||
function execSync(cmd, opts) {
|
||||
var stdoutFile = path.resolve(tempDir()+'/'+randomFileName()),
|
||||
codeFile = path.resolve(tempDir()+'/'+randomFileName()),
|
||||
scriptFile = path.resolve(tempDir()+'/'+randomFileName());
|
||||
scriptFile = path.resolve(tempDir()+'/'+randomFileName()),
|
||||
sleepFile = path.resolve(tempDir()+'/'+randomFileName());
|
||||
|
||||
var options = extend({
|
||||
silent: false
|
||||
silent: state.silent
|
||||
}, opts);
|
||||
|
||||
var previousStdoutContent = '';
|
||||
// Echoes stdout changes from running process, if not silent
|
||||
function updateStdout() {
|
||||
if (state.silent || options.silent || !fs.existsSync(stdoutFile))
|
||||
if (options.silent || !fs.existsSync(stdoutFile))
|
||||
return;
|
||||
|
||||
var stdoutContent = fs.readFileSync(stdoutFile, 'utf8');
|
||||
@ -1214,9 +1307,9 @@ function execSync(cmd, opts) {
|
||||
fs.writeFileSync('"+escape(codeFile)+"', err ? err.code.toString() : '0'); \
|
||||
});";
|
||||
|
||||
if (fs.existsSync(scriptFile)) fs.unlinkSync(scriptFile);
|
||||
if (fs.existsSync(stdoutFile)) fs.unlinkSync(stdoutFile);
|
||||
if (fs.existsSync(codeFile)) fs.unlinkSync(codeFile);
|
||||
if (fs.existsSync(scriptFile)) _unlinkSync(scriptFile);
|
||||
if (fs.existsSync(stdoutFile)) _unlinkSync(stdoutFile);
|
||||
if (fs.existsSync(codeFile)) _unlinkSync(codeFile);
|
||||
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
child.exec('node '+scriptFile, {
|
||||
@ -1225,8 +1318,11 @@ function execSync(cmd, opts) {
|
||||
});
|
||||
|
||||
// The wait loop
|
||||
while (!fs.existsSync(codeFile)) { updateStdout(); };
|
||||
while (!fs.existsSync(stdoutFile)) { updateStdout(); };
|
||||
// sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
|
||||
// (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
|
||||
// CPU usage, though apparently not so much on Windows)
|
||||
while (!fs.existsSync(codeFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); };
|
||||
while (!fs.existsSync(stdoutFile)) { updateStdout(); fs.writeFileSync(sleepFile, 'a'); };
|
||||
|
||||
// At this point codeFile exists, but it's not necessarily flushed yet.
|
||||
// Keep reading it until it is.
|
||||
@ -1236,10 +1332,12 @@ function execSync(cmd, opts) {
|
||||
|
||||
var stdout = fs.readFileSync(stdoutFile, 'utf8');
|
||||
|
||||
fs.unlinkSync(scriptFile);
|
||||
fs.unlinkSync(stdoutFile);
|
||||
fs.unlinkSync(codeFile);
|
||||
|
||||
// No biggie if we can't erase the files now -- they're in a temp dir anyway
|
||||
try { _unlinkSync(scriptFile); } catch(e) {};
|
||||
try { _unlinkSync(stdoutFile); } catch(e) {};
|
||||
try { _unlinkSync(codeFile); } catch(e) {};
|
||||
try { _unlinkSync(sleepFile); } catch(e) {};
|
||||
|
||||
// True if successful, false if not
|
||||
var obj = {
|
||||
code: code,
|
||||
@ -1257,8 +1355,9 @@ function expand(list) {
|
||||
list.forEach(function(listEl) {
|
||||
// Wildcard present?
|
||||
if (listEl.search(/\*/) > -1) {
|
||||
for (file in _ls('', listEl))
|
||||
_ls('', listEl).forEach(function(file) {
|
||||
expanded.push(file);
|
||||
});
|
||||
} else {
|
||||
expanded.push(listEl);
|
||||
}
|
||||
@ -1290,3 +1389,33 @@ function extend(target) {
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// Normalizes _unlinkSync() across platforms to match Unix behavior, i.e.
|
||||
// file can be unlinked even if it's read-only, see joyent/node#3006
|
||||
function _unlinkSync(file) {
|
||||
try {
|
||||
fs.unlinkSync(file);
|
||||
} catch(e) {
|
||||
// Try to override file permission
|
||||
if (e.code === 'EPERM') {
|
||||
fs.chmodSync(file, '0666');
|
||||
fs.unlinkSync(file);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hack to determine if file has write permissions for current user
|
||||
// Avoids having to check user, group, etc, but it's probably slow
|
||||
function isWriteable(file) {
|
||||
var writePermission = true;
|
||||
try {
|
||||
var __fd = fs.openSync(file, 'a');
|
||||
fs.closeSync(__fd);
|
||||
} catch(e) {
|
||||
writePermission = false;
|
||||
}
|
||||
|
||||
return writePermission;
|
||||
}
|
||||
|
61
make.js
61
make.js
@ -97,9 +97,10 @@ target.bundle = function() {
|
||||
'worker.js',
|
||||
'../external/jpgjs/jpg.js',
|
||||
'jpx.js',
|
||||
'bidi.js'];
|
||||
'bidi.js',
|
||||
'metadata.js'];
|
||||
|
||||
if (!exists(BUILD_DIR))
|
||||
if (!test('-d', BUILD_DIR))
|
||||
mkdir(BUILD_DIR);
|
||||
|
||||
cd('src');
|
||||
@ -142,10 +143,10 @@ target.pagesrepo = function() {
|
||||
echo();
|
||||
echo('### Creating fresh clone of gh-pages');
|
||||
|
||||
if (!exists(BUILD_DIR))
|
||||
if (!test('-d', BUILD_DIR))
|
||||
mkdir(BUILD_DIR);
|
||||
|
||||
if (!exists(GH_PAGES_DIR)) {
|
||||
if (!test('-d', GH_PAGES_DIR)) {
|
||||
echo();
|
||||
echo('Cloning project repo...');
|
||||
echo('(This operation can take a while, depending on network conditions)');
|
||||
@ -277,10 +278,10 @@ target.firefox = function() {
|
||||
// We don't need pdf.js anymore since its inlined
|
||||
rm('-Rf', FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR);
|
||||
// Remove '.DS_Store' and other hidden files
|
||||
for (file in find(FIREFOX_BUILD_DIR)) {
|
||||
find(FIREFOX_BUILD_DIR).forEach(function(file) {
|
||||
if (file.match(/^\./))
|
||||
rm('-f', file);
|
||||
}
|
||||
});
|
||||
|
||||
// Update the build version number
|
||||
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/install.rdf');
|
||||
@ -304,10 +305,10 @@ target.firefox = function() {
|
||||
// List all files for mozilla-central
|
||||
cd(FIREFOX_BUILD_DIR);
|
||||
var extensionFiles = '';
|
||||
for (file in find(FIREFOX_MC_EXTENSION_FILES)) {
|
||||
find(FIREFOX_MC_EXTENSION_FILES).forEach(function(file){
|
||||
if (test('-f', file))
|
||||
extensionFiles += file+'\n';
|
||||
}
|
||||
});
|
||||
extensionFiles.to('extension-files');
|
||||
};
|
||||
|
||||
@ -360,10 +361,19 @@ target.test = function() {
|
||||
target.unittest();
|
||||
};
|
||||
|
||||
//
|
||||
// make bottest
|
||||
// (Special tests for the Github bot)
|
||||
//
|
||||
target.bottest = function() {
|
||||
target.browsertest({noreftest: true});
|
||||
// target.unittest();
|
||||
};
|
||||
|
||||
//
|
||||
// make browsertest
|
||||
//
|
||||
target.browsertest = function() {
|
||||
target.browsertest = function(options) {
|
||||
cd(ROOT_DIR);
|
||||
echo();
|
||||
echo('### Running browser tests');
|
||||
@ -371,14 +381,16 @@ target.browsertest = function() {
|
||||
var PDF_TEST = env['PDF_TEST'] || 'test_manifest.json',
|
||||
PDF_BROWSERS = env['PDF_BROWSERS'] || 'resources/browser_manifests/browser_manifest.json';
|
||||
|
||||
if (!exists('test/' + PDF_BROWSERS)) {
|
||||
if (!test('-f', 'test/' + PDF_BROWSERS)) {
|
||||
echo('Browser manifest file test/' + PDF_BROWSERS + ' does not exist.');
|
||||
echo('Try copying one of the examples in test/resources/browser_manifests/');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
var reftest = (options && options.noreftest) ? '' : '--reftest';
|
||||
|
||||
cd('test');
|
||||
exec(PYTHON_BIN + ' test.py --reftest --browserManifestFile=' + PDF_BROWSERS +
|
||||
exec(PYTHON_BIN + ' -u test.py '+reftest+' --browserManifestFile=' + PDF_BROWSERS +
|
||||
' --manifestFile=' + PDF_TEST, {async: true});
|
||||
};
|
||||
|
||||
@ -390,10 +402,37 @@ target.unittest = function() {
|
||||
echo();
|
||||
echo('### Running unit tests');
|
||||
|
||||
if (!which('make')) {
|
||||
echo('make not found. Skipping unit tests...');
|
||||
return;
|
||||
}
|
||||
|
||||
cd('test/unit');
|
||||
exec('make', {async: true});
|
||||
};
|
||||
|
||||
//
|
||||
// make botmakeref
|
||||
//
|
||||
target.botmakeref = function() {
|
||||
cd(ROOT_DIR);
|
||||
echo();
|
||||
echo('### Creating reference images');
|
||||
|
||||
var PDF_TEST = env['PDF_TEST'] || 'test_manifest.json',
|
||||
PDF_BROWSERS = env['PDF_BROWSERS'] || 'resources/browser_manifests/browser_manifest.json';
|
||||
|
||||
if (!test('-f', 'test/' + PDF_BROWSERS)) {
|
||||
echo('Browser manifest file test/' + PDF_BROWSERS + ' does not exist.');
|
||||
echo('Try copying one of the examples in test/resources/browser_manifests/');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cd('test');
|
||||
exec(PYTHON_BIN + ' -u test.py --masterMode --noPrompts --browserManifestFile=' + PDF_BROWSERS,
|
||||
{async: true});
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
12
src/bidi.js
12
src/bidi.js
@ -132,9 +132,9 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||
|
||||
// get types, fill arrays
|
||||
|
||||
var chars = new Array(strLength);
|
||||
var types = new Array(strLength);
|
||||
var oldtypes = new Array(strLength);
|
||||
var chars = [];
|
||||
var types = [];
|
||||
var oldtypes = [];
|
||||
var numBidi = 0;
|
||||
|
||||
for (var i = 0; i < strLength; ++i) {
|
||||
@ -176,16 +176,12 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
var levels = new Array(strLength);
|
||||
var levels = [];
|
||||
|
||||
for (var i = 0; i < strLength; ++i) {
|
||||
levels[i] = startLevel;
|
||||
}
|
||||
|
||||
var diffChars = new Array(strLength);
|
||||
var diffLevels = new Array(strLength);
|
||||
var diffTypes = new Array(strLength);
|
||||
|
||||
/*
|
||||
X1-X10: skip most of this, since we are NOT doing the embeddings.
|
||||
*/
|
||||
|
@ -756,24 +756,26 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var charWidth = glyph.width * fontSize * 0.001 +
|
||||
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||
|
||||
var scaledX = x / fontSizeScale;
|
||||
switch (textRenderingMode) {
|
||||
default: // other unsupported rendering modes
|
||||
case TextRenderingMode.FILL:
|
||||
case TextRenderingMode.FILL_ADD_TO_PATH:
|
||||
ctx.fillText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.STROKE:
|
||||
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
||||
ctx.strokeText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.FILL_STROKE:
|
||||
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
||||
ctx.fillText(char, scaledX, 0);
|
||||
ctx.strokeText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.INVISIBLE:
|
||||
break;
|
||||
if (!glyph.disabled) {
|
||||
var scaledX = x / fontSizeScale;
|
||||
switch (textRenderingMode) {
|
||||
default: // other unsupported rendering modes
|
||||
case TextRenderingMode.FILL:
|
||||
case TextRenderingMode.FILL_ADD_TO_PATH:
|
||||
ctx.fillText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.STROKE:
|
||||
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
||||
ctx.strokeText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.FILL_STROKE:
|
||||
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
||||
ctx.fillText(char, scaledX, 0);
|
||||
ctx.strokeText(char, scaledX, 0);
|
||||
break;
|
||||
case TextRenderingMode.INVISIBLE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x += charWidth;
|
||||
|
@ -220,7 +220,7 @@ var AlternateCS = (function AlternateCSClosure() {
|
||||
var baseNumComps = base.numComps;
|
||||
var baseBuf = new Uint8Array(baseNumComps * length);
|
||||
var numComps = this.numComps;
|
||||
var scaled = new Array(numComps);
|
||||
var scaled = [];
|
||||
|
||||
for (var i = 0; i < length; i += numComps) {
|
||||
for (var z = 0; z < numComps; ++z)
|
||||
|
35
src/core.js
35
src/core.js
@ -587,14 +587,6 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
this.mainXRefEntriesOffset);
|
||||
this.xref = xref;
|
||||
this.catalog = new Catalog(xref);
|
||||
if (xref.trailer && xref.trailer.has('ID')) {
|
||||
var fileID = '';
|
||||
var id = xref.fetchIfRef(xref.trailer.get('ID'))[0];
|
||||
id.split('').forEach(function(el) {
|
||||
fileID += Number(el.charCodeAt(0)).toString(16);
|
||||
});
|
||||
this.fileID = fileID;
|
||||
}
|
||||
},
|
||||
get numPages() {
|
||||
var linearization = this.linearization;
|
||||
@ -602,21 +594,33 @@ var PDFDocModel = (function PDFDocModelClosure() {
|
||||
// shadow the prototype getter
|
||||
return shadow(this, 'numPages', num);
|
||||
},
|
||||
getDocumentInfo: function pdfDocGetDocumentInfo() {
|
||||
var info;
|
||||
if (this.xref.trailer.has('Info'))
|
||||
info = this.xref.fetch(this.xref.trailer.get('Info'));
|
||||
|
||||
return shadow(this, 'getDocumentInfo', info);
|
||||
},
|
||||
getFingerprint: function pdfDocGetFingerprint() {
|
||||
if (this.fileID) {
|
||||
return this.fileID;
|
||||
var xref = this.xref, fileID;
|
||||
if (xref.trailer.has('ID')) {
|
||||
fileID = '';
|
||||
var id = xref.fetchIfRef(xref.trailer.get('ID'))[0];
|
||||
id.split('').forEach(function(el) {
|
||||
fileID += Number(el.charCodeAt(0)).toString(16);
|
||||
});
|
||||
} else {
|
||||
// If we got no fileID, then we generate one,
|
||||
// from the first 100 bytes of PDF
|
||||
var data = this.stream.bytes.subarray(0, 100);
|
||||
var hash = calculateMD5(data, 0, data.length);
|
||||
var strHash = '';
|
||||
fileID = '';
|
||||
for (var i = 0, length = hash.length; i < length; i++) {
|
||||
strHash += Number(hash[i]).toString(16);
|
||||
fileID += Number(hash[i]).toString(16);
|
||||
}
|
||||
|
||||
return strHash;
|
||||
}
|
||||
|
||||
return shadow(this, 'getFingerprint', fileID);
|
||||
},
|
||||
getPage: function pdfDocGetPage(n) {
|
||||
return this.catalog.getPage(n);
|
||||
@ -645,6 +649,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
this.stream = stream;
|
||||
this.pdfModel = new PDFDocModel(stream);
|
||||
this.fingerprint = this.pdfModel.getFingerprint();
|
||||
this.info = this.pdfModel.getDocumentInfo();
|
||||
this.catalog = this.pdfModel.catalog;
|
||||
this.objs = new PDFObjects();
|
||||
|
||||
@ -785,7 +790,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
error('Only 3 component or 1 component can be returned');
|
||||
|
||||
var img = new Image();
|
||||
img.onload = (function jpegImageLoaderOnload() {
|
||||
img.onload = (function messageHandler_onloadClosure() {
|
||||
var width = img.width;
|
||||
var height = img.height;
|
||||
var size = width * height;
|
||||
|
@ -805,6 +805,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
var firstChar = xref.fetchIfRef(dict.get('FirstChar')) || 0;
|
||||
var lastChar = xref.fetchIfRef(dict.get('LastChar')) || maxCharIndex;
|
||||
var fontName = xref.fetchIfRef(descriptor.get('FontName'));
|
||||
// Some bad pdf's have a string as the font name.
|
||||
if (isString(fontName))
|
||||
fontName = new Name(fontName);
|
||||
assertWellFormed(isName(fontName), 'invalid font name');
|
||||
|
||||
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
|
||||
|
1600
src/fonts.js
1600
src/fonts.js
File diff suppressed because it is too large
Load Diff
@ -81,7 +81,7 @@ var PDFFunction = (function PDFFunctionClosure() {
|
||||
function toMultiArray(arr) {
|
||||
var inputLength = arr.length;
|
||||
var outputLength = arr.length / 2;
|
||||
var out = new Array(outputLength);
|
||||
var out = [];
|
||||
var index = 0;
|
||||
for (var i = 0; i < inputLength; i += 2) {
|
||||
out[index] = [arr[i], arr[i + 1]];
|
||||
@ -364,7 +364,7 @@ var PDFFunction = (function PDFFunctionClosure() {
|
||||
return cache.get(key);
|
||||
|
||||
var stack = evaluator.execute(initialStack);
|
||||
var transformed = new Array(numOutputs);
|
||||
var transformed = [];
|
||||
for (i = numOutputs - 1; i >= 0; --i) {
|
||||
var out = stack.pop();
|
||||
var rangeIndex = 2 * i;
|
||||
|
@ -365,7 +365,7 @@ var PDFImage = (function PDFImageClosure() {
|
||||
|
||||
function loadJpegStream(id, imageData, objs) {
|
||||
var img = new Image();
|
||||
img.onload = (function jpegImageLoaderOnload() {
|
||||
img.onload = (function loadJpegStream_onloadClosure() {
|
||||
objs.resolve(id, img);
|
||||
});
|
||||
img.src = 'data:image/jpeg;base64,' + window.btoa(imageData);
|
||||
|
@ -159,7 +159,7 @@ var JpxImage = (function JpxImageClosure() {
|
||||
})();
|
||||
|
||||
// Implements C.3. Arithmetic decoding procedures
|
||||
var ArithmeticDecoder = (function arithmeticDecoderClosure() {
|
||||
var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
|
||||
var QeTable = [
|
||||
{qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
|
||||
{qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
|
||||
|
66
src/metadata.js
Normal file
66
src/metadata.js
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
var Metadata = PDFJS.Metadata = (function MetadataClosure() {
|
||||
function Metadata(meta) {
|
||||
if (typeof meta === 'string') {
|
||||
var parser = new DOMParser();
|
||||
meta = parser.parseFromString(meta, 'application/xml');
|
||||
} else if (!(meta instanceof Document)) {
|
||||
error('Metadata: Invalid metadata object');
|
||||
}
|
||||
|
||||
this.metaDocument = meta;
|
||||
this.metadata = {};
|
||||
this.parse();
|
||||
}
|
||||
|
||||
Metadata.prototype = {
|
||||
parse: function() {
|
||||
var doc = this.metaDocument;
|
||||
var rdf = doc.documentElement;
|
||||
|
||||
if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in <xmpmeta>
|
||||
rdf = rdf.firstChild;
|
||||
while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
|
||||
rdf = rdf.nextSibling;
|
||||
}
|
||||
|
||||
var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
|
||||
if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
|
||||
return;
|
||||
|
||||
var childNodes = rdf.childNodes, desc, namespace, entries, entry;
|
||||
|
||||
for (var i = 0, length = childNodes.length; i < length; i++) {
|
||||
desc = childNodes[i];
|
||||
if (desc.nodeName.toLowerCase() !== 'rdf:description')
|
||||
continue;
|
||||
|
||||
entries = [];
|
||||
for (var ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
|
||||
if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text')
|
||||
entries.push(desc.childNodes[ii]);
|
||||
}
|
||||
|
||||
for (ii = 0, iLength = entries.length; ii < iLength; ii++) {
|
||||
var entry = entries[ii];
|
||||
var name = entry.nodeName.toLowerCase();
|
||||
this.metadata[name] = entry.textContent.trim();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
get: function(name) {
|
||||
return this.metadata[name] || null;
|
||||
},
|
||||
|
||||
has: function(name) {
|
||||
return typeof this.metadata[name] !== 'undefined';
|
||||
}
|
||||
};
|
||||
|
||||
return Metadata;
|
||||
})();
|
16
src/obj.js
16
src/obj.js
@ -111,6 +111,22 @@ var Catalog = (function CatalogClosure() {
|
||||
}
|
||||
|
||||
Catalog.prototype = {
|
||||
get metadata() {
|
||||
var ref = this.catDict.get('Metadata');
|
||||
var stream = this.xref.fetchIfRef(ref);
|
||||
var metadata;
|
||||
if (stream && isDict(stream.dict)) {
|
||||
var type = stream.dict.get('Type');
|
||||
var subtype = stream.dict.get('Subtype');
|
||||
|
||||
if (isName(type) && isName(subtype) &&
|
||||
type.name === 'Metadata' && subtype.name === 'XML') {
|
||||
metadata = stringToPDFString(bytesToString(stream.getBytes()));
|
||||
}
|
||||
}
|
||||
|
||||
return shadow(this, 'metadata', metadata);
|
||||
},
|
||||
get toplevelPagesDict() {
|
||||
var pagesObj = this.catDict.get('Pages');
|
||||
assertWellFormed(isRef(pagesObj), 'invalid top-level pages reference');
|
||||
|
@ -2056,7 +2056,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
|
||||
if (this.eoblock) {
|
||||
code = this.lookBits(7);
|
||||
p = twoDimTable[code];
|
||||
if (p[0] > 0) {
|
||||
if (p && p[0] > 0) {
|
||||
this.eatBits(p[0]);
|
||||
return p[1];
|
||||
}
|
||||
|
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -25,6 +25,8 @@
|
||||
!issue1249.pdf
|
||||
!smaskdim.pdf
|
||||
!type4psfunc.pdf
|
||||
!issue1350.pdf
|
||||
!S2.pdf
|
||||
!zerowidthline.pdf
|
||||
!issue1002.pdf
|
||||
!issue925.pdf
|
||||
|
BIN
test/pdfs/issue1002.pdf
Normal file
BIN
test/pdfs/issue1002.pdf
Normal file
Binary file not shown.
1
test/pdfs/issue1309.pdf.link
Normal file
1
test/pdfs/issue1309.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
http://www.lufthansa.com/mediapool/pdf/31/media_907231.pdf
|
1
test/pdfs/issue1317.pdf.link
Normal file
1
test/pdfs/issue1317.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
http://iliad.fr/presse/2012/CP_080312_Free_mobile.pdf
|
2184
test/pdfs/issue1350.pdf
Normal file
2184
test/pdfs/issue1350.pdf
Normal file
File diff suppressed because one or more lines are too long
1
test/pdfs/preistabelle.pdf.link
Normal file
1
test/pdfs/preistabelle.pdf.link
Normal file
@ -0,0 +1 @@
|
||||
http://www.fyve.de/downloads/Preistabelle_FYVE_Oktober_2010.pdf
|
@ -1 +1 @@
|
||||
http://www.mit.edu/~6.033/writing-samples/usmanm_dp1.pdf
|
||||
http://web.mit.edu/6.033/2011/wwwdocs/writing-samples/usmanm_dp1.pdf
|
||||
|
@ -1 +1 @@
|
||||
http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf
|
||||
http://web.archive.org/web/20110623114753/http://www.cdc.gov/ncidod/dvbid/westnile/languages/chinese.pdf
|
||||
|
@ -480,6 +480,20 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "preistabelle",
|
||||
"file": "pdfs/preistabelle.pdf",
|
||||
"md5": "d2f0b2086160d4f3d325c79a5dc1fb4d",
|
||||
"rounds": 1,
|
||||
"pageLimit": 2,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1350",
|
||||
"file": "pdfs/issue1350.pdf",
|
||||
"md5": "92f72a04a4d9d05b2dd433b51f32ab1f",
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue925",
|
||||
"file": "pdfs/issue925.pdf",
|
||||
"md5": "f58fe943090aff89dcc8e771bc0db4c2",
|
||||
@ -508,6 +522,13 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1002",
|
||||
"file": "pdfs/issue1002.pdf",
|
||||
"md5": "af62d6cd95079322d4af18edd960d15c",
|
||||
"rounds": 1,
|
||||
"link": false,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1243",
|
||||
"file": "pdfs/issue1243.pdf",
|
||||
"md5": "130c849b83513d5ac5e03c6421fc7489",
|
||||
@ -523,5 +544,19 @@
|
||||
"pageLimit": 2,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1309",
|
||||
"file": "pdfs/issue1309.pdf",
|
||||
"md5": "e835fb7f3dab3073ad37d0bd3c6399fa",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1317",
|
||||
"file": "pdfs/issue1317.pdf",
|
||||
"md5": "6fb46275b30c48c8985617d4f86199e3",
|
||||
"rounds": 1,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
}
|
||||
]
|
||||
|
223
test/unit/font_spec.js
Normal file
223
test/unit/font_spec.js
Normal file
@ -0,0 +1,223 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('font', function() {
|
||||
function hexDump(bytes) {
|
||||
var line = '';
|
||||
for (var i = 0, ii = bytes.length; i < ii; ++i) {
|
||||
var b = bytes[i].toString(16);
|
||||
if (b.length < 2)
|
||||
b = '0' + b;
|
||||
line += b.toString(16);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
// This example font comes from the CFF spec:
|
||||
// http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
|
||||
var exampleFont = '0100040100010101134142434445462b' +
|
||||
'54696d65732d526f6d616e000101011f' +
|
||||
'f81b00f81c02f81d03f819041c6f000d' +
|
||||
'fb3cfb6efa7cfa1605e911b8f1120003' +
|
||||
'01010813183030312e30303754696d65' +
|
||||
'7320526f6d616e54696d657300000002' +
|
||||
'010102030e0e7d99f92a99fb7695f773' +
|
||||
'8b06f79a93fc7c8c077d99f85695f75e' +
|
||||
'9908fb6e8cf87393f7108b09a70adf0b' +
|
||||
'f78e14';
|
||||
var fontData = [];
|
||||
for (var i = 0; i < exampleFont.length; i += 2) {
|
||||
var hex = exampleFont.substr(i, 2);
|
||||
fontData.push(parseInt(hex, 16));
|
||||
}
|
||||
var bytes = new Uint8Array(fontData);
|
||||
fontData = {getBytes: function() { return bytes}};
|
||||
|
||||
function bytesToString(bytesArray) {
|
||||
var str = '';
|
||||
for (var i = 0, ii = bytesArray.length; i < ii; i++)
|
||||
str += String.fromCharCode(bytesArray[i]);
|
||||
return str;
|
||||
}
|
||||
|
||||
describe('CFFParser', function() {
|
||||
var parser = new CFFParser(fontData);
|
||||
var cff = parser.parse();
|
||||
|
||||
it('parses header', function() {
|
||||
var header = cff.header;
|
||||
expect(header.major).toEqual(1);
|
||||
expect(header.minor).toEqual(0);
|
||||
expect(header.hdrSize).toEqual(4);
|
||||
expect(header.offSize).toEqual(1);
|
||||
});
|
||||
|
||||
it('parses name index', function() {
|
||||
var names = cff.names;
|
||||
expect(names.length).toEqual(1);
|
||||
expect(names[0]).toEqual('ABCDEF+Times-Roman');
|
||||
});
|
||||
|
||||
it('sanitizes name index', function() {
|
||||
var index = new CFFIndex();
|
||||
index.add(['['.charCodeAt(0), 'a'.charCodeAt(0)]);
|
||||
|
||||
var names = parser.parseNameIndex(index);
|
||||
expect(names).toEqual(['_a']);
|
||||
|
||||
index = new CFFIndex();
|
||||
var longName = [];
|
||||
for (var i = 0; i < 129; i++)
|
||||
longName.push(0);
|
||||
index.add(longName);
|
||||
names = parser.parseNameIndex(index);
|
||||
expect(names[0].length).toEqual(127);
|
||||
});
|
||||
|
||||
it('parses string index', function() {
|
||||
var strings = cff.strings;
|
||||
expect(strings.count).toEqual(3);
|
||||
expect(strings.get(0)).toEqual('.notdef');
|
||||
expect(strings.get(391)).toEqual('001.007');
|
||||
});
|
||||
|
||||
it('parses top dict', function() {
|
||||
var topDict = cff.topDict;
|
||||
// 391 version 392 FullName 393 FamilyName 389 Weight 28416 UniqueID
|
||||
// -168 -218 1000 898 FontBBox 94 CharStrings 45 102 Private
|
||||
expect(topDict.getByName('version')).toEqual(391);
|
||||
expect(topDict.getByName('FullName')).toEqual(392);
|
||||
expect(topDict.getByName('FamilyName')).toEqual(393);
|
||||
expect(topDict.getByName('Weight')).toEqual(389);
|
||||
expect(topDict.getByName('UniqueID')).toEqual(28416);
|
||||
expect(topDict.getByName('FontBBox')).toEqual([-168, -218, 1000, 898]);
|
||||
expect(topDict.getByName('CharStrings')).toEqual(94);
|
||||
expect(topDict.getByName('Private')).toEqual([45, 102]);
|
||||
});
|
||||
|
||||
it('parses predefined charsets', function() {
|
||||
var charset = parser.parseCharsets(0, 0, null, true);
|
||||
expect(charset.predefined).toEqual(true);
|
||||
});
|
||||
|
||||
it('parses charset format 0', function() {
|
||||
// The first three bytes make the offset large enough to skip predefined.
|
||||
var bytes = new Uint8Array([0x00, 0x00, 0x00,
|
||||
0x00, // format
|
||||
0x00, 0x02 // sid/cid
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
|
||||
expect(charset.charset[1]).toEqual('exclam');
|
||||
|
||||
// CID font
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
|
||||
expect(charset.charset[1]).toEqual(2);
|
||||
});
|
||||
|
||||
it('parses charset format 1', function() {
|
||||
// The first three bytes make the offset large enough to skip predefined.
|
||||
var bytes = new Uint8Array([0x00, 0x00, 0x00,
|
||||
0x01, // format
|
||||
0x00, 0x08, // sid/cid start
|
||||
0x01 // sid/cid left
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
|
||||
expect(charset.charset).toEqual(['.notdef', 'quoteright', 'parenleft']);
|
||||
|
||||
// CID font
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
|
||||
expect(charset.charset).toEqual(['.notdef', 8, 9]);
|
||||
});
|
||||
|
||||
it('parses charset format 2', function() {
|
||||
// format 2 is the same as format 1 but the left is card16
|
||||
// The first three bytes make the offset large enough to skip predefined.
|
||||
var bytes = new Uint8Array([0x00, 0x00, 0x00,
|
||||
0x02, // format
|
||||
0x00, 0x08, // sid/cid start
|
||||
0x00, 0x01 // sid/cid left
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
|
||||
expect(charset.charset).toEqual(['.notdef', 'quoteright', 'parenleft']);
|
||||
|
||||
// CID font
|
||||
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
|
||||
expect(charset.charset).toEqual(['.notdef', 8, 9]);
|
||||
});
|
||||
|
||||
it('parses encoding format 0', function() {
|
||||
// The first two bytes make the offset large enough to skip predefined.
|
||||
var bytes = new Uint8Array([0x00, 0x00,
|
||||
0x00, // format
|
||||
0x01, // count
|
||||
0x08 // start
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
|
||||
expect(encoding.encoding).toEqual({0x8: 1});
|
||||
});
|
||||
|
||||
it('parses encoding format 1', function() {
|
||||
// The first two bytes make the offset large enough to skip predefined.
|
||||
var bytes = new Uint8Array([0x00, 0x00,
|
||||
0x01, // format
|
||||
0x01, // num ranges
|
||||
0x07, // range1 start
|
||||
0x01 // range2 left
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
|
||||
expect(encoding.encoding).toEqual({0x7: 0x01, 0x08: 0x02});
|
||||
});
|
||||
|
||||
it('parses fdselect format 0', function() {
|
||||
var bytes = new Uint8Array([0x00, // format
|
||||
0x00, // gid: 0 fd: 0
|
||||
0x01 // gid: 1 fd: 1
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var fdSelect = parser.parseFDSelect(0, 2);
|
||||
expect(fdSelect.fdSelect).toEqual([0, 1]);
|
||||
});
|
||||
|
||||
it('parses fdselect format 3', function() {
|
||||
var bytes = new Uint8Array([0x03, // format
|
||||
0x00, 0x02, // range count
|
||||
0x00, 0x00, // first gid
|
||||
0x09, // font dict 1 id
|
||||
0x00, 0x02, // nex gid
|
||||
0x0a, // font dict 2 gid
|
||||
0x00, 0x04 // sentinel (last gid)
|
||||
]);
|
||||
parser.bytes = bytes;
|
||||
var fdSelect = parser.parseFDSelect(0, 2);
|
||||
expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]);
|
||||
});
|
||||
// TODO fdArray
|
||||
});
|
||||
describe('CFFCompiler', function() {
|
||||
it('encodes integers', function() {
|
||||
var c = new CFFCompiler();
|
||||
// all the examples from the spec
|
||||
expect(c.encodeInteger(0)).toEqual([0x8b]);
|
||||
expect(c.encodeInteger(100)).toEqual([0xef]);
|
||||
expect(c.encodeInteger(-100)).toEqual([0x27]);
|
||||
expect(c.encodeInteger(1000)).toEqual([0xfa, 0x7c]);
|
||||
expect(c.encodeInteger(-1000)).toEqual([0xfe, 0x7c]);
|
||||
expect(c.encodeInteger(10000)).toEqual([0x1c, 0x27, 0x10]);
|
||||
expect(c.encodeInteger(-10000)).toEqual([0x1c, 0xd8, 0xf0]);
|
||||
expect(c.encodeInteger(100000)).toEqual([0x1d, 0x00, 0x01, 0x86, 0xa0]);
|
||||
expect(c.encodeInteger(-100000)).toEqual([0x1d, 0xff, 0xfe, 0x79, 0x60]);
|
||||
});
|
||||
it('encodes floats', function() {
|
||||
var c = new CFFCompiler();
|
||||
expect(c.encodeFloat(-2.25)).toEqual([0x1e, 0xe2, 0xa2, 0x5f]);
|
||||
expect(c.encodeFloat(5e-11)).toEqual([0x1e, 0x5c, 0x11, 0xff]);
|
||||
});
|
||||
// TODO a lot more compiler tests
|
||||
});
|
||||
});
|
@ -25,6 +25,7 @@ load:
|
||||
- ../../src/bidi.js
|
||||
- ../../external/jpgjs/jpg.js
|
||||
- ../unit/obj_spec.js
|
||||
- ../unit/font_spec.js
|
||||
- ../unit/function_spec.js
|
||||
- ../unit/crypto_spec.js
|
||||
- ../unit/stream_spec.js
|
||||
|
@ -391,11 +391,43 @@ canvas {
|
||||
}
|
||||
}
|
||||
|
||||
#loading {
|
||||
#loadingBox {
|
||||
margin: 100px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#loadingBar {
|
||||
background-color: #333;
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
clear: both;
|
||||
margin:0px;
|
||||
line-height: 0;
|
||||
border-radius: 4px;
|
||||
width: 15em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
#loadingBar .progress {
|
||||
background-color: green;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
|
||||
background: #b4e391;
|
||||
background: -moz-linear-gradient(top, #b4e391 0%, #61c419 50%, #b4e391 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b4e391), color-stop(50%,#61c419), color-stop(100%,#b4e391));
|
||||
background: -webkit-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
|
||||
background: -o-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
|
||||
background: -ms-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
|
||||
background: linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%);
|
||||
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#PDFBug {
|
||||
font-size: 10px;
|
||||
position: fixed;
|
||||
|
@ -11,6 +11,7 @@
|
||||
<!-- PDFJSSCRIPT_INCLUDE_BUILD -->
|
||||
<script type="text/javascript" src="../src/core.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/util.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/metadata.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/canvas.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/obj.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
<script type="text/javascript" src="../src/function.js"></script> <!-- PDFJSSCRIPT_REMOVE_CORE -->
|
||||
@ -142,7 +143,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loading">Loading... 0%</div>
|
||||
<div id="loadingBox">
|
||||
<div id="loading">Loading... 0%</div>
|
||||
<div id="loadingBar"><div class="progress"></div></div>
|
||||
</div>
|
||||
<div id="viewer"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -36,6 +36,48 @@ var Cache = function cacheCache(size) {
|
||||
};
|
||||
};
|
||||
|
||||
var ProgressBar = (function ProgressBarClosure() {
|
||||
|
||||
function clamp(v, min, max) {
|
||||
return Math.min(Math.max(v, min), max);
|
||||
}
|
||||
|
||||
function ProgressBar(id, opts) {
|
||||
|
||||
// Fetch the sub-elements for later
|
||||
this.div = document.querySelector(id + ' .progress');
|
||||
|
||||
// Get options, with sensible defaults
|
||||
this.height = opts.height || 100;
|
||||
this.width = opts.width || 100;
|
||||
this.units = opts.units || '%';
|
||||
this.percent = opts.percent || 0;
|
||||
|
||||
// Initialize heights
|
||||
this.div.style.height = this.height + this.units;
|
||||
}
|
||||
|
||||
ProgressBar.prototype = {
|
||||
|
||||
updateBar: function ProgressBar_updateBar() {
|
||||
var progressSize = this.width * this._percent / 100;
|
||||
|
||||
this.div.style.width = progressSize + this.units;
|
||||
},
|
||||
|
||||
get percent() {
|
||||
return this._percent;
|
||||
},
|
||||
|
||||
set percent(val) {
|
||||
this._percent = clamp(val, 0, 100);
|
||||
this.updateBar();
|
||||
}
|
||||
};
|
||||
|
||||
return ProgressBar;
|
||||
})();
|
||||
|
||||
var RenderingQueue = (function RenderingQueueClosure() {
|
||||
function RenderingQueue() {
|
||||
this.items = [];
|
||||
@ -271,6 +313,10 @@ var PDFView = {
|
||||
|
||||
document.title = getFileName(url) || url;
|
||||
|
||||
if (!PDFView.loadingBar) {
|
||||
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
PDFJS.getPdf(
|
||||
{
|
||||
@ -411,6 +457,8 @@ var PDFView = {
|
||||
var percent = Math.round(level * 100);
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.textContent = 'Loading... ' + percent + '%';
|
||||
|
||||
PDFView.loadingBar.percent = percent;
|
||||
},
|
||||
|
||||
load: function pdfViewLoad(data, scale) {
|
||||
@ -425,8 +473,8 @@ var PDFView = {
|
||||
var errorWrapper = document.getElementById('errorWrapper');
|
||||
errorWrapper.setAttribute('hidden', 'true');
|
||||
|
||||
var loadingIndicator = document.getElementById('loading');
|
||||
loadingIndicator.setAttribute('hidden', 'true');
|
||||
var loadingBox = document.getElementById('loadingBox');
|
||||
loadingBox.setAttribute('hidden', 'true');
|
||||
|
||||
var sidebar = document.getElementById('sidebarView');
|
||||
sidebar.parentNode.scrollTop = 0;
|
||||
@ -510,6 +558,24 @@ var PDFView = {
|
||||
// Setting the default one.
|
||||
this.parseScale(kDefaultScale, true);
|
||||
}
|
||||
|
||||
this.metadata = null;
|
||||
var metadata = pdf.catalog.metadata;
|
||||
var info = this.documentInfo = pdf.info;
|
||||
var pdfTitle;
|
||||
|
||||
if (metadata) {
|
||||
this.metadata = metadata = new PDFJS.Metadata(metadata);
|
||||
|
||||
if (metadata.has('dc:title'))
|
||||
pdfTitle = metadata.get('dc:title');
|
||||
}
|
||||
|
||||
if (!pdfTitle && info && info.has('Title'))
|
||||
pdfTitle = info.get('Title');
|
||||
|
||||
if (pdfTitle)
|
||||
document.title = pdfTitle;
|
||||
},
|
||||
|
||||
setHash: function pdfViewSetHash(hash) {
|
||||
@ -1206,10 +1272,6 @@ window.addEventListener('load', function webViewerLoad(evt) {
|
||||
sidebarScrollView.addEventListener('scroll', updateThumbViewArea, true);
|
||||
}, true);
|
||||
|
||||
window.addEventListener('unload', function webViewerUnload(evt) {
|
||||
window.scrollTo(0, 0);
|
||||
}, true);
|
||||
|
||||
/**
|
||||
* Render the next not yet visible page already such that it is
|
||||
* hopefully ready once the user scrolls to it.
|
||||
|
Loading…
Reference in New Issue
Block a user