Compare commits

..

No commits in common. "master" and "v1.4.20" have entirely different histories.

504 changed files with 30715 additions and 46929 deletions

136
.eslintrc
View file

@ -1,136 +0,0 @@
{
"parserOptions": {
"ecmaVersion": 5,
},
"env": {
"browser": true,
"es6": true,
"worker": true,
"amd": true,
},
globals: {
"PDFJSDev": false,
"exports": false,
"SystemJS": false,
},
"rules": {
// Possible errors
"no-cond-assign": ["error", "except-parens"],
"no-constant-condition": ["error", { "checkLoops": false, }],
"no-dupe-args": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": ["error", { "allowEmptyCatch": true, }],
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-extra-semi": "error",
"no-func-assign": "error",
"no-inner-declarations": ["error", "functions"],
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-obj-calls": "error",
"no-regex-spaces": "error",
"no-sparse-arrays": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"use-isnan": "error",
"valid-typeof": ["error", { "requireStringLiterals": true, }],
// Best Practices
"accessor-pairs": ["error", { "setWithoutGet": true, }],
"curly": ["error", "all"],
"eqeqeq": ["error", "always"],
"no-caller": "error",
"no-else-return": "error",
"no-empty-pattern": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-fallthrough": "error",
"no-floating-decimal": "error",
"no-global-assign": "error",
"no-implied-eval": "error",
"no-iterator": "error",
"no-lone-blocks": "error",
"no-multi-spaces": "error",
"no-multi-str": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
"no-new": "error",
"no-octal-escape": "error",
"no-octal": "error",
"no-redeclare": "error",
"no-self-assign": "error",
"no-self-compare": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"no-useless-call": "error",
"no-useless-concat": "error",
"wrap-iife": ["error", "any"],
"yoda": ["error", "never", { "onlyEquality": true, }],
// Strict Mode
"strict": ["error", "global"],
// Variables
"no-catch-shadow": "error",
"no-delete-var": "error",
"no-label-var": "error",
"no-shadow-restricted-names": "error",
"no-undef-init": "error",
"no-undef": ["error", { "typeof": true, }],
"no-unused-vars": ["error", {
"vars": "local",
"args": "none",
}],
// Stylistic Issues
"array-bracket-spacing": ["error", "never"],
"block-spacing": ["error", "always"],
"brace-style": ["error", "1tbs", {
"allowSingleLine": false,
}],
"comma-spacing": ["error", { "before": false, "after": true, }],
"comma-style": ["error", "last"],
"eol-last": "error",
"func-call-spacing": ["error", "never"],
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "strict", }],
"keyword-spacing": ["error", { "before": true, "after": true, }],
"linebreak-style": ["error", "unix"],
"max-len": ["error", 80],
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
"new-parens": "error",
"no-array-constructor": "error",
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 0, "maxBOF": 1, }],
"no-new-object": "error",
"no-tabs": "error",
"no-trailing-spaces": ["error", { "skipBlankLines": false, }],
"no-whitespace-before-property": "error",
"operator-linebreak": ["error", "after", { "overrides": { ":": "ignore", } }],
"quotes": ["error", "single"],
"semi-spacing": ["error", { "before": false, "after": true, }],
"semi": ["error", "always"],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", { "anonymous": "ignore", "named": "never", }],
"space-in-parens": ["error", "never"],
"space-infix-ops": ["error", { "int32Hint": false }],
"space-unary-ops": ["error", { "words": true, "nonwords": false, }],
"spaced-comment": ["error", "always", {
"line": {
"exceptions": ["//", "#else", "#endif"],
"markers": ["#if", "#elif", "#include", "#expand", "#error"],
},
"block": {
"balanced": true,
}
}],
// ECMAScript 6
},
}

View file

@ -1,17 +0,0 @@
Link to PDF file (or attach file here):
Configuration:
- Web browser and its version:
- Operating system and its version:
- PDF.js version:
- Is an extension:
Steps to reproduce the problem:
1.
2.
What is the expected behavior? (add screenshot)
What went wrong? (add screenshot)
Link to a viewer (if hosted on a site other than mozilla.github.io/pdf.js or as Firefox/Chrome extension):

View file

@ -3,14 +3,15 @@ l10n/
docs/
node_modules/
examples/
external/bcmaps/
external/webL10n/
external/shelljs/
external/jpgjs/
external/jasmine/
external/cmapscompress/
external/builder/fixtures/
external/builder/fixtures_esprima/
external/importL10n/
shared/
test/tmp/
test/features/
test/pdfs/
test/resources/
test/font/*_spec.js
*~/

32
.jshintrc Normal file
View file

@ -0,0 +1,32 @@
{
// Environments
"browser": true,
"devel": true,
"worker": true,
"predef": [
"Promise",
"require",
"define",
"exports"
],
// Enforcing
"maxlen": 80,
"quotmark": "single",
"trailing": true,
"curly": true,
"undef": true,
"noarg": true,
"nonbsp": true,
"eqeqeq": true,
// Relaxing
"boss": true,
"funcscope": true,
"globalstrict": true,
"loopfunc": true,
"maxerr": 1000,
"nonstandard": true,
"sub": true,
"validthis": true
}

View file

@ -1,11 +1,3 @@
language: node_js
node_js:
- node
cache:
directories:
- node_modules
install:
- npm install -g npm@latest
- npm install -g gulp-cli
- npm install
- npm update
- "0.12"

View file

@ -4,7 +4,7 @@ The issues are used to track both bugs filed by users and specific work items fo
If the issue is related to errors produced by a specific PDF, please always include the PDF by providing a URL where contributors can download it. Without a PDF for reproduction, such issues will be closed. We understand that many PDFs contain sensitive information, however having a PDF is essential to resolving the issue and building our regression testing suite. If possible, try creating a reduced example exhibiting the problem but not containing sensitive data. Also small PDFs are best suited for our regression testing. If an important issue only shows on sensitive PDFs, contributors might be willing to accept these PDFs via a secure exchange.
The issue tracking system is designed to record a single technical problem. A bug report is something where a developer/contributor can work on. The GitHub issue tracker is not a good place for general, not well thought out or unworkable ideas. Most likely a discussion-type issue will not be addressed for a long time or closed as invalid. The best place for general discussions is our #pdfjs IRC channel on irc.mozilla.org.
The issue tracking system is designed to record a single technical problem. A bug report is something where a developer/contributor can work on. The GitHub issue tracker is not a good place for general, not well thought out or unworkable ideas. Most likely a discussion-type issue will not be addressed for a long time or closed as invalid. The best place is our dev-pdf-js@lists.mozilla.org mailing list. You can subscribe to it using http://lists.mozilla.org or Google Groups. This way you will reach not only developers. As an alternative, you can join our weekly engineering meeting to discuss new ideas for the project.
If you are developing a custom solution, first check the examples at https://github.com/mozilla/pdf.js#learning and search existing issues. If this does not help, please prepare a short well-documented example that demonstrates the problem and make it accessible online on your website, JS Bin, GitHub, etc. before opening a new issue or contacting us on the IRC channel -- keep in mind that just code snippets won't help us troubleshoot the problem.

View file

@ -9,39 +9,38 @@ rendering PDFs.
## Contributing
PDF.js is an open source project and always looking for more contributors. To
get involved, visit:
get involved checkout:
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md)
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/CONTRIBUTING.md)
+ [Code Contribution Guide](https://github.com/mozilla/pdf.js/wiki/Contributing)
+ [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=5-good-beginner-bug&page=1&sort=created&state=open)
+ [Projects](https://github.com/mozilla/pdf.js/projects)
+ [Priorities](https://github.com/mozilla/pdf.js/milestones)
+ [Attend a Public Meeting](https://github.com/mozilla/pdf.js/wiki/Weekly-Public-Meetings)
Feel free to stop by #pdfjs on irc.mozilla.org for questions or guidance.
For further questions or guidance feel free to stop by #pdfjs on
irc.mozilla.org.
## Getting Started
### Online demo
+ https://mozilla.github.io/pdf.js/web/viewer.html
+ http://mozilla.github.io/pdf.js/web/viewer.html
### Browser Extensions
#### Firefox (and Seamonkey)
#### Firefox and Seamonkey
PDF.js is built into version 19+ of Firefox, however one extension is still available:
PDF.js is built into version 19+ of Firefox, however the extension is still available:
+ [Development Version](http://mozilla.github.io/pdf.js/extensions/firefox/pdf.js.xpi) - This extension is mainly intended for developers/testers, and it is updated every time new code is merged into the PDF.js codebase. It should be quite stable, but might break from time to time.
+ [Development Version](http://mozilla.github.io/pdf.js/extensions/firefox/pdf.js.xpi) - This version is updated every time new code is merged into the PDF.js codebase. This should be quite stable but still might break from time to time. This version is also reported to work when installed as extension in Seamonkey 2.39.
+ Please note that the extension is *not* guaranteed to be compatible with Firefox versions that are *older* than the current ESR version, see the [Release Calendar](https://wiki.mozilla.org/RapidRelease/Calendar#Past_branch_dates).
+ The extension should also work in Seamonkey, provided that it is based on a Firefox version as above (see [Which version of Firefox does SeaMonkey 2.x correspond with?](https://wiki.mozilla.org/SeaMonkey/FAQ#General)), but we do *not* guarantee compatibility.
#### Chrome
#### Chrome and Opera
+ The official extension for Chrome can be installed from the [Chrome Web Store](https://chrome.google.com/webstore/detail/pdf-viewer/oemmndcbldboiebfnladdacbdfmadadm).
*This extension is maintained by [@Rob--W](https://github.com/Rob--W).*
+ Build Your Own - Get the code as explained below and issue `gulp chromium`. Then open
+ Opera has also published an extension for their browser at the [Opera add-ons catalog](https://addons.opera.com/en/extensions/details/pdf-viewer/).
+ Build Your Own - Get the code as explained below and issue `node make chromium`. Then open
Chrome, go to `Tools > Extension` and load the (unpackaged) extension from the
directory `build/chromium`.
@ -53,19 +52,16 @@ To get a local copy of the current code, clone it using git:
$ cd pdf.js
Next, install Node.js via the [official package](http://nodejs.org) or via
[nvm](https://github.com/creationix/nvm). You need to install the gulp package
globally (see also [gulp's getting started](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md#getting-started)):
$ npm install -g gulp-cli
If everything worked out, install all dependencies for PDF.js:
[nvm](https://github.com/creationix/nvm). If everything worked out, run
$ npm install
to install all dependencies for PDF.js.
Finally you need to start a local web server as some browsers do not allow opening
PDF files using a file:// URL. Run
$ gulp server
$ node make server
and then you can open
@ -77,10 +73,10 @@ It is also possible to view all test PDF files on the right side by opening
## Building PDF.js
In order to bundle all `src/` files into two production scripts and build the generic
viewer, run:
In order to bundle all `src/` files into two productions scripts and build the generic
viewer, issue:
$ gulp generic
$ node make generic
This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory.
Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will
@ -88,21 +84,15 @@ be loaded by `pdf.js`. If you want to support more browsers than Firefox you'll
to include `compatibility.js` from `build/generic/web/`. The PDF.js files are large and
should be minified for production.
## Using PDF.js in a web application
To use PDF.js in a web application you can choose to use a pre-built version of the library
or to build it from source. We supply pre-built versions for usage with NPM and Bower under
the `pdfjs-dist` name. For more information and examples please refer to the
[wiki page](https://github.com/mozilla/pdf.js/wiki/Setup-pdf.js-in-a-website) on this subject.
## Learning
You can play with the PDF.js API directly from your browser using the live
You can play with the PDF.js API directly from your browser through the live
demos below:
+ [Interactive examples](http://mozilla.github.io/pdf.js/examples/index.html#interactive-examples)
+ [Hello world](http://mozilla.github.io/pdf.js/examples/learning/helloworld.html)
+ [Simple reader with prev/next page controls](http://mozilla.github.io/pdf.js/examples/learning/prevnext.html)
The repository contains a hello world example that you can run locally:
The repo contains a hello world example that you can run locally:
+ [examples/helloworld/](https://github.com/mozilla/pdf.js/blob/master/examples/helloworld/)
@ -111,7 +101,12 @@ contributor Julian Viereck:
+ http://www.youtube.com/watch?v=Iv15UY-4Fg8
More learning resources can be found at:
You can read more about PDF.js here:
+ http://andreasgal.com/2011/06/15/pdf-js/
+ http://blog.mozilla.com/cjones/2011/06/15/overview-of-pdf-js-guts/
Even more learning resources can be found at:
+ https://github.com/mozilla/pdf.js/wiki/Additional-Learning-Resources
@ -125,10 +120,19 @@ Talk to us on IRC:
+ #pdfjs on irc.mozilla.org
File an issue:
Join our mailing list:
+ https://github.com/mozilla/pdf.js/issues/new
+ dev-pdf-js@lists.mozilla.org
Subscribe either using lists.mozilla.org or Google Groups:
+ https://lists.mozilla.org/listinfo/dev-pdf-js
+ https://groups.google.com/group/mozilla.dev.pdf-js/topics
Follow us on twitter: @pdfjs
+ http://twitter.com/#!/pdfjs
Weekly Public Meetings
+ https://github.com/mozilla/pdf.js/wiki/Weekly-Public-Meetings

View file

@ -61,25 +61,3 @@ var viewport = page.getViewport(1);
var scale = desiredWidth / viewport.width;
var scaledViewport = page.getViewport(scale);
```
## Interactive examples
### Hello World with document load error handling
The example demonstrates how promises can be used to handle errors during loading.
It also demonstrates how to wait until page loaded and rendered.
<script async src="//jsfiddle.net/pdfjs/9engc9mw/embed/js,html,result/"></script>
### Hello World using base64 encoded PDF
The PDF.js can accept any decoded base64 data as an array.
<script async src="//jsfiddle.net/pdfjs/cq0asLqz/embed/js,html,result/"></script>
### Previous/Next example
The same canvas cannot be used to perform to draw two pages at the same time --
the example demonstrate how to wait on previous operation to be complete.
<script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/js,html,result/"></script>

View file

@ -107,7 +107,7 @@ $ cd pdf.js
## Trying the Viewer
With the prebuilt or source version open `web/viewer.html` in a browser and the test pdf should load. Note: the worker is not enabled for file:// urls, so use a server. If you're using the source build and have node, you can run `gulp server`.
With the prebuilt or source version open `web/viewer.html` in a browser and the test pdf should load. Note: the worker is not enabled for file:// urls, so use a server. If you're using the source build and have node, you can run `node make server`.
## More Information

View file

@ -10,5 +10,5 @@ template: layout.jade
<p class="text-center">
<a type="button" class="btn btn-lg btn-default" href="getting_started/#download">Download</a>
<a type="button" class="btn btn-lg btn-default" href="web/viewer.html">Demo</a>
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js">GitHub Project</a>
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js">Github Project</a>
</p>

View file

@ -1,11 +0,0 @@
## Overview
Example to demonstrate PDF.js library usage for rendering files with AcroForms.
## Getting started
Build PDF.js using `gulp dist` and run `gulp server` to start a web server.
You can then work with the example at
http://localhost:8888/examples/acroforms/acroforms.html.
Refer to `acroforms.js` for the source code of the example.

View file

@ -1,44 +0,0 @@
<!DOCTYPE html>
<!--
Copyright 2017 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 dir="ltr">
<head>
<meta charset="utf-8">
<title>AcroForms example</title>
<link rel="stylesheet" href="../../build/dist/web/pdf_viewer.css">
<script src="../../build/dist/build/pdf.js"></script>
<script src="../../build/dist/web/pdf_viewer.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
.page {
position: relative;
}
</style>
</head>
<body>
<div id="pageContainer"></div>
<script src="acroforms.js"></script>
</body>
</html>

View file

@ -1,49 +0,0 @@
/* Copyright 2017 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.
*/
'use strict';
PDFJS.workerSrc = '../../build/dist/build/pdf.worker.js';
var DEFAULT_URL = '../../test/pdfs/f1040.pdf';
var DEFAULT_SCALE = 1.0;
var container = document.getElementById('pageContainer');
// Fetch the PDF document from the URL using promises.
PDFJS.getDocument(DEFAULT_URL).then(function (doc) {
// Use a promise to fetch and render the next page.
var promise = Promise.resolve();
for (var i = 1; i <= doc.numPages; i++) {
promise = promise.then(function (pageNum) {
return doc.getPage(pageNum).then(function (pdfPage) {
// Create the page view.
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: pageNum,
scale: DEFAULT_SCALE,
defaultViewport: pdfPage.getViewport(DEFAULT_SCALE),
annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory(),
renderInteractiveForms: true,
});
// Associate the actual page with the view and draw it.
pdfPageView.setPdfPage(pdfPage);
return pdfPageView.draw();
});
}.bind(null, i));
}
});

160
examples/acroforms/forms.js Normal file
View file

@ -0,0 +1,160 @@
//
// Basic AcroForms input controls rendering
//
'use strict';
// Specify the PDF with AcroForm here
var pdfWithFormsPath = '../../test/pdfs/f1040.pdf';
var formFields = {};
function setupForm(div, content, viewport) {
function bindInputItem(input, item) {
if (input.name in formFields) {
var value = formFields[input.name];
if (input.type == 'checkbox') {
input.checked = value;
} else if (!input.type || input.type == 'text') {
input.value = value;
}
}
input.onchange = function pageViewSetupInputOnBlur() {
if (input.type == 'checkbox') {
formFields[input.name] = input.checked;
} else if (!input.type || input.type == 'text') {
formFields[input.name] = input.value;
}
};
}
function createElementWithStyle(tagName, item) {
var element = document.createElement(tagName);
var rect = PDFJS.Util.normalizeRect(
viewport.convertToViewportRectangle(item.rect));
element.style.left = Math.floor(rect[0]) + 'px';
element.style.top = Math.floor(rect[1]) + 'px';
element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
return element;
}
function assignFontStyle(element, item) {
var fontStyles = '';
if ('fontSize' in item) {
fontStyles += 'font-size: ' + Math.round(item.fontSize *
viewport.fontScale) + 'px;';
}
switch (item.textAlignment) {
case 0:
fontStyles += 'text-align: left;';
break;
case 1:
fontStyles += 'text-align: center;';
break;
case 2:
fontStyles += 'text-align: right;';
break;
}
element.setAttribute('style', element.getAttribute('style') + fontStyles);
}
content.getAnnotations().then(function(items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
switch (item.subtype) {
case 'Widget':
if (item.fieldType != 'Tx' && item.fieldType != 'Btn' &&
item.fieldType != 'Ch') {
break;
}
var inputDiv = createElementWithStyle('div', item);
inputDiv.className = 'inputHint';
div.appendChild(inputDiv);
var input;
if (item.fieldType == 'Tx') {
input = createElementWithStyle('input', item);
}
if (item.fieldType == 'Btn') {
input = createElementWithStyle('input', item);
if (item.flags & 32768) {
input.type = 'radio';
// radio button is not supported
} else if (item.flags & 65536) {
input.type = 'button';
// pushbutton is not supported
} else {
input.type = 'checkbox';
}
}
if (item.fieldType == 'Ch') {
input = createElementWithStyle('select', item);
// select box is not supported
}
input.className = 'inputControl';
input.name = item.fullName;
input.title = item.alternativeText;
assignFontStyle(input, item);
bindInputItem(input, item);
div.appendChild(input);
break;
}
}
});
}
function renderPage(div, pdf, pageNumber, callback) {
pdf.getPage(pageNumber).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var pageDisplayWidth = viewport.width;
var pageDisplayHeight = viewport.height;
var pageDivHolder = document.createElement('div');
pageDivHolder.className = 'pdfpage';
pageDivHolder.style.width = pageDisplayWidth + 'px';
pageDivHolder.style.height = pageDisplayHeight + 'px';
div.appendChild(pageDivHolder);
// Prepare canvas using PDF page dimensions
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = pageDisplayWidth;
canvas.height = pageDisplayHeight;
pageDivHolder.appendChild(canvas);
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).promise.then(callback);
// Prepare and populate form elements layer
var formDiv = document.createElement('div');
pageDivHolder.appendChild(formDiv);
setupForm(formDiv, page, viewport);
});
}
// In production, the bundled pdf.js shall be used instead of RequireJS.
require.config({paths: {'pdfjs': '../../src'}});
require(['pdfjs/display/api'], function (api) {
// In production, change this to point to the built `pdf.worker.js` file.
PDFJS.workerSrc = '../../src/worker_loader.js';
// Fetch the PDF document from the URL using promises.
api.getDocument(pdfWithFormsPath).then(function getPdfForm(pdf) {
// Rendering all pages starting from first
var viewer = document.getElementById('viewer');
var pageNumber = 1;
renderPage(viewer, pdf, pageNumber++, function pageRenderingComplete() {
if (pageNumber > pdf.numPages) {
return; // All pages rendered
}
// Continue rendering of the next page
renderPage(viewer, pdf, pageNumber++, pageRenderingComplete);
});
});
});

View file

@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<script src="../../node_modules/requirejs/require.js"></script>
<style>
.pdfpage { position:relative; top: 0; left: 0; border: solid 1px black; margin: 10px; }
.pdfpage > canvas { position: absolute; top: 0; left: 0; }
.pdfpage > div { position: absolute; top: 0; left: 0; }
.inputControl { background: transparent; border: 0px none; position: absolute; margin: auto; }
.inputControl[type='checkbox'] { margin: 0px; }
.inputHint { opacity: 0.2; background: #ccc; position: absolute; }
</style>
<script src="forms.js"></script>
</head>
<body>
<div id="viewer"></div>
</body>
</html>

View file

@ -1 +0,0 @@
node_modules/

View file

@ -1,26 +0,0 @@
## Overview
Example to demonstrate PDF.js library usage with Browserify.
## Getting started
Build project and install the example dependencies:
$ gulp dist
$ cd examples/browserify
$ npm install
To build Browserify bundles, run `gulp build`. If you are running
a web server, you can observe the build results at
http://localhost:8888/examples/browserify/index.html
See main.js, worker.js and gulpfile.js files. Please notice that PDF.js
packaging requires packaging of the main application and PDF.js worker code,
and the `workerSrc` path shall be set to the latter file. The pdf.worker.js file
shall be excluded from the main bundle.
Alternatives to the gulp commands (without compression) are:
$ mkdir -p ../../build/browserify
$ node_modules/.bin/browserify main.js -u ./node_modules/pdfjs-dist/build/pdf.worker.js -o ../../build/browserify/main.bundle.js
$ node_modules/.bin/browserify worker.js -o ../../build/browserify/pdf.worker.bundle.js

View file

@ -1,34 +0,0 @@
var gulp = require('gulp');
var browserify = require('browserify');
var streamify = require('gulp-streamify');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var OUTPUT_PATH = '../../build/browserify';
var TMP_FILE_PREFIX = '../../build/browserify_';
gulp.task('build-bundle', function() {
return browserify('main.js', {output: TMP_FILE_PREFIX + 'main.tmp'})
.ignore(require.resolve('pdfjs-dist/build/pdf.worker')) // Reducing size
.bundle()
.pipe(source(TMP_FILE_PREFIX + 'main.tmp'))
.pipe(streamify(uglify()))
.pipe(rename('main.bundle.js'))
.pipe(gulp.dest(OUTPUT_PATH));
});
gulp.task('build-worker', function() {
// We can create our own viewer (see worker.js) or use already defined one.
var workerSrc = require.resolve('pdfjs-dist/build/pdf.worker.entry');
return browserify(workerSrc, {output: TMP_FILE_PREFIX + 'worker.tmp'})
.bundle()
.pipe(source(TMP_FILE_PREFIX + 'worker.tmp'))
.pipe(streamify(uglify({compress:{
sequences: false // Chrome has issue with the generated code if true
}})))
.pipe(rename('pdf.worker.bundle.js'))
.pipe(gulp.dest(OUTPUT_PATH));
});
gulp.task('build', ['build-bundle', 'build-worker']);

View file

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>browserify example</title>
<script src="../../build/browserify/main.bundle.js"></script>
</head>
<body>
<canvas id="theCanvas"></canvas>
</body>
</html>

View file

@ -1,35 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for browserify.
require('pdfjs-dist');
var pdfPath = '../helloworld/helloworld.pdf';
// Setting worker path to worker bundle.
PDFJS.workerSrc = '../../build/browserify/pdf.worker.bundle.js';
// It is also possible to disable workers via `PDFJS.disableWorker = true`,
// however that might degrade the UI performance in web browsers.
// Loading a document.
var loadingTask = PDFJS.getDocument(pdfPath);
loadingTask.promise.then(function (pdfDocument) {
// Request a first page
return pdfDocument.getPage(1).then(function (pdfPage) {
// Display page on the existing canvas with 100% scale.
var viewport = pdfPage.getViewport(1.0);
var canvas = document.getElementById('theCanvas');
canvas.width = viewport.width;
canvas.height = viewport.height;
var ctx = canvas.getContext('2d');
var renderTask = pdfPage.render({
canvasContext: ctx,
viewport: viewport
});
return renderTask.promise;
});
}).catch(function (reason) {
console.error('Error: ' + reason);
});

View file

@ -1,16 +0,0 @@
{
"name": "browserify-pdf.js-example",
"version": "0.1.0",
"devDependencies": {
"browserify": "^13.0.0",
"gulp": "^3.9.1",
"gulp-rename": "^1.2.2",
"gulp-streamify": "^1.0.2",
"gulp-uglify": "^1.5.3",
"pdfjs-dist": "../../build/dist",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"build": "gulp build"
}
}

View file

@ -1,7 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/licenses/publicdomain/
// Hello world example for browserify: worker bundle.
(typeof window !== 'undefined' ? window : {}).pdfjsDistBuildPdfWorker =
require('pdfjs-dist/build/pdf.worker');

View file

@ -29,14 +29,16 @@ limitations under the License.
}
</style>
<link rel="stylesheet" href="../../build/dist/web/pdf_viewer.css">
<link rel="stylesheet" href="../../build/components/pdf_viewer.css">
<script src="../../build/dist/build/pdf.js"></script>
<script src="../../build/dist/web/pdf_viewer.js"></script>
<!-- for legacy browsers -->
<script src="../../build/components/compatibility.js"></script>
<script src="../../build/pdf.js"></script>
<script src="../../build/components/pdf_viewer.js"></script>
</head>
<body tabindex="1">
<div id="pageContainer" class="pdfViewer singlePageView"></div>
<div id="pageContainer" class="pdfPage"></div>
<script src="pageviewer.js"></script>
</body>

View file

@ -16,17 +16,17 @@
'use strict';
if (!PDFJS.PDFViewer || !PDFJS.getDocument) {
alert('Please build the pdfjs-dist library using\n' +
' `gulp dist`');
alert('Please build the library and components using\n' +
' `node make generic components`');
}
// The workerSrc property shall be specified.
//
PDFJS.workerSrc = '../../build/dist/build/pdf.worker.js';
PDFJS.workerSrc = '../../build/pdf.worker.js';
// Some PDFs need external cmaps.
//
// PDFJS.cMapUrl = '../../build/dist/cmaps/';
// PDFJS.cMapUrl = '../../external/bcmaps/';
// PDFJS.cMapPacked = true;
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';

View file

@ -35,10 +35,12 @@ limitations under the License.
}
</style>
<link rel="stylesheet" href="../../build/dist/web/pdf_viewer.css">
<link rel="stylesheet" href="../../build/components/pdf_viewer.css">
<script src="../../build/dist/build/pdf.js"></script>
<script src="../../build/dist/web/pdf_viewer.js"></script>
<!-- for legacy browsers -->
<script src="../../build/components/compatibility.js"></script>
<script src="../../build/pdf.js"></script>
<script src="../../build/components/pdf_viewer.js"></script>
</head>
<body tabindex="1">

View file

@ -16,21 +16,20 @@
'use strict';
if (!PDFJS.PDFViewer || !PDFJS.getDocument) {
alert('Please build the pdfjs-dist library using\n' +
' `gulp dist`');
alert('Please build the library and components using\n' +
' `node make generic components`');
}
// The workerSrc property shall be specified.
//
PDFJS.workerSrc = '../../build/dist/build/pdf.worker.js';
PDFJS.workerSrc = '../../build/pdf.worker.js';
// Some PDFs need external cmaps.
//
// PDFJS.cMapUrl = '../../build/dist/cmaps/';
// PDFJS.cMapUrl = '../../external/bcmaps/';
// PDFJS.cMapPacked = true;
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
var SEARCH_FOR = ''; // try 'Mozilla';
var container = document.getElementById('viewerContainer');
@ -43,19 +42,9 @@ var pdfViewer = new PDFJS.PDFViewer({
});
pdfLinkService.setViewer(pdfViewer);
// (Optionally) enable find controller.
var pdfFindController = new PDFJS.PDFFindController({
pdfViewer: pdfViewer
});
pdfViewer.setFindController(pdfFindController);
container.addEventListener('pagesinit', function () {
// We can use pdfViewer now, e.g. let's change default scale.
pdfViewer.currentScaleValue = 'page-width';
if (SEARCH_FOR) { // We can try search for things
pdfFindController.executeCommand('find', {query: SEARCH_FOR});
}
});
// Loading document.

View file

@ -8,7 +8,7 @@ simple and human-readable PDF.
Instead of simply opening `index.html` in a browser, you must serve the page
using a web server. This can be done on your local machine without an internet
connection. In the root directory of PDF.js, run `gulp server` in a
connection. In the root directory of PDF.js, run `node make server` in a
terminal. The example can then be viewed using the following URL:
`http://localhost:8888/examples/helloworld/index.html`

View file

@ -1,12 +1,10 @@
'use strict';
// In production, the bundled pdf.js shall be used instead of SystemJS.
Promise.all([SystemJS.import('pdfjs/display/api'),
SystemJS.import('pdfjs/display/global')])
.then(function (modules) {
var api = modules[0], global = modules[1];
// In production, the bundled pdf.js shall be used instead of RequireJS.
require.config({paths: {'pdfjs': '../../src'}});
require(['pdfjs/display/api'], function (api) {
// In production, change this to point to the built `pdf.worker.js` file.
global.PDFJS.workerSrc = '../../src/worker_loader.js';
PDFJS.workerSrc = '../../src/worker_loader.js';
// Fetch the PDF document from the URL using promises.
api.getDocument('helloworld.pdf').then(function (pdf) {

View file

@ -2,8 +2,7 @@
<html>
<head>
<script src="../../node_modules/systemjs/dist/system.js"></script>
<script src="../../systemjs.config.js"></script>
<script src="../../node_modules/requirejs/require.js"></script>
<script src="hello.js"></script>
</head>

View file

@ -13,7 +13,7 @@
<!-- for legacy browsers add compatibility.js -->
<!--<script src="../compatibility.js"></script>-->
<script src="../../build/generic/build/pdf.js"></script>
<script src="../../build/pdf.js"></script>
<script id="script">
//
@ -32,7 +32,7 @@
//
// The workerSrc property shall be specified.
//
PDFJS.workerSrc = '../../build/generic/build/pdf.worker.js';
PDFJS.workerSrc = '../../build/pdf.worker.js';
//
// Asynchronous download PDF

View file

@ -10,7 +10,10 @@
<canvas id="the-canvas" style="border:1px solid black"></canvas>
<script src="../../build/generic/build/pdf.js"></script>
<!-- for legacy browsers we need to use compatibility.js -->
<script src="../../web/compatibility.js"></script>
<script src="../../build/pdf.js"></script>
<script id="script">
// atob() is used to convert base64 encoded PDF to binary-like data.
@ -40,7 +43,7 @@
//
// The workerSrc property shall be specified.
//
PDFJS.workerSrc = '../../build/generic/build/pdf.worker.js';
PDFJS.workerSrc = '../../build/pdf.worker.js';
// Opening PDF by passing its binary data as a string. It is still preferable
// to use Uint8Array, but string or array-like structure will work too.

View file

@ -22,7 +22,7 @@
<!-- for legacy browsers add compatibility.js -->
<!--<script src="../compatibility.js"></script>-->
<script src="../../build/generic/build/pdf.js"></script>
<script src="../../build/pdf.js"></script>
<script id="script">
//
@ -44,7 +44,7 @@
// pdf.js's one, or the pdf.js is executed via eval(), the workerSrc property
// shall be specified.
//
// PDFJS.workerSrc = '../../build/generic/build/pdf.worker.js';
// PDFJS.workerSrc = '../../build/pdf.worker.js';
var pdfDoc = null,
pageNum = 1,

View file

@ -1,11 +0,0 @@
## Overview
Example to demonstrate PDF.js library usage with a viewer optimized for mobile usage.
## Getting started
Build PDF.js using `gulp dist` and run `gulp server` to start a web server.
You can then work with the mobile viewer at
http://localhost:8888/examples/mobile-viewer/viewer.html.
Refer to `viewer.js` for the source code of the mobile viewer.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -1,76 +0,0 @@
<!DOCTYPE html>
<!--
Copyright 2016 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 dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>PDF.js viewer</title>
<link rel="stylesheet" href="../../build/dist/web/pdf_viewer.css">
<link rel="stylesheet" type="text/css" href="viewer.css">
<script src="../../build/dist/build/pdf.js"></script>
<script src="../../build/dist/web/pdf_viewer.js"></script>
<script src="viewer.js"></script>
</head>
<body>
<header>
<h1 id="title"></h1>
</header>
<div id="viewerContainer">
<div id="viewer" class="pdfViewer"></div>
</div>
<div id="loadingBar">
<div class="progress"></div>
<div class="glimmer"></div>
</div>
<div id="errorWrapper" hidden="true">
<div id="errorMessageLeft">
<span id="errorMessage"></span>
<button id="errorShowMore">
More Information
</button>
<button id="errorShowLess">
Less Information
</button>
</div>
<div id="errorMessageRight">
<button id="errorClose">
Close
</button>
</div>
<div class="clearBoth"></div>
<textarea id="errorMoreInfo" hidden="true" readonly="readonly"></textarea>
</div>
<footer>
<button class="toolbarButton pageUp" title="Previous Page" id="previous"></button>
<button class="toolbarButton pageDown" title="Next Page" id="next"></button>
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1">
<button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut"></button>
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
</footer>
</body>
</html>

View file

@ -120,6 +120,10 @@ DOMElement.prototype = {
},
}
global.window = global;
global.navigator = { userAgent: 'node' };
global.document = {
childNodes : [],

View file

@ -4,7 +4,7 @@
//
// Basic node example that prints document metadata and text content.
// Requires single file built version of PDF.js -- please run
// `gulp singlefile` before running the example.
// `node make singlefile` before running the example.
//
var fs = require('fs');
@ -12,8 +12,8 @@ var fs = require('fs');
// HACK adding DOMParser to read XMP metadata.
global.DOMParser = require('./domparsermock.js').DOMParserMock;
// Run `gulp dist` to generate 'pdfjs-dist' npm package files.
var pdfjsLib = require('../../build/dist');
// Run `node make dist` to generate 'pdfjs-dist' npm package files.
require('../../build/dist');
// Loading file from file system into typed array
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
@ -21,7 +21,7 @@ var data = new Uint8Array(fs.readFileSync(pdfPath));
// Will be using promises to load document, pages and misc data instead of
// callback.
pdfjsLib.getDocument(data).then(function (doc) {
PDFJS.getDocument(data).then(function (doc) {
var numPages = doc.numPages;
console.log('# Document Loaded');
console.log('Number of Pages: ' + numPages);

View file

@ -10,8 +10,8 @@ var fs = require('fs');
// HACK few hacks to let PDF.js be loaded not as a module in global space.
require('./domstubs.js');
// Run `gulp dist` to generate 'pdfjs-dist' npm package files.
var pdfjsLib = require('../../build/dist');
// Run `node make dist` to generate 'pdfjs-dist' npm package files.
require('../../build/dist');
// Loading file from file system into typed array
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
@ -44,7 +44,7 @@ function getFileNameFromPath(path) {
// Will be using promises to load document, pages and misc data instead of
// callback.
pdfjsLib.getDocument(data).then(function (doc) {
PDFJS.getDocument(data).then(function (doc) {
var numPages = doc.numPages;
console.log('# Document Loaded');
console.log('Number of Pages: ' + numPages);
@ -59,7 +59,7 @@ pdfjsLib.getDocument(data).then(function (doc) {
console.log();
return page.getOperatorList().then(function (opList) {
var svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
var svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs);
svgGfx.embedFonts = true;
return svgGfx.getSVG(opList, viewport).then(function (svg) {
var svgDump = svg.toString();

View file

@ -2,25 +2,21 @@
<html>
<head>
<meta charset="utf-8">
<title>PDF.js SVG viewer example</title>
<script src="../../node_modules/systemjs/dist/system.js"></script>
<script src="../../systemjs.config.js"></script>
<script src="../../node_modules/requirejs/require.js"></script>
<script src="viewer.js"></script>
<style>
body {
background-color: #404040;
background-color: gray;
}
.pageContainer {
border: 1px solid #000;
margin: 5px auto;
background-color: #FFF;
border : 1px solid black;
margin : 5px auto;
background-color : white;
}
</style>
</style>
<title>SVG Viewer Example</title>
</head>
<body>

View file

@ -1,55 +1,58 @@
'use strict';
var DEFAULT_SCALE = 1.5;
// Parse query string to extract some parameters (it can fail for some input)
var query = document.location.href.replace(/^[^?]*(\?([^#]*))?(#.*)?/, '$2');
var queryParams = query ? JSON.parse('{' + query.split('&').map(function (a) {
return a.split('=').map(decodeURIComponent).map(JSON.stringify).join(': ');
}).join(',') + '}') : {};
var url = queryParams.file || '../../web/compressed.tracemonkey-pldi-09.pdf';
var url = queryParams.file || '../../test/pdfs/liveprogramming.pdf';
var scale = +queryParams.scale || 1.5;
function renderDocument(pdf) {
var numPages = pdf.numPages;
// Using promise to fetch the page
// For testing only.
var MAX_NUM_PAGES = 50;
var ii = Math.min(MAX_NUM_PAGES, numPages);
function renderDocument(pdf, svgLib) {
var promise = Promise.resolve();
for (var i = 1; i <= pdf.numPages; i++) {
for (var i = 1; i <= ii; i++) {
var anchor = document.createElement('a');
anchor.setAttribute('name', 'page=' + i);
anchor.setAttribute('title', 'Page ' + i);
document.body.appendChild(anchor);
// Using promise to fetch and render the next page
promise = promise.then(function (pageNum) {
promise = promise.then(function (pageNum, anchor) {
return pdf.getPage(pageNum).then(function (page) {
var viewport = page.getViewport(DEFAULT_SCALE);
var viewport = page.getViewport(scale);
var container = document.createElement('div');
container.id = 'pageContainer' + pageNum;
container.className = 'pageContainer';
container.style.width = viewport.width + 'px';
container.style.height = viewport.height + 'px';
document.body.appendChild(container);
anchor.appendChild(container);
return page.getOperatorList().then(function (opList) {
var svgGfx = new svgLib.SVGGraphics(page.commonObjs, page.objs);
var svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs);
return svgGfx.getSVG(opList, viewport).then(function (svg) {
container.appendChild(svg);
});
});
});
}.bind(null, i));
}.bind(null, i, anchor));
}
}
Promise.all([SystemJS.import('pdfjs/display/api'),
SystemJS.import('pdfjs/display/svg'),
SystemJS.import('pdfjs/display/global')])
.then(function (modules) {
var api = modules[0], svg = modules[1], global = modules[2];
// In production, the bundled pdf.js shall be used instead of RequireJS.
require.config({paths: {'pdfjs': '../../src'}});
require(['pdfjs/display/api', 'pdfjs/display/svg'], function (api, svg) {
// In production, change this to point to the built `pdf.worker.js` file.
global.PDFJS.workerSrc = '../../src/worker_loader.js';
// In production, change this to point to where the cMaps are placed.
global.PDFJS.cMapUrl = '../../external/bcmaps/';
global.PDFJS.cMapPacked = true;
PDFJS.workerSrc = '../../src/worker_loader.js';
// Fetch the PDF document from the URL using promises.
api.getDocument(url).then(function (doc) {
renderDocument(doc, svg);
});
api.getDocument(url).then(renderDocument);
});

View file

@ -1,7 +1,6 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Text-only PDF.js example</title>
<script src="../../build/generic/build/pdf.js"></script>
<script src="pdf2svg.js"></script>

View file

@ -18,7 +18,7 @@ var PAGE_NUMBER = 1;
var PAGE_SCALE = 1.5;
var SVG_NS = 'http://www.w3.org/2000/svg';
PDFJS.workerSrc = '../../build/generic/build/pdf.worker.js';
PDFJS.workerSrc = '../../build/pdf.worker.js';
function buildSVG(viewport, textContent) {
// Building SVG with size of the viewport (for simplicity)
@ -30,7 +30,7 @@ function buildSVG(viewport, textContent) {
// processing all items
textContent.items.forEach(function (textItem) {
// we have to take in account viewport transform, which includes scale,
// we have to take in account viewport transform, which incudes scale,
// rotation and Y-axis flip, and not forgetting to flip text.
var tx = PDFJS.Util.transform(
PDFJS.Util.transform(viewport.transform, textItem.transform),
@ -63,7 +63,7 @@ function pageLoaded() {
document.addEventListener('DOMContentLoaded', function () {
if (typeof PDFJS === 'undefined') {
alert('Built version of PDF.js was not found.\n' +
'Please run `gulp generic`.');
'Please run `node make generic`.');
return;
}
pageLoaded();

View file

@ -1,19 +1,18 @@
## Overview
Example to demonstrate PDF.js library usage with Webpack.
Example to demonstrate PDF.js library usage with webpack.
## Getting started
Build project and install the example dependencies:
$ gulp dist
$ cd examples/webpack
$ npm install
$ node make dist
$ cd examples/webpack
$ npm install
To build Webpack bundles, run `node_modules/.bin/webpack`. If you are running
To build webpack bundles, run `node_modules/.bin/webpack`. If you are running
a web server, you can observe the build results at
http://localhost:8888/examples/webpack/index.html
See main.js and webpack.config.js files. Please notice that PDF.js
packaging requires packaging of the main application and PDF.js worker code,
and the `workerSrc` path shall be set to the latter file.
See main.js and webpack.config.js files. Please notice that PDF.js packaging
requires 'entry' loader.

View file

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<title>webpack example</title>
<script src="../../build/webpack/main.bundle.js"></script>
<script src="../../build/webpack/bundle.js"></script>
</head>
<body>
<canvas id="theCanvas"></canvas>

View file

@ -3,18 +3,15 @@
// Hello world example for webpack.
var pdfjsLib = require('pdfjs-dist');
require('pdfjs-dist');
var pdfPath = '../helloworld/helloworld.pdf';
// Setting worker path to worker bundle.
pdfjsLib.PDFJS.workerSrc = '../../build/webpack/pdf.worker.bundle.js';
// It is also possible to disable workers via `PDFJS.disableWorker = true`,
// however that might degrade the UI performance in web browsers.
// Loading a document.
var loadingTask = pdfjsLib.getDocument(pdfPath);
var loadingTask = PDFJS.getDocument(pdfPath);
loadingTask.promise.then(function (pdfDocument) {
// Request a first page
return pdfDocument.getPage(1).then(function (pdfPage) {

View file

@ -3,6 +3,7 @@
"version": "0.1.0",
"devDependencies": {
"webpack": "~1.12.9",
"entry-loader": "~0.1.0",
"pdfjs-dist": "../../build/dist"
}
}

View file

@ -3,14 +3,11 @@ var path = require('path');
module.exports = {
context: __dirname,
entry: {
'main': './main.js',
'pdf.worker': 'pdfjs-dist/build/pdf.worker.entry'
},
entry: './main.js',
output: {
path: path.join(__dirname, '../../build/webpack'),
publicPath: '../../build/webpack/',
filename: '[name].bundle.js'
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.UglifyJsPlugin({

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

View file

Before

Width:  |  Height:  |  Size: 640 B

After

Width:  |  Height:  |  Size: 640 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

Before

Width:  |  Height:  |  Size: 564 B

After

Width:  |  Height:  |  Size: 564 B

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -1,4 +1,4 @@
/* Copyright 2016 Mozilla Foundation
/* 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.
@ -25,23 +25,6 @@ html {
font-size: 10px;
}
header {
background-color: #f4f4f4;
}
header h1 {
border-bottom: 1px solid #d8d8d8;
color: #858585;
font-size: 23px;
font-style: italic;
font-weight: normal;
overflow: hidden;
padding: 10px;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
body {
background: url(images/document_bg.png);
color: #fff;
@ -74,6 +57,7 @@ footer {
box-shadow: 0 -0.2rem 0.5rem rgba(50, 50, 50, 0.75);
}
.toolbarButton {
display: block;
padding: 0;

View file

@ -0,0 +1,88 @@
<!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 dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>PDF.js viewer</title>
<script src="../pdfjs-components/build/pdf.js"></script>
<script src="../pdfjs-components/web/pdf_viewer.js"></script>
<script src="/shared/js/l10n.js"></script>
<!-- Localization -->
<meta name="defaultLanguage" content="en-US">
<meta name="availableLanguages" content="ach,af,ak,an,ar,as,ast,az,be,bg,bn-BD,bn-IN,br,bs,ca,cs,csb,cy,da,de,el,en-GB,en-ZA,eo,es-AR,es-CL,es-ES,es-MX,et,eu,fa,ff,fi,fr,fy-NL,ga-IE,gd,gl,gu-IN,he,hi-IN,hr,hu,hy-AM,id,is,it,ja,ka,kk,km,kn,ko,ku,lg,lij,lt,lv,mai,mk,ml,mn,mr,ms,my,nb-NO,nl,nn-NO,nso,oc,or,pa-IN,pl,pt-BR,pt-PT,rm,ro,ru,rw,sah,si,sk,sl,son,sq,sr,sv-SE,sw,ta,ta-LK,te,th,tl,tn,tr,uk,ur,vi,wo,xh,zh-CN,zh-TW,zu">
<link rel="localization" href="locale/{locale}/viewer.properties">
<script src="viewer.js"></script>
<!-- Web Components -->
<link rel="stylesheet" type="text/css" href="/shared/elements/gaia-theme/gaia-theme.css">
<script src="/shared/elements/config.js" defer></script>
<script src="/shared/elements/gaia-header/dist/gaia-header.js" defer></script>
<link rel="stylesheet" type="text/css" href="../pdfjs-components/web/pdf_viewer.css">
<link rel="stylesheet" type="text/css" href="viewer.css">
</head>
<body>
<section role="region" id="activityHeader" class="skin-organic theme-settings">
<gaia-header id="header" action="close">
<h1 id="activityTitle"></h1>
</gaia-header>
<footer id="open-toolbar">
<button class="toolbarButton pageUp" title="Previous Page" id="previous" data-l10n-id="previous"></button>
<button class="toolbarButton pageDown" title="Next Page" id="next" data-l10n-id="next"></button>
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1">
<button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut" data-l10n-id="zoom_out"></button>
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn" data-l10n-id="zoom_in"></button>
</footer>
</section>
<div id="viewerContainer">
<div id="viewer" class="pdfViewer"></div>
</div>
<div id="loadingBar">
<div class="progress"></div>
<div class="glimmer"></div>
</div>
<div id="errorWrapper" hidden='true'>
<div id="errorMessageLeft">
<span id="errorMessage"></span>
<button id="errorShowMore" data-l10n-id="error_more_info">
More Information
</button>
<button id="errorShowLess" data-l10n-id="error_less_info" hidden='true'>
Less Information
</button>
</div>
<div id="errorMessageRight">
<button id="errorClose" data-l10n-id="error_close">
Close
</button>
</div>
<div class="clearBoth"></div>
<textarea id="errorMoreInfo" hidden='true' readonly="readonly"></textarea>
</div>
</body>
</html>

View file

@ -1,4 +1,4 @@
/* Copyright 2016 Mozilla Foundation
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -12,71 +12,49 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals PDFJS */
/* globals PDFJS, Promise */
'use strict';
if (!PDFJS.PDFViewer || !PDFJS.getDocument) {
alert('Please build the pdfjs-dist library using\n' +
' `gulp dist`');
}
PDFJS.useOnlyCssZoom = true;
PDFJS.disableTextLayer = true;
PDFJS.maxImageSize = 1024 * 1024;
PDFJS.workerSrc = '../../build/dist/build/pdf.worker.js';
PDFJS.cMapUrl = '../../build/dist/cmaps/';
PDFJS.workerSrc = '../pdfjs-components/build/pdf.worker.js';
PDFJS.cMapUrl = '../pdfjs-components/cmaps/';
PDFJS.cMapPacked = true;
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
var DEFAULT_SCALE_DELTA = 1.1;
var MIN_SCALE = 0.25;
var MAX_SCALE = 10.0;
var DEFAULT_SCALE_VALUE = 'auto';
var PDFViewerApplication = {
pdfLoadingTask: null,
pdfDocument: null,
pdfViewer: null,
pdfHistory: null,
pdfLinkService: null,
/**
* Opens PDF document specified by URL.
* @returns {Promise} - Returns the promise, which is resolved when document
* is opened.
*/
open: function (params) {
if (this.pdfLoadingTask) {
// We need to destroy already opened document
return this.close().then(function () {
// ... and repeat the open() call.
return this.open(params);
}.bind(this));
}
var url = params.url;
var url = params.url, originalUrl = params.originalUrl;
var self = this;
this.setTitleUsingUrl(url);
this.setTitleUsingUrl(originalUrl);
// Loading document.
var loadingTask = PDFJS.getDocument(url);
this.pdfLoadingTask = loadingTask;
loadingTask.onProgress = function (progressData) {
self.progress(progressData.loaded / progressData.total);
};
return loadingTask.promise.then(function (pdfDocument) {
loadingTask.then(function (pdfDocument) {
// Document loaded, specifying document for the viewer.
self.pdfDocument = pdfDocument;
self.pdfViewer.setDocument(pdfDocument);
self.pdfLinkService.setDocument(pdfDocument);
self.pdfHistory.initialize(pdfDocument.fingerprint);
this.pdfDocument = pdfDocument;
this.pdfViewer.setDocument(pdfDocument);
this.pdfLinkService.setDocument(pdfDocument);
this.pdfHistory.initialize(pdfDocument.fingerprint);
self.loadingBar.hide();
self.setTitleUsingMetadata(pdfDocument);
}, function (exception) {
this.loadingBar.hide();
this.setTitleUsingMetadata(pdfDocument);
}.bind(this), function (exception) {
var message = exception && exception.message;
var loadingErrorMessage = mozL10n.get('loading_error', null,
'An error occurred while loading the PDF.');
@ -102,32 +80,6 @@ var PDFViewerApplication = {
});
},
/**
* Closes opened PDF document.
* @returns {Promise} - Returns the promise, which is resolved when all
* destruction is completed.
*/
close: function () {
var errorWrapper = document.getElementById('errorWrapper');
errorWrapper.setAttribute('hidden', 'true');
if (!this.pdfLoadingTask) {
return Promise.resolve();
}
var promise = this.pdfLoadingTask.destroy();
this.pdfLoadingTask = null;
if (this.pdfDocument) {
this.pdfDocument = null;
this.pdfViewer.setDocument(null);
this.pdfLinkService.setDocument(null, null);
}
return promise;
},
get loadingBar() {
var bar = new PDFJS.ProgressBar('#loadingBar', {});
@ -136,7 +88,7 @@ var PDFViewerApplication = {
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
this.url = url;
var title = PDFJS.getFilenameFromUrl(url) || url;
var title = PDFJS.getFileName(url) || url;
try {
title = decodeURIComponent(title);
} catch (e) {
@ -182,7 +134,7 @@ var PDFViewerApplication = {
setTitle: function pdfViewSetTitle(title) {
document.title = title;
document.getElementById('title').textContent = title;
document.getElementById('activityTitle').textContent = title;
},
error: function pdfViewError(message, moreInfo) {
@ -321,11 +273,10 @@ var PDFViewerApplication = {
document.getElementById('pageNumber').addEventListener('change',
function() {
// Handle the user inputting a floating point number.
PDFViewerApplication.page = (this.value | 0);
// Ensure that the page number input displays the correct value, even if the
// value entered by the user was invalid (e.g. a floating point number).
if (this.value !== PDFViewerApplication.page.toString()) {
if (this.value !== (this.value | 0).toString()) {
this.value = PDFViewerApplication.page;
}
});
@ -337,9 +288,11 @@ var PDFViewerApplication = {
container.addEventListener('pagechange', function (evt) {
var page = evt.pageNumber;
if (evt.previousPageNumber !== page) {
document.getElementById('pageNumber').value = page;
}
var numPages = PDFViewerApplication.pagesCount;
document.getElementById('pageNumber').value = page;
document.getElementById('previous').disabled = (page <= 1);
document.getElementById('next').disabled = (page >= numPages);
}, true);
@ -359,9 +312,38 @@ document.addEventListener('DOMContentLoaded', function () {
});
})();
// We need to delay opening until all HTML is loaded.
PDFViewerApplication.animationStartedPromise.then(function () {
PDFViewerApplication.open({
url: DEFAULT_URL
// Support of the new version of navigator.mozL10n -- in PDF.js older/custom
// version is used.
var mozL10n = {
get: function (id, args, fallback) {
var s = (navigator.mozL10n && navigator.mozL10n.get(id)) || fallback;
s = s.replace(/\{\{\s*(\w+)\s*\}\}/g, function (all, key) {
return args[key] || '';
});
return s;
},
translate: function (fragment) {
if (navigator.mozL10n) {
navigator.mozL10n.translateFragment(fragment);
}
}
};
window.navigator.mozSetMessageHandler('activity', function(activity) {
var blob = activity.source.data.blob;
var fileURL = activity.source.data.url ||
activity.source.data.filename ||
' '; // if no url or filename, use a non-empty string
var url = URL.createObjectURL(blob);
// We need to delay opening until all HTML is loaded.
PDFViewerApplication.animationStartedPromise.then(function () {
PDFViewerApplication.open({url: url, originalUrl: fileURL});
var header = document.getElementById('header');
header.addEventListener('action', function() {
activity.postResult('close');
});
});
});

View file

@ -0,0 +1,283 @@
/**
* (c) 2013 Rob Wu <gwnRob@gmail.com>
* Released under the MIT license
* https://github.com/Rob--W/chrome-api/chrome.tabs.executeScriptInFrame
*
* Implements the chrome.tabs.executeScriptInFrame API.
* This API is similar to the chrome.tabs.executeScript method, except
* that it also recognizes the "frameId" property.
* This frameId can be obtained through the webNavigation or webRequest API.
*
* When an error occurs, chrome.runtime.lastError is set.
*
* Required permissions:
* webRequest
* webRequestBlocking
* Host permissions for the tab
*
* In addition, the following field must also be set in manifest.json:
* "web_accessible_resources": ["getFrameId"]
*/
/* globals chrome, console */
(function() {
/* jshint browser:true, maxlen:100 */
'use strict';
chrome.tabs.executeScriptInFrame = executeScript;
// This URL is used to communicate the frameId. The resource is never
// visited, so it should be a non-existent location. Do not use *, ", '
// or line breaks in the file name.
var URL_WHAT_IS_MY_FRAME_ID = chrome.extension.getURL('getFrameId');
// The callback will be called within ... ms:
// Don't set a too low value.
var MAXIMUM_RESPONSE_TIME_MS = 1000;
// Callbacks are stored here until they're invoked.
// Key = dummyUrl, value = callback function
var callbacks = {};
chrome.webRequest.onBeforeRequest.addListener(function showFrameId(details) {
// Positive integer frameId >= 0
// Since an image is used as a data transport, we add 1 to get a
// non-zero width.
var frameId = details.frameId + 1;
// Assume that the frameId fits in three bytes - which is a very
// reasonable assumption.
var width = String.fromCharCode(frameId & 0xFF, (frameId >> 8) & 0xFF);
// When frameId > 0xFFFF, use the height to convey the additional
// information. Again, add 1 to make sure that the height is non-zero.
var height = String.fromCharCode((frameId >> 16) + 1, 0);
// Convert data to base64 to avoid loss of bytes
var image = 'data:image/gif;base64,' + btoa(
// 4749 4638 3961 (GIF header)
'GIF89a' +
// Logical Screen Width (LSB)
width +
// Logical Screen Height (LSB)
height +
// "No Global Color Table follows"
'\x00' +
// Background color
'\xff' +
// No aspect information is given
'\x00' +
// (image descriptor)
// Image Separator
'\x2c' +
// Image Position (Left & Top)
'\x00\x00\x00\x00' +
// Image Width (LSB)
width +
// Image Height (LSB)
height +
// Local Color Table is not present
'\x00' +
// (End of image descriptor)
// Image data
'\x02\x02\x44\x01\x00' +
// GIF trailer
'\x3b'
);
return {redirectUrl: image};
}, {
urls: [URL_WHAT_IS_MY_FRAME_ID + '*'],
types: ['image']
}, ['blocking']);
chrome.runtime.onMessage.addListener(function(message, sender,
sendResponse) {
if (message && message.executeScriptCallback) {
var callback = callbacks[message.identifier];
if (callback) {
if (message.hello) {
clearTimeout(callback.timer);
return;
}
delete callbacks[message.identifier];
// Result within an array to be consistent with the
// chrome.tabs.executeScript API.
callback([message.evalResult]);
} else {
console.warn('Callback not found for response in tab ' +
sender.tab.id);
}
}
});
/**
* Execute content script in a specific frame.
*
* @param tabId {integer} required
* @param details.frameId {integer} required
* @param details.code {string} Code or file is required (not both)
* @param details.file {string} Code or file is required (not both)
* @param details.runAt {optional string} One of "document_start",
* "document_end", "document_idle"
* @param callback {optional function(optional result array)} When an error
* occurs, result
* is not set.
*/
function executeScript(tabId, details, callback) {
console.assert(typeof details === 'object',
'details must be an object (argument 0)');
var frameId = details.frameId;
console.assert(typeof tabId === 'number',
'details.tabId must be a number');
console.assert(typeof frameId === 'number',
'details.frameId must be a number');
var sourceType = ('code' in details ? 'code' : 'file');
console.assert(sourceType in details, 'No source code or file specified');
var sourceValue = details[sourceType];
console.assert(typeof sourceValue === 'string',
'details.' + sourceType + ' must be a string');
var runAt = details.runAt;
if (!callback) {
callback = function() {/* no-op*/};
}
console.assert(typeof callback === 'function',
'callback must be a function');
if (frameId === 0) {
// No need for heavy lifting if we want to inject the script
// in the main frame
var injectDetails = {
allFrames: false,
runAt: runAt
};
injectDetails[sourceType] = sourceValue;
chrome.tabs.executeScript(tabId, injectDetails, callback);
return;
}
var identifier = Math.random().toString(36);
if (sourceType === 'code') {
executeScriptInFrame();
} else { // sourceType === 'file'
(function() {
var x = new XMLHttpRequest();
x.open('GET', chrome.extension.getURL(sourceValue), true);
x.onload = function() {
sourceValue = x.responseText;
executeScriptInFrame();
};
x.onerror = function executeScriptResourceFetchError() {
var message = 'Failed to load file: "' + sourceValue + '".';
console.error('executeScript: ' + message);
chrome.runtime.lastError = chrome.extension.lastError =
{ message: message };
try {
callback();
} finally {
chrome.runtime.lastError = chrome.extension.lastError = undefined;
}
};
x.send();
})();
}
function executeScriptInFrame() {
callbacks[identifier] = callback;
chrome.tabs.executeScript(tabId, {
code: '(' + DETECT_FRAME + ')(' +
'window,' +
JSON.stringify(identifier) + ',' +
frameId + ',' +
JSON.stringify(sourceValue) + ')',
allFrames: true,
runAt: 'document_start'
}, function(results) {
if (results) {
callback.timer = setTimeout(executeScriptTimedOut,
MAXIMUM_RESPONSE_TIME_MS);
} else {
// Failed :(
delete callbacks[identifier];
callback();
}
});
}
function executeScriptTimedOut() {
var callback = callbacks[identifier];
if (!callback) {
return;
}
delete callbacks[identifier];
var message = 'Failed to execute script: Frame ' + frameId +
' not found in tab ' + tabId;
console.error('executeScript: ' + message);
chrome.runtime.lastError = chrome.extension.lastError =
{ message: message };
try {
callback();
} finally {
chrome.runtime.lastError = chrome.extension.lastError = undefined;
}
}
}
/**
* Code executed as a content script.
*/
var DETECT_FRAME = '' + function checkFrame(window, identifier, frameId,
code) {
var i;
if ('__executeScript_frameId__' in window) {
evalAsContentScript();
} else {
// Do NOT use new Image() because of http://crbug.com/245296
// in Chrome 27-29
i = window.document.createElement('img');
i.onload = function() {
window.__executeScript_frameId__ = (this.naturalWidth - 1) +
(this.naturalHeight - 1 << 16);
evalAsContentScript();
};
// Trigger webRequest event to get frameId
// (append extra characters to bust the cache)
i.src = 'URL_WHAT_IS_MY_FRAME_ID?' +
Math.random().toString(36).slice(-6);
}
for (i = 0 ; i < window.frames.length; ++i) {
try {
var frame = window.frames[i];
var scheme = frame.location.protocol;
if (scheme !== 'https:' && scheme !== 'http:' && scheme !== 'file:') {
checkFrame(frame, identifier, frameId, code);
}
} catch (e) {
// blocked by same origin policy, so it's not a javascript:/about:blank
// URL. chrome.tabs.executeScript will run the script for the frame.
}
}
function evalAsContentScript() {
if (window.__executeScript_frameId__ !== frameId) {
return;
}
// Send an early message to make sure that any blocking code
// in the evaluated code does not cause the time-out in the background
// page to be triggered
chrome.runtime.sendMessage({
executeScriptCallback: true,
hello: true,
identifier: identifier
});
var result = null;
try {
// jshint evil:true
result = window.eval(code);
} finally {
chrome.runtime.sendMessage({
executeScriptCallback: true,
evalResult: result,
identifier: identifier
});
}
}
}.toString().replace('URL_WHAT_IS_MY_FRAME_ID', URL_WHAT_IS_MY_FRAME_ID);
})();

View file

@ -23,10 +23,31 @@ function getViewerURL(pdf_url) {
return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
}
if (CSS.supports('animation', '0s')) {
document.addEventListener('animationstart', onAnimationStart, true);
} else {
document.addEventListener('webkitAnimationStart', onAnimationStart, true);
// (un)prefixed property names
var createShadowRoot, shadowRoot;
if (typeof Element.prototype.createShadowRoot !== 'undefined') {
// Chrome 35+
createShadowRoot = 'createShadowRoot';
shadowRoot = 'shadowRoot';
} else if (typeof Element.prototype.webkitCreateShadowRoot !== 'undefined') {
// Chrome 25 - 34
createShadowRoot = 'webkitCreateShadowRoot';
shadowRoot = 'webkitShadowRoot';
try {
document.createElement('embed').webkitCreateShadowRoot();
} catch (e) {
// Only supported since Chrome 33.
createShadowRoot = shadowRoot = '';
}
}
// Only observe the document if we can make use of Shadow DOM.
if (createShadowRoot) {
if (CSS.supports('animation', '0s')) {
document.addEventListener('animationstart', onAnimationStart, true);
} else {
document.addEventListener('webkitAnimationStart', onAnimationStart, true);
}
}
function onAnimationStart(event) {
@ -36,9 +57,10 @@ function onAnimationStart(event) {
}
// Called for every <object> or <embed> element in the page.
// This may change the type, src/data attributes and/or the child nodes of the
// element. This function only affects elements for the first call. Subsequent
// invocations have no effect.
// It does not trigger any Mutation observers, but it may modify the
// shadow DOM rooted under the given element.
// Calling this function multiple times for the same element is safe, i.e.
// it has no side effects.
function watchObjectOrEmbed(elem) {
var mimeType = elem.type;
if (mimeType && 'application/pdf' !== mimeType.toLowerCase()) {
@ -64,35 +86,33 @@ function watchObjectOrEmbed(elem) {
return;
}
if (elem.__I_saw_this_element) {
if (elem[shadowRoot]) {
// If the element already has a shadow root, assume that we've already
// seen this element.
return;
}
elem.__I_saw_this_element = true;
var tagName = elem.tagName.toUpperCase();
var updateEmbedOrObject;
if (tagName === 'EMBED') {
updateEmbedOrObject = updateEmbedElement;
} else if (tagName === 'OBJECT') {
updateEmbedOrObject = updateObjectElement;
} else {
return;
}
var lastSrc;
var isUpdating = false;
elem[createShadowRoot]();
function updateViewerFrame() {
if (!isUpdating) {
isUpdating = true;
try {
if (lastSrc !== elem[srcAttribute]) {
updateEmbedOrObject(elem);
lastSrc = elem[srcAttribute];
}
} finally {
isUpdating = false;
}
var path = elem[srcAttribute];
if (!path) {
elem[shadowRoot].textContent = '';
} else {
elem[shadowRoot].innerHTML =
// Set display: inline-block; to the host element (<embed>/<object>) to
// ensure that the dimensions defined on the host element are applied to
// the iframe (http://crbug.com/358648).
// The styles are declared in the shadow DOM to allow page authors to
// override these styles (e.g. .style.display = 'none';).
'<style>\n' +
// Chrome 35+
':host { display: inline-block; }\n' +
// Chrome 33 and 34 (not 35+ because of http://crbug.com/351248)
'*:not(style):not(iframe) { display: inline-block; }\n' +
'iframe { width: 100%; height: 100%; border: 0; }\n' +
'</style>' +
'<iframe allowfullscreen></iframe>';
elem[shadowRoot].lastChild.src = getEmbeddedViewerURL(path);
}
}
@ -108,97 +128,6 @@ function watchObjectOrEmbed(elem) {
});
}
// Display the PDF Viewer in an <embed>.
function updateEmbedElement(elem) {
if (elem.type === 'text/html' && elem.src.lastIndexOf(VIEWER_URL, 0) === 0) {
// The viewer is already shown.
return;
}
// The <embed> tag needs to be removed and re-inserted before any src changes
// are effective.
var parentNode = elem.parentNode;
var nextSibling = elem.nextSibling;
if (parentNode) {
parentNode.removeChild(elem);
}
elem.type = 'text/html';
elem.src = getEmbeddedViewerURL(elem.src);
if (parentNode) {
parentNode.insertBefore(elem, nextSibling);
}
}
// Display the PDF Viewer in an <object>.
function updateObjectElement(elem) {
// <object> elements are terrible. Experiments (in49.0.2623.75) show that the
// following happens:
// - When fallback content is shown (e.g. because the built-in PDF Viewer is
// disabled), updating the "data" attribute has no effect. Not surprising
// considering that HTMLObjectElement::m_useFallbackContent is not reset
// once it is set to true. Source:
// WebKit/Source/core/html/HTMLObjectElement.cpp#378 (rev 749fe30d676b6c14).
// - When the built-in PDF Viewer plugin is enabled, updating the "data"
// attribute reloads the content (provided that the type was correctly set).
// - When <object type=text/html data="chrome-extension://..."> is used
// (tested with a data-URL, data:text/html,<object...>, the extension's
// origin whitelist is not set up, so the viewer can't load the PDF file.
// - The content of the <object> tag may be affected by <param> tags.
//
// To make sure that our solution works for all cases, we will insert a frame
// as fallback content and force the <object> tag to render its fallback
// content.
var iframe = elem.firstElementChild;
if (!iframe || !iframe.__inserted_by_pdfjs) {
iframe = createFullSizeIframe();
elem.textContent = '';
elem.appendChild(iframe);
iframe.__inserted_by_pdfjs = true;
}
iframe.src = getEmbeddedViewerURL(elem.data);
// Some bogus content type that is not handled by any plugin.
elem.type = 'application/not-a-pee-dee-eff-type';
// Force the <object> to reload and render its fallback content.
elem.data += '';
// Usually the browser renders plugin content in this tag, which is completely
// oblivious of styles such as padding, but we insert and render child nodes,
// so force padding to be zero to avoid undesired dimension changes.
elem.style.padding = '0';
// <object> and <embed> elements have a "display:inline" style by default.
// Despite this property, when a plugin is loaded in the tag, the tag is
// treated like "display:inline-block". However, when the browser does not
// render plugin content, the <object> tag does not behave like that, and as
// a result the width and height is ignored.
// Force "display:inline-block" to make sure that the width/height as set by
// web pages is respected.
// (<embed> behaves as expected with the default display value, but setting it
// to display:inline-block doesn't hurt).
elem.style.display = 'inline-block';
}
// Create an <iframe> element without borders that takes the full width and
// height.
function createFullSizeIframe() {
var iframe = document.createElement('iframe');
iframe.style.background = 'none';
iframe.style.border = 'none';
iframe.style.borderRadius = 'none';
iframe.style.boxShadow = 'none';
iframe.style.cssFloat = 'none';
iframe.style.display = 'block';
iframe.style.height = '100%';
iframe.style.margin = '0';
iframe.style.maxHeight = 'none';
iframe.style.maxWidth = 'none';
iframe.style.position = 'static';
iframe.style.transform = 'none';
iframe.style.visibility = 'visible';
iframe.style.width = '100%';
return iframe;
}
// Get the viewer URL, provided that the path is a valid URL.
function getEmbeddedViewerURL(path) {
var fragment = /^([^#]*)(#.*)?$/.exec(path);

View file

@ -27,8 +27,6 @@ limitations under the License.
'ftp',
'file',
'chrome-extension',
'blob',
'data',
// Chromium OS
'filesystem',
// Chromium OS, shorthand for filesystem:<origin>/external/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 594 B

After

Width:  |  Height:  |  Size: 622 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 712 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

@ -14,7 +14,8 @@
"<all_urls>",
"tabs",
"webNavigation",
"storage"
"storage",
"streamsPrivate"
],
"content_scripts": [{
"matches": [
@ -36,6 +37,9 @@
"filesystem:*.pdf"
]
}],
"mime_types": [
"application/pdf"
],
"storage": {
"managed_schema": "preferences_schema.json"
},
@ -57,14 +61,13 @@
},
"incognito": "split",
"web_accessible_resources": [
"getFrameId",
"content/web/viewer.html",
"http:/*",
"https:/*",
"ftp:/*",
"file:/*",
"chrome-extension:/*",
"blob:*",
"data:*",
"filesystem:/*",
"drive:*"
]

View file

@ -1,70 +0,0 @@
/*
Copyright 2016 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.
*/
/* eslint strict: ["error", "function"] */
/* globals chrome */
(function() {
'use strict';
var storageLocal = chrome.storage.local;
var storageSync = chrome.storage.sync;
if (!storageSync) {
// No sync storage area - nothing to migrate to.
return;
}
getStorageNames(function(storageKeys) {
storageLocal.get(storageKeys, function(values) {
if (!values || !Object.keys(values).length) {
// No local storage - nothing to migrate.
return;
}
migrateToSyncStorage(values);
});
});
function getStorageNames(callback) {
var x = new XMLHttpRequest();
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
x.open('get', chrome.runtime.getURL(schema_location));
x.onload = function() {
var storageKeys = Object.keys(x.response.properties);
callback(storageKeys);
};
x.responseType = 'json';
x.send();
}
// Save |values| to storage.sync and delete the values with that key from
// storage.local.
function migrateToSyncStorage(values) {
storageSync.set(values, function() {
if (chrome.runtime.lastError) {
console.error('Failed to migrate settings due to an error: ' +
chrome.runtime.lastError.message);
return;
}
// Migration successful. Delete local settings.
storageLocal.remove(Object.keys(values), function() {
// In theory remove() could fail (e.g. if the browser's storage
// backend is corrupt), but since storageSync.set succeeded, consider
// the migration successful.
console.log(
'Successfully migrated preferences from local to sync storage.');
});
});
}
})();

View file

@ -80,21 +80,6 @@ body {
</div>
</template>
<template id="externalLinkTarget-template">
<div class="settings-row">
<label>
<span></span>
<select>
<option value="0">Default</option>
<option value="1">Current window/tab</option>
<option value="2">New window/tab</option>
<option value="3">Parent window/tab</option>
<option value="4">Top window/tab</option>
</select>
</label>
</div>
</template>
<script src="options.js"></script>
</body>
</html>

View file

@ -13,18 +13,12 @@ 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.
*/
/* globals chrome */
/* globals chrome, Promise */
'use strict';
var storageAreaName = chrome.storage.sync ? 'sync' : 'local';
var storageArea = chrome.storage[storageAreaName];
Promise.all([
new Promise(function getManagedPrefs(resolve) {
if (!chrome.storage.managed) {
resolve({});
return;
}
// Get preferences as set by the system administrator.
chrome.storage.managed.get(null, function(prefs) {
// Managed storage may be disabled, e.g. in Opera.
@ -32,7 +26,7 @@ Promise.all([
});
}),
new Promise(function getUserPrefs(resolve) {
storageArea.get(null, function(prefs) {
chrome.storage.local.get(null, function(prefs) {
resolve(prefs || {});
});
}),
@ -80,8 +74,6 @@ Promise.all([
renderPreference = renderDefaultZoomValue(prefSchema.title);
} else if (prefName === 'sidebarViewOnLoad') {
renderPreference = renderSidebarViewOnLoad(prefSchema.title);
} else if (prefName === 'externalLinkTarget') {
renderPreference = renderExternalLinkTarget(prefSchema.title);
} else {
// Should NEVER be reached. Only happens if a new type of preference is
// added to the storage manifest.
@ -99,7 +91,7 @@ Promise.all([
// Reset button to restore default settings.
document.getElementById('reset-button').onclick = function() {
userPrefs = {};
storageArea.remove(prefNames, function() {
chrome.storage.local.remove(prefNames, function() {
renderedPrefNames.forEach(function(prefName) {
renderPreferenceFunctions[prefName](getPrefValue(prefName));
});
@ -108,7 +100,7 @@ Promise.all([
// Automatically update the UI when the preferences were changed elsewhere.
chrome.storage.onChanged.addListener(function(changes, areaName) {
var prefs = areaName === storageAreaName ? userPrefs :
var prefs = areaName === 'local' ? userPrefs :
areaName === 'managed' ? managedPrefs : null;
if (prefs) {
renderedPrefNames.forEach(function(prefName) {
@ -142,7 +134,7 @@ function renderBooleanPref(shortDescription, description, prefName) {
checkbox.onchange = function() {
var pref = {};
pref[prefName] = this.checked;
storageArea.set(pref);
chrome.storage.local.set(pref);
};
wrapper.querySelector('span').textContent = shortDescription;
document.getElementById('settings-boxes').appendChild(wrapper);
@ -157,7 +149,7 @@ function renderDefaultZoomValue(shortDescription) {
var wrapper = importTemplate('defaultZoomValue-template');
var select = wrapper.querySelector('select');
select.onchange = function() {
storageArea.set({
chrome.storage.local.set({
defaultZoomValue: this.value
});
};
@ -186,7 +178,7 @@ function renderSidebarViewOnLoad(shortDescription) {
var wrapper = importTemplate('sidebarViewOnLoad-template');
var select = wrapper.querySelector('select');
select.onchange = function() {
storageArea.set({
chrome.storage.local.set({
sidebarViewOnLoad: parseInt(this.value)
});
};
@ -198,20 +190,3 @@ function renderSidebarViewOnLoad(shortDescription) {
}
return renderPreference;
}
function renderExternalLinkTarget(shortDescription) {
var wrapper = importTemplate('externalLinkTarget-template');
var select = wrapper.querySelector('select');
select.onchange = function() {
storageArea.set({
externalLinkTarget: parseInt(this.value)
});
};
wrapper.querySelector('span').textContent = shortDescription;
document.getElementById('settings-boxes').appendChild(wrapper);
function renderPreference(value) {
select.value = value;
}
return renderPreference;
}

View file

@ -0,0 +1,285 @@
/*
Copyright 2013 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.
*/
/* globals chrome, URL, getViewerURL, Features */
(function() {
'use strict';
if (!chrome.streamsPrivate) {
// Aww, PDF.js is still not whitelisted... See http://crbug.com/326949
console.warn('streamsPrivate not available, PDF from FTP or POST ' +
'requests will not be displayed using this extension! ' +
'See http://crbug.com/326949');
chrome.runtime.onMessage.addListener(function(message, sender,
sendResponse) {
if (message && message.action === 'getPDFStream') {
sendResponse();
}
});
return;
}
//
// Stream URL storage manager
//
// Hash map of "<tab id>": { "<pdf url>": ["<stream url>", ...], ... }
var urlToStream = {};
chrome.streamsPrivate.onExecuteMimeTypeHandler.addListener(handleStream);
// Chrome before 27 does not support tabIds on stream events.
var streamSupportsTabId = true;
// "tabId" used for Chrome before 27.
var STREAM_NO_TABID = 0;
function hasStream(tabId, pdfUrl) {
var streams = urlToStream[streamSupportsTabId ? tabId : STREAM_NO_TABID];
return (streams && streams[pdfUrl] && streams[pdfUrl].length > 0);
}
/**
* Get stream URL for a given tabId and PDF url. The retrieved stream URL
* will be removed from the list.
* @return {object} An object with property url (= blob:-URL) and
* property contentLength (= expected size)
*/
function getStream(tabId, pdfUrl) {
if (!streamSupportsTabId) {
tabId = STREAM_NO_TABID;
}
if (hasStream(tabId, pdfUrl)) {
var streamInfo = urlToStream[tabId][pdfUrl].shift();
if (urlToStream[tabId][pdfUrl].length === 0) {
delete urlToStream[tabId][pdfUrl];
if (Object.keys(urlToStream[tabId]).length === 0) {
delete urlToStream[tabId];
}
}
return streamInfo;
}
}
function setStream(tabId, pdfUrl, streamUrl, expectedSize) {
tabId = tabId || STREAM_NO_TABID;
if (!urlToStream[tabId]) {
urlToStream[tabId] = {};
}
if (!urlToStream[tabId][pdfUrl]) {
urlToStream[tabId][pdfUrl] = [];
}
urlToStream[tabId][pdfUrl].push({
streamUrl: streamUrl,
contentLength: expectedSize
});
}
// http://crbug.com/276898 - the onExecuteMimeTypeHandler event is sometimes
// dispatched in the wrong incognito profile. To work around the bug, transfer
// the stream information from the incognito session when the bug is detected.
function transferStreamToIncognitoProfile(tabId, pdfUrl) {
if (chrome.extension.inIncognitoContext) {
console.log('Already within incognito profile. Aborted stream transfer.');
return;
}
var streamInfo = getStream(tabId, pdfUrl);
if (!streamInfo) {
return;
}
console.log('Attempting to transfer stream info to a different profile...');
var itemId = 'streamInfo:' + window.performance.now();
var items = {};
items[itemId] = {
tabId: tabId,
pdfUrl: pdfUrl,
streamUrl: streamInfo.streamUrl,
contentLength: streamInfo.contentLength
};
// The key will be removed whenever an incognito session is started,
// or when an incognito session is active.
chrome.storage.local.set(items, function() {
chrome.extension.isAllowedIncognitoAccess(function(isAllowedAccess) {
if (!isAllowedAccess) {
// If incognito is disabled, forget about the stream.
console.warn('Incognito is disabled, unexpected unknown stream.');
chrome.storage.local.remove(items);
}
});
});
}
if (chrome.extension.inIncognitoContext) {
var importStream = function(itemId, streamInfo) {
if (itemId.lastIndexOf('streamInfo:', 0) !== 0) {
return;
}
console.log('Importing stream info from non-incognito profile',
streamInfo);
handleStream('', streamInfo.pdfUrl, streamInfo.streamUrl,
streamInfo.tabId, streamInfo.contentLength);
chrome.storage.local.remove(itemId);
};
var handleStorageItems = function(items) {
Object.keys(items).forEach(function(itemId) {
var item = items[itemId];
if (item.oldValue && !item.newValue) {
return; // storage remove event
}
if (item.newValue) {
item = item.newValue; // storage setter event
}
importStream(itemId, item);
});
};
// Parse information that was set before the event pages were ready.
chrome.storage.local.get(null, handleStorageItems);
chrome.storage.onChanged.addListener(handleStorageItems);
}
// End of work-around for crbug 276898
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message && message.action === 'getPDFStream') {
var pdfUrl = message.data;
var streamInfo = getStream(sender.tab.id, pdfUrl) || {};
sendResponse({
streamUrl: streamInfo.streamUrl,
contentLength: streamInfo.contentLength,
extensionSupportsFTP: Features.extensionSupportsFTP
});
}
});
//
// PDF detection and activation of PDF viewer.
//
/**
* Callback for when we receive a stream
*
* @param mimeType {string} The mime type of the incoming stream
* @param pdfUrl {string} The full URL to the file
* @param streamUrl {string} The url pointing to the open stream
* @param tabId {number} The ID of the tab in which the stream has been opened
* (undefined before Chrome 27, http://crbug.com/225605)
* @param expectedSize {number} The expected content length of the stream.
* (added in Chrome 29, http://crbug.com/230346)
*/
function handleStream(mimeType, pdfUrl, streamUrl, tabId, expectedSize) {
if (typeof mimeType === 'object') {
// API change: argument list -> object, see crbug.com/345882
// documentation: chrome/common/extensions/api/streams_private.idl
var streamInfo = mimeType;
mimeType = streamInfo.mimeType;
pdfUrl = streamInfo.originalUrl;
streamUrl = streamInfo.streamUrl;
tabId = streamInfo.tabId;
expectedSize = streamInfo.expectedContentSize;
}
console.log('Intercepted ' + mimeType + ' in tab ' + tabId + ' with URL ' +
pdfUrl + '\nAvailable as: ' + streamUrl);
streamSupportsTabId = typeof tabId === 'number';
setStream(tabId, pdfUrl, streamUrl, expectedSize);
if (!tabId) { // Chrome doesn't set the tabId before v27
// PDF.js targets Chrome 28+ because of fatal bugs in incognito mode
// for older versions of Chrome. So, don't bother implementing a fallback.
// For those who are interested, either loop through all tabs, or use the
// webNavigation.onBeforeNavigate event to map pdfUrls to tab + frame IDs.
return;
}
// Check if the frame has already been rendered.
chrome.webNavigation.getAllFrames({
tabId: tabId
}, function(details) {
if (details) {
details = details.filter(function(frame) {
return (frame.url === pdfUrl);
});
if (details.length > 0) {
if (details.length !== 1) {
// (Rare case) Multiple frames with same URL.
// TODO(rob): Find a better way to handle this case
// (e.g. open in new tab).
console.warn('More than one frame found for tabId ' + tabId +
' with URL ' + pdfUrl + '. Using first frame.');
}
details = details[0];
details = {
tabId: tabId,
frameId: details.frameId,
url: details.url
};
handleWebNavigation(details);
} else {
console.warn('No webNavigation frames found for tabId ' + tabId);
}
} else {
console.warn('Unable to get frame information for tabId ' + tabId);
// This branch may occur when a new incognito session is launched.
// The event is dispatched in the non-incognito session while it should
// be dispatched in the incognito session. See http://crbug.com/276898
transferStreamToIncognitoProfile(tabId, pdfUrl);
}
});
}
/**
* This method is called when the chrome.streamsPrivate API has intercepted
* the PDF stream. This method detects such streams, finds the frame where
* the request was made, and loads the viewer in that frame.
*
* @param details {object}
* @param details.tabId {number} The ID of the tab
* @param details.url {string} The URL being navigated when the error
* occurred.
* @param details.frameId {number} 0 indicates the navigation happens in
* the tab content window; a positive value
* indicates navigation in a subframe.
*/
function handleWebNavigation(details) {
var tabId = details.tabId;
var frameId = details.frameId;
var pdfUrl = details.url;
if (!hasStream(tabId, pdfUrl)) {
console.log('No PDF stream found in tab ' + tabId + ' for ' + pdfUrl);
return;
}
var viewerUrl = getViewerURL(pdfUrl);
if (frameId === 0) { // Main frame
console.log('Going to render PDF Viewer in main frame for ' + pdfUrl);
chrome.tabs.update(tabId, {
url: viewerUrl
});
} else {
console.log('Going to render PDF Viewer in sub frame for ' + pdfUrl);
// Non-standard Chrome API. chrome.tabs.executeScriptInFrame and docs
// is available at https://github.com/Rob--W/chrome-api
chrome.tabs.executeScriptInFrame(tabId, {
frameId: frameId,
code: 'location.href = ' + JSON.stringify(viewerUrl) + ';'
}, function(result) {
if (!result) { // Did the tab disappear? Is the frame inaccessible?
console.warn('Frame not found, viewer not rendered in tab ' + tabId);
}
});
}
}
})();

View file

@ -13,7 +13,6 @@ 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.
*/
/* eslint strict: ["error", "function"] */
/* globals chrome, getViewerURL */
(function() {

View file

@ -14,12 +14,12 @@ 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.
-->
<script src="chrome.tabs.executeScriptInFrame.js"></script>
<script src="feature-detect.js"></script>
<script src="options/migration.js"></script>
<script src="preserve-referer.js"></script>
<script src="pdfHandler.js"></script>
<script src="extension-router.js"></script>
<script src="pdfHandler-v2.js"></script>
<script src="pdfHandler-vcros.js"></script>
<script src="pageAction/background.js"></script>
<script src="suppress-update.js"></script>
<script src="telemetry.js"></script>

View file

@ -54,7 +54,7 @@ function isPdfDownloadable(details) {
* @return {undefined|{name: string, value: string}} The header, if found.
*/
function getHeaderFromHeaders(headers, headerName) {
for (var i = 0; i < headers.length; ++i) {
for (var i=0; i<headers.length; ++i) {
var header = headers[i];
if (header.name.toLowerCase() === headerName) {
return header;
@ -72,20 +72,10 @@ function getHeaderFromHeaders(headers, headerName) {
function isPdfFile(details) {
var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');
if (header) {
var headerValue = header.value.toLowerCase().split(';', 1)[0].trim();
if (headerValue === 'application/pdf') {
return true;
}
if (headerValue === 'application/octet-stream') {
if (details.url.toLowerCase().indexOf('.pdf') > 0) {
return true;
}
var cdHeader =
getHeaderFromHeaders(details.responseHeaders, 'content-disposition');
if (cdHeader && /\.pdf(["']|$)/i.test(cdHeader.value)) {
return true;
}
}
var headerValue = header.value.toLowerCase().split(';',1)[0].trim();
return (headerValue === 'application/pdf' ||
headerValue === 'application/octet-stream' &&
details.url.toLowerCase().indexOf('.pdf') > 0);
}
}
@ -143,8 +133,46 @@ chrome.webRequest.onHeadersReceived.addListener(
url: viewerUrl
});
return { cancel: true };
} else {
// Sub frame. Requires some more work...
// The navigation will be cancelled at the end of the webRequest cycle.
chrome.webNavigation.onErrorOccurred.addListener(function listener(nav) {
if (nav.tabId !== details.tabId || nav.frameId !== details.frameId) {
return;
}
chrome.webNavigation.onErrorOccurred.removeListener(listener);
// Locate frame and insert viewer
chrome.tabs.executeScriptInFrame(details.tabId, {
frameId: details.frameId,
code: 'location.href = ' + JSON.stringify(viewerUrl) + ';'
}, function(result) {
if (!result) {
console.warn('Frame not found! Opening viewer in new tab...');
chrome.tabs.create({
url: viewerUrl
});
}
});
}, {
url: [{ urlEquals: details.url.split('#', 1)[0] }]
});
// Prevent frame from rendering by using X-Frame-Options.
// Do not use { cancel: true }, because that makes the frame inaccessible
// to the content script that has to replace the frame's URL.
return {
responseHeaders: [{
name: 'X-Content-Type-Options',
value: 'nosniff'
}, {
name: 'X-Frame-Options',
value: 'deny'
}]
};
}
console.warn('Child frames are not supported in ancient Chrome builds!');
// Immediately abort the request, because the frame that initiated the
// request will be replaced with the PDF Viewer (within a split second).
},
{
urls: [
@ -152,7 +180,7 @@ chrome.webRequest.onHeadersReceived.addListener(
],
types: ['main_frame', 'sub_frame']
},
['blocking', 'responseHeaders']);
['blocking','responseHeaders']);
chrome.webRequest.onBeforeRequest.addListener(
function onBeforeRequestForFTP(details) {
@ -224,32 +252,6 @@ chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
});
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message && message.action === 'getParentOrigin') {
// getParentOrigin is used to determine whether it is safe to embed a
// sensitive (local) file in a frame.
if (!sender.tab) {
sendResponse('');
return;
}
// TODO: This should be the URL of the parent frame, not the tab. But
// chrome-extension:-URLs are not visible in the webNavigation API
// (https://crbug.com/326768), so the next best thing is using the tab's URL
// for making security decisions.
var parentUrl = sender.tab.url;
if (!parentUrl) {
sendResponse('');
return;
}
if (parentUrl.lastIndexOf('file:', 0) === 0) {
sendResponse('file://');
return;
}
// The regexp should always match for valid URLs, but in case it doesn't,
// just give the full URL (e.g. data URLs).
var origin = /^[^:]+:\/\/[^/]+/.exec(parentUrl);
sendResponse(origin ? origin[1] : parentUrl);
return true;
}
if (message && message.action === 'isAllowedFileSchemeAccess') {
chrome.extension.isAllowedFileSchemeAccess(sendResponse);
return true;

View file

@ -75,51 +75,6 @@
"useOnlyCssZoom": {
"type": "boolean",
"default": false
},
"externalLinkTarget": {
"title": "External links target window",
"description": "Controls how external links will be opened.\n 0 = default.\n 1 = replaces current window.\n 2 = new window/tab.\n 3 = parent.\n 4 = in top window.",
"type": "integer",
"enum": [
0,
1,
2,
3,
4
],
"default": 0
},
"disablePageLabels": {
"type": "boolean",
"default": false
},
"disableTelemetry": {
"title": "Disable telemetry",
"type": "boolean",
"description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.",
"default": false
},
"enhanceTextSelection": {
"type": "boolean",
"default": false
},
"renderer": {
"type": "string",
"enum": [
"canvas",
"svg"
],
"default": "canvas"
},
"renderInteractiveForms": {
"type": "boolean",
"default": false
},
"enablePrintAutoRotate": {
"title": "Automatically rotate printed pages",
"description": "When enabled, pages whose orientation differ from the first page are rotated when printed.",
"type": "boolean",
"default": false
}
}
}

View file

@ -1,163 +0,0 @@
/*
Copyright 2016 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.
*/
/* eslint strict: ["error", "function"] */
/* globals chrome, crypto, Headers, Request */
(function() {
'use strict';
// This module sends the browser and extension version to a server, to
// determine whether it is safe to drop support for old Chrome versions in
// future extension updates.
//
// The source code for the server is available at:
// https://github.com/Rob--W/pdfjs-telemetry
var LOG_URL = 'https://pdfjs.robwu.nl/logpdfjs';
// The minimum time to wait before sending a ping, so that we don't send too
// many requests even if the user restarts their browser very often.
// We want one ping a day, so a minimum delay of 12 hours should be OK.
var MINIMUM_TIME_BETWEEN_PING = 12 * 36E5;
if (chrome.extension.inIncognitoContext) {
// The extension uses incognito split mode, so there are two background
// pages. Only send telemetry when not in incognito mode.
return;
}
if (chrome.runtime.id !== 'oemmndcbldboiebfnladdacbdfmadadm') {
// Only send telemetry for the official PDF.js extension.
console.warn('Disabled telemetry because this is not an official build.');
return;
}
maybeSendPing();
setInterval(maybeSendPing, 36E5);
function maybeSendPing() {
getLoggingPref(function(didOptOut) {
if (didOptOut) {
// Respect the user's decision to not send statistics.
return;
}
if (!navigator.onLine) {
// No network available; Wait until the next scheduled ping opportunity.
// Even if onLine is true, the server may still be unreachable. But
// because it is impossible to tell whether a request failed due to the
// inability to connect, or a deliberate connection termination by the
// server, we don't validate the response and assume that the request
// succeeded. This ensures that the server cannot ask the client to
// send more pings.
return;
}
var lastTime = parseInt(localStorage.telemetryLastTime) || 0;
var wasUpdated = didUpdateSinceLastCheck();
if (!wasUpdated && Date.now() - lastTime < MINIMUM_TIME_BETWEEN_PING) {
return;
}
localStorage.telemetryLastTime = Date.now();
var deduplication_id = getDeduplicationId(wasUpdated);
var extension_version = chrome.runtime.getManifest().version;
if (window.Request && 'mode' in Request.prototype) {
// fetch is supported in extensions since Chrome 42 (though the above
// feature-detection method detects Chrome 43+).
// Unlike XMLHttpRequest, fetch omits credentials such as cookies in the
// requests, which guarantees that the server cannot track the client
// via HTTP cookies.
fetch(LOG_URL, {
method: 'POST',
headers: new Headers({
'Deduplication-Id': deduplication_id,
'Extension-Version': extension_version,
}),
// Set mode=cors so that the above custom headers are included in the
// request.
mode: 'cors',
});
return;
}
var x = new XMLHttpRequest();
x.open('POST', LOG_URL);
x.setRequestHeader('Deduplication-Id', deduplication_id);
x.setRequestHeader('Extension-Version', extension_version);
x.send();
});
}
/**
* Generate a 40-bit hexadecimal string (=10 letters, 1.1E12 possibilities).
* This is used by the server to discard duplicate entries of the same browser
* version when the log data is aggregated.
*/
function getDeduplicationId(wasUpdated) {
var id = localStorage.telemetryDeduplicationId;
// The ID is only used to deduplicate reports for the same browser version,
// so it is OK to change the ID if the browser is updated. By changing the
// ID, the server cannot track users for a long period even if it wants to.
if (!id || !/^[0-9a-f]{10}$/.test(id) || wasUpdated) {
id = '';
var buf = new Uint8Array(5);
crypto.getRandomValues(buf);
for (var i = 0; i < buf.length; ++i) {
var c = buf[i];
id += (c >>> 4).toString(16) + (c & 0xF).toString(16);
}
localStorage.telemetryDeduplicationId = id;
}
return id;
}
/**
* Returns whether the browser has received a major update since the last call
* to this function.
*/
function didUpdateSinceLastCheck() {
var chromeVersion = /Chrome\/(\d+)\./.exec(navigator.userAgent);
chromeVersion = chromeVersion && chromeVersion[1];
if (!chromeVersion || localStorage.telemetryLastVersion === chromeVersion) {
return false;
}
localStorage.telemetryLastVersion = chromeVersion;
return true;
}
/**
* Get the value of the telemetry preference. The callback is invoked with a
* boolean if a preference is found, and with the undefined value otherwise.
*/
function getLoggingPref(callback) {
// Try to look up the preference in the storage, in the following order:
var areas = ['sync', 'local', 'managed'];
next();
function next(result) {
var storageAreaName = areas.shift();
if (typeof result === 'boolean' || !storageAreaName) {
callback(result);
return;
}
if (!chrome.storage[storageAreaName]) {
next();
return;
}
chrome.storage[storageAreaName].get('disableTelemetry', function(items) {
next(items && items.disableTelemetry);
});
}
}
})();

View file

@ -1,38 +0,0 @@
{
"extends": [
../../.eslintrc
],
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
// Best Practices
"consistent-return": "error",
// Variables
"no-shadow": "error",
"no-unused-vars": ["error", {
"vars": "local",
"varsIgnorePattern": "^Cc|Ci|Cu|Cr|EXPORTED_SYMBOLS",
"args": "none",
}],
// Stylistic Issues
"no-nested-ternary": "error",
"quotes": ["error", "double"],
"space-before-function-paren": ["error", "never"],
// ECMAScript 6
"arrow-body-style": ["error", "as-needed"],
"arrow-parens": ["error", "always"],
"arrow-spacing": ["error", { "before": true, "after": true, }],
"constructor-super": "error",
"no-confusing-arrow": "error",
"no-const-assign": "error",
"no-dupe-class-members": "error",
"no-useless-constructor": "error",
"object-shorthand": ["error", "always", { "avoidQuotes": true }],
},
}

Some files were not shown because too many files have changed in this diff Show more