Compare commits
No commits in common. "master" and "v4.4.168" have entirely different histories.
13
.eslintignore
Normal file
13
.eslintignore
Normal file
@ -0,0 +1,13 @@
|
||||
build/
|
||||
l10n/
|
||||
docs/
|
||||
node_modules/
|
||||
external/bcmaps/
|
||||
external/builder/fixtures/
|
||||
external/builder/fixtures_babel/
|
||||
external/quickjs/
|
||||
external/openjpeg/
|
||||
test/tmp/
|
||||
test/pdfs/
|
||||
web/locale/
|
||||
*~/
|
||||
267
.eslintrc
Normal file
267
.eslintrc
Normal file
@ -0,0 +1,267 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2022,
|
||||
"sourceType": "module",
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"import",
|
||||
"json",
|
||||
"mozilla",
|
||||
"no-unsanitized",
|
||||
"sort-exports",
|
||||
"unicorn",
|
||||
],
|
||||
|
||||
"extends": [
|
||||
"plugin:json/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es2022": true,
|
||||
"worker": true,
|
||||
},
|
||||
|
||||
"globals": {
|
||||
"PDFJSDev": "readonly",
|
||||
"__non_webpack_import__": "readonly",
|
||||
},
|
||||
|
||||
"rules": {
|
||||
// Plugins
|
||||
"import/export": "error",
|
||||
"import/exports-last": "error",
|
||||
"import/extensions": ["error", "always", { "ignorePackages": true, }],
|
||||
"import/first": "error",
|
||||
"import/named": "error",
|
||||
"import/no-cycle": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-commonjs": "error",
|
||||
"import/no-mutable-exports": "error",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-unresolved": ["error", {
|
||||
"ignore": ["display", "pdfjs", "pdfjs-lib", "pdfjs-web", "web", "fluent-bundle", "fluent-dom"],
|
||||
}],
|
||||
"mozilla/avoid-removeChild": "error",
|
||||
"mozilla/use-includes-instead-of-indexOf": "error",
|
||||
"no-unsanitized/method": "error",
|
||||
"no-unsanitized/property": "error",
|
||||
"sort-exports/sort-exports": ["error", {
|
||||
"ignoreCase": true,
|
||||
}],
|
||||
"unicorn/no-abusive-eslint-disable": "error",
|
||||
"unicorn/no-array-push-push": "error",
|
||||
"unicorn/no-instanceof-array": "error",
|
||||
"unicorn/no-invalid-remove-event-listener": "error",
|
||||
"unicorn/no-new-buffer": "error",
|
||||
"unicorn/no-typeof-undefined": ["error", {
|
||||
"checkGlobalVariables": false,
|
||||
}],
|
||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
||||
"unicorn/no-useless-spread": "error",
|
||||
"unicorn/prefer-array-find": "error",
|
||||
"unicorn/prefer-array-flat": "error",
|
||||
"unicorn/prefer-array-flat-map": "error",
|
||||
"unicorn/prefer-array-index-of": "error",
|
||||
"unicorn/prefer-array-some": "error",
|
||||
"unicorn/prefer-at": "error",
|
||||
"unicorn/prefer-date-now": "error",
|
||||
"unicorn/prefer-dom-node-append": "error",
|
||||
"unicorn/prefer-dom-node-remove": "error",
|
||||
"unicorn/prefer-logical-operator-over-ternary": "error",
|
||||
"unicorn/prefer-modern-dom-apis": "error",
|
||||
"unicorn/prefer-modern-math-apis": "error",
|
||||
"unicorn/prefer-negative-index": "error",
|
||||
"unicorn/prefer-optional-catch-binding": "error",
|
||||
"unicorn/prefer-regexp-test": "error",
|
||||
"unicorn/prefer-string-replace-all": "error",
|
||||
"unicorn/prefer-string-starts-ends-with": "error",
|
||||
"unicorn/prefer-ternary": ["error", "only-single-line"],
|
||||
|
||||
// Possible errors
|
||||
"for-direction": "error",
|
||||
"getter-return": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-cond-assign": ["error", "except-parens"],
|
||||
"no-constant-condition": ["error", { "checkLoops": false, }],
|
||||
"no-debugger": "error",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty": ["error", { "allowEmptyCatch": true, }],
|
||||
"no-empty-character-class": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-inner-declarations": ["error", "functions"],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-promise-executor-return": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-setter-return": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unsafe-optional-chaining": ["error", { "disallowArithmeticOperators": true }],
|
||||
"no-unused-private-class-members": "error",
|
||||
"use-isnan": ["error", { "enforceForIndexOf": true, }],
|
||||
"valid-typeof": ["error", { "requireStringLiterals": true, }],
|
||||
|
||||
// Best Practices
|
||||
"accessor-pairs": ["error", {
|
||||
"setWithoutGet": true,
|
||||
"enforceForClassMembers": true,
|
||||
}],
|
||||
"consistent-return": "error",
|
||||
"curly": ["error", "all"],
|
||||
"default-case-last": "error",
|
||||
"dot-notation": "error",
|
||||
"eqeqeq": ["error", "always"],
|
||||
"grouped-accessor-pairs": ["error", "getBeforeSet"],
|
||||
"no-alert": "error",
|
||||
"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-lonely-if": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-new": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-symbol": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-octal": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-await": "error",
|
||||
"no-self-assign": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-return": "error",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-spread": "error",
|
||||
"wrap-iife": ["error", "any"],
|
||||
"yoda": ["error", "never", {
|
||||
"exceptRange": true,
|
||||
}],
|
||||
|
||||
// Strict Mode
|
||||
"strict": ["off", "global"],
|
||||
|
||||
// Variables
|
||||
"no-delete-var": "error",
|
||||
"no-label-var": "error",
|
||||
"no-shadow": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-undef-init": "error",
|
||||
"no-undef": ["error", { "typeof": true, }],
|
||||
"no-unused-vars": ["error", {
|
||||
"vars": "all",
|
||||
"args": "none",
|
||||
}],
|
||||
"no-use-before-define": ["error", {
|
||||
"functions": false,
|
||||
"classes": false,
|
||||
"variables": false,
|
||||
}],
|
||||
|
||||
// Stylistic Issues
|
||||
"lines-between-class-members": ["error", "always"],
|
||||
"max-len": ["error", {
|
||||
"code": 1000,
|
||||
"comments": 80,
|
||||
"ignoreUrls": true
|
||||
}],
|
||||
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
|
||||
"no-array-constructor": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0, "maxBOF": 1, }],
|
||||
"no-nested-ternary": "error",
|
||||
"no-new-object": "error",
|
||||
"no-restricted-syntax": ["error",
|
||||
{
|
||||
"selector": "BinaryExpression[operator='instanceof'][right.name='Object']",
|
||||
"message": "Use `typeof` rather than `instanceof Object`.",
|
||||
},
|
||||
{
|
||||
"selector": "CallExpression[callee.name='assert'][arguments.length!=2]",
|
||||
"message": "`assert()` must always be invoked with two arguments.",
|
||||
},
|
||||
{
|
||||
"selector": "CallExpression[callee.name='isCmd'][arguments.length<2]",
|
||||
"message": "Use `instanceof Cmd` rather than `isCmd()` with one argument.",
|
||||
},
|
||||
{
|
||||
"selector": "CallExpression[callee.name='isDict'][arguments.length<2]",
|
||||
"message": "Use `instanceof Dict` rather than `isDict()` with one argument.",
|
||||
},
|
||||
{
|
||||
"selector": "CallExpression[callee.name='isName'][arguments.length<2]",
|
||||
"message": "Use `instanceof Name` rather than `isName()` with one argument.",
|
||||
},
|
||||
{
|
||||
"selector": "NewExpression[callee.name='Cmd']",
|
||||
"message": "Use `Cmd.get()` rather than `new Cmd()`.",
|
||||
},
|
||||
{
|
||||
"selector": "NewExpression[callee.name='Name']",
|
||||
"message": "Use `Name.get()` rather than `new Name()`.",
|
||||
},
|
||||
{
|
||||
"selector": "NewExpression[callee.name='Ref']",
|
||||
"message": "Use `Ref.get()` rather than `new Ref()`.",
|
||||
},
|
||||
],
|
||||
"no-unneeded-ternary": "error",
|
||||
"operator-assignment": "error",
|
||||
"prefer-exponentiation-operator": "error",
|
||||
"spaced-comment": ["error", "always", {
|
||||
"block": {
|
||||
"balanced": true,
|
||||
}
|
||||
}],
|
||||
|
||||
// ECMAScript 6
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"constructor-super": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-this-before-super": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-var": "error",
|
||||
"object-shorthand": ["error", "always", {
|
||||
"avoidQuotes": true,
|
||||
}],
|
||||
"prefer-const": "error",
|
||||
"require-yield": "error",
|
||||
"sort-imports": ["error", {
|
||||
"ignoreCase": true,
|
||||
}],
|
||||
"template-curly-spacing": ["error", "never"],
|
||||
},
|
||||
}
|
||||
5
.github/ISSUE_TEMPLATE/bug.yml
vendored
5
.github/ISSUE_TEMPLATE/bug.yml
vendored
@ -5,8 +5,6 @@ body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Attach (recommended) or Link to PDF file
|
||||
description: Without this information the issue may be closed without comment
|
||||
placeholder: Please place only the PDF file in this field
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@ -16,7 +14,6 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Web browser and its version
|
||||
description: Please ensure that it's supported, refer to [the FAQ](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@ -27,13 +24,11 @@ body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: PDF.js version
|
||||
description: Please find official releases [here](https://github.com/mozilla/pdf.js/releases)
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Is the bug present in the latest PDF.js version?
|
||||
description: Please check the [online demo](https://github.com/mozilla/pdf.js#online-demo)
|
||||
options: ["Yes", "No"]
|
||||
default: 0
|
||||
validations:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,4 +1,4 @@
|
||||
blank_issues_enabled: false
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Need help?
|
||||
url: https://github.com/mozilla/pdf.js/discussions
|
||||
|
||||
2
.github/fluent_linter_config.yml
vendored
2
.github/fluent_linter_config.yml
vendored
@ -25,5 +25,3 @@ CO01:
|
||||
exclusions:
|
||||
files: []
|
||||
messages: []
|
||||
VC:
|
||||
disabled: false
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -11,16 +11,16 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [20, 22, 24]
|
||||
node-version: [18, lts/*, 21]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
||||
8
.github/workflows/codeql.yml
vendored
8
.github/workflows/codeql.yml
vendored
@ -18,18 +18,18 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: security-and-quality
|
||||
|
||||
- name: Autobuild CodeQL
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v4
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
8
.github/workflows/fluent_linter.yml
vendored
8
.github/workflows/fluent_linter.yml
vendored
@ -25,12 +25,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Use Python 3.14
|
||||
uses: actions/setup-python@v6
|
||||
- name: Use Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.14'
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install Fluent dependencies
|
||||
|
||||
10
.github/workflows/font_tests.yml
vendored
10
.github/workflows/font_tests.yml
vendored
@ -36,22 +36,22 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Use Python 3.14
|
||||
uses: actions/setup-python@v6
|
||||
- name: Use Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.14'
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install Fonttools
|
||||
|
||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@ -15,12 +15,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
||||
8
.github/workflows/publish_release.yml
vendored
8
.github/workflows/publish_release.yml
vendored
@ -17,12 +17,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
@ -34,4 +34,6 @@ jobs:
|
||||
run: npx gulp dist
|
||||
|
||||
- name: Publish the `pdfjs-dist` library to NPM
|
||||
run: npm publish ./build/dist
|
||||
run: npm publish ./build/dist --provenance
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
6
.github/workflows/publish_website.yml
vendored
6
.github/workflows/publish_website.yml
vendored
@ -17,12 +17,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
INPUT_PATH: build/gh-pages
|
||||
|
||||
- name: Upload the website
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: github-pages
|
||||
path: ${{ runner.temp }}/website.tar
|
||||
|
||||
4
.github/workflows/types_tests.yml
vendored
4
.github/workflows/types_tests.yml
vendored
@ -15,12 +15,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
||||
7
.gitpod.Dockerfile
vendored
Normal file
7
.gitpod.Dockerfile
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
FROM gitpod/workspace-full-vnc
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN sudo apt-get update && \
|
||||
sudo apt-get install -yq firefox && \
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
13
.gitpod.yml
Normal file
13
.gitpod.yml
Normal file
@ -0,0 +1,13 @@
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
tasks:
|
||||
- command: |
|
||||
gp await-port 8888 && gp preview $(gp url 8888)/web/viewer.html && echo '[{"name": "Firefox","path": "/usr/bin/firefox"}]' | jq '.' > test/resources/browser_manifests/browser_manifest.json
|
||||
|
||||
- init: npm install -g gulp-cli && npm install
|
||||
command: gulp server
|
||||
ports:
|
||||
- port: 8888
|
||||
onOpen: ignore
|
||||
- port: 6080
|
||||
onOpen: ignore
|
||||
@ -5,10 +5,7 @@ node_modules/
|
||||
external/bcmaps/
|
||||
external/builder/fixtures/
|
||||
external/builder/fixtures_babel/
|
||||
external/openjpeg/
|
||||
external/qcms/
|
||||
external/quickjs/
|
||||
test/stats/results/
|
||||
test/tmp/
|
||||
test/pdfs/
|
||||
web/locale/
|
||||
|
||||
15
.prettierrc
15
.prettierrc
@ -9,17 +9,10 @@
|
||||
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["tsconfig.json", ".prettierrc"],
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
files: ["tsconfig.json"],
|
||||
options: {
|
||||
parser: "json",
|
||||
},
|
||||
},
|
||||
{
|
||||
"files": ["**/*.html"],
|
||||
"options": {
|
||||
"parser": "html",
|
||||
"printWidth": 160
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
{
|
||||
"chrome": {
|
||||
"skipDownload": false
|
||||
},
|
||||
"firefox": {
|
||||
"skipDownload": false,
|
||||
"version": "nightly"
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@ external/bcmaps/
|
||||
external/builder/fixtures/
|
||||
external/builder/fixtures_babel/
|
||||
external/quickjs/
|
||||
test/stats/results/
|
||||
test/tmp/
|
||||
test/pdfs/
|
||||
web/locale/
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
export default {
|
||||
rules: {
|
||||
valid: true,
|
||||
|
||||
custom: [
|
||||
(reporter, $, ast, { filename }) => {
|
||||
reporter.name = "no-svg-fill-context-fill";
|
||||
|
||||
const svg = $.find("svg");
|
||||
const fill = svg.attr("fill");
|
||||
if (fill === "context-fill") {
|
||||
reporter.error(
|
||||
"Fill attribute on svg element must not be set to 'context-fill'",
|
||||
svg[0],
|
||||
ast
|
||||
);
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
ignore: [
|
||||
"build/**",
|
||||
"l10n/**",
|
||||
"docs/**",
|
||||
"node_modules/**",
|
||||
"external/bcmaps/**",
|
||||
"external/builder/fixtures/**",
|
||||
"external/builder/fixtures_babel/**",
|
||||
"external/quickjs/**",
|
||||
"test/tmp/**",
|
||||
"test/pdfs/**",
|
||||
"web/locale/**",
|
||||
"*~/**",
|
||||
],
|
||||
};
|
||||
5
AUTHORS
5
AUTHORS
@ -8,21 +8,16 @@ Andreas Gal <gal@mozilla.com>
|
||||
Artur Adib <aadib@mozilla.com>
|
||||
Brendan Dahl <bdahl@mozilla.com>
|
||||
Bill Walker <bwalker@mozilla.com>
|
||||
Calixte Denizet <calixte@mozilla.com>
|
||||
Chris G Jones <cjones@mozilla.com>
|
||||
David Quintana <gigaherz@gmail.com>
|
||||
Emily Wachowiak <ewachowiak@mozilla.com>
|
||||
Felix Kälberer <@fkaelberer>
|
||||
Jakob Miland <saebekassebil@gmail.com>
|
||||
Jonas Jenwald <jonas.jenwald@gmail.com>
|
||||
Julian Viereck
|
||||
Justin D'Arcangelo <justindarc@gmail.com>
|
||||
Kalervo Kujala
|
||||
Marco Castelluccio <mcastelluccio@mozilla.com>
|
||||
Marie-Lilas Onanga Ozavino <monangaozavino@mozilla.com>
|
||||
Michał Gołębiowski-Owczarek <m.goleb@gmail.com>
|
||||
Ophir Lojkine <@lovasoa>
|
||||
Ryan Casey <rcasey@mozilla.com>
|
||||
Rob Wu <rob@robwu.nl>
|
||||
Shaon Barman <shaon.barman@gmail.com>
|
||||
Sehyun Park <premed055515@gmail.com>
|
||||
|
||||
11
README.md
11
README.md
@ -1,4 +1,4 @@
|
||||
# PDF.js [](https://github.com/mozilla/pdf.js/actions/workflows/ci.yml?query=branch%3Amaster)
|
||||
# PDF.js [](https://github.com/mozilla/pdf.js/actions?query=workflow%3ACI+branch%3Amaster)
|
||||
|
||||
[PDF.js](https://mozilla.github.io/pdf.js/) is a Portable Document Format (PDF) viewer that is built with HTML5.
|
||||
|
||||
@ -14,7 +14,7 @@ get involved, visit:
|
||||
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/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?q=is%3Aissue%20state%3Aopen%20label%3Agood-beginner-bug)
|
||||
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=good-beginner-bug&page=1&sort=created&state=open)
|
||||
+ [Projects](https://github.com/mozilla/pdf.js/projects)
|
||||
|
||||
Feel free to stop by our [Matrix room](https://chat.mozilla.org/#/room/#pdfjs:mozilla.org) for questions or guidance.
|
||||
@ -57,6 +57,9 @@ all dependencies for PDF.js:
|
||||
|
||||
$ npm install
|
||||
|
||||
> [!NOTE]
|
||||
> On MacOS M1/M2 you may see some `node-gyp`-related errors when running `npm install`. This is because one of our dependencies, `"canvas"`, does not provide pre-built binaries for this platform and instead `npm` will try to build it from source. Please make sure to first install the necessary native dependencies using `brew`: https://github.com/Automattic/node-canvas#compiling.
|
||||
|
||||
Finally, you need to start a local web server as some browsers do not allow opening
|
||||
PDF files using a `file://` URL. Run:
|
||||
|
||||
@ -90,7 +93,7 @@ be loaded by `pdf.js`. The PDF.js files are large and should be minified for pro
|
||||
## 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 under
|
||||
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.
|
||||
|
||||
@ -134,4 +137,4 @@ Talk to us on Matrix:
|
||||
|
||||
File an issue:
|
||||
|
||||
+ https://github.com/mozilla/pdf.js/issues/new/choose
|
||||
+ https://github.com/mozilla/pdf.js/issues/new
|
||||
|
||||
@ -1,473 +0,0 @@
|
||||
import globals from "globals";
|
||||
|
||||
import import_ from "eslint-plugin-import";
|
||||
import jasmine from "eslint-plugin-jasmine";
|
||||
import json from "eslint-plugin-json";
|
||||
import noUnsanitized from "eslint-plugin-no-unsanitized";
|
||||
import perfectionist from "eslint-plugin-perfectionist";
|
||||
import prettierRecommended from "eslint-plugin-prettier/recommended";
|
||||
import unicorn from "eslint-plugin-unicorn";
|
||||
|
||||
const jsFiles = folder => {
|
||||
const prefix = folder === "." ? "" : folder + "/";
|
||||
return [prefix + "**/*.js", prefix + "**/*.jsm", prefix + "**/*.mjs"];
|
||||
};
|
||||
|
||||
// Include all files referenced in extensions/chromium/background.js
|
||||
const chromiumExtensionServiceWorkerFiles = [
|
||||
"extensions/chromium/extension-router.js",
|
||||
"extensions/chromium/options/migration.js",
|
||||
"extensions/chromium/pdfHandler.js",
|
||||
"extensions/chromium/preserve-referer.js",
|
||||
"extensions/chromium/suppress-update.js",
|
||||
"extensions/chromium/telemetry.js",
|
||||
];
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: [
|
||||
"**/build/",
|
||||
"**/l10n/",
|
||||
"**/docs/",
|
||||
"**/node_modules/",
|
||||
"external/bcmaps/",
|
||||
"external/builder/fixtures/",
|
||||
"external/builder/fixtures_babel/",
|
||||
"external/openjpeg/",
|
||||
"external/qcms/",
|
||||
"external/quickjs/",
|
||||
"test/stats/results/",
|
||||
"test/tmp/",
|
||||
"test/pdfs/",
|
||||
"web/locale/",
|
||||
"web/wasm/",
|
||||
"**/*~/",
|
||||
],
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
Base configuration
|
||||
\* ======================================================================== */
|
||||
|
||||
prettierRecommended,
|
||||
{
|
||||
files: ["**/*.json"],
|
||||
...json.configs.recommended,
|
||||
},
|
||||
{
|
||||
files: jsFiles("."),
|
||||
ignores: chromiumExtensionServiceWorkerFiles,
|
||||
languageOptions: {
|
||||
globals: globals.browser,
|
||||
},
|
||||
},
|
||||
{
|
||||
files: jsFiles("."),
|
||||
|
||||
plugins: {
|
||||
import: import_.flatConfigs.recommended.plugins.import,
|
||||
json,
|
||||
"no-unsanitized": noUnsanitized,
|
||||
perfectionist,
|
||||
unicorn,
|
||||
},
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.worker,
|
||||
PDFJSDev: "readonly",
|
||||
__raw_import__: "readonly",
|
||||
},
|
||||
|
||||
ecmaVersion: 2025,
|
||||
sourceType: "module",
|
||||
},
|
||||
|
||||
rules: {
|
||||
"import/export": "error",
|
||||
"import/exports-last": "error",
|
||||
"import/extensions": ["error", "always", { ignorePackages: true }],
|
||||
"import/first": "error",
|
||||
"import/named": "error",
|
||||
"import/no-cycle": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-commonjs": "error",
|
||||
"import/no-mutable-exports": "error",
|
||||
"import/no-restricted-paths": [
|
||||
"error",
|
||||
{
|
||||
zones: [
|
||||
{
|
||||
target: "./web",
|
||||
from: "./src",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"import/no-self-import": "error",
|
||||
"import/no-unresolved": [
|
||||
"error",
|
||||
{
|
||||
ignore: [
|
||||
"display",
|
||||
"pdfjs",
|
||||
"pdfjs-lib",
|
||||
"pdfjs-web",
|
||||
"web",
|
||||
"fluent-bundle",
|
||||
"fluent-dom",
|
||||
// See https://github.com/firebase/firebase-admin-node/discussions/1359.
|
||||
"eslint-plugin-perfectionist",
|
||||
],
|
||||
},
|
||||
],
|
||||
"no-unsanitized/method": "error",
|
||||
"no-unsanitized/property": "error",
|
||||
"perfectionist/sort-exports": "error",
|
||||
"perfectionist/sort-named-exports": "error",
|
||||
"unicorn/no-abusive-eslint-disable": "error",
|
||||
"unicorn/no-array-reduce": ["error", { allowSimpleOperations: true }],
|
||||
"unicorn/no-console-spaces": "error",
|
||||
"unicorn/no-instanceof-builtins": "error",
|
||||
"unicorn/no-invalid-remove-event-listener": "error",
|
||||
"unicorn/no-new-buffer": "error",
|
||||
"unicorn/no-single-promise-in-promise-methods": "error",
|
||||
"unicorn/no-typeof-undefined": ["error", { checkGlobalVariables: false }],
|
||||
"unicorn/no-unnecessary-array-flat-depth": "error",
|
||||
"unicorn/no-unnecessary-array-splice-count": "error",
|
||||
"unicorn/no-unnecessary-slice-end": "error",
|
||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
||||
"unicorn/no-useless-spread": "error",
|
||||
"unicorn/prefer-array-find": "error",
|
||||
"unicorn/prefer-array-flat": "error",
|
||||
"unicorn/prefer-array-flat-map": "error",
|
||||
"unicorn/prefer-array-index-of": "error",
|
||||
"unicorn/prefer-array-some": "error",
|
||||
"unicorn/prefer-at": "error",
|
||||
"unicorn/prefer-date-now": "error",
|
||||
"unicorn/prefer-dom-node-append": "error",
|
||||
"unicorn/prefer-dom-node-remove": "error",
|
||||
"unicorn/prefer-import-meta-properties": "error",
|
||||
"unicorn/prefer-includes": "error",
|
||||
"unicorn/prefer-logical-operator-over-ternary": "error",
|
||||
"unicorn/prefer-modern-dom-apis": "error",
|
||||
"unicorn/prefer-modern-math-apis": "error",
|
||||
"unicorn/prefer-negative-index": "error",
|
||||
"unicorn/prefer-optional-catch-binding": "error",
|
||||
"unicorn/prefer-regexp-test": "error",
|
||||
"unicorn/prefer-single-call": "error",
|
||||
"unicorn/prefer-string-replace-all": "error",
|
||||
"unicorn/prefer-string-starts-ends-with": "error",
|
||||
"unicorn/prefer-ternary": ["error", "only-single-line"],
|
||||
"unicorn/throw-new-error": "error",
|
||||
|
||||
// Possible errors
|
||||
"for-direction": "error",
|
||||
"getter-return": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-cond-assign": ["error", "except-parens"],
|
||||
"no-constant-condition": ["error", { checkLoops: false }],
|
||||
"no-debugger": "error",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty": ["error", { allowEmptyCatch: true }],
|
||||
"no-empty-character-class": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-inner-declarations": ["error", "functions"],
|
||||
"no-invalid-regexp": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-obj-calls": "error",
|
||||
"no-promise-executor-return": "error",
|
||||
"no-regex-spaces": "error",
|
||||
"no-setter-return": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unexpected-multiline": "error",
|
||||
"no-unreachable": "error",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unsafe-optional-chaining": [
|
||||
"error",
|
||||
{ disallowArithmeticOperators: true },
|
||||
],
|
||||
"no-unused-private-class-members": "error",
|
||||
"use-isnan": ["error", { enforceForIndexOf: true }],
|
||||
"valid-typeof": ["error", { requireStringLiterals: true }],
|
||||
|
||||
// Best Practices
|
||||
"accessor-pairs": [
|
||||
"error",
|
||||
{ setWithoutGet: true, enforceForClassMembers: true },
|
||||
],
|
||||
"consistent-return": "error",
|
||||
curly: ["error", "all"],
|
||||
"default-case-last": "error",
|
||||
"dot-notation": "error",
|
||||
eqeqeq: ["error", "always"],
|
||||
"grouped-accessor-pairs": ["error", "getBeforeSet"],
|
||||
"no-alert": "error",
|
||||
"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-lonely-if": "error",
|
||||
"no-multi-str": "error",
|
||||
"no-new": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-symbol": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-octal": "error",
|
||||
"no-redeclare": "error",
|
||||
"no-return-await": "error",
|
||||
"no-self-assign": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-labels": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-catch": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-return": "error",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-spread": "error",
|
||||
"wrap-iife": ["error", "any"],
|
||||
yoda: ["error", "never", { exceptRange: true }],
|
||||
|
||||
// Strict Mode
|
||||
strict: ["off", "global"],
|
||||
|
||||
// Variables
|
||||
"no-delete-var": "error",
|
||||
"no-label-var": "error",
|
||||
"no-shadow": "error",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-undef-init": "error",
|
||||
"no-undef": ["error", { typeof: true }],
|
||||
"no-unused-vars": ["error", { vars: "all", args: "none" }],
|
||||
"no-use-before-define": [
|
||||
"error",
|
||||
{ functions: false, classes: false, variables: false },
|
||||
],
|
||||
|
||||
// Stylistic Issues
|
||||
"lines-between-class-members": ["error", "always"],
|
||||
"max-len": ["error", { code: 1000, comments: 80, ignoreUrls: true }],
|
||||
"new-cap": ["error", { newIsCap: true, capIsNew: false }],
|
||||
"no-array-constructor": "error",
|
||||
"no-multiple-empty-lines": ["error", { max: 1, maxEOF: 0, maxBOF: 1 }],
|
||||
"no-nested-ternary": "error",
|
||||
"no-new-object": "error",
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector:
|
||||
"BinaryExpression[operator='instanceof'][right.name='Object']",
|
||||
message: "Use `typeof` rather than `instanceof Object`.",
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='assert'][arguments.length!=2]",
|
||||
message: "`assert()` must always be invoked with two arguments.",
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='isCmd'][arguments.length<2]",
|
||||
message:
|
||||
"Use `instanceof Cmd` rather than `isCmd()` with one argument.",
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='isDict'][arguments.length<2]",
|
||||
message:
|
||||
"Use `instanceof Dict` rather than `isDict()` with one argument.",
|
||||
},
|
||||
{
|
||||
selector: "CallExpression[callee.name='isName'][arguments.length<2]",
|
||||
message:
|
||||
"Use `instanceof Name` rather than `isName()` with one argument.",
|
||||
},
|
||||
{
|
||||
selector: "NewExpression[callee.name='Cmd']",
|
||||
message: "Use `Cmd.get()` rather than `new Cmd()`.",
|
||||
},
|
||||
{
|
||||
selector: "NewExpression[callee.name='Name']",
|
||||
message: "Use `Name.get()` rather than `new Name()`.",
|
||||
},
|
||||
{
|
||||
selector: "NewExpression[callee.name='ObjectLoader']",
|
||||
message:
|
||||
"Use `ObjectLoader.load()` rather than `new ObjectLoader()`.",
|
||||
},
|
||||
{
|
||||
selector: "NewExpression[callee.name='Ref']",
|
||||
message: "Use `Ref.get()` rather than `new Ref()`.",
|
||||
},
|
||||
{
|
||||
selector: "ExportNamedDeclaration[declaration]",
|
||||
message:
|
||||
"Separate the declaration and the export statement, using `export { ... }`.",
|
||||
},
|
||||
{
|
||||
selector: "ExportDefaultDeclaration:has(> :declaration)",
|
||||
message:
|
||||
"Separate the declaration and the export statement, using `export default <variable name>`.",
|
||||
},
|
||||
],
|
||||
"no-unneeded-ternary": "error",
|
||||
"operator-assignment": "error",
|
||||
"prefer-exponentiation-operator": "error",
|
||||
"spaced-comment": ["error", "always", { block: { balanced: true } }],
|
||||
|
||||
// ECMAScript 6
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"constructor-super": "error",
|
||||
"no-class-assign": "error",
|
||||
"no-const-assign": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-this-before-super": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-var": "error",
|
||||
"object-shorthand": ["error", "always", { avoidQuotes: true }],
|
||||
"prefer-const": "error",
|
||||
"require-yield": "error",
|
||||
"sort-imports": ["error", { ignoreCase: true }],
|
||||
"template-curly-spacing": ["error", "never"],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: jsFiles("src"),
|
||||
rules: {
|
||||
"no-console": "error",
|
||||
},
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
Test-specific rules
|
||||
\* ======================================================================== */
|
||||
|
||||
{
|
||||
files: jsFiles("test"),
|
||||
|
||||
plugins: { jasmine },
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.jasmine,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
...jasmine.configs.recommended.rules,
|
||||
"jasmine/new-line-before-expect": "off",
|
||||
"jasmine/new-line-between-declarations": "off",
|
||||
"jasmine/no-focused-tests": "error",
|
||||
"jasmine/no-pending-tests": "off",
|
||||
"jasmine/no-spec-dupes": ["error", "branch"],
|
||||
"jasmine/no-suite-dupes": ["error", "branch"],
|
||||
"jasmine/prefer-jasmine-matcher": "off",
|
||||
"jasmine/prefer-toHaveBeenCalledWith": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: jsFiles("test/unit"),
|
||||
rules: {
|
||||
"import/no-unresolved": ["error", { ignore: ["pdfjs/"] }],
|
||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: jsFiles("test/integration"),
|
||||
rules: {
|
||||
"no-console": ["error", { allow: ["warn", "error"] }],
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector: "CallExpression[callee.name='waitForTimeout']",
|
||||
message:
|
||||
"`waitForTimeout` can cause intermittent failures and should not be used (see issue #17656 for replacements).",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
External libraries
|
||||
\* ======================================================================== */
|
||||
|
||||
{
|
||||
files: jsFiles("external"),
|
||||
|
||||
languageOptions: { globals: globals.node },
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
Examples
|
||||
\* ======================================================================== */
|
||||
|
||||
{
|
||||
files: jsFiles("examples"),
|
||||
|
||||
languageOptions: {
|
||||
globals: {
|
||||
pdfjsImageDecoders: false,
|
||||
pdfjsLib: false,
|
||||
pdfjsViewer: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [...jsFiles("examples/node"), ...jsFiles("examples/webpack")],
|
||||
|
||||
languageOptions: { globals: globals.node },
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
Chromium extension
|
||||
\* ======================================================================== */
|
||||
|
||||
{
|
||||
files: jsFiles("extensions/chromium"),
|
||||
|
||||
languageOptions: {
|
||||
globals: globals.webextensions,
|
||||
sourceType: "script",
|
||||
},
|
||||
|
||||
rules: {
|
||||
"no-var": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: chromiumExtensionServiceWorkerFiles,
|
||||
|
||||
languageOptions: {
|
||||
globals: globals.serviceworker,
|
||||
sourceType: "script",
|
||||
},
|
||||
},
|
||||
|
||||
/* ======================================================================== *\
|
||||
Other
|
||||
\* ======================================================================== */
|
||||
{
|
||||
files: ["gulpfile.mjs"],
|
||||
languageOptions: { globals: globals.node },
|
||||
},
|
||||
];
|
||||
11
examples/.eslintrc
Normal file
11
examples/.eslintrc
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": [
|
||||
"../.eslintrc"
|
||||
],
|
||||
|
||||
"globals": {
|
||||
"pdfjsImageDecoders": false,
|
||||
"pdfjsLib": false,
|
||||
"pdfjsViewer": false,
|
||||
},
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2014 Mozilla Foundation
|
||||
|
||||
@ -15,29 +15,29 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html dir="ltr" mozdisallowselectionprint>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="google" content="notranslate" />
|
||||
<title>PDF.js page viewer using built components</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="google" content="notranslate">
|
||||
<title>PDF.js page viewer using built components</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" />
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
|
||||
<body tabindex="1">
|
||||
<div id="pageContainer" class="pdfViewer singlePageView"></div>
|
||||
<body tabindex="1">
|
||||
<div id="pageContainer" class="pdfViewer singlePageView"></div>
|
||||
|
||||
<script src="pageviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
<script src="pageviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2014 Mozilla Foundation
|
||||
|
||||
@ -15,37 +15,37 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html dir="ltr" mozdisallowselectionprint>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="google" content="notranslate" />
|
||||
<title>PDF.js viewer using built components</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="google" content="notranslate">
|
||||
<title>PDF.js viewer using built components</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#viewerContainer {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#viewerContainer {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" />
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
|
||||
<body tabindex="1">
|
||||
<div id="viewerContainer">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
<body tabindex="1">
|
||||
<div id="viewerContainer">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
|
||||
<script src="simpleviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
<script src="simpleviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2014 Mozilla Foundation
|
||||
|
||||
@ -15,37 +15,37 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html dir="ltr" mozdisallowselectionprint>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="google" content="notranslate" />
|
||||
<title>PDF.js Single Page Viewer using built components</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="google" content="notranslate">
|
||||
<title>PDF.js Single Page Viewer using built components</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#viewerContainer {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#viewerContainer {
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css" />
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
</head>
|
||||
|
||||
<body tabindex="1">
|
||||
<div id="viewerContainer">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
<body tabindex="1">
|
||||
<div id="viewerContainer">
|
||||
<div id="viewer" class="pdfViewer"></div>
|
||||
</div>
|
||||
|
||||
<script src="singlepageviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
<script src="singlepageviewer.mjs" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2018 Mozilla Foundation
|
||||
|
||||
@ -15,26 +15,26 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html dir="ltr" mozdisallowselectionprint>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<meta name="google" content="notranslate" />
|
||||
<title>PDF.js standalone JpegImage parser</title>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="google" content="notranslate">
|
||||
<title>PDF.js standalone JpegImage parser</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
background-color: #808080;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.mjs" type="module"></script>
|
||||
</head>
|
||||
<script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.mjs" type="module"></script>
|
||||
</head>
|
||||
|
||||
<body tabindex="1">
|
||||
<canvas id="jpegCanvas" width="0" height="0"></canvas>
|
||||
<body tabindex="1">
|
||||
<canvas id="jpegCanvas" width="0" height="0"></canvas>
|
||||
|
||||
<script src="jpeg_viewer.mjs" type="module"></script>
|
||||
</body>
|
||||
<script src="jpeg_viewer.mjs" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,71 +1,76 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>'Hello, world!' example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>'Hello, world!' example</h1>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>'Hello, world!' example</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas>
|
||||
<h1>'Hello, world!' example</h1>
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
||||
|
||||
<script id="script" type="module">
|
||||
//
|
||||
// If absolute URL from the remote server is provided, configure the CORS
|
||||
// header on that server.
|
||||
//
|
||||
const url = "./helloworld.pdf";
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
|
||||
//
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
<script id="script" type="module">
|
||||
//
|
||||
// If absolute URL from the remote server is provided, configure the CORS
|
||||
// header on that server.
|
||||
//
|
||||
const url = './helloworld.pdf';
|
||||
|
||||
//
|
||||
// Asynchronous download PDF
|
||||
//
|
||||
const loadingTask = pdfjsLib.getDocument(url);
|
||||
const pdf = await loadingTask.promise;
|
||||
//
|
||||
// Fetch the first page
|
||||
//
|
||||
const page = await pdf.getPage(1);
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({ scale });
|
||||
// Support HiDPI-screens.
|
||||
const outputScale = window.devicePixelRatio || 1;
|
||||
//
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
|
||||
//
|
||||
// Prepare canvas using PDF page dimensions
|
||||
//
|
||||
const canvas = document.getElementById("the-canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
//
|
||||
// Asynchronous download PDF
|
||||
//
|
||||
const loadingTask = pdfjsLib.getDocument(url);
|
||||
const pdf = await loadingTask.promise;
|
||||
//
|
||||
// Fetch the first page
|
||||
//
|
||||
const page = await pdf.getPage(1);
|
||||
const scale = 1.5;
|
||||
const viewport = page.getViewport({ scale });
|
||||
// Support HiDPI-screens.
|
||||
const outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
//
|
||||
// Prepare canvas using PDF page dimensions
|
||||
//
|
||||
const canvas = document.getElementById("the-canvas");
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
</script>
|
||||
const transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
|
||||
<hr />
|
||||
<h2>JavaScript code:</h2>
|
||||
<pre id="code"></pre>
|
||||
<script>
|
||||
document.getElementById("code").textContent = document.getElementById("script").text;
|
||||
</script>
|
||||
</body>
|
||||
//
|
||||
// Render PDF page into canvas context
|
||||
//
|
||||
const renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
<h2>JavaScript code:</h2>
|
||||
<pre id="code"></pre>
|
||||
<script>
|
||||
document.getElementById('code').textContent =
|
||||
document.getElementById('script').text;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,77 +1,81 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>'Hello, world!' base64 example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>'Hello, world!' example</h1>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>'Hello, world!' base64 example</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas>
|
||||
<h1>'Hello, world!' example</h1>
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
||||
|
||||
<script id="script" type="module">
|
||||
// atob() is used to convert base64 encoded PDF to binary-like data.
|
||||
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
|
||||
// Base64_encoding_and_decoding.)
|
||||
var pdfData = atob(
|
||||
"JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog" +
|
||||
"IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv" +
|
||||
"TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K" +
|
||||
"Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg" +
|
||||
"L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+" +
|
||||
"PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u" +
|
||||
"dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq" +
|
||||
"Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU" +
|
||||
"CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu" +
|
||||
"ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g" +
|
||||
"CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw" +
|
||||
"MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v" +
|
||||
"dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G"
|
||||
);
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
|
||||
//
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
<script id="script" type="module">
|
||||
// atob() is used to convert base64 encoded PDF to binary-like data.
|
||||
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
|
||||
// Base64_encoding_and_decoding.)
|
||||
var pdfData = atob(
|
||||
'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
|
||||
'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
|
||||
'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
|
||||
'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
|
||||
'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
|
||||
'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
|
||||
'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
|
||||
'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
|
||||
'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
|
||||
'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
|
||||
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
|
||||
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
|
||||
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
|
||||
|
||||
// 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.
|
||||
var loadingTask = pdfjsLib.getDocument({ data: pdfData });
|
||||
var pdf = await loadingTask.promise;
|
||||
// Fetch the first page.
|
||||
var page = await pdf.getPage(1);
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
//
|
||||
// The workerSrc property shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
|
||||
// Prepare canvas using PDF page dimensions.
|
||||
var canvas = document.getElementById("the-canvas");
|
||||
var context = canvas.getContext("2d");
|
||||
// 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.
|
||||
var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
|
||||
var pdf = await loadingTask.promise;
|
||||
// Fetch the first page.
|
||||
var page = await pdf.getPage(1);
|
||||
var scale = 1.5;
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
// Prepare canvas using PDF page dimensions.
|
||||
var canvas = document.getElementById('the-canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
|
||||
// Render PDF page into canvas context.
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
</script>
|
||||
var transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
|
||||
<hr />
|
||||
<h2>JavaScript code:</h2>
|
||||
<pre id="code"></pre>
|
||||
<script>
|
||||
document.getElementById("code").textContent = document.getElementById("script").text;
|
||||
</script>
|
||||
</body>
|
||||
// Render PDF page into canvas context.
|
||||
var renderContext = {
|
||||
canvasContext: context,
|
||||
transform,
|
||||
viewport,
|
||||
};
|
||||
page.render(renderContext);
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
<h2>JavaScript code:</h2>
|
||||
<pre id="code"></pre>
|
||||
<script>
|
||||
document.getElementById('code').textContent =
|
||||
document.getElementById('script').text;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,134 +1,139 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Previous/Next example</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>'Previous/Next' example</h1>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Previous/Next example</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div>
|
||||
<button id="prev" type="button">Previous</button>
|
||||
<button id="next" type="button">Next</button>
|
||||
|
||||
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
|
||||
</div>
|
||||
<h1>'Previous/Next' example</h1>
|
||||
|
||||
<div>
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr"></canvas>
|
||||
</div>
|
||||
<div>
|
||||
<button id="prev">Previous</button>
|
||||
<button id="next">Next</button>
|
||||
|
||||
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
|
||||
</div>
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<div>
|
||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
||||
</div>
|
||||
|
||||
<script id="script" type="module">
|
||||
//
|
||||
// If absolute URL from the remote server is provided, configure the CORS
|
||||
// header on that server.
|
||||
//
|
||||
var url = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
|
||||
//
|
||||
// In cases when the pdf.worker.js is located at the different folder than the
|
||||
// PDF.js's one, or the PDF.js is executed via eval(), the workerSrc property
|
||||
// shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
||||
<script id="script" type="module">
|
||||
//
|
||||
// If absolute URL from the remote server is provided, configure the CORS
|
||||
// header on that server.
|
||||
//
|
||||
var url = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||
|
||||
var pdfDoc = null,
|
||||
pageNum = 1,
|
||||
pageRendering = false,
|
||||
pageNumPending = null,
|
||||
scale = 0.8,
|
||||
canvas = document.getElementById("the-canvas"),
|
||||
ctx = canvas.getContext("2d");
|
||||
//
|
||||
// In cases when the pdf.worker.js is located at the different folder than the
|
||||
// PDF.js's one, or the PDF.js is executed via eval(), the workerSrc property
|
||||
// shall be specified.
|
||||
//
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
||||
|
||||
/**
|
||||
* Get page info from document, resize canvas accordingly, and render page.
|
||||
* @param num Page number.
|
||||
*/
|
||||
function renderPage(num) {
|
||||
pageRendering = true;
|
||||
// Using promise to fetch the page
|
||||
pdfDoc.getPage(num).then(function (page) {
|
||||
var viewport = page.getViewport({ scale: scale });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
var pdfDoc = null,
|
||||
pageNum = 1,
|
||||
pageRendering = false,
|
||||
pageNumPending = null,
|
||||
scale = 0.8,
|
||||
canvas = document.getElementById('the-canvas'),
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
/**
|
||||
* Get page info from document, resize canvas accordingly, and render page.
|
||||
* @param num Page number.
|
||||
*/
|
||||
function renderPage(num) {
|
||||
pageRendering = true;
|
||||
// Using promise to fetch the page
|
||||
pdfDoc.getPage(num).then(function(page) {
|
||||
var viewport = page.getViewport({ scale: scale, });
|
||||
// Support HiDPI-screens.
|
||||
var outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
var transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
||||
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
transform: transform,
|
||||
viewport: viewport,
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
var transform = outputScale !== 1
|
||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
||||
: null;
|
||||
|
||||
// Wait for rendering to finish
|
||||
renderTask.promise.then(function () {
|
||||
pageRendering = false;
|
||||
if (pageNumPending !== null) {
|
||||
// New page rendering is pending
|
||||
renderPage(pageNumPending);
|
||||
pageNumPending = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
// Render PDF page into canvas context
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
transform: transform,
|
||||
viewport: viewport,
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
|
||||
// Update page counters
|
||||
document.getElementById("page_num").textContent = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* If another page rendering in progress, waits until the rendering is
|
||||
* finished. Otherwise, executes rendering immediately.
|
||||
*/
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
pageNumPending = num;
|
||||
} else {
|
||||
renderPage(num);
|
||||
// Wait for rendering to finish
|
||||
renderTask.promise.then(function () {
|
||||
pageRendering = false;
|
||||
if (pageNumPending !== null) {
|
||||
// New page rendering is pending
|
||||
renderPage(pageNumPending);
|
||||
pageNumPending = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Displays previous page.
|
||||
*/
|
||||
function onPrevPage() {
|
||||
if (pageNum <= 1) {
|
||||
return;
|
||||
}
|
||||
pageNum--;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById("prev").addEventListener("click", onPrevPage);
|
||||
// Update page counters
|
||||
document.getElementById('page_num').textContent = num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays next page.
|
||||
*/
|
||||
function onNextPage() {
|
||||
if (pageNum >= pdfDoc.numPages) {
|
||||
return;
|
||||
}
|
||||
pageNum++;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById("next").addEventListener("click", onNextPage);
|
||||
/**
|
||||
* If another page rendering in progress, waits until the rendering is
|
||||
* finished. Otherwise, executes rendering immediately.
|
||||
*/
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
pageNumPending = num;
|
||||
} else {
|
||||
renderPage(num);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously downloads PDF.
|
||||
*/
|
||||
var loadingTask = pdfjsLib.getDocument(url);
|
||||
pdfDoc = await loadingTask.promise;
|
||||
document.getElementById("page_count").textContent = pdfDoc.numPages;
|
||||
/**
|
||||
* Displays previous page.
|
||||
*/
|
||||
function onPrevPage() {
|
||||
if (pageNum <= 1) {
|
||||
return;
|
||||
}
|
||||
pageNum--;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('prev').addEventListener('click', onPrevPage);
|
||||
|
||||
// Initial/first page rendering
|
||||
renderPage(pageNum);
|
||||
</script>
|
||||
</body>
|
||||
/**
|
||||
* Displays next page.
|
||||
*/
|
||||
function onNextPage() {
|
||||
if (pageNum >= pdfDoc.numPages) {
|
||||
return;
|
||||
}
|
||||
pageNum++;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('next').addEventListener('click', onNextPage);
|
||||
|
||||
/**
|
||||
* Asynchronously downloads PDF.
|
||||
*/
|
||||
var loadingTask = pdfjsLib.getDocument(url);
|
||||
pdfDoc = await loadingTask.promise;
|
||||
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
||||
|
||||
// Initial/first page rendering
|
||||
renderPage(pageNum);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -113,8 +113,8 @@ footer {
|
||||
background-color: rgb(0 0 0 / 0);
|
||||
font-size: 1.2rem;
|
||||
color: rgb(255 255 255 / 1);
|
||||
background-image:
|
||||
url(images/div_line_left.png), url(images/div_line_right.png);
|
||||
background-image: url(images/div_line_left.png),
|
||||
url(images/div_line_right.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left, right;
|
||||
background-size: 0.2rem, 0.2rem;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2016 Mozilla Foundation
|
||||
|
||||
@ -16,13 +16,13 @@ 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" />
|
||||
<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="../../node_modules/pdfjs-dist/web/pdf_viewer.css" />
|
||||
<link rel="stylesheet" type="text/css" href="viewer.css" />
|
||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||
<link rel="stylesheet" type="text/css" href="viewer.css">
|
||||
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
||||
@ -43,15 +43,15 @@ limitations under the License.
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous" type="button"></button>
|
||||
<button class="toolbarButton pageDown" title="Next Page" id="next" type="button"></button>
|
||||
<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" />
|
||||
<input type="number" id="pageNumber" class="toolbarField pageNumber" value="1" size="4" min="1">
|
||||
|
||||
<button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut" type="button"></button>
|
||||
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn" type="button"></button>
|
||||
<button class="toolbarButton zoomOut" title="Zoom Out" id="zoomOut"></button>
|
||||
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
|
||||
</footer>
|
||||
|
||||
<script src="viewer.mjs" type="module"></script>
|
||||
<script src="viewer.mjs" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -91,10 +91,10 @@ const PDFViewerApplication = {
|
||||
let key = "pdfjs-loading-error";
|
||||
if (reason instanceof pdfjsLib.InvalidPDFException) {
|
||||
key = "pdfjs-invalid-file-error";
|
||||
} else if (reason instanceof pdfjsLib.ResponseException) {
|
||||
key = reason.missing
|
||||
? "pdfjs-missing-file-error"
|
||||
: "pdfjs-unexpected-response-error";
|
||||
} else if (reason instanceof pdfjsLib.MissingPDFException) {
|
||||
key = "pdfjs-missing-file-error";
|
||||
} else if (reason instanceof pdfjsLib.UnexpectedResponseException) {
|
||||
key = "pdfjs-unexpected-response-error";
|
||||
}
|
||||
self.l10n.get(key).then(msg => {
|
||||
self.error(msg, { message: reason?.message });
|
||||
|
||||
9
examples/node/.eslintrc
Normal file
9
examples/node/.eslintrc
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": [
|
||||
"../.eslintrc"
|
||||
],
|
||||
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
}
|
||||
@ -9,7 +9,9 @@ Install the dependencies and build the PDF.js library:
|
||||
$ npm install
|
||||
$ gulp dist-install
|
||||
|
||||
Run the example to convert the first page of a PDF file to a PNG image:
|
||||
Install the Node canvas library and run the example to convert the first page of a
|
||||
PDF file to a PNG image:
|
||||
|
||||
$ npm install canvas
|
||||
$ cd examples/node/pdf2png
|
||||
$ node pdf2png.mjs
|
||||
$ node pdf2png.js
|
||||
|
||||
@ -13,9 +13,41 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { strict as assert } from "assert";
|
||||
import Canvas from "canvas";
|
||||
import fs from "fs";
|
||||
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
||||
|
||||
class NodeCanvasFactory {
|
||||
create(width, height) {
|
||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
||||
const canvas = Canvas.createCanvas(width, height);
|
||||
const context = canvas.getContext("2d");
|
||||
return {
|
||||
canvas,
|
||||
context,
|
||||
};
|
||||
}
|
||||
|
||||
reset(canvasAndContext, width, height) {
|
||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
||||
canvasAndContext.canvas.width = width;
|
||||
canvasAndContext.canvas.height = height;
|
||||
}
|
||||
|
||||
destroy(canvasAndContext) {
|
||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
||||
|
||||
// Zeroing the width and height cause Firefox to release graphics
|
||||
// resources immediately, which can greatly reduce memory consumption.
|
||||
canvasAndContext.canvas.width = 0;
|
||||
canvasAndContext.canvas.height = 0;
|
||||
canvasAndContext.canvas = null;
|
||||
canvasAndContext.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Some PDFs need external cmaps.
|
||||
const CMAP_URL = "../../../node_modules/pdfjs-dist/cmaps/";
|
||||
const CMAP_PACKED = true;
|
||||
@ -24,6 +56,8 @@ const CMAP_PACKED = true;
|
||||
const STANDARD_FONT_DATA_URL =
|
||||
"../../../node_modules/pdfjs-dist/standard_fonts/";
|
||||
|
||||
const canvasFactory = new NodeCanvasFactory();
|
||||
|
||||
// Loading file from file system into typed array.
|
||||
const pdfPath =
|
||||
process.argv[2] || "../../../web/compressed.tracemonkey-pldi-09.pdf";
|
||||
@ -35,6 +69,7 @@ const loadingTask = getDocument({
|
||||
cMapUrl: CMAP_URL,
|
||||
cMapPacked: CMAP_PACKED,
|
||||
standardFontDataUrl: STANDARD_FONT_DATA_URL,
|
||||
canvasFactory,
|
||||
});
|
||||
|
||||
try {
|
||||
@ -43,7 +78,6 @@ try {
|
||||
// Get the first page.
|
||||
const page = await pdfDocument.getPage(1);
|
||||
// Render the page on a Node canvas with 100% scale.
|
||||
const canvasFactory = pdfDocument.canvasFactory;
|
||||
const viewport = page.getViewport({ scale: 1.0 });
|
||||
const canvasAndContext = canvasFactory.create(
|
||||
viewport.width,
|
||||
@ -57,7 +91,7 @@ try {
|
||||
const renderTask = page.render(renderContext);
|
||||
await renderTask.promise;
|
||||
// Convert the canvas to an image buffer.
|
||||
const image = canvasAndContext.canvas.toBuffer("image/png");
|
||||
const image = canvasAndContext.canvas.toBuffer();
|
||||
fs.writeFile("output.png", image, function (error) {
|
||||
if (error) {
|
||||
console.error("Error: " + error);
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Text-only PDF.js example</title>
|
||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
||||
<script src="pdf2svg.mjs" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Text-only PDF.js example</p>
|
||||
<div id="pageContainer" style="display: inline-block; border: solid 1px black"></div>
|
||||
</body>
|
||||
</head>
|
||||
<body>
|
||||
<p>Text-only PDF.js example</p>
|
||||
<div id="pageContainer" style="display: inline-block; border: solid 1px black;">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
9
examples/webpack/.eslintrc
Normal file
9
examples/webpack/.eslintrc
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": [
|
||||
"../.eslintrc"
|
||||
],
|
||||
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>webpack example</title>
|
||||
<script src="../../build/webpack/main.bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="theCanvas"></canvas>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>webpack example</title>
|
||||
<script src="../../build/webpack/main.bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="theCanvas"></canvas>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
22
extensions/chromium/.eslintrc
Normal file
22
extensions/chromium/.eslintrc
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": [
|
||||
../../.eslintrc
|
||||
],
|
||||
|
||||
"env": {
|
||||
"webextensions": true
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"mozilla"
|
||||
],
|
||||
|
||||
"parserOptions": {
|
||||
"sourceType": "script"
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"mozilla/import-globals": "error",
|
||||
"no-var": "off",
|
||||
},
|
||||
}
|
||||
@ -16,16 +16,13 @@ limitations under the License.
|
||||
|
||||
"use strict";
|
||||
|
||||
var VIEWER_URL = chrome.runtime.getURL("content/web/viewer.html");
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
|
||||
function getViewerURL(pdf_url) {
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
||||
}
|
||||
|
||||
document.addEventListener("animationstart", onAnimationStart, true);
|
||||
if (document.contentType === "application/pdf") {
|
||||
chrome.runtime.sendMessage({ action: "canRequestBody" }, maybeRenderPdfDoc);
|
||||
}
|
||||
|
||||
function onAnimationStart(event) {
|
||||
if (event.animationName === "pdfjs-detected-object-or-embed") {
|
||||
@ -224,38 +221,3 @@ function getEmbeddedViewerURL(path) {
|
||||
path = a.href;
|
||||
return getViewerURL(path) + fragment;
|
||||
}
|
||||
|
||||
function maybeRenderPdfDoc(isNotPOST) {
|
||||
if (!isNotPOST) {
|
||||
// The document was loaded through a POST request, but we cannot access the
|
||||
// original response body, nor safely send a new request to fetch the PDF.
|
||||
// Until #4483 is fixed, POST requests should be ignored.
|
||||
return;
|
||||
}
|
||||
|
||||
// Detected PDF that was not redirected by the declarativeNetRequest rules.
|
||||
// Maybe because this was served without Content-Type and sniffed as PDF.
|
||||
// Or because this is Chrome 127-, which does not support responseHeaders
|
||||
// condition in declarativeNetRequest (DNR), and PDF requests are therefore
|
||||
// not redirected via DNR.
|
||||
|
||||
// In any case, load the viewer.
|
||||
console.log(`Detected PDF via document, opening viewer for ${document.URL}`);
|
||||
|
||||
// Ideally we would use logic consistent with the DNR logic, like this:
|
||||
// location.href = getEmbeddedViewerURL(document.URL);
|
||||
// ... unfortunately, this causes Chrome to crash until version 129, fixed by
|
||||
// https://chromium.googlesource.com/chromium/src/+/8c42358b2cc549553d939efe7d36515d80563da7%5E%21/
|
||||
// Work around this by replacing the body with an iframe of the viewer.
|
||||
// Interestingly, Chrome's built-in PDF viewer uses a similar technique.
|
||||
const shadowRoot = document.body.attachShadow({ mode: "closed" });
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.style.position = "absolute";
|
||||
iframe.style.top = "0";
|
||||
iframe.style.left = "0";
|
||||
iframe.style.width = "100%";
|
||||
iframe.style.height = "100%";
|
||||
iframe.style.border = "0 none";
|
||||
iframe.src = getEmbeddedViewerURL(document.URL);
|
||||
shadowRoot.append(iframe);
|
||||
}
|
||||
|
||||
@ -17,12 +17,13 @@ limitations under the License.
|
||||
"use strict";
|
||||
|
||||
(function ExtensionRouterClosure() {
|
||||
var VIEWER_URL = chrome.runtime.getURL("content/web/viewer.html");
|
||||
var CRX_BASE_URL = chrome.runtime.getURL("/");
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
var CRX_BASE_URL = chrome.extension.getURL("/");
|
||||
|
||||
var schemes = [
|
||||
"http",
|
||||
"https",
|
||||
"ftp",
|
||||
"file",
|
||||
"chrome-extension",
|
||||
"blob",
|
||||
@ -46,7 +47,6 @@ limitations under the License.
|
||||
}
|
||||
var scheme = url.slice(0, schemeIndex).toLowerCase();
|
||||
if (schemes.includes(scheme)) {
|
||||
// NOTE: We cannot use the `updateUrlHash` function in this context.
|
||||
url = url.split("#", 1)[0];
|
||||
if (url.charAt(schemeIndex) === ":") {
|
||||
url = encodeURIComponent(url);
|
||||
@ -56,50 +56,73 @@ limitations under the License.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveViewerURL(originalUrl) {
|
||||
if (originalUrl.startsWith(CRX_BASE_URL)) {
|
||||
// TODO(rob): Use declarativeWebRequest once declared URL-encoding is
|
||||
// supported, see http://crbug.com/273589
|
||||
// (or rewrite the query string parser in viewer.js to get it to
|
||||
// recognize the non-URL-encoded PDF URL.)
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
function (details) {
|
||||
// This listener converts chrome-extension://.../http://...pdf to
|
||||
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
|
||||
var url = parseExtensionURL(originalUrl);
|
||||
var url = parseExtensionURL(details.url);
|
||||
if (url) {
|
||||
url = VIEWER_URL + "?file=" + url;
|
||||
var i = originalUrl.indexOf("#");
|
||||
var i = details.url.indexOf("#");
|
||||
if (i > 0) {
|
||||
url += originalUrl.slice(i);
|
||||
url += details.url.slice(i);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
self.addEventListener("fetch", event => {
|
||||
const req = event.request;
|
||||
if (req.destination === "document") {
|
||||
var url = resolveViewerURL(req.url);
|
||||
if (url) {
|
||||
console.log("Redirecting " + req.url + " to " + url);
|
||||
event.respondWith(Response.redirect(url));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ctrl + F5 bypasses service worker. the pretty extension URLs will fail to
|
||||
// resolve in that case. Catch this and redirect to destination.
|
||||
chrome.webNavigation.onErrorOccurred.addListener(
|
||||
details => {
|
||||
if (details.frameId !== 0) {
|
||||
// Not a top-level frame. Cannot easily navigate a specific child frame.
|
||||
return;
|
||||
}
|
||||
const url = resolveViewerURL(details.url);
|
||||
if (url) {
|
||||
console.log(`Redirecting ${details.url} to ${url} (fallback)`);
|
||||
chrome.tabs.update(details.tabId, { url });
|
||||
console.log("Redirecting " + details.url + " to " + url);
|
||||
return { redirectUrl: url };
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
{ url: [{ urlPrefix: CRX_BASE_URL }] }
|
||||
{
|
||||
types: ["main_frame", "sub_frame"],
|
||||
urls: schemes.map(function (scheme) {
|
||||
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
|
||||
return CRX_BASE_URL + scheme + "*";
|
||||
}),
|
||||
},
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
// When session restore is used, viewer pages may be loaded before the
|
||||
// webRequest event listener is attached (= page not found).
|
||||
// Or the extension could have been crashed (OOM), leaving a sad tab behind.
|
||||
// Reload these tabs.
|
||||
chrome.tabs.query(
|
||||
{
|
||||
url: CRX_BASE_URL + "*:*",
|
||||
},
|
||||
function (tabsFromLastSession) {
|
||||
for (const { id } of tabsFromLastSession) {
|
||||
chrome.tabs.reload(id);
|
||||
}
|
||||
}
|
||||
);
|
||||
console.log("Set up extension URL router.");
|
||||
|
||||
Object.keys(localStorage).forEach(function (key) {
|
||||
// The localStorage item is set upon unload by chromecom.js.
|
||||
var parsedKey = /^unload-(\d+)-(true|false)-(.+)/.exec(key);
|
||||
if (parsedKey) {
|
||||
var timeStart = parseInt(parsedKey[1], 10);
|
||||
var isHidden = parsedKey[2] === "true";
|
||||
var url = parsedKey[3];
|
||||
if (Date.now() - timeStart < 3000) {
|
||||
// Is it a new item (younger than 3 seconds)? Assume that the extension
|
||||
// just reloaded, so restore the tab (work-around for crbug.com/511670).
|
||||
chrome.tabs.create({
|
||||
url:
|
||||
chrome.runtime.getURL("restoretab.html") +
|
||||
"?" +
|
||||
encodeURIComponent(url) +
|
||||
"#" +
|
||||
encodeURIComponent(localStorage.getItem(key)),
|
||||
active: !isHidden,
|
||||
});
|
||||
}
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
BIN
extensions/chromium/icon19.png
Normal file
BIN
extensions/chromium/icon19.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 679 B |
BIN
extensions/chromium/icon38.png
Normal file
BIN
extensions/chromium/icon38.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"minimum_chrome_version": "103",
|
||||
"manifest_version": 3,
|
||||
"minimum_chrome_version": "88",
|
||||
"manifest_version": 2,
|
||||
"name": "PDF Viewer",
|
||||
"version": "PDFJSSCRIPT_VERSION",
|
||||
"description": "Uses HTML5 to display PDF files directly in the browser.",
|
||||
@ -10,52 +10,61 @@
|
||||
"16": "icon16.png"
|
||||
},
|
||||
"permissions": [
|
||||
"alarms",
|
||||
"declarativeNetRequestWithHostAccess",
|
||||
"fileBrowserHandler",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"<all_urls>",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"storage"
|
||||
],
|
||||
"host_permissions": ["<all_urls>"],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["http://*/*", "https://*/*", "file://*/*"],
|
||||
"matches": ["http://*/*", "https://*/*", "ftp://*/*", "file://*/*"],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true,
|
||||
"css": ["contentstyle.css"],
|
||||
"js": ["contentscript.js"]
|
||||
}
|
||||
],
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self'"
|
||||
},
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"file_browser_handlers": [
|
||||
{
|
||||
"id": "open-as-pdf",
|
||||
"default_title": "Open with PDF Viewer",
|
||||
"file_filters": ["filesystem:*.pdf"]
|
||||
}
|
||||
],
|
||||
"storage": {
|
||||
"managed_schema": "preferences_schema.json"
|
||||
},
|
||||
"options_ui": {
|
||||
"page": "options/options.html"
|
||||
"page": "options/options.html",
|
||||
"chrome_style": true
|
||||
},
|
||||
"options_page": "options/options.html",
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
"page": "pdfHandler.html"
|
||||
},
|
||||
"page_action": {
|
||||
"default_icon": {
|
||||
"19": "icon19.png",
|
||||
"38": "icon38.png"
|
||||
},
|
||||
"default_title": "Show PDF URL",
|
||||
"default_popup": "pageActionPopup.html"
|
||||
},
|
||||
"incognito": "split",
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [
|
||||
"content/web/viewer.html",
|
||||
"http:/*",
|
||||
"https:/*",
|
||||
"file:/*",
|
||||
"chrome-extension:/*",
|
||||
"blob:*",
|
||||
"data:*",
|
||||
"filesystem:/*",
|
||||
"drive:*"
|
||||
],
|
||||
"matches": ["<all_urls>"],
|
||||
"extension_ids": ["*"]
|
||||
}
|
||||
"content/web/viewer.html",
|
||||
"http:/*",
|
||||
"https:/*",
|
||||
"ftp:/*",
|
||||
"file:/*",
|
||||
"chrome-extension:/*",
|
||||
"blob:*",
|
||||
"data:*",
|
||||
"filesystem:/*",
|
||||
"drive:*"
|
||||
]
|
||||
}
|
||||
|
||||
@ -13,14 +13,10 @@ 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";
|
||||
/* eslint strict: ["error", "function"] */
|
||||
|
||||
chrome.runtime.onInstalled.addListener(({ reason }) => {
|
||||
if (reason !== "update") {
|
||||
// We only need to run migration logic for extension updates, not for new
|
||||
// installs or browser updates.
|
||||
return;
|
||||
}
|
||||
(function () {
|
||||
"use strict";
|
||||
var storageLocal = chrome.storage.local;
|
||||
var storageSync = chrome.storage.sync;
|
||||
|
||||
@ -41,12 +37,16 @@ chrome.runtime.onInstalled.addListener(({ reason }) => {
|
||||
});
|
||||
});
|
||||
|
||||
async function getStorageNames(callback) {
|
||||
function getStorageNames(callback) {
|
||||
var x = new XMLHttpRequest();
|
||||
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
||||
var res = await fetch(chrome.runtime.getURL(schema_location));
|
||||
var storageManifest = await res.json();
|
||||
var storageKeys = Object.keys(storageManifest.properties);
|
||||
callback(storageKeys);
|
||||
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
|
||||
@ -150,4 +150,4 @@ chrome.runtime.onInstalled.addListener(({ reason }) => {
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
@ -15,171 +15,166 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>PDF.js viewer options</title>
|
||||
<style>
|
||||
body {
|
||||
min-width: 400px; /* a page at the settings page is at least 400px wide */
|
||||
margin: 14px 17px; /* already added by default in Chrome 40.0.2212.0 */
|
||||
}
|
||||
.settings-row {
|
||||
margin: 1em 0;
|
||||
}
|
||||
.checkbox label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
.checkbox label input {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings-boxes"></div>
|
||||
<button id="reset-button" type="button">Restore default settings</button>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>PDF.js viewer options</title>
|
||||
<style>
|
||||
/* TODO: Remove as much custom CSS as possible - crbug.com/446511 */
|
||||
body {
|
||||
min-width: 400px; /* a page at the settings page is at least 400px wide */
|
||||
margin: 14px 17px; /* already added by default in Chrome 40.0.2212.0 */
|
||||
}
|
||||
.settings-row {
|
||||
margin: 0.65em 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="settings-boxes"></div>
|
||||
<button id="reset-button">Restore default settings</button>
|
||||
|
||||
<template id="checkbox-template">
|
||||
<div class="settings-row checkbox">
|
||||
<label>
|
||||
<input type="checkbox" />
|
||||
<span></span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="checkbox-template">
|
||||
<!-- Chromium's style: //src/extensions/renderer/resources/extension.css -->
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox">
|
||||
<span></span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="viewerCssTheme-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Use system theme</option>
|
||||
<option value="1">Light theme</option>
|
||||
<option value="2">Dark theme</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="viewerCssTheme-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Use system theme</option>
|
||||
<option value="1">Light theme</option>
|
||||
<option value="2">Dark theme</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="viewOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">Show previous position</option>
|
||||
<option value="1">Show initial position</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="viewOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">Show previous position</option>
|
||||
<option value="1">Show initial position</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="defaultZoomValue-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="auto" selected="selected">Automatic Zoom</option>
|
||||
<option value="page-actual">Actual Size</option>
|
||||
<option value="page-fit">Page Fit</option>
|
||||
<option value="page-width">Page Width</option>
|
||||
<option value="custom" class="custom-zoom" hidden></option>
|
||||
<option value="50">50%</option>
|
||||
<option value="75">75%</option>
|
||||
<option value="100">100%</option>
|
||||
<option value="125">125%</option>
|
||||
<option value="150">150%</option>
|
||||
<option value="200">200%</option>
|
||||
<option value="300">300%</option>
|
||||
<option value="400">400%</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="defaultZoomValue-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="auto" selected="selected">Automatic Zoom</option>
|
||||
<option value="page-actual">Actual Size</option>
|
||||
<option value="page-fit">Page Fit</option>
|
||||
<option value="page-width">Page Width</option>
|
||||
<option value="custom" class="custom-zoom" hidden></option>
|
||||
<option value="50">50%</option>
|
||||
<option value="75">75%</option>
|
||||
<option value="100">100%</option>
|
||||
<option value="125">125%</option>
|
||||
<option value="150">150%</option>
|
||||
<option value="200">200%</option>
|
||||
<option value="300">300%</option>
|
||||
<option value="400">400%</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="sidebarViewOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">Do not show sidebar</option>
|
||||
<option value="1">Show thumbnails in sidebar</option>
|
||||
<option value="2">Show document outline in sidebar</option>
|
||||
<option value="3">Show attachments in sidebar</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="sidebarViewOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">Do not show sidebar</option>
|
||||
<option value="1">Show thumbnails in sidebar</option>
|
||||
<option value="2">Show document outline in sidebar</option>
|
||||
<option value="3">Show attachments in sidebar</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="cursorToolOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Text selection tool</option>
|
||||
<option value="1">Hand tool</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="cursorToolOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Text selection tool</option>
|
||||
<option value="1">Hand tool</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="textLayerMode-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Disable text selection</option>
|
||||
<option value="1">Enable text selection</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="textLayerMode-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="0">Disable text selection</option>
|
||||
<option value="1">Enable text selection</option>
|
||||
</select>
|
||||
</label>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
<template id="scrollModeOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="3">Page scrolling</option>
|
||||
<option value="0">Vertical scrolling</option>
|
||||
<option value="1">Horizontal scrolling</option>
|
||||
<option value="2">Wrapped scrolling</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="scrollModeOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="3">Page scrolling</option>
|
||||
<option value="0">Vertical scrolling</option>
|
||||
<option value="1">Horizontal scrolling</option>
|
||||
<option value="2">Wrapped scrolling</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="spreadModeOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">No spreads</option>
|
||||
<option value="1">Odd spreads</option>
|
||||
<option value="2">Even spreads</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template id="spreadModeOnLoad-template">
|
||||
<div class="settings-row">
|
||||
<label>
|
||||
<span></span>
|
||||
<select>
|
||||
<option value="-1">Default</option>
|
||||
<option value="0">No spreads</option>
|
||||
<option value="1">Odd spreads</option>
|
||||
<option value="2">Even spreads</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="options.js"></script>
|
||||
</body>
|
||||
<script src="options.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
45
extensions/chromium/pageAction/background.js
Normal file
45
extensions/chromium/pageAction/background.js
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
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.
|
||||
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";
|
||||
|
||||
(function PageActionClosure() {
|
||||
/**
|
||||
* @param {number} tabId - ID of tab where the page action will be shown.
|
||||
* @param {string} url - URL to be displayed in page action.
|
||||
*/
|
||||
function showPageAction(tabId, displayUrl) {
|
||||
// rewriteUrlClosure in viewer.js ensures that the URL looks like
|
||||
// chrome-extension://[extensionid]/http://example.com/file.pdf
|
||||
var url = /^chrome-extension:\/\/[a-p]{32}\/([^#]+)/.exec(displayUrl);
|
||||
if (url) {
|
||||
url = url[1];
|
||||
chrome.pageAction.setPopup({
|
||||
tabId,
|
||||
popup: "/pageAction/popup.html?file=" + encodeURIComponent(url),
|
||||
});
|
||||
chrome.pageAction.show(tabId);
|
||||
} else {
|
||||
console.log("Unable to get PDF url from " + displayUrl);
|
||||
}
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (message, sender) {
|
||||
if (message === "showPageAction" && sender.tab) {
|
||||
showPageAction(sender.tab.id, sender.tab.url);
|
||||
}
|
||||
});
|
||||
})();
|
||||
44
extensions/chromium/pageAction/popup.html
Normal file
44
extensions/chromium/pageAction/popup.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
Copyright 2012 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<style>
|
||||
html {
|
||||
/* maximum width of popup as defined in Chromium's source code as kMaxWidth
|
||||
//src/chrome/browser/ui/views/extensions/extension_popup.cc
|
||||
//src/chrome/browser/ui/gtk/extensions/extension_popup_gtk.cc
|
||||
*/
|
||||
width: 800px;
|
||||
/* in case Chromium decides to lower the value of kMaxWidth */
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body contentEditable="plaintext-only" spellcheck="false">
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
25
extensions/chromium/pageAction/popup.js
Normal file
25
extensions/chromium/pageAction/popup.js
Normal file
@ -0,0 +1,25 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var url = location.search.match(/[&?]file=([^&]+)/i);
|
||||
if (url) {
|
||||
url = decodeURIComponent(url[1]);
|
||||
document.body.textContent = url;
|
||||
// Set cursor to end of the content-editable section.
|
||||
window.getSelection().selectAllChildren(document.body);
|
||||
window.getSelection().collapseToEnd();
|
||||
}
|
||||
102
extensions/chromium/pdfHandler-vcros.js
Normal file
102
extensions/chromium/pdfHandler-vcros.js
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
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.
|
||||
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"] */
|
||||
/* import-globals-from pdfHandler.js */
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
if (!chrome.fileBrowserHandler) {
|
||||
// Not on Chromium OS, bail out
|
||||
return;
|
||||
}
|
||||
chrome.fileBrowserHandler.onExecute.addListener(onExecuteFileBrowserHandler);
|
||||
|
||||
/**
|
||||
* Invoked when "Open with PDF Viewer" is chosen in the File browser.
|
||||
*
|
||||
* @param {string} id File browser action ID as specified in
|
||||
* manifest.json
|
||||
* @param {Object} details Object of type FileHandlerExecuteEventDetails
|
||||
*/
|
||||
function onExecuteFileBrowserHandler(id, details) {
|
||||
if (id !== "open-as-pdf") {
|
||||
return;
|
||||
}
|
||||
var fileEntries = details.entries;
|
||||
// "tab_id" is the currently documented format, but it is inconsistent with
|
||||
// the other Chrome APIs that use "tabId" (http://crbug.com/179767)
|
||||
var tabId = details.tab_id || details.tabId;
|
||||
if (tabId > 0) {
|
||||
chrome.tabs.get(tabId, function (tab) {
|
||||
openViewer(tab && tab.windowId, fileEntries);
|
||||
});
|
||||
} else {
|
||||
// Re-use existing window, if available.
|
||||
chrome.windows.getLastFocused(function (chromeWindow) {
|
||||
var windowId = chromeWindow && chromeWindow.id;
|
||||
if (windowId) {
|
||||
chrome.windows.update(windowId, { focused: true });
|
||||
}
|
||||
openViewer(windowId, fileEntries);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the PDF Viewer for the given list of PDF files.
|
||||
*
|
||||
* @param {number} windowId
|
||||
* @param {Array} fileEntries List of Entry objects (HTML5 FileSystem API)
|
||||
*/
|
||||
function openViewer(windowId, fileEntries) {
|
||||
if (!fileEntries.length) {
|
||||
return;
|
||||
}
|
||||
var fileEntry = fileEntries.shift();
|
||||
var url = fileEntry.toURL();
|
||||
// Use drive: alias to get shorter (more human-readable) URLs.
|
||||
url = url.replace(
|
||||
/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//,
|
||||
"drive:"
|
||||
);
|
||||
url = getViewerURL(url);
|
||||
|
||||
if (windowId) {
|
||||
chrome.tabs.create(
|
||||
{
|
||||
windowId,
|
||||
active: true,
|
||||
url,
|
||||
},
|
||||
function () {
|
||||
openViewer(windowId, fileEntries);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
chrome.windows.create(
|
||||
{
|
||||
type: "normal",
|
||||
focused: true,
|
||||
url,
|
||||
},
|
||||
function (chromeWindow) {
|
||||
openViewer(chromeWindow.id, fileEntries);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
})();
|
||||
24
extensions/chromium/pdfHandler.html
Normal file
24
extensions/chromium/pdfHandler.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!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.
|
||||
-->
|
||||
<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-vcros.js"></script>
|
||||
<script src="pageAction/background.js"></script>
|
||||
<script src="suppress-update.js"></script>
|
||||
<script src="telemetry.js"></script>
|
||||
@ -13,256 +13,11 @@ 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 canRequestBody */ // From preserve-referer.js
|
||||
/* import-globals-from preserve-referer.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
var VIEWER_URL = chrome.runtime.getURL("content/web/viewer.html");
|
||||
|
||||
// Use in-memory storage to ensure that the DNR rules have been registered at
|
||||
// least once per session. runtime.onInstalled would have been the most fitting
|
||||
// event to ensure that, except there are cases where it does not fire when
|
||||
// needed. E.g. in incognito mode: https://issues.chromium.org/issues/41029550
|
||||
chrome.storage.session.get({ hasPdfRedirector: false }, async items => {
|
||||
if (items?.hasPdfRedirector) {
|
||||
return;
|
||||
}
|
||||
const rules = await chrome.declarativeNetRequest.getDynamicRules();
|
||||
if (rules.length) {
|
||||
// Dynamic rules persist across extension updates. We don't expect other
|
||||
// dynamic rules, so just remove them all.
|
||||
await chrome.declarativeNetRequest.updateDynamicRules({
|
||||
removeRuleIds: rules.map(r => r.id),
|
||||
});
|
||||
}
|
||||
await registerPdfRedirectRule();
|
||||
|
||||
// Only set the flag in the end, so that we know for sure that all
|
||||
// asynchronous initialization logic has run. If not, then we will run the
|
||||
// logic again at the next background wakeup.
|
||||
chrome.storage.session.set({ hasPdfRedirector: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers declarativeNetRequest rules to redirect PDF requests to the viewer.
|
||||
* The caller should clear any previously existing dynamic DNR rules.
|
||||
*
|
||||
* The logic here is the declarative version of the runtime logic in the
|
||||
* webRequest.onHeadersReceived implementation at
|
||||
* https://github.com/mozilla/pdf.js/blob/0676ea19cf17023ec8c2d6ad69a859c345c01dc1/extensions/chromium/pdfHandler.js#L34-L152
|
||||
*/
|
||||
async function registerPdfRedirectRule() {
|
||||
// "allow" means to ignore rules (from this extension) with lower priority.
|
||||
const ACTION_IGNORE_OTHER_RULES = { type: "allow" };
|
||||
|
||||
// Redirect to viewer. The rule condition is expected to specify regexFilter
|
||||
// that matches the full request URL.
|
||||
const ACTION_REDIRECT_TO_VIEWER = {
|
||||
type: "redirect",
|
||||
redirect: {
|
||||
// DNR does not support transformations such as encodeURIComponent on the
|
||||
// match, so we just concatenate the URL as is without modifications.
|
||||
// TODO: use "?file=\\0" when DNR supports transformations as proposed at
|
||||
// https://github.com/w3c/webextensions/issues/636#issuecomment-2165978322
|
||||
regexSubstitution: VIEWER_URL + "?DNR:\\0",
|
||||
},
|
||||
};
|
||||
|
||||
// Rules in order of priority (highest priority rule first).
|
||||
// The required "id" fields will be auto-generated later.
|
||||
const addRules = [
|
||||
{
|
||||
// Do not redirect for URLs containing pdfjs.action=download.
|
||||
condition: {
|
||||
urlFilter: "pdfjs.action=download",
|
||||
resourceTypes: ["main_frame", "sub_frame"],
|
||||
},
|
||||
action: ACTION_IGNORE_OTHER_RULES,
|
||||
},
|
||||
{
|
||||
// Redirect local PDF files if isAllowedFileSchemeAccess is true. No-op
|
||||
// otherwise and then handled by webNavigation.onBeforeNavigate below.
|
||||
condition: {
|
||||
regexFilter: "^file://.*\\.pdf$",
|
||||
resourceTypes: ["main_frame", "sub_frame"],
|
||||
},
|
||||
action: ACTION_REDIRECT_TO_VIEWER,
|
||||
},
|
||||
{
|
||||
// Respect the Content-Disposition:attachment header in sub_frame. But:
|
||||
// Display the PDF viewer regardless of the Content-Disposition header if
|
||||
// the file is displayed in the main frame, since most often users want to
|
||||
// view a PDF, and servers are often misconfigured.
|
||||
condition: {
|
||||
urlFilter: "*",
|
||||
resourceTypes: ["sub_frame"], // Note: no main_frame, handled below.
|
||||
responseHeaders: [
|
||||
{
|
||||
header: "content-disposition",
|
||||
values: ["attachment*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
action: ACTION_IGNORE_OTHER_RULES,
|
||||
},
|
||||
{
|
||||
// If the query string contains "=download", do not unconditionally force
|
||||
// viewer to open the PDF, but first check whether the Content-Disposition
|
||||
// header specifies an attachment. This allows sites like Google Drive to
|
||||
// operate correctly (#6106).
|
||||
condition: {
|
||||
urlFilter: "=download",
|
||||
resourceTypes: ["main_frame"], // No sub_frame, was handled before.
|
||||
responseHeaders: [
|
||||
{
|
||||
header: "content-disposition",
|
||||
values: ["attachment*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
action: ACTION_IGNORE_OTHER_RULES,
|
||||
},
|
||||
{
|
||||
// Regular http(s) PDF requests.
|
||||
condition: {
|
||||
regexFilter: "^.*$",
|
||||
// The viewer does not have the original request context and issues a
|
||||
// GET request. The original response to POST requests is unavailable.
|
||||
excludedRequestMethods: ["post"],
|
||||
resourceTypes: ["main_frame", "sub_frame"],
|
||||
responseHeaders: [
|
||||
{
|
||||
header: "content-type",
|
||||
values: ["application/pdf", "application/pdf;*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
action: ACTION_REDIRECT_TO_VIEWER,
|
||||
},
|
||||
{
|
||||
// Wrong MIME-type, but a PDF file according to the file name in the URL.
|
||||
condition: {
|
||||
regexFilter: "^.*\\.pdf\\b.*$",
|
||||
// The viewer does not have the original request context and issues a
|
||||
// GET request. The original response to POST requests is unavailable.
|
||||
excludedRequestMethods: ["post"],
|
||||
resourceTypes: ["main_frame", "sub_frame"],
|
||||
responseHeaders: [
|
||||
{
|
||||
header: "content-type",
|
||||
values: ["application/octet-stream", "application/octet-stream;*"],
|
||||
},
|
||||
],
|
||||
},
|
||||
action: ACTION_REDIRECT_TO_VIEWER,
|
||||
},
|
||||
{
|
||||
// Wrong MIME-type, but a PDF file according to Content-Disposition.
|
||||
condition: {
|
||||
regexFilter: "^.*$",
|
||||
// The viewer does not have the original request context and issues a
|
||||
// GET request. The original response to POST requests is unavailable.
|
||||
excludedRequestMethods: ["post"],
|
||||
resourceTypes: ["main_frame", "sub_frame"],
|
||||
responseHeaders: [
|
||||
{
|
||||
header: "content-disposition",
|
||||
values: ["*.pdf", '*.pdf"*', "*.pdf'*"],
|
||||
},
|
||||
],
|
||||
// We only want to match by content-disposition if Content-Type is set
|
||||
// to application/octet-stream. The responseHeaders condition is a
|
||||
// logical OR instead of AND, so to simulate the AND condition we use
|
||||
// the double negation of excludedResponseHeaders + excludedValues.
|
||||
// This matches any request whose content-type header is set and not
|
||||
// "application/octet-stream". It will also match if "content-type" is
|
||||
// not set, but we are okay with that since the browser would usually
|
||||
// try to sniff the MIME type in that case.
|
||||
excludedResponseHeaders: [
|
||||
{
|
||||
header: "content-type",
|
||||
excludedValues: [
|
||||
"application/octet-stream",
|
||||
"application/octet-stream;*",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
action: ACTION_REDIRECT_TO_VIEWER,
|
||||
},
|
||||
];
|
||||
for (const [i, rule] of addRules.entries()) {
|
||||
// id must be unique and at least 1, but i starts at 0. So add +1.
|
||||
rule.id = i + 1;
|
||||
rule.priority = addRules.length - i;
|
||||
}
|
||||
try {
|
||||
// Note: condition.responseHeaders is only supported in Chrome 128+, but
|
||||
// does not trigger errors in Chrome 123 - 127 as explained at:
|
||||
// https://github.com/w3c/webextensions/issues/638#issuecomment-2181124486
|
||||
// We need to detect this and avoid registering rules, because otherwise all
|
||||
// requests are redirected to the viewer instead of just PDF requests,
|
||||
// because Chrome accepts rules while ignoring the responseHeaders condition
|
||||
// - also reported at https://crbug.com/347186592
|
||||
if (!(await isHeaderConditionSupported())) {
|
||||
throw new Error("DNR responseHeaders condition is not supported.");
|
||||
}
|
||||
await chrome.declarativeNetRequest.updateDynamicRules({ addRules });
|
||||
} catch (e) {
|
||||
// When we do not register DNR rules for any reason, fall back to catching
|
||||
// PDF documents via maybeRenderPdfDoc in contentscript.js.
|
||||
console.error("Failed to register rules to redirect PDF requests.");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// For the source and explanation of this logic, see
|
||||
// https://github.com/w3c/webextensions/issues/638#issuecomment-2181124486
|
||||
async function isHeaderConditionSupported() {
|
||||
const ruleId = 123456; // Some rule ID that is not already used elsewhere.
|
||||
try {
|
||||
// Throws synchronously if not supported.
|
||||
await chrome.declarativeNetRequest.updateSessionRules({
|
||||
addRules: [
|
||||
{
|
||||
id: ruleId,
|
||||
condition: {
|
||||
responseHeaders: [{ header: "whatever" }],
|
||||
urlFilter: "|does_not_match_anything",
|
||||
},
|
||||
action: { type: "block" },
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch {
|
||||
return false; // responseHeaders condition not supported.
|
||||
}
|
||||
// Chrome may recognize the properties but have the implementation behind a
|
||||
// flag. When the implementation is disabled, validation is skipped too.
|
||||
try {
|
||||
await chrome.declarativeNetRequest.updateSessionRules({
|
||||
removeRuleIds: [ruleId],
|
||||
addRules: [
|
||||
{
|
||||
id: ruleId,
|
||||
condition: {
|
||||
responseHeaders: [],
|
||||
urlFilter: "|does_not_match_anything",
|
||||
},
|
||||
action: { type: "block" },
|
||||
},
|
||||
],
|
||||
});
|
||||
return false; // Validation skipped = feature disabled.
|
||||
} catch {
|
||||
return true; // Validation worked = feature enabled.
|
||||
} finally {
|
||||
await chrome.declarativeNetRequest.updateSessionRules({
|
||||
removeRuleIds: [ruleId],
|
||||
});
|
||||
}
|
||||
}
|
||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
||||
|
||||
function getViewerURL(pdf_url) {
|
||||
// |pdf_url| may contain a fragment such as "#page=2". That should be passed
|
||||
@ -276,42 +31,174 @@ function getViewerURL(pdf_url) {
|
||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url) + hash;
|
||||
}
|
||||
|
||||
// If the user has not granted access to file:-URLs, then declarativeNetRequest
|
||||
// will not catch the request. It is still visible through the webNavigation
|
||||
// API though, and we can replace the tab with the viewer.
|
||||
// The viewer will detect that it has no access to file:-URLs, and prompt the
|
||||
// user to activate file permissions.
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(
|
||||
function (details) {
|
||||
// Note: pdfjs.action=download is not checked here because that code path
|
||||
// is not reachable for local files through the viewer when we do not have
|
||||
// file:-access.
|
||||
if (details.frameId === 0) {
|
||||
chrome.extension.isAllowedFileSchemeAccess(function (isAllowedAccess) {
|
||||
if (isAllowedAccess) {
|
||||
// Expected to be handled by DNR. Don't do anything.
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||
* event. The property "url" is read.
|
||||
* @returns {boolean} True if the PDF file should be downloaded.
|
||||
*/
|
||||
function isPdfDownloadable(details) {
|
||||
if (details.url.includes("pdfjs.action=download")) {
|
||||
return true;
|
||||
}
|
||||
// Display the PDF viewer regardless of the Content-Disposition header if the
|
||||
// file is displayed in the main frame, since most often users want to view
|
||||
// a PDF, and servers are often misconfigured.
|
||||
// If the query string contains "=download", do not unconditionally force the
|
||||
// viewer to open the PDF, but first check whether the Content-Disposition
|
||||
// header specifies an attachment. This allows sites like Google Drive to
|
||||
// operate correctly (#6106).
|
||||
if (details.type === "main_frame" && !details.url.includes("=download")) {
|
||||
return false;
|
||||
}
|
||||
var cdHeader =
|
||||
details.responseHeaders &&
|
||||
getHeaderFromHeaders(details.responseHeaders, "content-disposition");
|
||||
return cdHeader && /^attachment/i.test(cdHeader.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the header from the list of headers for a given name.
|
||||
* @param {Array} headers responseHeaders of webRequest.onHeadersReceived
|
||||
* @returns {undefined|{name: string, value: string}} The header, if found.
|
||||
*/
|
||||
function getHeaderFromHeaders(headers, headerName) {
|
||||
for (const header of headers) {
|
||||
if (header.name.toLowerCase() === headerName) {
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the request is a PDF file.
|
||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||
* event. The properties "responseHeaders" and "url"
|
||||
* are read.
|
||||
* @returns {boolean} True if the resource is a PDF file.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a set of headers, and set "Content-Disposition: attachment".
|
||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||
* event. The property "responseHeaders" is read and
|
||||
* modified if needed.
|
||||
* @returns {Object|undefined} The return value for the onHeadersReceived event.
|
||||
* Object with key "responseHeaders" if the headers
|
||||
* have been modified, undefined otherwise.
|
||||
*/
|
||||
function getHeadersWithContentDispositionAttachment(details) {
|
||||
var headers = details.responseHeaders;
|
||||
var cdHeader = getHeaderFromHeaders(headers, "content-disposition");
|
||||
if (!cdHeader) {
|
||||
cdHeader = { name: "Content-Disposition" };
|
||||
headers.push(cdHeader);
|
||||
}
|
||||
if (!/^attachment/i.test(cdHeader.value)) {
|
||||
cdHeader.value = "attachment" + cdHeader.value.replace(/^[^;]+/i, "");
|
||||
return { responseHeaders: headers };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
function (details) {
|
||||
if (details.method !== "GET") {
|
||||
// Don't intercept POST requests until http://crbug.com/104058 is fixed.
|
||||
return undefined;
|
||||
}
|
||||
if (!isPdfFile(details)) {
|
||||
return undefined;
|
||||
}
|
||||
if (isPdfDownloadable(details)) {
|
||||
// Force download by ensuring that Content-Disposition: attachment is set
|
||||
return getHeadersWithContentDispositionAttachment(details);
|
||||
}
|
||||
|
||||
var viewerUrl = getViewerURL(details.url);
|
||||
|
||||
// Implemented in preserve-referer.js
|
||||
saveReferer(details);
|
||||
|
||||
return { redirectUrl: viewerUrl };
|
||||
},
|
||||
{
|
||||
urls: ["<all_urls>"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
},
|
||||
["blocking", "responseHeaders"]
|
||||
);
|
||||
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
function (details) {
|
||||
if (isPdfDownloadable(details)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var viewerUrl = getViewerURL(details.url);
|
||||
|
||||
return { redirectUrl: viewerUrl };
|
||||
},
|
||||
{
|
||||
urls: ["file://*/*.pdf", "file://*/*.PDF"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
},
|
||||
["blocking"]
|
||||
);
|
||||
|
||||
chrome.extension.isAllowedFileSchemeAccess(function (isAllowedAccess) {
|
||||
if (isAllowedAccess) {
|
||||
return;
|
||||
}
|
||||
// If the user has not granted access to file:-URLs, then the webRequest API
|
||||
// will not catch the request. It is still visible through the webNavigation
|
||||
// API though, and we can replace the tab with the viewer.
|
||||
// The viewer will detect that it has no access to file:-URLs, and prompt the
|
||||
// user to activate file permissions.
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(
|
||||
function (details) {
|
||||
if (details.frameId === 0 && !isPdfDownloadable(details)) {
|
||||
chrome.tabs.update(details.tabId, {
|
||||
url: getViewerURL(details.url),
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
url: [
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".pdf",
|
||||
},
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".PDF",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
{
|
||||
url: [
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".pdf",
|
||||
},
|
||||
{
|
||||
urlPrefix: "file://",
|
||||
pathSuffix: ".PDF",
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||||
if (message && message.action === "getParentOrigin") {
|
||||
@ -358,11 +245,6 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||||
url,
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
if (message && message.action === "canRequestBody") {
|
||||
sendResponse(canRequestBody(sender.tab.id, sender.frameId));
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
@ -51,35 +51,7 @@
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"enableAltText": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableGuessAltText": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"enableAltTextModelDownload": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"enableNewAltTextWhenAddingImage": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"altTextLearnMoreUrl": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"commentLearnMoreUrl": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"enableSignatureEditor": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableUpdatedAddImage": {
|
||||
"enableML": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
@ -102,13 +74,21 @@
|
||||
"description": "Whether to allow execution of active content (JavaScript) by PDF files.",
|
||||
"default": false
|
||||
},
|
||||
"enableHighlightEditor": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableHighlightFloatingButton": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"highlightEditorColors": {
|
||||
"type": "string",
|
||||
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F,yellow_HCM=#FFFFCC,green_HCM=#53FFBC,blue_HCM=#80EBFF,pink_HCM=#F6B8FF,red_HCM=#C50043"
|
||||
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
|
||||
},
|
||||
"enableStampEditor": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"disableRange": {
|
||||
"title": "Disable range requests",
|
||||
@ -176,10 +156,6 @@
|
||||
"enum": [-1, 0, 3, 15],
|
||||
"default": 0
|
||||
},
|
||||
"capCanvasAreaFactor": {
|
||||
"type": "integer",
|
||||
"default": 200
|
||||
},
|
||||
"enablePermissions": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
@ -232,21 +208,6 @@
|
||||
"description": "The color is a string as defined in CSS. Its goal is to help improve readability in high contrast mode",
|
||||
"type": "string",
|
||||
"default": "CanvasText"
|
||||
},
|
||||
"enableAutoLinking": {
|
||||
"description": "Enable creation of hyperlinks from text that look like URLs.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"enableComment": {
|
||||
"description": "Enable creation of comment annotations.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"enableOptimizedPartialRendering": {
|
||||
"description": "Enable tracking of PDF operations to optimize partial rendering.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,14 +13,20 @@ 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.
|
||||
*/
|
||||
/* import-globals-from pdfHandler.js */
|
||||
/* exported saveReferer */
|
||||
|
||||
"use strict";
|
||||
/**
|
||||
* This file is one part of the Referer persistency implementation. The other
|
||||
* part resides in chromecom.js.
|
||||
*
|
||||
* This file collects Referer headers for every http(s) request, and temporarily
|
||||
* stores the request headers in a dictionary, for REFERRER_IN_MEMORY_TIME ms.
|
||||
* This file collects request headers for every http(s) request, and temporarily
|
||||
* stores the request headers in a dictionary. Upon completion of the request
|
||||
* (success or failure), the headers are discarded.
|
||||
* pdfHandler.js will call saveReferer(details) when it is about to redirect to
|
||||
* the viewer. Upon calling saveReferer, the Referer header is extracted from
|
||||
* the request headers and saved.
|
||||
*
|
||||
* When the viewer is opened, it opens a port ("chromecom-referrer"). This port
|
||||
* is used to set up the webRequest listeners that stick the Referer headers to
|
||||
@ -30,64 +36,49 @@ limitations under the License.
|
||||
* See setReferer in chromecom.js for more explanation of this logic.
|
||||
*/
|
||||
|
||||
/* exported canRequestBody */ // Used in pdfHandler.js
|
||||
|
||||
// Remembers the request headers for every http(s) page request for the duration
|
||||
// of the request.
|
||||
var g_requestHeaders = {};
|
||||
// g_referrers[tabId][frameId] = referrer of PDF frame.
|
||||
var g_referrers = {};
|
||||
var g_referrerTimers = {};
|
||||
// The background script will eventually suspend after 30 seconds of inactivity.
|
||||
// This can be delayed when extension events are firing. To prevent the data
|
||||
// from being kept in memory for too long, cap the data duration to 5 minutes.
|
||||
var REFERRER_IN_MEMORY_TIME = 300000;
|
||||
|
||||
// g_postRequests[tabId] = Set of frameId that were loaded via POST.
|
||||
var g_postRequests = {};
|
||||
|
||||
var rIsReferer = /^referer$/i;
|
||||
chrome.webRequest.onSendHeaders.addListener(
|
||||
function saveReferer(details) {
|
||||
const { tabId, frameId, requestHeaders, method } = details;
|
||||
g_referrers[tabId] ??= {};
|
||||
g_referrers[tabId][frameId] = requestHeaders.find(h =>
|
||||
rIsReferer.test(h.name)
|
||||
)?.value;
|
||||
setCanRequestBody(tabId, frameId, method !== "GET");
|
||||
forgetReferrerEventually(tabId);
|
||||
},
|
||||
{ urls: ["*://*/*"], types: ["main_frame", "sub_frame"] },
|
||||
["requestHeaders", "extraHeaders"]
|
||||
);
|
||||
|
||||
function forgetReferrerEventually(tabId) {
|
||||
if (g_referrerTimers[tabId]) {
|
||||
clearTimeout(g_referrerTimers[tabId]);
|
||||
(function () {
|
||||
var requestFilter = {
|
||||
urls: ["*://*/*"],
|
||||
types: ["main_frame", "sub_frame"],
|
||||
};
|
||||
chrome.webRequest.onSendHeaders.addListener(
|
||||
function (details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
},
|
||||
requestFilter,
|
||||
["requestHeaders", "extraHeaders"]
|
||||
);
|
||||
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onErrorOccurred.addListener(forgetHeaders, requestFilter);
|
||||
function forgetHeaders(details) {
|
||||
delete g_requestHeaders[details.requestId];
|
||||
}
|
||||
g_referrerTimers[tabId] = setTimeout(() => {
|
||||
delete g_referrers[tabId];
|
||||
delete g_referrerTimers[tabId];
|
||||
delete g_postRequests[tabId];
|
||||
}, REFERRER_IN_MEMORY_TIME);
|
||||
}
|
||||
})();
|
||||
|
||||
// Keeps track of whether a document in tabId + frameId is loaded through a
|
||||
// POST form submission. Although this logic has nothing to do with referrer
|
||||
// tracking, it is still here to enable re-use of the webRequest listener above.
|
||||
function setCanRequestBody(tabId, frameId, isPOST) {
|
||||
if (isPOST) {
|
||||
g_postRequests[tabId] ??= new Set();
|
||||
g_postRequests[tabId].add(frameId);
|
||||
} else {
|
||||
g_postRequests[tabId]?.delete(frameId);
|
||||
/**
|
||||
* @param {object} details - onHeadersReceived event data.
|
||||
*/
|
||||
function saveReferer(details) {
|
||||
var referer =
|
||||
g_requestHeaders[details.requestId] &&
|
||||
getHeaderFromHeaders(g_requestHeaders[details.requestId], "referer");
|
||||
referer = (referer && referer.value) || "";
|
||||
if (!g_referrers[details.tabId]) {
|
||||
g_referrers[details.tabId] = {};
|
||||
}
|
||||
g_referrers[details.tabId][details.frameId] = referer;
|
||||
}
|
||||
|
||||
function canRequestBody(tabId, frameId) {
|
||||
// Returns true unless the frame is known to be loaded through a POST request.
|
||||
// If the background suspends, the information may be lost. This is acceptable
|
||||
// because the information is only potentially needed shortly after document
|
||||
// load, by contentscript.js.
|
||||
return !g_postRequests[tabId]?.has(frameId);
|
||||
}
|
||||
chrome.tabs.onRemoved.addListener(function (tabId) {
|
||||
delete g_referrers[tabId];
|
||||
});
|
||||
|
||||
// This method binds a webRequest event handler which adds the Referer header
|
||||
// to matching PDF resource requests (only if the Referer is non-empty). The
|
||||
@ -96,13 +87,15 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
if (port.name !== "chromecom-referrer") {
|
||||
return;
|
||||
}
|
||||
// Note: sender.frameId is only set in Chrome 41+.
|
||||
if (!("frameId" in port.sender)) {
|
||||
port.disconnect();
|
||||
return;
|
||||
}
|
||||
var tabId = port.sender.tab.id;
|
||||
var frameId = port.sender.frameId;
|
||||
var dnrRequestId;
|
||||
|
||||
// If the PDF is viewed for the first time, then the referer will be set here.
|
||||
// Note: g_referrers could be empty if the background script was suspended by
|
||||
// the browser. In that case, chromecom.js may send us the referer (below).
|
||||
var referer = (g_referrers[tabId] && g_referrers[tabId][frameId]) || "";
|
||||
port.onMessage.addListener(function (data) {
|
||||
// If the viewer was opened directly (without opening a PDF URL first), then
|
||||
@ -111,49 +104,80 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
if (data.referer) {
|
||||
referer = data.referer;
|
||||
}
|
||||
dnrRequestId = data.dnrRequestId;
|
||||
setStickyReferrer(dnrRequestId, tabId, data.requestUrl, referer, () => {
|
||||
// Acknowledge the message, and include the latest referer for this frame.
|
||||
port.postMessage(referer);
|
||||
});
|
||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
if (referer) {
|
||||
// Only add a blocking request handler if the referer has to be rewritten.
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||
onBeforeSendHeaders,
|
||||
{
|
||||
urls: [data.requestUrl],
|
||||
types: ["xmlhttprequest"],
|
||||
tabId,
|
||||
},
|
||||
["blocking", "requestHeaders", "extraHeaders"]
|
||||
);
|
||||
}
|
||||
// Acknowledge the message, and include the latest referer for this frame.
|
||||
port.postMessage(referer);
|
||||
});
|
||||
|
||||
// The port is only disconnected when the other end reloads.
|
||||
port.onDisconnect.addListener(function () {
|
||||
unsetStickyReferrer(dnrRequestId);
|
||||
if (g_referrers[tabId]) {
|
||||
delete g_referrers[tabId][frameId];
|
||||
}
|
||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
chrome.webRequest.onHeadersReceived.removeListener(exposeOnHeadersReceived);
|
||||
});
|
||||
});
|
||||
|
||||
function setStickyReferrer(dnrRequestId, tabId, url, referer, callback) {
|
||||
if (!referer) {
|
||||
unsetStickyReferrer(dnrRequestId);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const rule = {
|
||||
id: dnrRequestId,
|
||||
condition: {
|
||||
urlFilter: `|${url}|`,
|
||||
// The viewer and background are presumed to have the same origin:
|
||||
initiatorDomains: [location.hostname], // = chrome.runtime.id.
|
||||
resourceTypes: ["xmlhttprequest"],
|
||||
tabIds: [tabId],
|
||||
// Expose some response headers for fetch API calls from PDF.js;
|
||||
// This is a work-around for https://crbug.com/784528
|
||||
chrome.webRequest.onHeadersReceived.addListener(
|
||||
exposeOnHeadersReceived,
|
||||
{
|
||||
urls: ["https://*/*"],
|
||||
types: ["xmlhttprequest"],
|
||||
tabId,
|
||||
},
|
||||
action: {
|
||||
type: "modifyHeaders",
|
||||
requestHeaders: [{ operation: "set", header: "referer", value: referer }],
|
||||
},
|
||||
};
|
||||
chrome.declarativeNetRequest.updateSessionRules(
|
||||
{ removeRuleIds: [dnrRequestId], addRules: [rule] },
|
||||
callback
|
||||
["blocking", "responseHeaders"]
|
||||
);
|
||||
}
|
||||
|
||||
function unsetStickyReferrer(dnrRequestId) {
|
||||
if (dnrRequestId) {
|
||||
chrome.declarativeNetRequest.updateSessionRules({
|
||||
removeRuleIds: [dnrRequestId],
|
||||
});
|
||||
function onBeforeSendHeaders(details) {
|
||||
if (details.frameId !== frameId) {
|
||||
return undefined;
|
||||
}
|
||||
var headers = details.requestHeaders;
|
||||
var refererHeader = getHeaderFromHeaders(headers, "referer");
|
||||
if (!refererHeader) {
|
||||
refererHeader = { name: "Referer" };
|
||||
headers.push(refererHeader);
|
||||
} else if (
|
||||
refererHeader.value &&
|
||||
refererHeader.value.lastIndexOf("chrome-extension:", 0) !== 0
|
||||
) {
|
||||
// Sanity check. If the referer is set, and the value is not the URL of
|
||||
// this extension, then the request was not initiated by this extension.
|
||||
return undefined;
|
||||
}
|
||||
refererHeader.value = referer;
|
||||
return { requestHeaders: headers };
|
||||
}
|
||||
}
|
||||
|
||||
function exposeOnHeadersReceived(details) {
|
||||
if (details.frameId !== frameId) {
|
||||
return undefined;
|
||||
}
|
||||
var headers = details.responseHeaders;
|
||||
var aceh = getHeaderFromHeaders(headers, "access-control-expose-headers");
|
||||
// List of headers that PDF.js uses in src/display/network_utils.js
|
||||
var acehValue =
|
||||
"accept-ranges,content-encoding,content-length,content-disposition";
|
||||
if (aceh) {
|
||||
aceh.value += "," + acehValue;
|
||||
} else {
|
||||
aceh = { name: "Access-Control-Expose-Headers", value: acehValue };
|
||||
headers.push(aceh);
|
||||
}
|
||||
return { responseHeaders: headers };
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright 2024 Mozilla Foundation
|
||||
<!doctype html>
|
||||
<!--
|
||||
Copyright 2015 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,15 +13,5 @@ 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";
|
||||
|
||||
importScripts(
|
||||
"options/migration.js",
|
||||
"preserve-referer.js",
|
||||
"pdfHandler.js",
|
||||
"extension-router.js",
|
||||
"suppress-update.js",
|
||||
"telemetry.js"
|
||||
);
|
||||
-->
|
||||
<script src="restoretab.js"></script>
|
||||
31
extensions/chromium/restoretab.js
Normal file
31
extensions/chromium/restoretab.js
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2015 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is part of the work-around for crbug.com/511670.
|
||||
* - chromecom.js sets the URL and history state upon unload.
|
||||
* - extension-router.js retrieves the saved state and opens restoretab.html
|
||||
* - restoretab.html (this script) restores the URL and history state.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var url = decodeURIComponent(location.search.slice(1));
|
||||
var historyState = decodeURIComponent(location.hash.slice(1));
|
||||
|
||||
historyState = historyState === "undefined" ? null : JSON.parse(historyState);
|
||||
|
||||
history.replaceState(historyState, null, url);
|
||||
location.reload();
|
||||
@ -20,10 +20,7 @@ limitations under the License.
|
||||
// viewer is not displaying any PDF files. Otherwise the tabs would close, which
|
||||
// is quite disruptive (crbug.com/511670).
|
||||
chrome.runtime.onUpdateAvailable.addListener(function () {
|
||||
chrome.tabs.query({ url: chrome.runtime.getURL("*") }, tabs => {
|
||||
if (tabs?.length) {
|
||||
return;
|
||||
}
|
||||
if (chrome.extension.getViews({ type: "tab" }).length === 0) {
|
||||
chrome.runtime.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -42,35 +42,8 @@ limitations under the License.
|
||||
return;
|
||||
}
|
||||
|
||||
// The localStorage API is unavailable in service workers. We store data in
|
||||
// chrome.storage.local and use this "localStorage" object to enable
|
||||
// synchronous access in the logic.
|
||||
const localStorage = {
|
||||
telemetryLastTime: 0,
|
||||
telemetryDeduplicationId: "",
|
||||
telemetryLastVersion: "",
|
||||
};
|
||||
|
||||
chrome.alarms.onAlarm.addListener(alarm => {
|
||||
if (alarm.name === "maybeSendPing") {
|
||||
maybeSendPing();
|
||||
}
|
||||
});
|
||||
chrome.storage.session.get({ didPingCheck: false }, async items => {
|
||||
if (items?.didPingCheck) {
|
||||
return;
|
||||
}
|
||||
maybeSendPing();
|
||||
await chrome.alarms.clear("maybeSendPing");
|
||||
await chrome.alarms.create("maybeSendPing", { periodInMinutes: 60 });
|
||||
chrome.storage.session.set({ didPingCheck: true });
|
||||
});
|
||||
|
||||
function updateLocalStorage(key, value) {
|
||||
localStorage[key] = value;
|
||||
// Note: We mirror the data in localStorage because the following is async.
|
||||
chrome.storage.local.set({ [key]: value });
|
||||
}
|
||||
maybeSendPing();
|
||||
setInterval(maybeSendPing, 36e5);
|
||||
|
||||
function maybeSendPing() {
|
||||
getLoggingPref(function (didOptOut) {
|
||||
@ -88,20 +61,12 @@ limitations under the License.
|
||||
// send more pings.
|
||||
return;
|
||||
}
|
||||
doSendPing();
|
||||
});
|
||||
}
|
||||
|
||||
function doSendPing() {
|
||||
chrome.storage.local.get(localStorage, items => {
|
||||
Object.assign(localStorage, items);
|
||||
|
||||
var lastTime = parseInt(localStorage.telemetryLastTime) || 0;
|
||||
var wasUpdated = didUpdateSinceLastCheck();
|
||||
if (!wasUpdated && Date.now() - lastTime < MINIMUM_TIME_BETWEEN_PING) {
|
||||
return;
|
||||
}
|
||||
updateLocalStorage("telemetryLastTime", Date.now());
|
||||
localStorage.telemetryLastTime = Date.now();
|
||||
|
||||
var deduplication_id = getDeduplicationId(wasUpdated);
|
||||
var extension_version = chrome.runtime.getManifest().version;
|
||||
@ -139,7 +104,7 @@ limitations under the License.
|
||||
for (const c of buf) {
|
||||
id += (c >>> 4).toString(16) + (c & 0xf).toString(16);
|
||||
}
|
||||
updateLocalStorage("telemetryDeduplicationId", id);
|
||||
localStorage.telemetryDeduplicationId = id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@ -154,7 +119,7 @@ limitations under the License.
|
||||
if (!chromeVersion || localStorage.telemetryLastVersion === chromeVersion) {
|
||||
return false;
|
||||
}
|
||||
updateLocalStorage("telemetryLastVersion", chromeVersion);
|
||||
localStorage.telemetryLastVersion = chromeVersion;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
22
extensions/firefox/.eslintrc
Normal file
22
extensions/firefox/.eslintrc
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
// Note: The root .eslintrc file will define the base rules,
|
||||
// but mozilla/recommended will override them for the rules it sets. Finally,
|
||||
// the rules in this file will take precedence.
|
||||
"extends": [
|
||||
"plugin:mozilla/recommended",
|
||||
],
|
||||
|
||||
"plugins": [
|
||||
"mozilla"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
// Other rules mozilla/recommended hasn't enabled yet.
|
||||
"no-shadow": "error",
|
||||
"arrow-body-style": ["error", "as-needed"],
|
||||
"arrow-parens": ["error", "always"],
|
||||
"constructor-super": "error",
|
||||
"no-confusing-arrow": "error",
|
||||
"no-useless-constructor": "error",
|
||||
},
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
/* Copyright 2024 Mozilla Foundation
|
||||
/* Copyright 2018 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -13,16 +13,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { InkDrawOutline } from "./inkdraw.js";
|
||||
|
||||
class ContourDrawOutline extends InkDrawOutline {
|
||||
toSVGPath() {
|
||||
let path = super.toSVGPath();
|
||||
if (!path.endsWith("Z")) {
|
||||
path += "Z";
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
export { ContourDrawOutline };
|
||||
export const PdfJsDefaultPreferences = Object.freeze(
|
||||
PDFJSDev.eval("DEFAULT_PREFERENCES")
|
||||
);
|
||||
9
external/.eslintrc
vendored
Normal file
9
external/.eslintrc
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": [
|
||||
../.eslintrc
|
||||
],
|
||||
|
||||
"env": {
|
||||
"node": true,
|
||||
},
|
||||
}
|
||||
@ -1,7 +1,10 @@
|
||||
import { types as t, transformSync } from "@babel/core";
|
||||
import fs from "fs";
|
||||
import { join as joinPaths } from "path";
|
||||
import vm from "vm";
|
||||
|
||||
const PDFJS_PREPROCESSOR_NAME = "PDFJSDev";
|
||||
const ROOT_PREFIX = "$ROOT/";
|
||||
|
||||
function isPDFJSPreprocessor(obj) {
|
||||
return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;
|
||||
@ -37,6 +40,18 @@ function handlePreprocessorAction(ctx, actionName, args, path) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
case "json":
|
||||
if (!t.isStringLiteral(arg)) {
|
||||
throw new Error("Path to JSON is not provided");
|
||||
}
|
||||
let jsonPath = arg.value;
|
||||
if (jsonPath.startsWith(ROOT_PREFIX)) {
|
||||
jsonPath = joinPaths(
|
||||
ctx.rootPath,
|
||||
jsonPath.substring(ROOT_PREFIX.length)
|
||||
);
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
}
|
||||
throw new Error("Unsupported action");
|
||||
} catch (e) {
|
||||
@ -47,25 +62,6 @@ function handlePreprocessorAction(ctx, actionName, args, path) {
|
||||
}
|
||||
|
||||
function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
function removeUnusedFunctions(path) {
|
||||
let removed;
|
||||
do {
|
||||
removed = false;
|
||||
path.scope.crawl();
|
||||
for (const name in path.scope.bindings) {
|
||||
const binding = path.scope.bindings[name];
|
||||
if (!binding.referenced) {
|
||||
const { path: bindingPath } = binding;
|
||||
if (bindingPath.isFunctionDeclaration()) {
|
||||
bindingPath.remove();
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we removed some functions, there might be new unused ones
|
||||
} while (removed);
|
||||
}
|
||||
|
||||
return {
|
||||
name: "babel-plugin-pdfjs-preprocessor",
|
||||
manipulateOptions({ parserOpts }) {
|
||||
@ -172,27 +168,23 @@ function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
path.replaceWith(t.inherits(t.valueToNode(result), path.node));
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node.callee, { name: "__raw_import__" })) {
|
||||
if (t.isIdentifier(node.callee, { name: "__non_webpack_import__" })) {
|
||||
if (node.arguments.length !== 1) {
|
||||
throw new Error("Invalid `__raw_import__` usage.");
|
||||
throw new Error("Invalid `__non_webpack_import__` usage.");
|
||||
}
|
||||
// Replace it with a standard `import`-call and attempt to ensure that
|
||||
// various bundlers will leave it alone; this *must* include Webpack.
|
||||
// Replace it with a standard `import`-call and
|
||||
// ensure that Webpack will leave it alone.
|
||||
const source = node.arguments[0];
|
||||
source.leadingComments = [
|
||||
{
|
||||
type: "CommentBlock",
|
||||
value: "webpackIgnore: true",
|
||||
},
|
||||
{
|
||||
type: "CommentBlock",
|
||||
value: "@vite-ignore",
|
||||
},
|
||||
];
|
||||
path.replaceWith(t.importExpression(source));
|
||||
}
|
||||
},
|
||||
"BlockStatement|StaticBlock": {
|
||||
BlockStatement: {
|
||||
// Visit node in post-order so that recursive flattening
|
||||
// of blocks works correctly.
|
||||
exit(path) {
|
||||
@ -223,10 +215,6 @@ function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
}
|
||||
subExpressionIndex++;
|
||||
}
|
||||
|
||||
if (node.type === "StaticBlock" && node.body.length === 0) {
|
||||
path.remove();
|
||||
}
|
||||
},
|
||||
},
|
||||
Function: {
|
||||
@ -244,8 +232,6 @@ function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
// Function body ends with return without arg -- removing it.
|
||||
body.pop();
|
||||
}
|
||||
|
||||
removeUnusedFunctions(path);
|
||||
},
|
||||
},
|
||||
ClassMethod: {
|
||||
@ -268,26 +254,6 @@ function babelPluginPDFJSPreprocessor(babel, ctx) {
|
||||
}
|
||||
},
|
||||
},
|
||||
Program: {
|
||||
exit(path) {
|
||||
if (path.node.sourceType === "module") {
|
||||
removeUnusedFunctions(path);
|
||||
}
|
||||
},
|
||||
},
|
||||
MemberExpression(path) {
|
||||
// The Emscripten Compiler (emcc) generates code that allows the caller
|
||||
// to provide the Wasm module (thorugh Module.instantiateWasm), with
|
||||
// a fallback in case .instantiateWasm is not provided.
|
||||
// We always define instantiateWasm, so we can hard-code the check
|
||||
// and let our dead code elimination logic remove the unused fallback.
|
||||
if (
|
||||
path.parentPath.isIfStatement({ test: path.node }) &&
|
||||
path.matchesPattern("Module.instantiateWasm")
|
||||
) {
|
||||
path.replaceWith(t.booleanLiteral(true));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
4
external/builder/builder.mjs
vendored
4
external/builder/builder.mjs
vendored
@ -151,7 +151,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
let state = STATE_NONE;
|
||||
const stack = [];
|
||||
const control =
|
||||
/^(?:\/\/|\s*\/\*|\s*<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:\*\/|-->)?$)?/;
|
||||
/^(?:\/\/|\s*\/\*|<!--)\s*#(if|elif|else|endif|expand|include|error)\b(?:\s+(.*?)(?:\*\/|-->)?$)?/;
|
||||
|
||||
while ((line = readLine()) !== null) {
|
||||
++lineNumber;
|
||||
@ -213,7 +213,7 @@ function preprocess(inFilename, outFilename, defines) {
|
||||
) {
|
||||
writeLine(
|
||||
line
|
||||
.replaceAll(/^\/\/|^\s*<!--/g, " ")
|
||||
.replaceAll(/^\/\/|^<!--/g, " ")
|
||||
.replaceAll(/(^\s*)\/\*/g, "$1 ")
|
||||
.replaceAll(/\*\/$|-->$/g, "")
|
||||
);
|
||||
|
||||
@ -8,4 +8,3 @@ function test() {
|
||||
}
|
||||
"4";
|
||||
}
|
||||
test();
|
||||
|
||||
1
external/builder/fixtures_babel/blocks.js
vendored
1
external/builder/fixtures_babel/blocks.js
vendored
@ -17,4 +17,3 @@ function test() {
|
||||
"4";
|
||||
}
|
||||
}
|
||||
test();
|
||||
|
||||
@ -2,12 +2,10 @@ function f1() {
|
||||
"1";
|
||||
"2";
|
||||
}
|
||||
f1();
|
||||
function f2() {
|
||||
"1";
|
||||
"2";
|
||||
}
|
||||
f2();
|
||||
function f3() {
|
||||
if ("1") {
|
||||
"1";
|
||||
@ -17,4 +15,3 @@ function f3() {
|
||||
"4";
|
||||
}
|
||||
}
|
||||
f3();
|
||||
|
||||
3
external/builder/fixtures_babel/comments.js
vendored
3
external/builder/fixtures_babel/comments.js
vendored
@ -6,7 +6,6 @@ function f1() {
|
||||
"2";
|
||||
/* tail */
|
||||
}
|
||||
f1();
|
||||
|
||||
function f2() {
|
||||
// head
|
||||
@ -15,7 +14,6 @@ function f2() {
|
||||
"2";
|
||||
// tail
|
||||
}
|
||||
f2();
|
||||
|
||||
function f3() {
|
||||
if ("1") { // begin block
|
||||
@ -26,4 +24,3 @@ function f3() {
|
||||
"4";
|
||||
}
|
||||
}
|
||||
f3();
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
function f1() {}
|
||||
f1();
|
||||
function f2() {
|
||||
return 1;
|
||||
}
|
||||
f2();
|
||||
function f3() {
|
||||
var i = 0;
|
||||
throw "test";
|
||||
}
|
||||
f3();
|
||||
function f4() {
|
||||
var i = 0;
|
||||
}
|
||||
f4();
|
||||
var obj = {
|
||||
method1() {},
|
||||
method2() {}
|
||||
|
||||
4
external/builder/fixtures_babel/deadcode.js
vendored
4
external/builder/fixtures_babel/deadcode.js
vendored
@ -2,20 +2,17 @@ function f1() {
|
||||
return;
|
||||
var i = 0;
|
||||
}
|
||||
f1();
|
||||
|
||||
function f2() {
|
||||
return 1;
|
||||
var i = 0;
|
||||
}
|
||||
f2();
|
||||
|
||||
function f3() {
|
||||
var i = 0;
|
||||
throw "test";
|
||||
var j = 0;
|
||||
}
|
||||
f3();
|
||||
|
||||
function f4() {
|
||||
var i = 0;
|
||||
@ -25,7 +22,6 @@ function f4() {
|
||||
throw "test";
|
||||
var j = 0;
|
||||
}
|
||||
f4();
|
||||
|
||||
var obj = {
|
||||
method1() { return; var i = 0; },
|
||||
|
||||
@ -10,6 +10,9 @@ var g = {
|
||||
},
|
||||
j: 2
|
||||
};
|
||||
var h = {
|
||||
test: "test"
|
||||
};
|
||||
var i = '0';
|
||||
var j = {
|
||||
i: 1
|
||||
|
||||
1
external/builder/fixtures_babel/evals.js
vendored
1
external/builder/fixtures_babel/evals.js
vendored
@ -5,6 +5,7 @@ var d = PDFJSDev.test('FALSE');
|
||||
var e = PDFJSDev.eval('TRUE');
|
||||
var f = PDFJSDev.eval('TEXT');
|
||||
var g = PDFJSDev.eval('OBJ');
|
||||
var h = PDFJSDev.json('$ROOT/external/builder/fixtures_babel/evals.json');
|
||||
var i = typeof PDFJSDev === 'undefined' ? PDFJSDev.eval('FALSE') : '0';
|
||||
var j = typeof PDFJSDev !== 'undefined' ? PDFJSDev.eval('OBJ.obj') : '0';
|
||||
var k = !PDFJSDev.test('TRUE');
|
||||
|
||||
1
external/builder/fixtures_babel/evals.json
vendored
Normal file
1
external/builder/fixtures_babel/evals.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{ "test": "test" }
|
||||
@ -16,4 +16,3 @@ if ('1') {
|
||||
function f1() {
|
||||
"1";
|
||||
}
|
||||
f1();
|
||||
|
||||
1
external/builder/fixtures_babel/ifs.js
vendored
1
external/builder/fixtures_babel/ifs.js
vendored
@ -32,4 +32,3 @@ function f1() {
|
||||
"2";
|
||||
}
|
||||
}
|
||||
f1();
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
import { Test } from "import-name";
|
||||
import { Test2 } from './non-alias';
|
||||
export { Test3 } from "import-name";
|
||||
await import(
|
||||
/*webpackIgnore: true*/
|
||||
/*@vite-ignore*/
|
||||
"./non-alias");
|
||||
await import( /*webpackIgnore: true*/"./non-alias");
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Test } from 'import-alias';
|
||||
import { Test2 } from './non-alias';
|
||||
export { Test3 } from 'import-alias';
|
||||
await __raw_import__("./non-alias");
|
||||
await __non_webpack_import__("./non-alias");
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
class A {
|
||||
static {
|
||||
foo();
|
||||
}
|
||||
static {
|
||||
var a = 0;
|
||||
}
|
||||
}
|
||||
20
external/builder/fixtures_babel/staticblock.js
vendored
20
external/builder/fixtures_babel/staticblock.js
vendored
@ -1,20 +0,0 @@
|
||||
class A {
|
||||
static {}
|
||||
static {
|
||||
{ foo() }
|
||||
}
|
||||
static {
|
||||
{;}
|
||||
}
|
||||
static {
|
||||
if (PDFJSDev.test('TRUE')) {
|
||||
var a = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
if (PDFJSDev.test('FALSE')) {
|
||||
var a = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
function usedByUsed() {}
|
||||
function used() {
|
||||
usedByUsed();
|
||||
}
|
||||
used();
|
||||
@ -1,14 +0,0 @@
|
||||
function usedByUsed() {}
|
||||
function usedByUnused() {}
|
||||
function usedByRemovedCode() {}
|
||||
|
||||
function used() {
|
||||
usedByUsed();
|
||||
return;
|
||||
usedByRemovedCode();
|
||||
}
|
||||
function unused() {
|
||||
usedByUnused();
|
||||
}
|
||||
|
||||
used();
|
||||
3
external/builder/test-fixtures.mjs
vendored
3
external/builder/test-fixtures.mjs
vendored
@ -1,8 +1,9 @@
|
||||
import * as builder from "./builder.mjs";
|
||||
import { fileURLToPath } from "url";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
let errors = 0;
|
||||
|
||||
|
||||
3
external/builder/test-fixtures_babel.mjs
vendored
3
external/builder/test-fixtures_babel.mjs
vendored
@ -1,8 +1,9 @@
|
||||
import { fileURLToPath } from "url";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { preprocessPDFJSCode } from "./babel-plugin-pdfjs-preprocessor.mjs";
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
let errors = 0;
|
||||
|
||||
|
||||
BIN
external/iccs/CGATS001Compat-v2-micro.icc
vendored
BIN
external/iccs/CGATS001Compat-v2-micro.icc
vendored
Binary file not shown.
116
external/iccs/LICENSE
vendored
116
external/iccs/LICENSE
vendored
@ -1,116 +0,0 @@
|
||||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
10
external/iccs/README.md
vendored
10
external/iccs/README.md
vendored
@ -1,10 +0,0 @@
|
||||
## ICC
|
||||
|
||||
The file CGATS001Compat-v2-micro.icc used to convert colors from CMYK to RGB comes from:
|
||||
https://github.com/saucecontrol/Compact-ICC-Profiles
|
||||
|
||||
at revision bdd84663061bc4ae95ca70decff54f581e27f702.
|
||||
|
||||
## Licensing
|
||||
|
||||
[CGATS001Compat-v2-micro.icc](https://github.com/saucecontrol/Compact-ICC-Profiles/blob/master/profiles/CGATS001Compat-v2-micro.icc) is under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
7
external/importL10n/locales.mjs
vendored
7
external/importL10n/locales.mjs
vendored
@ -31,7 +31,7 @@ async function downloadLanguageCodes() {
|
||||
console.log("Downloading language codes...\n");
|
||||
|
||||
const ALL_LOCALES =
|
||||
"https://raw.githubusercontent.com/mozilla-firefox/firefox/main/browser/locales/all-locales";
|
||||
"https://hg.mozilla.org/mozilla-central/raw-file/tip/browser/locales/all-locales";
|
||||
|
||||
const response = await fetch(ALL_LOCALES);
|
||||
if (!response.ok) {
|
||||
@ -52,9 +52,8 @@ async function downloadLanguageFiles(root, langCode) {
|
||||
|
||||
// Constants for constructing the URLs. Translations are taken from the
|
||||
// Nightly channel as those are the most recent ones.
|
||||
const MOZ_CENTRAL_ROOT =
|
||||
"https://raw.githubusercontent.com/mozilla-l10n/firefox-l10n/main/";
|
||||
const MOZ_CENTRAL_PDFJS_DIR = "/toolkit/toolkit/pdfviewer/";
|
||||
const MOZ_CENTRAL_ROOT = "https://hg.mozilla.org/l10n-central/";
|
||||
const MOZ_CENTRAL_PDFJS_DIR = "/raw-file/default/toolkit/toolkit/pdfviewer/";
|
||||
|
||||
// Defines which files to download for each language.
|
||||
const files = ["viewer.ftl"];
|
||||
|
||||
39
external/openjpeg/LICENSE_OPENJPEG
vendored
39
external/openjpeg/LICENSE_OPENJPEG
vendored
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* The copyright in this software is being made available under the 2-clauses
|
||||
* BSD License, included below. This software may be subject to other third
|
||||
* party and contributor rights, including patent rights, and no such rights
|
||||
* are granted under this license.
|
||||
*
|
||||
* Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
|
||||
* Copyright (c) 2002-2014, Professor Benoit Macq
|
||||
* Copyright (c) 2003-2014, Antonin Descampe
|
||||
* Copyright (c) 2003-2009, Francois-Olivier Devaux
|
||||
* Copyright (c) 2005, Herve Drolon, FreeImage Team
|
||||
* Copyright (c) 2002-2003, Yannick Verschueren
|
||||
* Copyright (c) 2001-2003, David Janssens
|
||||
* Copyright (c) 2011-2012, Centre National d'Etudes Spatiales (CNES), France
|
||||
* Copyright (c) 2012, CS Systemes d'Information, France
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
22
external/openjpeg/LICENSE_PDFJS_OPENJPEG
vendored
22
external/openjpeg/LICENSE_PDFJS_OPENJPEG
vendored
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2024, Mozilla Foundation
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
19
external/openjpeg/openjpeg.js
vendored
19
external/openjpeg/openjpeg.js
vendored
File diff suppressed because one or more lines are too long
BIN
external/openjpeg/openjpeg.wasm
vendored
BIN
external/openjpeg/openjpeg.wasm
vendored
Binary file not shown.
17
external/openjpeg/openjpeg_nowasm_fallback.js
vendored
17
external/openjpeg/openjpeg_nowasm_fallback.js
vendored
File diff suppressed because one or more lines are too long
22
external/qcms/LICENSE_PDFJS_QCMS
vendored
22
external/qcms/LICENSE_PDFJS_QCMS
vendored
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2025, Mozilla Foundation
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
21
external/qcms/LICENSE_QCMS
vendored
21
external/qcms/LICENSE_QCMS
vendored
@ -1,21 +0,0 @@
|
||||
qcms
|
||||
Copyright (C) 2009-2024 Mozilla Corporation
|
||||
Copyright (C) 1998-2007 Marti Maria
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
12
external/qcms/README.md
vendored
12
external/qcms/README.md
vendored
@ -1,12 +0,0 @@
|
||||
## Build
|
||||
|
||||
In order to generate the files `qcms.js` and `qcms_bg.wasm`:
|
||||
* git clone https://github.com/mozilla/pdf.js.qcms/
|
||||
* the build requires to have a [Docker](https://www.docker.com/) setup and then:
|
||||
* `node build.js -C` to build the Docker image
|
||||
* `node build.js -co /pdf.js/external/qcms/` to compile the decoder
|
||||
|
||||
## Licensing
|
||||
|
||||
[qcms](https://github.com/FirefoxGraphics/qcms) is under [MIT](https://github.com/FirefoxGraphics/qcms/blob/main/COPYING)
|
||||
and [pdf.js.qcms](https://github.com/mozilla/pdf.js.qcms/) is released under [MIT](https://github.com/mozilla/pdf.js.qcms/blob/main/LICENSE) license so `qcms.js` and `qcms_bg.wasm` are released under [MIT](https://github.com/mozilla/pdf.js.qcms/blob/main/LICENSE) license too.
|
||||
259
external/qcms/qcms.js
vendored
259
external/qcms/qcms.js
vendored
@ -1,259 +0,0 @@
|
||||
/* THIS FILE IS GENERATED - DO NOT EDIT */
|
||||
import { copy_result, copy_rgb, make_cssRGB } from './qcms_utils.js';
|
||||
|
||||
let wasm;
|
||||
|
||||
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||
|
||||
let cachedUint8ArrayMemory0 = null;
|
||||
|
||||
function getUint8ArrayMemory0() {
|
||||
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
||||
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
||||
}
|
||||
return cachedUint8ArrayMemory0;
|
||||
}
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0;
|
||||
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
let WASM_VECTOR_LEN = 0;
|
||||
|
||||
function passArray8ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
||||
getUint8ArrayMemory0().set(arg, ptr / 1);
|
||||
WASM_VECTOR_LEN = arg.length;
|
||||
return ptr;
|
||||
}
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {Uint8Array} src
|
||||
*/
|
||||
export function qcms_convert_array(transformer, src) {
|
||||
const ptr0 = passArray8ToWasm0(src, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.qcms_convert_array(transformer, ptr0, len0);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src
|
||||
* @param {boolean} css
|
||||
*/
|
||||
export function qcms_convert_one(transformer, src, css) {
|
||||
wasm.qcms_convert_one(transformer, src, css);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src1
|
||||
* @param {number} src2
|
||||
* @param {number} src3
|
||||
* @param {boolean} css
|
||||
*/
|
||||
export function qcms_convert_three(transformer, src1, src2, src3, css) {
|
||||
wasm.qcms_convert_three(transformer, src1, src2, src3, css);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
* @param {number} src1
|
||||
* @param {number} src2
|
||||
* @param {number} src3
|
||||
* @param {number} src4
|
||||
* @param {boolean} css
|
||||
*/
|
||||
export function qcms_convert_four(transformer, src1, src2, src3, src4, css) {
|
||||
wasm.qcms_convert_four(transformer, src1, src2, src3, src4, css);
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {Uint8Array} mem
|
||||
* @param {DataType} in_type
|
||||
* @param {Intent} intent
|
||||
* @returns {number}
|
||||
*/
|
||||
export function qcms_transformer_from_memory(mem, in_type, intent) {
|
||||
const ptr0 = passArray8ToWasm0(mem, wasm.__wbindgen_malloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
const ret = wasm.qcms_transformer_from_memory(ptr0, len0, in_type, intent);
|
||||
return ret >>> 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Safety
|
||||
*
|
||||
* This function is called directly from JavaScript.
|
||||
* @param {number} transformer
|
||||
*/
|
||||
export function qcms_drop_transformer(transformer) {
|
||||
wasm.qcms_drop_transformer(transformer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @enum {0 | 1 | 2 | 3 | 4 | 5}
|
||||
*/
|
||||
export const DataType = Object.freeze({
|
||||
RGB8: 0, "0": "RGB8",
|
||||
RGBA8: 1, "1": "RGBA8",
|
||||
BGRA8: 2, "2": "BGRA8",
|
||||
Gray8: 3, "3": "Gray8",
|
||||
GrayA8: 4, "4": "GrayA8",
|
||||
CMYK: 5, "5": "CMYK",
|
||||
});
|
||||
/**
|
||||
* @enum {0 | 1 | 2 | 3}
|
||||
*/
|
||||
export const Intent = Object.freeze({
|
||||
Perceptual: 0, "0": "Perceptual",
|
||||
RelativeColorimetric: 1, "1": "RelativeColorimetric",
|
||||
Saturation: 2, "2": "Saturation",
|
||||
AbsoluteColorimetric: 3, "3": "AbsoluteColorimetric",
|
||||
});
|
||||
|
||||
async function __wbg_load(module, imports) {
|
||||
if (typeof Response === 'function' && module instanceof Response) {
|
||||
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
||||
try {
|
||||
return await WebAssembly.instantiateStreaming(module, imports);
|
||||
|
||||
} catch (e) {
|
||||
if (module.headers.get('Content-Type') != 'application/wasm') {
|
||||
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
||||
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = await module.arrayBuffer();
|
||||
return await WebAssembly.instantiate(bytes, imports);
|
||||
|
||||
} else {
|
||||
const instance = await WebAssembly.instantiate(module, imports);
|
||||
|
||||
if (instance instanceof WebAssembly.Instance) {
|
||||
return { instance, module };
|
||||
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function __wbg_get_imports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbg_copyresult_b08ee7d273f295dd = function(arg0, arg1) {
|
||||
copy_result(arg0 >>> 0, arg1 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbg_copyrgb_d60ce17bb05d9b67 = function(arg0) {
|
||||
copy_rgb(arg0 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbg_makecssRGB_893bf0cd9fdb302d = function(arg0) {
|
||||
make_cssRGB(arg0 >>> 0);
|
||||
};
|
||||
imports.wbg.__wbindgen_init_externref_table = function() {
|
||||
const table = wasm.__wbindgen_export_0;
|
||||
const offset = table.grow(4);
|
||||
table.set(0, undefined);
|
||||
table.set(offset + 0, undefined);
|
||||
table.set(offset + 1, null);
|
||||
table.set(offset + 2, true);
|
||||
table.set(offset + 3, false);
|
||||
;
|
||||
};
|
||||
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
};
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
function __wbg_init_memory(imports, memory) {
|
||||
|
||||
}
|
||||
|
||||
function __wbg_finalize_init(instance, module) {
|
||||
wasm = instance.exports;
|
||||
__wbg_init.__wbindgen_wasm_module = module;
|
||||
cachedUint8ArrayMemory0 = null;
|
||||
|
||||
|
||||
wasm.__wbindgen_start();
|
||||
return wasm;
|
||||
}
|
||||
|
||||
function initSync(module) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
if (Object.getPrototypeOf(module) === Object.prototype) {
|
||||
({module} = module)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
if (!(module instanceof WebAssembly.Module)) {
|
||||
module = new WebAssembly.Module(module);
|
||||
}
|
||||
|
||||
const instance = new WebAssembly.Instance(module, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
async function __wbg_init(module_or_path) {
|
||||
if (wasm !== undefined) return wasm;
|
||||
|
||||
|
||||
if (typeof module_or_path !== 'undefined') {
|
||||
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
||||
({module_or_path} = module_or_path)
|
||||
} else {
|
||||
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const imports = __wbg_get_imports();
|
||||
|
||||
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
||||
module_or_path = fetch(module_or_path);
|
||||
}
|
||||
|
||||
__wbg_init_memory(imports);
|
||||
|
||||
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
||||
|
||||
return __wbg_finalize_init(instance, module);
|
||||
}
|
||||
|
||||
export { initSync };
|
||||
export default __wbg_init;
|
||||
BIN
external/qcms/qcms_bg.wasm
vendored
BIN
external/qcms/qcms_bg.wasm
vendored
Binary file not shown.
84
external/qcms/qcms_utils.js
vendored
84
external/qcms/qcms_utils.js
vendored
@ -1,84 +0,0 @@
|
||||
/* Copyright 2025 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.
|
||||
*/
|
||||
|
||||
class QCMS {
|
||||
static #memoryArray = null;
|
||||
|
||||
static _memory = null;
|
||||
|
||||
static _mustAddAlpha = false;
|
||||
|
||||
static _destBuffer = null;
|
||||
|
||||
static _destOffset = 0;
|
||||
|
||||
static _destLength = 0;
|
||||
|
||||
static _cssColor = "";
|
||||
|
||||
static _makeHexColor = null;
|
||||
|
||||
static get _memoryArray() {
|
||||
const array = this.#memoryArray;
|
||||
if (array?.byteLength) {
|
||||
return array;
|
||||
}
|
||||
return (this.#memoryArray = new Uint8Array(this._memory.buffer));
|
||||
}
|
||||
}
|
||||
|
||||
function copy_result(ptr, len) {
|
||||
// This function is called from the wasm module (it's an external
|
||||
// "C" function). Its goal is to copy the result from the wasm memory
|
||||
// to the destination buffer without any intermediate copies.
|
||||
const { _mustAddAlpha, _destBuffer, _destOffset, _destLength, _memoryArray } =
|
||||
QCMS;
|
||||
if (len === _destLength) {
|
||||
_destBuffer.set(_memoryArray.subarray(ptr, ptr + len), _destOffset);
|
||||
return;
|
||||
}
|
||||
if (_mustAddAlpha) {
|
||||
for (let i = ptr, ii = ptr + len, j = _destOffset; i < ii; i += 3, j += 4) {
|
||||
_destBuffer[j] = _memoryArray[i];
|
||||
_destBuffer[j + 1] = _memoryArray[i + 1];
|
||||
_destBuffer[j + 2] = _memoryArray[i + 2];
|
||||
_destBuffer[j + 3] = 255;
|
||||
}
|
||||
} else {
|
||||
for (let i = ptr, ii = ptr + len, j = _destOffset; i < ii; i += 3, j += 4) {
|
||||
_destBuffer[j] = _memoryArray[i];
|
||||
_destBuffer[j + 1] = _memoryArray[i + 1];
|
||||
_destBuffer[j + 2] = _memoryArray[i + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copy_rgb(ptr) {
|
||||
const { _destBuffer, _destOffset, _memoryArray } = QCMS;
|
||||
_destBuffer[_destOffset] = _memoryArray[ptr];
|
||||
_destBuffer[_destOffset + 1] = _memoryArray[ptr + 1];
|
||||
_destBuffer[_destOffset + 2] = _memoryArray[ptr + 2];
|
||||
}
|
||||
|
||||
function make_cssRGB(ptr) {
|
||||
const { _memoryArray } = QCMS;
|
||||
QCMS._cssColor = QCMS._makeHexColor(
|
||||
_memoryArray[ptr],
|
||||
_memoryArray[ptr + 1],
|
||||
_memoryArray[ptr + 2]
|
||||
);
|
||||
}
|
||||
|
||||
export { copy_result, copy_rgb, make_cssRGB, QCMS };
|
||||
497
gulpfile.mjs
497
gulpfile.mjs
@ -12,6 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-env node */
|
||||
|
||||
import {
|
||||
babelPluginPDFJSPreprocessor,
|
||||
@ -21,6 +22,7 @@ import { exec, execSync, spawn, spawnSync } from "child_process";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import babel from "@babel/core";
|
||||
import crypto from "crypto";
|
||||
import { fileURLToPath } from "url";
|
||||
import fs from "fs";
|
||||
import gulp from "gulp";
|
||||
import hljs from "highlight.js";
|
||||
@ -30,26 +32,28 @@ import Metalsmith from "metalsmith";
|
||||
import ordered from "ordered-read-streams";
|
||||
import path from "path";
|
||||
import postcss from "gulp-postcss";
|
||||
import postcssDarkThemeClass from "postcss-dark-theme-class";
|
||||
import postcssDirPseudoClass from "postcss-dir-pseudo-class";
|
||||
import postcssDiscardComments from "postcss-discard-comments";
|
||||
import postcssLightDarkFunction from "@csstools/postcss-light-dark-function";
|
||||
import postcssNesting from "postcss-nesting";
|
||||
import { preprocess } from "./external/builder/builder.mjs";
|
||||
import relative from "metalsmith-html-relative";
|
||||
import rename from "gulp-rename";
|
||||
import replace from "gulp-replace";
|
||||
import stream from "stream";
|
||||
import streamqueue from "streamqueue";
|
||||
import TerserPlugin from "terser-webpack-plugin";
|
||||
import Vinyl from "vinyl";
|
||||
import webpack2 from "webpack";
|
||||
import webpackStream from "webpack-stream";
|
||||
import zip from "gulp-zip";
|
||||
|
||||
const __dirname = import.meta.dirname;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const BUILD_DIR = "build/";
|
||||
const L10N_DIR = "l10n/";
|
||||
const TEST_DIR = "test/";
|
||||
const EXTENSION_SRC_DIR = "extensions/";
|
||||
|
||||
const BASELINE_DIR = BUILD_DIR + "baseline/";
|
||||
const MOZCENTRAL_BASELINE_DIR = BUILD_DIR + "mozcentral.baseline/";
|
||||
@ -74,15 +78,17 @@ const COMMON_WEB_FILES = [
|
||||
];
|
||||
const MOZCENTRAL_DIFF_FILE = "mozcentral.diff";
|
||||
|
||||
const DIST_REPO_URL = "https://github.com/mozilla/pdfjs-dist";
|
||||
|
||||
const CONFIG_FILE = "pdfjs.config";
|
||||
const config = JSON.parse(fs.readFileSync(CONFIG_FILE).toString());
|
||||
|
||||
const ENV_TARGETS = [
|
||||
"last 2 versions",
|
||||
"Chrome >= 110",
|
||||
"Chrome >= 98",
|
||||
"Firefox ESR",
|
||||
"Safari >= 16.4",
|
||||
"Node >= 20",
|
||||
"Node >= 18",
|
||||
"> 1%",
|
||||
"not IE > 0",
|
||||
"not dead",
|
||||
@ -96,7 +102,7 @@ const AUTOPREFIXER_CONFIG = {
|
||||
const BABEL_TARGETS = ENV_TARGETS.join(", ");
|
||||
|
||||
const BABEL_PRESET_ENV_OPTS = Object.freeze({
|
||||
corejs: "3.46.0",
|
||||
corejs: "3.37.1",
|
||||
exclude: ["web.structured-clone"],
|
||||
shippedProposals: true,
|
||||
useBuiltIns: "usage",
|
||||
@ -189,9 +195,6 @@ function createWebpackAlias(defines) {
|
||||
"fluent-dom": "node_modules/@fluent/dom/esm/index.js",
|
||||
};
|
||||
const libraryAlias = {
|
||||
"display-cmap_reader_factory": "src/display/stubs.js",
|
||||
"display-standard_fontdata_factory": "src/display/stubs.js",
|
||||
"display-wasm_factory": "src/display/stubs.js",
|
||||
"display-fetch_stream": "src/display/stubs.js",
|
||||
"display-network": "src/display/stubs.js",
|
||||
"display-node_stream": "src/display/stubs.js",
|
||||
@ -202,7 +205,6 @@ function createWebpackAlias(defines) {
|
||||
"web-annotation_editor_params": "web/annotation_editor_params.js",
|
||||
"web-download_manager": "",
|
||||
"web-external_services": "",
|
||||
"web-new_alt_text_manager": "web/new_alt_text_manager.js",
|
||||
"web-null_l10n": "",
|
||||
"web-pdf_attachment_viewer": "web/pdf_attachment_viewer.js",
|
||||
"web-pdf_cursor_tools": "web/pdf_cursor_tools.js",
|
||||
@ -216,16 +218,10 @@ function createWebpackAlias(defines) {
|
||||
"web-preferences": "",
|
||||
"web-print_service": "",
|
||||
"web-secondary_toolbar": "web/secondary_toolbar.js",
|
||||
"web-signature_manager": "web/signature_manager.js",
|
||||
"web-toolbar": "web/toolbar.js",
|
||||
};
|
||||
|
||||
if (defines.CHROME) {
|
||||
libraryAlias["display-cmap_reader_factory"] =
|
||||
"src/display/cmap_reader_factory.js";
|
||||
libraryAlias["display-standard_fontdata_factory"] =
|
||||
"src/display/standard_fontdata_factory.js";
|
||||
libraryAlias["display-wasm_factory"] = "src/display/wasm_factory.js";
|
||||
libraryAlias["display-fetch_stream"] = "src/display/fetch_stream.js";
|
||||
libraryAlias["display-network"] = "src/display/network.js";
|
||||
|
||||
@ -238,11 +234,6 @@ function createWebpackAlias(defines) {
|
||||
// Aliases defined here must also be replicated in the paths section of
|
||||
// the tsconfig.json file for the type generation to work.
|
||||
// In the tsconfig.json files, the .js extension must be omitted.
|
||||
libraryAlias["display-cmap_reader_factory"] =
|
||||
"src/display/cmap_reader_factory.js";
|
||||
libraryAlias["display-standard_fontdata_factory"] =
|
||||
"src/display/standard_fontdata_factory.js";
|
||||
libraryAlias["display-wasm_factory"] = "src/display/wasm_factory.js";
|
||||
libraryAlias["display-fetch_stream"] = "src/display/fetch_stream.js";
|
||||
libraryAlias["display-network"] = "src/display/network.js";
|
||||
libraryAlias["display-node_stream"] = "src/display/node_stream.js";
|
||||
@ -294,6 +285,9 @@ function createWebpackConfig(
|
||||
BUNDLE_VERSION: versionInfo.version,
|
||||
BUNDLE_BUILD: versionInfo.commit,
|
||||
TESTING: defines.TESTING ?? process.env.TESTING === "true",
|
||||
BROWSER_PREFERENCES: defaultPreferencesDir
|
||||
? getBrowserPreferences(defaultPreferencesDir)
|
||||
: {},
|
||||
DEFAULT_PREFERENCES: defaultPreferencesDir
|
||||
? getDefaultPreferences(defaultPreferencesDir)
|
||||
: {},
|
||||
@ -302,12 +296,6 @@ function createWebpackConfig(
|
||||
const licenseHeaderLibre = fs
|
||||
.readFileSync("./src/license_header_libre.js")
|
||||
.toString();
|
||||
const versionInfoHeader = [
|
||||
"/**",
|
||||
` * pdfjsVersion = ${versionInfo.version}`,
|
||||
` * pdfjsBuild = ${versionInfo.commit}`,
|
||||
" */",
|
||||
].join("\n");
|
||||
const enableSourceMaps =
|
||||
!bundleDefines.MOZCENTRAL &&
|
||||
!bundleDefines.CHROME &&
|
||||
@ -341,39 +329,9 @@ function createWebpackConfig(
|
||||
const plugins = [];
|
||||
if (!disableLicenseHeader) {
|
||||
plugins.push(
|
||||
new webpack2.BannerPlugin({
|
||||
banner: licenseHeaderLibre + "\n" + versionInfoHeader,
|
||||
raw: true,
|
||||
})
|
||||
new webpack2.BannerPlugin({ banner: licenseHeaderLibre, raw: true })
|
||||
);
|
||||
}
|
||||
plugins.push({
|
||||
/** @param {import('webpack').Compiler} compiler */
|
||||
apply(compiler) {
|
||||
const errors = [];
|
||||
|
||||
compiler.hooks.afterCompile.tap("VerifyImportMeta", compilation => {
|
||||
for (const asset of compilation.getAssets()) {
|
||||
if (asset.name.endsWith(".mjs")) {
|
||||
const source = asset.source.source();
|
||||
if (
|
||||
typeof source === "string" &&
|
||||
/new URL\([^,)]*,\s*import\.meta\.url/.test(source)
|
||||
) {
|
||||
errors.push(
|
||||
`Output module ${asset.name} uses new URL(..., import.meta.url)`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
compiler.hooks.afterEmit.tap("VerifyImportMeta", compilation => {
|
||||
// Emit the errors after emitting the files, so that it's possible to
|
||||
// look at the contents of the invalid bundle.
|
||||
compilation.errors.push(...errors);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const alias = createWebpackAlias(bundleDefines);
|
||||
const experiments = isModule ? { outputModule: true } : undefined;
|
||||
@ -397,8 +355,9 @@ function createWebpackConfig(
|
||||
// V8 chokes on very long sequences, work around that.
|
||||
sequences: false,
|
||||
},
|
||||
format: {
|
||||
comments: /@lic|webpackIgnore|@vite-ignore|pdfjsVersion/i,
|
||||
mangle: {
|
||||
// Ensure that the `tweakWebpackOutput` function works.
|
||||
reserved: ["__webpack_exports__"],
|
||||
},
|
||||
keep_classnames: true,
|
||||
keep_fnames: true,
|
||||
@ -418,15 +377,8 @@ function createWebpackConfig(
|
||||
},
|
||||
devtool: enableSourceMaps ? "source-map" : undefined,
|
||||
module: {
|
||||
parser: {
|
||||
javascript: {
|
||||
importMeta: false,
|
||||
url: false,
|
||||
},
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
test: /\.[mc]?js$/,
|
||||
loader: "babel-loader",
|
||||
exclude: babelExcludeRegExp,
|
||||
options: {
|
||||
@ -497,6 +449,13 @@ function checkChromePreferencesFile(chromePrefsPath, webPrefs) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function tweakWebpackOutput(jsName) {
|
||||
return replace(
|
||||
/((?:\s|,)__webpack_exports__)(?:\s?)=(?:\s?)({};)/gm,
|
||||
(match, p1, p2) => `${p1} = globalThis.${jsName} = ${p2}`
|
||||
);
|
||||
}
|
||||
|
||||
function createMainBundle(defines) {
|
||||
const mainFileConfig = createWebpackConfig(defines, {
|
||||
filename: defines.MINIFIED ? "pdf.min.mjs" : "pdf.mjs",
|
||||
@ -506,7 +465,8 @@ function createMainBundle(defines) {
|
||||
});
|
||||
return gulp
|
||||
.src("./src/pdf.js", { encoding: false })
|
||||
.pipe(webpack2Stream(mainFileConfig));
|
||||
.pipe(webpack2Stream(mainFileConfig))
|
||||
.pipe(tweakWebpackOutput("pdfjsLib"));
|
||||
}
|
||||
|
||||
function createScriptingBundle(defines, extraOptions = undefined) {
|
||||
@ -574,7 +534,8 @@ function createSandboxBundle(defines, extraOptions = undefined) {
|
||||
|
||||
return gulp
|
||||
.src("./src/pdf.sandbox.js", { encoding: false })
|
||||
.pipe(webpack2Stream(sandboxFileConfig));
|
||||
.pipe(webpack2Stream(sandboxFileConfig))
|
||||
.pipe(tweakWebpackOutput("pdfjsSandbox"));
|
||||
}
|
||||
|
||||
function createWorkerBundle(defines) {
|
||||
@ -586,7 +547,8 @@ function createWorkerBundle(defines) {
|
||||
});
|
||||
return gulp
|
||||
.src("./src/pdf.worker.js", { encoding: false })
|
||||
.pipe(webpack2Stream(workerFileConfig));
|
||||
.pipe(webpack2Stream(workerFileConfig))
|
||||
.pipe(tweakWebpackOutput("pdfjsWorker"));
|
||||
}
|
||||
|
||||
function createWebBundle(defines, options) {
|
||||
@ -634,7 +596,8 @@ function createComponentsBundle(defines) {
|
||||
});
|
||||
return gulp
|
||||
.src("./web/pdf_viewer.component.js", { encoding: false })
|
||||
.pipe(webpack2Stream(componentsFileConfig));
|
||||
.pipe(webpack2Stream(componentsFileConfig))
|
||||
.pipe(tweakWebpackOutput("pdfjsViewer"));
|
||||
}
|
||||
|
||||
function createImageDecodersBundle(defines) {
|
||||
@ -648,7 +611,8 @@ function createImageDecodersBundle(defines) {
|
||||
});
|
||||
return gulp
|
||||
.src("./src/pdf.image_decoders.js", { encoding: false })
|
||||
.pipe(webpack2Stream(componentsFileConfig));
|
||||
.pipe(webpack2Stream(componentsFileConfig))
|
||||
.pipe(tweakWebpackOutput("pdfjsImageDecoders"));
|
||||
}
|
||||
|
||||
function createCMapBundle() {
|
||||
@ -658,19 +622,13 @@ function createCMapBundle() {
|
||||
});
|
||||
}
|
||||
|
||||
function createICCBundle() {
|
||||
return gulp.src(["external/iccs/*.icc", "external/iccs/LICENSE"], {
|
||||
base: "external/iccs",
|
||||
encoding: false,
|
||||
});
|
||||
}
|
||||
|
||||
function createStandardFontBundle() {
|
||||
return gulp.src(
|
||||
[
|
||||
"external/standard_fonts/*.pfb",
|
||||
"external/standard_fonts/*.ttf",
|
||||
"external/standard_fonts/LICENSE_*",
|
||||
"external/standard_fonts/LICENSE_FOXIT",
|
||||
"external/standard_fonts/LICENSE_LIBERATION",
|
||||
],
|
||||
{
|
||||
base: "external/standard_fonts",
|
||||
@ -679,26 +637,6 @@ function createStandardFontBundle() {
|
||||
);
|
||||
}
|
||||
|
||||
function createWasmBundle() {
|
||||
return ordered([
|
||||
gulp.src(
|
||||
[
|
||||
"external/openjpeg/*.wasm",
|
||||
"external/openjpeg/openjpeg_nowasm_fallback.js",
|
||||
"external/openjpeg/LICENSE_*",
|
||||
],
|
||||
{
|
||||
base: "external/openjpeg",
|
||||
encoding: false,
|
||||
}
|
||||
),
|
||||
gulp.src(["external/qcms/*.wasm", "external/qcms/LICENSE_*"], {
|
||||
base: "external/qcms",
|
||||
encoding: false,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
function checkFile(filePath) {
|
||||
try {
|
||||
const stat = fs.lstatSync(filePath);
|
||||
@ -731,8 +669,9 @@ function getTempFile(prefix, suffix) {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
function runTests(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function createTestSource(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
const source = stream.Readable({ objectMode: true });
|
||||
source._read = function () {
|
||||
console.log();
|
||||
console.log("### Running " + testsName + " tests");
|
||||
|
||||
@ -744,21 +683,17 @@ function runTests(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
if (!bot) {
|
||||
args.push("--reftest");
|
||||
} else {
|
||||
// The browser-tests are too slow in Google Chrome on the bots,
|
||||
// causing a timeout, hence disabling them for now.
|
||||
forceNoChrome = true;
|
||||
const os = process.env.OS;
|
||||
if (/windows/i.test(os)) {
|
||||
// The browser-tests are too slow in Google Chrome on the Windows
|
||||
// bot, causing a timeout, hence disabling them for now.
|
||||
forceNoChrome = true;
|
||||
}
|
||||
}
|
||||
if (xfaOnly) {
|
||||
args.push("--xfaOnly");
|
||||
}
|
||||
args.push("--manifestFile=" + PDF_TEST);
|
||||
collectArgs(
|
||||
{
|
||||
names: ["-t", "--testfilter"],
|
||||
hasValue: true,
|
||||
},
|
||||
args
|
||||
);
|
||||
break;
|
||||
case "unit":
|
||||
args.push("--unitTest");
|
||||
@ -770,8 +705,8 @@ function runTests(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
args.push("--integration");
|
||||
break;
|
||||
default:
|
||||
reject(new Error(`Unknown tests name '${testsName}'`));
|
||||
return;
|
||||
this.emit("error", new Error("Unknown name: " + testsName));
|
||||
return null;
|
||||
}
|
||||
if (bot) {
|
||||
args.push("--strictVerify");
|
||||
@ -779,9 +714,6 @@ function runTests(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
if (process.argv.includes("--noChrome") || forceNoChrome) {
|
||||
args.push("--noChrome");
|
||||
}
|
||||
if (process.argv.includes("--noFirefox")) {
|
||||
args.push("--noFirefox");
|
||||
}
|
||||
if (process.argv.includes("--headless")) {
|
||||
args.push("--headless");
|
||||
}
|
||||
@ -789,33 +721,13 @@ function runTests(testsName, { bot = false, xfaOnly = false } = {}) {
|
||||
const testProcess = startNode(args, { cwd: TEST_DIR, stdio: "inherit" });
|
||||
testProcess.on("close", function (code) {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Running ${testsName} tests failed.`));
|
||||
throw new Error(`Running ${testsName} tests failed.`);
|
||||
}
|
||||
resolve();
|
||||
source.push(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function collectArgs(options, args) {
|
||||
if (!Array.isArray(options)) {
|
||||
options = [options];
|
||||
}
|
||||
for (let i = 0, ii = process.argv.length; i < ii; i++) {
|
||||
const arg = process.argv[i];
|
||||
const option = options.find(opt => opt.names.includes(arg));
|
||||
if (!option) {
|
||||
continue;
|
||||
}
|
||||
if (!option.hasValue) {
|
||||
args.push(arg);
|
||||
continue;
|
||||
}
|
||||
const next = process.argv[i + 1];
|
||||
if (next && !next.startsWith("-")) {
|
||||
args.push(arg, next);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
return source;
|
||||
}
|
||||
|
||||
function makeRef(done, bot) {
|
||||
@ -825,28 +737,20 @@ function makeRef(done, bot) {
|
||||
let forceNoChrome = false;
|
||||
const args = ["test.mjs", "--masterMode"];
|
||||
if (bot) {
|
||||
// The browser-tests are too slow in Google Chrome on the bots,
|
||||
// causing a timeout, hence disabling them for now.
|
||||
forceNoChrome = true;
|
||||
|
||||
const os = process.env.OS;
|
||||
if (/windows/i.test(os)) {
|
||||
// The browser-tests are too slow in Google Chrome on the Windows
|
||||
// bot, causing a timeout, hence disabling them for now.
|
||||
forceNoChrome = true;
|
||||
}
|
||||
args.push("--noPrompts", "--strictVerify");
|
||||
}
|
||||
if (process.argv.includes("--noChrome") || forceNoChrome) {
|
||||
args.push("--noChrome");
|
||||
}
|
||||
if (process.argv.includes("--noFirefox")) {
|
||||
args.push("--noFirefox");
|
||||
}
|
||||
if (process.argv.includes("--headless")) {
|
||||
args.push("--headless");
|
||||
}
|
||||
collectArgs(
|
||||
{
|
||||
names: ["-t", "--testfilter"],
|
||||
hasValue: true,
|
||||
},
|
||||
args
|
||||
);
|
||||
|
||||
const testProcess = startNode(args, { cwd: TEST_DIR, stdio: "inherit" });
|
||||
testProcess.on("close", function (code) {
|
||||
@ -953,6 +857,13 @@ async function parseDefaultPreferences(dir) {
|
||||
"./" + DEFAULT_PREFERENCES_DIR + dir + "app_options.mjs"
|
||||
);
|
||||
|
||||
const browserPrefs = AppOptions.getAll(
|
||||
OptionKind.BROWSER,
|
||||
/* defaultOnly = */ true
|
||||
);
|
||||
if (Object.keys(browserPrefs).length === 0) {
|
||||
throw new Error("No browser preferences found.");
|
||||
}
|
||||
const prefs = AppOptions.getAll(
|
||||
OptionKind.PREFERENCE,
|
||||
/* defaultOnly = */ true
|
||||
@ -961,12 +872,23 @@ async function parseDefaultPreferences(dir) {
|
||||
throw new Error("No default preferences found.");
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
DEFAULT_PREFERENCES_DIR + dir + "browser_preferences.json",
|
||||
JSON.stringify(browserPrefs)
|
||||
);
|
||||
fs.writeFileSync(
|
||||
DEFAULT_PREFERENCES_DIR + dir + "default_preferences.json",
|
||||
JSON.stringify(prefs)
|
||||
);
|
||||
}
|
||||
|
||||
function getBrowserPreferences(dir) {
|
||||
const str = fs
|
||||
.readFileSync(DEFAULT_PREFERENCES_DIR + dir + "browser_preferences.json")
|
||||
.toString();
|
||||
return JSON.parse(str);
|
||||
}
|
||||
|
||||
function getDefaultPreferences(dir) {
|
||||
const str = fs
|
||||
.readFileSync(DEFAULT_PREFERENCES_DIR + dir + "default_preferences.json")
|
||||
@ -1120,9 +1042,7 @@ function buildGeneric(defines, dir) {
|
||||
})
|
||||
.pipe(gulp.dest(dir + "web")),
|
||||
createCMapBundle().pipe(gulp.dest(dir + "web/cmaps")),
|
||||
createICCBundle().pipe(gulp.dest(dir + "web/iccs")),
|
||||
createStandardFontBundle().pipe(gulp.dest(dir + "web/standard_fonts")),
|
||||
createWasmBundle().pipe(gulp.dest(dir + "web/wasm")),
|
||||
|
||||
preprocessHTML("web/viewer.html", defines).pipe(gulp.dest(dir + "web")),
|
||||
preprocessCSS("web/viewer.css", defines)
|
||||
@ -1131,7 +1051,7 @@ function buildGeneric(defines, dir) {
|
||||
postcssDirPseudoClass(),
|
||||
discardCommentsCSS(),
|
||||
postcssNesting(),
|
||||
postcssLightDarkFunction({ preserve: true }),
|
||||
postcssDarkThemeClass(),
|
||||
autoprefixer(AUTOPREFIXER_CONFIG),
|
||||
])
|
||||
)
|
||||
@ -1205,10 +1125,8 @@ function buildComponents(defines, dir) {
|
||||
"web/images/loading-icon.gif",
|
||||
"web/images/altText_*.svg",
|
||||
"web/images/editor-toolbar-*.svg",
|
||||
"web/images/messageBar_*.svg",
|
||||
"web/images/toolbarButton-{editorHighlight,menuArrow}.svg",
|
||||
"web/images/cursor-*.svg",
|
||||
"web/images/comment-*.svg",
|
||||
];
|
||||
|
||||
return ordered([
|
||||
@ -1222,7 +1140,6 @@ function buildComponents(defines, dir) {
|
||||
postcssDirPseudoClass(),
|
||||
discardCommentsCSS(),
|
||||
postcssNesting(),
|
||||
postcssLightDarkFunction({ preserve: true }),
|
||||
autoprefixer(AUTOPREFIXER_CONFIG),
|
||||
])
|
||||
)
|
||||
@ -1361,31 +1278,26 @@ gulp.task(
|
||||
)
|
||||
);
|
||||
|
||||
function createDefaultPrefsFile() {
|
||||
const defaultFileName = "PdfJsDefaultPrefs.js",
|
||||
overrideFileName = "PdfJsOverridePrefs.js";
|
||||
function preprocessDefaultPreferences(content) {
|
||||
const licenseHeader = fs.readFileSync("./src/license_header.js").toString();
|
||||
|
||||
const MODIFICATION_WARNING =
|
||||
"// THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT MANUALLY!\n//\n" +
|
||||
`// Any overrides should be placed in \`${overrideFileName}\`.\n`;
|
||||
"//\n// THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT MANUALLY!\n//\n";
|
||||
|
||||
const prefs = getDefaultPreferences("mozcentral/");
|
||||
const buf = [];
|
||||
const bundleDefines = {
|
||||
...DEFINES,
|
||||
DEFAULT_PREFERENCES: getDefaultPreferences("mozcentral/"),
|
||||
};
|
||||
|
||||
for (const name in prefs) {
|
||||
let value = prefs[name];
|
||||
content = preprocessPDFJSCode(
|
||||
{
|
||||
rootPath: __dirname,
|
||||
defines: bundleDefines,
|
||||
},
|
||||
content
|
||||
);
|
||||
|
||||
if (typeof value === "string") {
|
||||
value = `"${value}"`;
|
||||
}
|
||||
buf.push(`pref("pdfjs.${name}", ${value});`);
|
||||
}
|
||||
buf.sort();
|
||||
buf.unshift(licenseHeader, MODIFICATION_WARNING);
|
||||
buf.push(`\n#include ${overrideFileName}\n`);
|
||||
|
||||
return createStringSource(defaultFileName, buf.join("\n"));
|
||||
return licenseHeader + "\n" + MODIFICATION_WARNING + "\n" + content + "\n";
|
||||
}
|
||||
|
||||
function replaceMozcentralCSS() {
|
||||
@ -1413,7 +1325,8 @@ gulp.task(
|
||||
MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + "browser/extensions/pdfjs/",
|
||||
MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_EXTENSION_DIR + "content/",
|
||||
MOZCENTRAL_L10N_DIR =
|
||||
MOZCENTRAL_DIR + "browser/locales/en-US/pdfviewer/";
|
||||
MOZCENTRAL_DIR + "browser/locales/en-US/pdfviewer/",
|
||||
FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + "/firefox/content/";
|
||||
|
||||
const MOZCENTRAL_WEB_FILES = [
|
||||
...COMMON_WEB_FILES,
|
||||
@ -1451,11 +1364,9 @@ gulp.task(
|
||||
createCMapBundle().pipe(
|
||||
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/cmaps")
|
||||
),
|
||||
createICCBundle().pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/iccs")),
|
||||
createStandardFontBundle().pipe(
|
||||
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/standard_fonts")
|
||||
),
|
||||
createWasmBundle().pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + "web/wasm")),
|
||||
|
||||
preprocessHTML("web/viewer.html", defines).pipe(
|
||||
gulp.dest(MOZCENTRAL_CONTENT_DIR + "web")
|
||||
@ -1490,7 +1401,12 @@ gulp.task(
|
||||
gulp
|
||||
.src("LICENSE", { encoding: false })
|
||||
.pipe(gulp.dest(MOZCENTRAL_EXTENSION_DIR)),
|
||||
createDefaultPrefsFile().pipe(gulp.dest(MOZCENTRAL_EXTENSION_DIR)),
|
||||
gulp
|
||||
.src(FIREFOX_CONTENT_DIR + "PdfJsDefaultPreferences.sys.mjs", {
|
||||
encoding: false,
|
||||
})
|
||||
.pipe(transform("utf8", preprocessDefaultPreferences))
|
||||
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR)),
|
||||
]);
|
||||
}
|
||||
)
|
||||
@ -1555,15 +1471,9 @@ gulp.task(
|
||||
createCMapBundle().pipe(
|
||||
gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/cmaps")
|
||||
),
|
||||
createICCBundle().pipe(
|
||||
gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/iccs")
|
||||
),
|
||||
createStandardFontBundle().pipe(
|
||||
gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/standard_fonts")
|
||||
),
|
||||
createWasmBundle().pipe(
|
||||
gulp.dest(CHROME_BUILD_CONTENT_DIR + "web/wasm")
|
||||
),
|
||||
|
||||
preprocessHTML("web/viewer.html", defines).pipe(
|
||||
gulp.dest(CHROME_BUILD_CONTENT_DIR + "web")
|
||||
@ -1574,7 +1484,7 @@ gulp.task(
|
||||
postcssDirPseudoClass(),
|
||||
discardCommentsCSS(),
|
||||
postcssNesting(),
|
||||
postcssLightDarkFunction({ preserve: true }),
|
||||
postcssDarkThemeClass(),
|
||||
autoprefixer(AUTOPREFIXER_CONFIG),
|
||||
])
|
||||
)
|
||||
@ -1648,9 +1558,6 @@ function buildLibHelper(bundleDefines, inputStream, outputDir) {
|
||||
defines: bundleDefines,
|
||||
map: {
|
||||
"pdfjs-lib": "../pdf.js",
|
||||
"display-cmap_reader_factory": "./cmap_reader_factory.js",
|
||||
"display-standard_fontdata_factory": "./standard_fontdata_factory.js",
|
||||
"display-wasm_factory": "./wasm_factory.js",
|
||||
"display-fetch_stream": "./fetch_stream.js",
|
||||
"display-network": "./network.js",
|
||||
"display-node_stream": "./node_stream.js",
|
||||
@ -1676,6 +1583,9 @@ function buildLib(defines, dir) {
|
||||
BUNDLE_VERSION: versionInfo.version,
|
||||
BUNDLE_BUILD: versionInfo.commit,
|
||||
TESTING: defines.TESTING ?? process.env.TESTING === "true",
|
||||
BROWSER_PREFERENCES: getBrowserPreferences(
|
||||
defines.SKIP_BABEL ? "lib/" : "lib-legacy/"
|
||||
),
|
||||
DEFAULT_PREFERENCES: getDefaultPreferences(
|
||||
defines.SKIP_BABEL ? "lib/" : "lib-legacy/"
|
||||
),
|
||||
@ -1696,7 +1606,6 @@ function buildLib(defines, dir) {
|
||||
}),
|
||||
gulp.src("test/unit/*.js", { base: ".", encoding: false }),
|
||||
gulp.src("external/openjpeg/*.js", { base: "openjpeg/", encoding: false }),
|
||||
gulp.src("external/qcms/*.js", { base: "qcms/", encoding: false }),
|
||||
]);
|
||||
|
||||
return buildLibHelper(bundleDefines, inputStream, dir);
|
||||
@ -1824,55 +1733,57 @@ function setTestEnv(done) {
|
||||
|
||||
gulp.task(
|
||||
"test",
|
||||
gulp.series(setTestEnv, "generic", "components", async function runTest() {
|
||||
await runTests("unit");
|
||||
await runTests("browser");
|
||||
await runTests("integration");
|
||||
gulp.series(setTestEnv, "generic", "components", function runTest() {
|
||||
return streamqueue(
|
||||
{ objectMode: true },
|
||||
createTestSource("unit"),
|
||||
createTestSource("browser"),
|
||||
createTestSource("integration")
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"bottest",
|
||||
gulp.series(setTestEnv, "generic", "components", async function runBotTest() {
|
||||
await runTests("unit", { bot: true });
|
||||
await runTests("browser", { bot: true });
|
||||
await runTests("integration");
|
||||
gulp.series(setTestEnv, "generic", "components", function runBotTest() {
|
||||
return streamqueue(
|
||||
{ objectMode: true },
|
||||
createTestSource("unit", { bot: true }),
|
||||
createTestSource("browser", { bot: true }),
|
||||
createTestSource("integration")
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"xfatest",
|
||||
gulp.series(setTestEnv, "generic", "components", async function runXfaTest() {
|
||||
await runTests("unit");
|
||||
await runTests("browser", { xfaOnly: true });
|
||||
await runTests("integration");
|
||||
gulp.series(setTestEnv, "generic", "components", function runXfaTest() {
|
||||
return streamqueue(
|
||||
{ objectMode: true },
|
||||
createTestSource("unit"),
|
||||
createTestSource("browser", { xfaOnly: true }),
|
||||
createTestSource("integration")
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"botxfatest",
|
||||
gulp.series(
|
||||
setTestEnv,
|
||||
"generic",
|
||||
"components",
|
||||
async function runBotXfaTest() {
|
||||
await runTests("unit", { bot: true });
|
||||
await runTests("browser", { bot: true, xfaOnly: true });
|
||||
await runTests("integration");
|
||||
}
|
||||
)
|
||||
gulp.series(setTestEnv, "generic", "components", function runBotXfaTest() {
|
||||
return streamqueue(
|
||||
{ objectMode: true },
|
||||
createTestSource("unit", { bot: true }),
|
||||
createTestSource("browser", { bot: true, xfaOnly: true }),
|
||||
createTestSource("integration")
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"browsertest",
|
||||
gulp.series(
|
||||
setTestEnv,
|
||||
"generic",
|
||||
"components",
|
||||
async function runBrowserTest() {
|
||||
await runTests("browser");
|
||||
}
|
||||
)
|
||||
gulp.series(setTestEnv, "generic", "components", function runBrowserTest() {
|
||||
return createTestSource("browser");
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
@ -1881,30 +1792,33 @@ gulp.task(
|
||||
setTestEnv,
|
||||
"generic",
|
||||
"components",
|
||||
async function runBotBrowserTest() {
|
||||
await runTests("browser", { bot: true });
|
||||
function runBotBrowserTest() {
|
||||
return streamqueue(
|
||||
{ objectMode: true },
|
||||
createTestSource("browser", { bot: true })
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"unittest",
|
||||
gulp.series(setTestEnv, "generic", async function runUnitTest() {
|
||||
await runTests("unit");
|
||||
gulp.series(setTestEnv, "generic", function runUnitTest() {
|
||||
return createTestSource("unit");
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"integrationtest",
|
||||
gulp.series(setTestEnv, "generic", async function runIntegrationTest() {
|
||||
await runTests("integration");
|
||||
gulp.series(setTestEnv, "generic", function runIntegrationTest() {
|
||||
return createTestSource("integration");
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"fonttest",
|
||||
gulp.series(setTestEnv, async function runFontTest() {
|
||||
await runTests("font");
|
||||
gulp.series(setTestEnv, function runFontTest() {
|
||||
return createTestSource("font");
|
||||
})
|
||||
);
|
||||
|
||||
@ -2000,34 +1914,31 @@ function createBaseline(done) {
|
||||
|
||||
gulp.task(
|
||||
"unittestcli",
|
||||
gulp.series(
|
||||
setTestEnv,
|
||||
"generic-legacy",
|
||||
"lib-legacy",
|
||||
function runUnitTestCli(done) {
|
||||
const options = [
|
||||
"node_modules/jasmine/bin/jasmine",
|
||||
"JASMINE_CONFIG_PATH=test/unit/clitests.json",
|
||||
];
|
||||
const jasmineProcess = startNode(options, { stdio: "inherit" });
|
||||
jasmineProcess.on("close", function (code) {
|
||||
if (code !== 0) {
|
||||
done(new Error("Unit tests failed."));
|
||||
return;
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
)
|
||||
gulp.series(setTestEnv, "lib-legacy", function runUnitTestCli(done) {
|
||||
const options = [
|
||||
"node_modules/jasmine/bin/jasmine",
|
||||
"JASMINE_CONFIG_PATH=test/unit/clitests.json",
|
||||
];
|
||||
const jasmineProcess = startNode(options, { stdio: "inherit" });
|
||||
jasmineProcess.on("close", function (code) {
|
||||
if (code !== 0) {
|
||||
done(new Error("Unit tests failed."));
|
||||
return;
|
||||
}
|
||||
done();
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task("lint", function (done) {
|
||||
console.log();
|
||||
console.log("### Linting JS/CSS/JSON/SVG/HTML files");
|
||||
console.log("### Linting JS/CSS/JSON files");
|
||||
|
||||
// Ensure that we lint the Firefox specific *.jsm files too.
|
||||
const esLintOptions = [
|
||||
"node_modules/eslint/bin/eslint",
|
||||
"--ext",
|
||||
".js,.jsm,.mjs,.json",
|
||||
".",
|
||||
"--report-unused-disable-directives",
|
||||
];
|
||||
@ -2047,21 +1958,13 @@ gulp.task("lint", function (done) {
|
||||
const prettierOptions = [
|
||||
"node_modules/prettier/bin/prettier.cjs",
|
||||
"**/*.json",
|
||||
"**/*.html",
|
||||
];
|
||||
if (process.argv.includes("--fix")) {
|
||||
prettierOptions.push("--log-level", "error", "--write");
|
||||
prettierOptions.push("--log-level", "silent", "--write");
|
||||
} else {
|
||||
prettierOptions.push("--log-level", "warn", "--check");
|
||||
}
|
||||
|
||||
const svgLintOptions = [
|
||||
"node_modules/svglint/bin/cli.js",
|
||||
"**/*.svg",
|
||||
"--ci",
|
||||
"--no-summary",
|
||||
];
|
||||
|
||||
const esLintProcess = startNode(esLintOptions, { stdio: "inherit" });
|
||||
esLintProcess.on("close", function (esLintCode) {
|
||||
if (esLintCode !== 0) {
|
||||
@ -2082,19 +1985,8 @@ gulp.task("lint", function (done) {
|
||||
done(new Error("Prettier failed."));
|
||||
return;
|
||||
}
|
||||
|
||||
const svgLintProcess = startNode(svgLintOptions, {
|
||||
stdio: "inherit",
|
||||
});
|
||||
svgLintProcess.on("close", function (svgLintCode) {
|
||||
if (svgLintCode !== 0) {
|
||||
done(new Error("svglint failed."));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("files checked, no errors found");
|
||||
done();
|
||||
});
|
||||
console.log("files checked, no errors found");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -2133,15 +2025,6 @@ gulp.task(
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("dev-wasm", function () {
|
||||
const VIEWER_WASM_OUTPUT = "web/wasm/";
|
||||
|
||||
fs.rmSync(VIEWER_WASM_OUTPUT, { recursive: true, force: true });
|
||||
fs.mkdirSync(VIEWER_WASM_OUTPUT, { recursive: true });
|
||||
|
||||
return createWasmBundle().pipe(gulp.dest(VIEWER_WASM_OUTPUT));
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"dev-sandbox",
|
||||
gulp.series(
|
||||
@ -2177,13 +2060,6 @@ gulp.task(
|
||||
gulp.series("locale")
|
||||
);
|
||||
},
|
||||
function watchWasm() {
|
||||
gulp.watch(
|
||||
["external/openjpeg/*", "external/qcms/*"],
|
||||
{ ignoreInitial: false },
|
||||
gulp.series("dev-wasm")
|
||||
);
|
||||
},
|
||||
function watchDevSandbox() {
|
||||
gulp.watch(
|
||||
[
|
||||
@ -2288,8 +2164,6 @@ gulp.task("metalsmith", async function () {
|
||||
.use(
|
||||
layouts({
|
||||
directory: "docs/templates",
|
||||
pattern: "**",
|
||||
transform: "nunjucks",
|
||||
})
|
||||
)
|
||||
.use(relative())
|
||||
@ -2325,9 +2199,8 @@ function packageJson() {
|
||||
const DIST_NAME = "pdfjs-dist";
|
||||
const DIST_DESCRIPTION = "Generic build of Mozilla's PDF.js library.";
|
||||
const DIST_KEYWORDS = ["Mozilla", "pdf", "pdf.js"];
|
||||
const DIST_HOMEPAGE = "https://mozilla.github.io/pdf.js/";
|
||||
const DIST_HOMEPAGE = "http://mozilla.github.io/pdf.js/";
|
||||
const DIST_BUGS_URL = "https://github.com/mozilla/pdf.js/issues";
|
||||
const DIST_GIT_URL = "https://github.com/mozilla/pdf.js.git";
|
||||
const DIST_LICENSE = "Apache-2.0";
|
||||
|
||||
const npmManifest = {
|
||||
@ -2341,7 +2214,8 @@ function packageJson() {
|
||||
bugs: DIST_BUGS_URL,
|
||||
license: DIST_LICENSE,
|
||||
optionalDependencies: {
|
||||
"@napi-rs/canvas": "^0.1.81",
|
||||
canvas: "^2.11.2",
|
||||
path2d: "^0.2.0",
|
||||
},
|
||||
browser: {
|
||||
canvas: false,
|
||||
@ -2352,10 +2226,10 @@ function packageJson() {
|
||||
},
|
||||
repository: {
|
||||
type: "git",
|
||||
url: `git+${DIST_GIT_URL}`,
|
||||
url: `git+https://github.com/mozilla/pdf.js.git`,
|
||||
},
|
||||
engines: {
|
||||
node: ">=20.16.0 || >=22.3.0",
|
||||
node: ">=18",
|
||||
},
|
||||
scripts: {},
|
||||
};
|
||||
@ -2379,8 +2253,23 @@ gulp.task(
|
||||
"minified-legacy",
|
||||
"types",
|
||||
function createDist() {
|
||||
console.log();
|
||||
console.log("### Cloning baseline distribution");
|
||||
|
||||
fs.rmSync(DIST_DIR, { recursive: true, force: true });
|
||||
fs.mkdirSync(DIST_DIR, { recursive: true });
|
||||
safeSpawnSync("git", ["clone", "--depth", "1", DIST_REPO_URL, DIST_DIR]);
|
||||
|
||||
console.log();
|
||||
console.log("### Overwriting all files");
|
||||
|
||||
// Remove all files/folders, except for `.git` because it needs to be a
|
||||
// valid Git repository for the Git commands in the `dist` target to work.
|
||||
for (const entry of fs.readdirSync(DIST_DIR)) {
|
||||
if (entry !== ".git") {
|
||||
fs.rmSync(DIST_DIR + entry, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
return ordered([
|
||||
packageJson().pipe(gulp.dest(DIST_DIR)),
|
||||
@ -2400,24 +2289,12 @@ gulp.task(
|
||||
encoding: false,
|
||||
})
|
||||
.pipe(gulp.dest(DIST_DIR)),
|
||||
gulp
|
||||
.src(GENERIC_DIR + "web/iccs/**/*", {
|
||||
base: GENERIC_DIR + "web",
|
||||
encoding: false,
|
||||
})
|
||||
.pipe(gulp.dest(DIST_DIR)),
|
||||
gulp
|
||||
.src(GENERIC_DIR + "web/standard_fonts/**/*", {
|
||||
base: GENERIC_DIR + "web",
|
||||
encoding: false,
|
||||
})
|
||||
.pipe(gulp.dest(DIST_DIR)),
|
||||
gulp
|
||||
.src(GENERIC_DIR + "web/wasm/**/*", {
|
||||
base: GENERIC_DIR + "web",
|
||||
encoding: false,
|
||||
})
|
||||
.pipe(gulp.dest(DIST_DIR)),
|
||||
gulp
|
||||
.src(
|
||||
[
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user