Merge branch 'master' of github.com:mozilla/pdf.js into fallback-ui

Conflicts:
	extensions/firefox/components/PdfStreamConverter.js
This commit is contained in:
Brendan Dahl 2012-05-24 14:01:10 -07:00
commit 2da12930a6
43 changed files with 1052 additions and 179 deletions

View File

@ -0,0 +1,3 @@
resource pdf.js content/
component {d0c5195d-e798-49d4-b1d3-9324328b2291} components/PdfStreamConverter.js
contract @mozilla.org/streamconv;1?from=application/pdf&to=*/* {d0c5195d-e798-49d4-b1d3-9324328b2291}

View File

@ -11,8 +11,7 @@ const Cr = Components.results;
const Cu = Components.utils;
const PDFJS_EVENT_ID = 'pdf.js.message';
const PDF_CONTENT_TYPE = 'application/pdf';
const EXT_ID = 'uriloader@pdf.js';
const EXT_PREFIX = 'extensions.' + EXT_ID;
const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX';
const MAX_DATABASE_LENGTH = 4096;
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
@ -59,7 +58,7 @@ function getStringPref(pref, def) {
}
function log(aMsg) {
if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false))
if (!getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false))
return;
let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
Services.console.logStringMessage(msg);
@ -144,12 +143,12 @@ ChromeActions.prototype = {
// Protect against something sending tons of data to setDatabase.
if (data.length > MAX_DATABASE_LENGTH)
return;
setStringPref(EXT_PREFIX + '.database', data);
setStringPref(PREF_PREFIX + '.database', data);
},
getDatabase: function() {
if (inPrivateBrowsing)
return '{}';
return getStringPref(EXT_PREFIX + '.database', '{}');
return getStringPref(PREF_PREFIX + '.database', '{}');
},
getLocale: function() {
return getStringPref('general.useragent.locale', 'en-US');
@ -168,7 +167,7 @@ ChromeActions.prototype = {
}
},
pdfBugEnabled: function() {
return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false);
return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
},
fallback: function(url) {
var self = this;
@ -218,7 +217,7 @@ function PdfStreamConverter() {
PdfStreamConverter.prototype = {
// properties required for XPCOM registration:
classID: Components.ID('{6457a96b-2d68-439a-bcfa-44465fbcdbb1}'),
classID: Components.ID('{PDFJSSCRIPT_STREAM_CONVERTER_ID}'),
classDescription: 'pdf.js Component',
contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*',

View File

@ -1,27 +0,0 @@
<?xml version="1.0"?>
#filter substitution
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>uriloader@pdf.js</em:id>
<!-- PDFJS_LOCALIZED_METADATA -->
<em:name>PDF Viewer</em:name>
<em:version>PDFJSSCRIPT_VERSION</em:version>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>@FIREFOX_VERSION@</em:minVersion>
<em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
</Description>
</em:targetApplication>
<em:strictCompatibility>true</em:strictCompatibility>
<em:bootstrap>true</em:bootstrap>
<em:creator>Mozilla</em:creator>
<em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
<em:homepageURL>https://support.mozilla.org/kb/Opening%20PDF%20files%20within%20Firefox</em:homepageURL>
<em:type>2</em:type>
</Description>
</RDF>

8
l10n/cs/metadata.inc Normal file
View File

@ -0,0 +1,8 @@
<em:localized>
<Description>
<em:locale>cs</em:locale>
<em:name>PDF Viewer</em:name>
<em:description>Používá HTML5 pro zobrazení PDF souborů přímo ve Firefoxu.</em:description>
</Description>
</em:localized>

45
l10n/cs/viewer.properties Normal file
View File

@ -0,0 +1,45 @@
bookmark.title=Aktuální zobrazení(zkopírovat nebo otevřít v novém okně)
previous.title=Předchozí stránka
next.title=Další stránka
print.title=Tisk
download.title=Stáhnout
zoom_out.title=Zmenšit
zoom_in.title=Zvětšit
error_more_info=Více informací
error_less_info=Méně informací
error_close=Zavřít
error_build=PDF.JS Build: {{build}}
error_message=Zpráva:{{message}}
error_stack=Stack:{{stack}}
error_file=Soubor:{{file}}
error_line=Řádek:{{line}}
page_scale_width=Šířka stránky
page_scale_fit=Stránka
page_scale_auto=Automatické přibližení
page_scale_actual=Skutečná velikost
toggle_slider.title=Přepnout posuvník
thumbs.title=Zobrazit náhledy
outline.title=Zobrazit osnovu dokumentu
loading=Načítám... {{percent}}%
loading_error_indicator=Chyba
loading_error=Došlo k chybě při načítání PDF.
rendering_error=Došlo k chybě při vykreslování stránky.
page_label=Stránka:
page_of=z{{pageCount}}
no_outline=Žádné osnovy k dispozici
open_file.title=Otevřít soubor
text_annotation_type=[{{type}}Anotace]
toggle_slider_label=Přepnout posuvník
thumbs_label=Náhledy
outline_label=Přehled dokumentu
bookmark_label=Aktuální zobrazení
previous_label=Předchozí
next_label=Další
print_label=Tisk
download_label=Stáhnout
zoom_out_label=Zmenšit
zoom_in_label=Přiblížit
zoom.title=Zvětšit
thumb_page_title=Stránka{{page}}
thumb_page_canvas=Náhled stránky {{page}}
request_password=PDF je chráněn heslem:

View File

@ -17,7 +17,7 @@ page_scale_width=Sidebredde
page_scale_fit=Helside
page_scale_auto=Automatisk zoom
page_scale_actual=Faktisk størrelse
toggle_slider.title=Skift Slider
toggle_slider.title=Skift slider
thumbs.title=Vis thumbnails
outline.title=Vis dokumentoversigt
loading=Indlæser... {{percent}}%
@ -29,3 +29,17 @@ page_of=af {{pageCount}}
no_outline=Ingen dokumentoversigt tilgængelig
open_file.title=Åbn fil
text_annotation_type=[{{type}} Kommentar]
toggle_slider_label=Skift slider
thumbs_label=Thumbnails
outline_label=Dokumentoversigt
bookmark_label=Aktuel visning
previous_label=Forrige
next_label=Næste
print_label=Udskriv
download_label=Hent
zoom_out_label=Zoom ud
zoom_in_label=Zoom ind
zoom.title=Zoom
thumb_page_title=Side {{page}}
thumb_page_canvas=Thumbnail af side {{page}}
request_password=PDF filen er beskyttet med et kodeord:

View File

@ -42,3 +42,5 @@ zoom_in_label=Zoom In
zoom.title=Zoom
thumb_page_title=Page {{page}}
thumb_page_canvas=Thumbnail of Page {{page}}
request_password=PDF is protected by a password:
open_file_label=Open

7
l10n/fr/metadata.inc Normal file
View File

@ -0,0 +1,7 @@
<em:localized>
<Description>
<em:locale>fr</em:locale>
<em:name>PDF Viewer</em:name>
<em:description>Utilise HTML5 pour afficher les documents PDF directement dans Firefox.</em:description>
</Description>
</em:localized>

45
l10n/fr/viewer.properties Normal file
View File

@ -0,0 +1,45 @@
bookmark.title=Vue courante (copier ou ouvrir dans une nouvelle fenêtre)
previous.title=Précédente
next.title=Suivante
print.title=Imprimer
download.title=Télécharger
zoom_out.title=Zoom arrière
zoom_in.title=Zoom avant
error_more_info=Plus d'informations
error_less_info=Moins d'informations
error_close=Fermer
error_build=Version de PDF.JS : {{build}}
error_message=Message : {{message}}
error_stack=Pile : {{stack}}
error_file=Fichier : {{file}}
error_line=Ligne: {{line}}
page_scale_width=Largeur de la page
page_scale_fit=Ajuster à la page
page_scale_auto=Zoom automatique
page_scale_actual=Taille réelle
toggle_slider.title=Afficher/Masquer la barre latérale
thumbs.title=Afficher/masquer les vignettes
outline.title=Afficher/masquer la structure
loading=Chargement… {{percent}}%
loading_error_indicator=Erreur
loading_error=Une erreur est survenue lors du chargement du PDF.
rendering_error=Une erreur est survenue lors de l'affichage de la page.
page_label=Page :
page_of=sur {{pageCount}}
no_outline=Pas de structure disponible
open_file.title=Ouvrir un fichier
text_annotation_type=[Annotation {{type}}]
toggle_slider_label=Afficher/Masquer la barre latérale
thumbs_label=Vignettes
outline_label=Structure du document
bookmark_label=Vue courante
previous_label=Précédente
next_label=Suivante
print_label=Imprimer
download_label=Télécharger
zoom_out_label=Zoom arrière
zoom_in_label=Zoom avant
zoom.title=Zoom
thumb_page_title=Page {{page}}
thumb_page_canvas=Aperçu de la page {{page}}
request_password=Ce PDF est protégé par un mot de passe:

8
l10n/ja/metadata.inc Normal file
View File

@ -0,0 +1,8 @@
<em:localized>
<Description>
<em:locale>ja</em:locale>
<em:name>PDF Viewer</em:name>
<em:description>HTML5を使用して、Firefoxで直接PDFファイルを表示します。</em:description>
</Description>
</em:localized>

45
l10n/ja/viewer.properties Normal file
View File

@ -0,0 +1,45 @@
bookmark.title=現在のビュー (コピーまたは新しいウインドウで開く)
previous.title=前のページ
next.title=次のページ
print.title=印刷
download.title=ダウンロード
zoom_out.title=縮小
zoom_in.title=拡大
error_more_info=詳細情報
error_less_info=詳細情報の非表示
error_close=閉じる
error_build=PDF.JS Build: {{build}}
error_message=メッセージ: {{message}}
error_stack=スタック: {{stack}}
error_file=ファイル: {{file}}
error_line=ライン: {{line}}
page_scale_width=幅に合わせる
page_scale_fit=ページのサイズに合わせる
page_scale_auto=自動ズーム
page_scale_actual=実際のサイズ
toggle_slider.title=サイドバーの切り替え
thumbs.title=縮小版を表示
outline.title=文書の目次を表示
loading=読み込み中... {{percent}}%
loading_error_indicator=エラー
loading_error=PDFの読み込み中にエラーが発生しました
rendering_error=ページのレンダリング中にエラーが発生しました
page_label=ページ:
page_of=of {{pageCount}}
no_outline=利用可能な目次はありません
open_file.title=ファイルを開く
text_annotation_type=[{{type}} 注釈]
toggle_slider_label=サイドバーの切り替え
thumbs_label=縮小版
outline_label=文書の目次
bookmark_label=現在のビュー
previous_label=前へ
next_label=次へ
print_label=印刷
download_label=ダウンロード
zoom_out_label=縮小
zoom_in_label=拡大
zoom.title=ズーム
thumb_page_title=ページ {{page}}
thumb_page_canvas=ページの縮小版 {{page}}
request_password=PDFはパスワードによって保護されています

View File

@ -40,3 +40,6 @@ download_label=Загрузить
zoom_out_label=Уменьшить
zoom_in_label=Увеличить
zoom.title=Масштаб
thumb_page_title=Страница {{page}}
thumb_page_canvas=Уменьшенное изображение страницы {{page}}
request_password=PDF защищён паролем:

8
l10n/sv/metadata.inc Normal file
View File

@ -0,0 +1,8 @@
<em:localized>
<Description>
<em:locale>sv</em:locale>
<em:name>PDF Läsare</em:name>
<em:description>Använder HTML5 för att visa PDF filer direkt i Firefox.</em:description>
</Description>
</em:localized>

45
l10n/sv/viewer.properties Normal file
View File

@ -0,0 +1,45 @@
bookmark.title=Aktuell vy (visa eller öppna i nytt fönster)
previous.title=Föregående sida
next.title=Nästa sida
print.title=Skriv ut
download.title=Ladda ner
zoom_out.title=Zooma ut
zoom_in.title=Zooma in
error_more_info=Mer information
error_less_info=Mindre information
error_close=Stäng
error_build=PDF.JS bygge: {{build}}
error_message=Meddelande: {{message}}
error_stack=Stack: {{stack}}
error_file=Fil: {{file}}
error_line=Rad: {{line}}
page_scale_width=Sidbredd
page_scale_fit=Passa sida
page_scale_auto=Automatisk zoom
page_scale_actual=Faktisk storlek
toggle_slider.title=Visa/Dölj panel
thumbs.title=Visa miniatyrer
outline.title=Visa dokumentdisposition
loading=Laddar... {{percent}}%
loading_error_indicator=Fel
loading_error=Ett fel inträffade när PDF dokumentet laddades.
rendering_error=Ett fel inträffade när PDF dokumentet renderades.
page_label=Sida:
page_of=av {{pageCount}}
no_outline=Ingen dokumentdisposition tillgänglig
open_file.title=Öppna fil
text_annotation_type=[{{type}} Annotering]
toggle_slider_label=Visa/Dölj panel
thumbs_label=Miniatyrer
outline_label=Disposition
bookmark_label=Aktuell vy
previous_label=Föregående
next_label=Nästa
print_label=Skriv ut
download_label=Ladda ner
zoom_out_label=Zooma ut
zoom_in_label=Zooma in
zoom.title=Zooma
thumb_page_title=Sida {{page}}
thumb_page_canvas=Miniatyr av sida {{page}}
request_password=PDF dokumentet är skyddat av ett lösenord:

8
l10n/zh-CN/metadata.inc Normal file
View File

@ -0,0 +1,8 @@
<em:localized>
<Description>
<em:locale>zh-CN</em:locale>
<em:name>PDF 查看器</em:name>
<em:description>使用 HTML5 来支持在 Firefox 中直接显示 PDF 文件。</em:description>
</Description>
</em:localized>

View File

@ -0,0 +1,45 @@
bookmark.title=当前视图(复制或在新窗口中打开)
previous.title=上一页
next.title=下一页
print.title=打印
download.title=下载
zoom_out.title=缩小
zoom_in.title=放大
error_more_info=更多信息
error_less_info=更少信息
error_close=关闭
error_build=PDF.JS Build: {{build}}
error_message=Message: {{message}}
error_stack=Stack: {{stack}}
error_file=File: {{file}}
error_line=Line: {{line}}
page_scale_width=适合页宽
page_scale_fit=适合页面
page_scale_auto=自动缩放
page_scale_actual=实际大小
toggle_slider.title=切换侧栏
thumbs.title=显示缩略图
outline.title=显示文档大纲
loading=正在载入... {{percent}}%
loading_error_indicator=错误
loading_error=载入PDF时发生错误。
rendering_error=呈现页面时发生错误。
page_label=页:
page_of=/ {{pageCount}}
no_outline=无可用大纲
open_file.title=打开文件
text_annotation_type=[{{type}} 注解]
toggle_slider_label=切换侧栏
thumbs_label=缩略图
outline_label=文档大纲
bookmark_label=当前视图
previous_label=向上
next_label=向下
print_label=打印
download_label=下载
zoom_out_label=缩小
zoom_in_label=放大
zoom.title=缩放
thumb_page_title=页码 {{page}}
thumb_page_canvas=页面 {{page}} 的缩略图
request_password=PDF 被密码保护:

8
l10n/zh-TW/metadata.inc Normal file
View File

@ -0,0 +1,8 @@
<em:localized>
<Description>
<em:locale>zh-TW</em:locale>
<em:name>PDF 瀏覽器</em:name>
<em:description>利用 HTML5 技術在 Firefox 中直接顯示 PDF 格式檔案。</em:description>
</Description>
</em:localized>

View File

@ -0,0 +1,45 @@
bookmark.title=目前檢視(複製或在新視窗中開啟)
previous.title=上一頁
next.title=下一頁
print.title=列印
download.title=下載
zoom_out.title=縮小
zoom_in.title=放大
error_more_info=更多資訊
error_less_info=更少資訊
error_close=關閉
error_build=PDF.JS 版本號: {{build}}
error_message=錯誤信息: {{message}}
error_stack=堆疊: {{stack}}
error_file=檔案: {{file}}
error_line=行數: {{line}}
page_scale_width=符合頁寬
page_scale_fit=符合頁面
page_scale_auto=自動縮放
page_scale_actual=實際大小
toggle_slider.title=切換側邊欄
thumbs.title=顯示縮圖
outline.title=顯示文件綱要
loading=正在載入... {{percent}}%
loading_error_indicator=錯誤
loading_error=載入PDF檔案時發生錯誤。
rendering_error=渲染頁面時發生錯誤。
page_label=頁次:
page_of=, 共 {{pageCount}} 頁
no_outline=無可用的綱要
open_file.title=開啟檔案
text_annotation_type=[{{type}} 註解]
toggle_slider_label=切換側邊欄
thumbs_label=縮圖
outline_label=文件綱要
bookmark_label=目前檢視
previous_label=上一頁
next_label=下一頁
print_label=列印
download_label=下載
zoom_out_label=縮小
zoom_in_label=放大
zoom.title=縮放
thumb_page_title=第 {{page}} 頁
thumb_page_canvas=第 {{page}} 頁的縮圖
request_password=PDF 檔案受密碼保護:

31
make.js
View File

@ -9,7 +9,11 @@ var ROOT_DIR = __dirname + '/', // absolute path to project's root
LOCALE_SRC_DIR = 'l10n/',
GH_PAGES_DIR = BUILD_DIR + 'gh-pages/',
REPO = 'git@github.com:mozilla/pdf.js.git',
PYTHON_BIN = 'python2.7';
PYTHON_BIN = 'python2.7',
MOZCENTRAL_PREF_PREFIX = 'pdfjs',
FIREFOX_PREF_PREFIX = 'extensions.uriloader@pdf.js',
MOZCENTRAL_STREAM_CONVERTER_ID = 'd0c5195d-e798-49d4-b1d3-9324328b2291',
FIREFOX_STREAM_CONVERTER_ID = '6457a96b-2d68-439a-bcfa-44465fbcdbb1';
//
// make all
@ -352,6 +356,9 @@ target.firefox = function() {
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/install.rdf');
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, FIREFOX_BUILD_DIR + '/update.rdf');
sed('-i', /PDFJSSCRIPT_STREAM_CONVERTER_ID/, FIREFOX_STREAM_CONVERTER_ID, FIREFOX_BUILD_DIR + 'components/PdfStreamConverter.js');
sed('-i', /PDFJSSCRIPT_PREF_PREFIX/, FIREFOX_PREF_PREFIX, FIREFOX_BUILD_DIR + 'components/PdfStreamConverter.js');
// Update localized metadata
var localizedMetadata = cat(EXTENSION_SRC_DIR + '/firefox/metadata.inc');
sed('-i', /.*PDFJS_LOCALIZED_METADATA.*\n/, localizedMetadata, FIREFOX_BUILD_DIR + '/install.rdf');
@ -381,16 +388,16 @@ target.mozcentral = function() {
echo('### Building mozilla-central extension');
var MOZCENTRAL_DIR = BUILD_DIR + 'mozcentral/',
MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + 'browser/app/profile/extensions/uriloader@pdf.js/',
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_TEST_DIR = MOZCENTRAL_EXTENSION_DIR + 'test/',
FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + '/firefox/content/',
FIREFOX_EXTENSION_FILES_TO_COPY =
['*.js',
['components/*.js',
'*.svg',
'*.png',
'*.manifest',
'install.rdf.in',
'README.mozilla',
'components',
'../../LICENSE'],
@ -398,10 +405,7 @@ target.mozcentral = function() {
[LOCALE_SRC_DIR + 'en-US/viewer.properties',
LOCALE_SRC_DIR + 'en-US/chrome.properties'],
FIREFOX_MC_EXTENSION_FILES =
['bootstrap.js',
'icon.png',
'icon64.png',
'chrome.manifest',
['chrome.manifest',
'components',
'content',
'LICENSE'];
@ -420,6 +424,8 @@ target.mozcentral = function() {
// Copy extension files
cd('extensions/firefox');
cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_EXTENSION_DIR);
mv('-f', ROOT_DIR + MOZCENTRAL_EXTENSION_DIR + '/chrome-mozcentral.manifest',
ROOT_DIR + MOZCENTRAL_EXTENSION_DIR + '/chrome.manifest')
cd(ROOT_DIR);
// Copy a standalone version of pdf.js inside the content directory
@ -451,9 +457,11 @@ target.mozcentral = function() {
cp(DEFAULT_LOCALE_FILES, MOZCENTRAL_L10N_DIR);
// Update the build version number
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'install.rdf.in');
sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'README.mozilla');
sed('-i', /PDFJSSCRIPT_STREAM_CONVERTER_ID/, MOZCENTRAL_STREAM_CONVERTER_ID, MOZCENTRAL_EXTENSION_DIR + 'components/PdfStreamConverter.js');
sed('-i', /PDFJSSCRIPT_PREF_PREFIX/, MOZCENTRAL_PREF_PREFIX, MOZCENTRAL_EXTENSION_DIR + 'components/PdfStreamConverter.js');
// List all files for mozilla-central
cd(MOZCENTRAL_EXTENSION_DIR);
var extensionFiles = '';
@ -462,6 +470,11 @@ target.mozcentral = function() {
extensionFiles += file+'\n';
});
extensionFiles.to('extension-files');
cd(ROOT_DIR);
// Copy test files
mkdir('-p', MOZCENTRAL_TEST_DIR);
cp('-Rf', 'test/mozcentral/*', MOZCENTRAL_TEST_DIR);
};
//

View File

@ -7,20 +7,46 @@
* is used, which means it must follow the same origin rules that any XHR does
* e.g. No cross domain requests without CORS.
*
* @param {string|TypedAray} source Either a url to a PDF is located or a
* typed array (Uint8Array) already populated with data.
* @param {Object} headers An object containing the http headers like this:
* { Authorization: "BASIC XXX" }.
* @param {string|TypedAray|object} source Can be an url to where a PDF is
* located, a typed array (Uint8Array) already populated with data or
* and parameter object with the following possible fields:
* - url - The URL of the PDF.
* - data - A typed array with PDF data.
* - httpHeaders - Basic authentication headers.
* - password - For decrypting password-protected PDFs.
*
* @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
*/
PDFJS.getDocument = function getDocument(source, headers) {
PDFJS.getDocument = function getDocument(source) {
var url, data, headers, password, parameters = {};
if (typeof source === 'string') {
url = source;
} else if (isArrayBuffer(source)) {
data = source;
} else if (typeof source === 'object') {
url = source.url;
data = source.data;
headers = source.httpHeaders;
password = source.password;
parameters.password = password || null;
if (!url && !data)
error('Invalid parameter array, need either .data or .url');
} else {
error('Invalid parameter in getDocument, need either Uint8Array, ' +
'string or a parameter object');
}
var promise = new PDFJS.Promise();
var transport = new WorkerTransport(promise);
if (typeof source === 'string') {
if (data) {
// assuming the data is array, instantiating directly from it
transport.sendData(data, parameters);
} else if (url) {
// fetch url
PDFJS.getPdf(
{
url: source,
url: url,
progress: function getPDFProgress(evt) {
if (evt.lengthComputable)
promise.progress({
@ -35,12 +61,10 @@ PDFJS.getDocument = function getDocument(source, headers) {
headers: headers
},
function getPDFLoad(data) {
transport.sendData(data);
transport.sendData(data, parameters);
});
} else {
// assuming the source is array, instantiating directly from it
transport.sendData(source);
}
return promise;
};
@ -122,6 +146,11 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
});
return promise;
},
isEncrypted: function PDFDocumentProxy_isEncrypted() {
var promise = new PDFJS.Promise();
promise.resolve(this.pdfInfo.encrypted);
return promise;
},
destroy: function PDFDocumentProxy_destroy() {
this.transport.destroy();
}
@ -467,6 +496,14 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.workerReadyPromise.resolve(pdfDocument);
}, this);
messageHandler.on('NeedPassword', function transportPassword(data) {
this.workerReadyPromise.reject(data.exception.message, data.exception);
}, this);
messageHandler.on('IncorrectPassword', function transportBadPass(data) {
this.workerReadyPromise.reject(data.exception.message, data.exception);
}, this);
messageHandler.on('GetPage', function transportPage(data) {
var pageInfo = data.pageInfo;
var page = new PDFPageProxy(pageInfo, this);
@ -569,8 +606,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
});
},
sendData: function WorkerTransport_sendData(data) {
this.messageHandler.send('GetDocRequest', data);
sendData: function WorkerTransport_sendData(data, params) {
this.messageHandler.send('GetDocRequest', {data: data, params: params});
},
getPage: function WorkerTransport_getPage(pageNumber, promise) {

View File

@ -320,19 +320,19 @@ var Page = (function PageClosure() {
* `PDFDocument` objects on the main thread created.
*/
var PDFDocument = (function PDFDocumentClosure() {
function PDFDocument(arg, callback) {
function PDFDocument(arg, password) {
if (isStream(arg))
init.call(this, arg);
init.call(this, arg, password);
else if (isArrayBuffer(arg))
init.call(this, new Stream(arg));
init.call(this, new Stream(arg), password);
else
error('PDFDocument: Unknown argument type');
}
function init(stream) {
function init(stream, password) {
assertWellFormed(stream.length > 0, 'stream must have data');
this.stream = stream;
this.setup();
this.setup(password);
this.acroForm = this.catalog.catDict.get('AcroForm');
}
@ -423,11 +423,12 @@ var PDFDocument = (function PDFDocumentClosure() {
}
// May not be a PDF file, continue anyway.
},
setup: function PDFDocument_setup(ownerPassword, userPassword) {
setup: function PDFDocument_setup(password) {
this.checkHeader();
var xref = new XRef(this.stream,
this.startXRef,
this.mainXRefEntriesOffset);
this.mainXRefEntriesOffset,
password);
this.xref = xref;
this.catalog = new Catalog(xref);
},

View File

@ -419,13 +419,14 @@ var CipherTransform = (function CipherTransformClosure() {
})();
var CipherTransformFactory = (function CipherTransformFactoryClosure() {
var defaultPasswordBytes = new Uint8Array([
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
function prepareKeyData(fileId, password, ownerPassword, userPassword,
flags, revision, keyLength, encryptMetadata) {
var defaultPasswordBytes = new Uint8Array([
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
var hashData = new Uint8Array(100), i = 0, j, n;
if (password) {
n = Math.min(32, password.length);
@ -462,9 +463,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
var cipher, checkData;
if (revision >= 3) {
// padded password in hashData, we can use this array for user
// password check
i = 32;
for (i = 0; i < 32; ++i)
hashData[i] = defaultPasswordBytes[i];
for (j = 0, n = fileId.length; j < n; ++j)
hashData[i++] = fileId[j];
cipher = new ARCFourCipher(encryptionKey);
@ -477,16 +477,53 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
cipher = new ARCFourCipher(derivedKey);
checkData = cipher.encryptBlock(checkData);
}
for (j = 0, n = checkData.length; j < n; ++j) {
if (userPassword[j] != checkData[j])
return null;
}
} else {
cipher = new ARCFourCipher(encryptionKey);
checkData = cipher.encryptBlock(hashData.subarray(0, 32));
}
for (j = 0, n = checkData.length; j < n; ++j) {
if (userPassword[j] != checkData[j])
error('incorrect password');
checkData = cipher.encryptBlock(defaultPasswordBytes);
for (j = 0, n = checkData.length; j < n; ++j) {
if (userPassword[j] != checkData[j])
return null;
}
}
return encryptionKey;
}
function decodeUserPassword(password, ownerPassword, revision, keyLength) {
var hashData = new Uint8Array(32), i = 0, j, n;
n = Math.min(32, password.length);
for (; i < n; ++i)
hashData[i] = password[i];
j = 0;
while (i < 32) {
hashData[i++] = defaultPasswordBytes[j++];
}
var hash = calculateMD5(hashData, 0, i);
var keyLengthInBytes = keyLength >> 3;
if (revision >= 3) {
for (j = 0; j < 50; ++j) {
hash = calculateMD5(hash, 0, hash.length);
}
}
var cipher, userPassword;
if (revision >= 3) {
userPassword = ownerPassword;
var derivedKey = new Uint8Array(keyLengthInBytes), k;
for (j = 19; j >= 0; j--) {
for (k = 0; k < keyLengthInBytes; ++k)
derivedKey[k] = hash[k] ^ j;
cipher = new ARCFourCipher(derivedKey);
userPassword = cipher.encryptBlock(userPassword);
}
} else {
cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes));
userPassword = cipher.encryptBlock(ownerPassword);
}
return userPassword;
}
var identityName = new Name('Identity');
@ -516,10 +553,25 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
if (password)
passwordBytes = stringToBytes(password);
this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
ownerPassword, userPassword,
flags, revision,
keyLength, encryptMetadata);
var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
ownerPassword, userPassword, flags,
revision, keyLength, encryptMetadata);
if (!encryptionKey && !password) {
throw new PasswordException('No password given', 'needpassword');
} else if (!encryptionKey && password) {
// Attempting use the password as an owner password
var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
revision, keyLength);
encryptionKey = prepareKeyData(fileIdBytes, decodedPassword,
ownerPassword, userPassword, flags,
revision, keyLength, encryptMetadata);
}
if (!encryptionKey)
throw new PasswordException('Incorrect Password', 'incorrectpassword');
this.encryptionKey = encryptionKey;
if (algorithm == 4) {
this.cf = dict.get('CF');
this.stmf = dict.get('StmF') || identityName;

View File

@ -108,39 +108,21 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// Compatibility
BX: 'beginCompat',
EX: 'endCompat'
EX: 'endCompat',
// (reserved partial commands for the lexer)
BM: null,
BD: null,
'true': null,
fa: null,
fal: null,
fals: null,
'false': null,
nu: null,
nul: null,
'null': null
};
function splitCombinedOperations(operations) {
// Two or more operations can be combined together, trying to find which
// operations were concatenated.
var result = [];
var opIndex = 0;
if (!operations) {
return null;
}
while (opIndex < operations.length) {
var currentOp = '';
for (var op in OP_MAP) {
if (op == operations.substr(opIndex, op.length) &&
op.length > currentOp.length) {
currentOp = op;
}
}
if (currentOp.length > 0) {
result.push(operations.substr(opIndex, currentOp.length));
opIndex += currentOp.length;
} else {
return null;
}
}
return result;
}
PartialEvaluator.prototype = {
getOperatorList: function PartialEvaluator_getOperatorList(stream,
resources,
@ -284,39 +266,19 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
resources = resources || new Dict();
var xobjs = resources.get('XObject') || new Dict();
var patterns = resources.get('Pattern') || new Dict();
var parser = new Parser(new Lexer(stream), false, xref);
var parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
var res = resources;
var hasNextObj = false, nextObjs;
var args = [], obj;
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
while (true) {
if (hasNextObj) {
obj = nextObjs.pop();
hasNextObj = (nextObjs.length > 0);
} else {
obj = parser.getObj();
if (isEOF(obj))
break;
}
obj = parser.getObj();
if (isEOF(obj))
break;
if (isCmd(obj)) {
var cmd = obj.cmd;
var fn = OP_MAP[cmd];
if (!fn) {
// invalid content command, trying to recover
var cmds = splitCombinedOperations(cmd);
if (cmds) {
cmd = cmds[0];
fn = OP_MAP[cmd];
// feeding other command on the next iteration
hasNextObj = true;
nextObjs = [];
for (var idx = 1; idx < cmds.length; idx++) {
nextObjs.push(Cmd.get(cmds[idx]));
}
}
}
assertWellFormed(fn, 'Unknown command "' + cmd + '"');
// TODO figure out how to type-check vararg functions
@ -659,8 +621,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
} else if (octet == 0x3E) {
if (token.length) {
// XXX guessing chars size by checking number size in the CMap
if (token.length <= 2 && properties.composite)
// Heuristic: guessing chars size by checking numbers sizes
// in the CMap entries.
if (token.length == 2 && properties.composite)
properties.wideChars = false;
if (token.length <= 4) {

View File

@ -1976,9 +1976,9 @@ var Font = (function FontClosure() {
this.isSymbolicFont = false;
}
// heuristics: if removed more than 2 glyphs encoding WinAnsiEncoding
// does not set properly
if (glyphsRemoved > 2) {
// heuristics: if removed more than 10 glyphs encoding WinAnsiEncoding
// does not set properly (broken PDFs have about 100 removed glyphs)
if (glyphsRemoved > 10) {
warn('Switching TrueType encoding to MacRomanEncoding for ' +
this.name + ' font');
encoding = Encodings.MacRomanEncoding;
@ -3477,7 +3477,7 @@ var CFFFont = (function CFFFontClosure() {
this.properties = properties;
var parser = new CFFParser(file, properties);
var cff = parser.parse();
var cff = parser.parse(true);
var compiler = new CFFCompiler(cff);
this.readExtra(cff);
try {
@ -3568,7 +3568,7 @@ var CFFParser = (function CFFParserClosure() {
this.properties = properties;
}
CFFParser.prototype = {
parse: function CFFParser_parse() {
parse: function CFFParser_parse(normalizeCIDData) {
var properties = this.properties;
var cff = new CFF();
this.cff = cff;
@ -3623,6 +3623,21 @@ var CFFParser = (function CFFParserClosure() {
cff.charset = charset;
cff.encoding = encoding;
if (!cff.isCIDFont || !normalizeCIDData)
return cff;
// DirectWrite does not like CID fonts data. Trying to convert/flatten
// the font data and remove CID properties.
if (cff.fdArray.length !== 1)
error('Unable to normalize CID font in CFF data');
var fontDict = cff.fdArray[0];
fontDict.setByKey(17, topDict.getByName('CharStrings'));
cff.topDict = fontDict;
cff.isCIDFont = false;
delete cff.fdArray;
delete cff.fdSelect;
return cff;
},
parseHeader: function CFFParser_parseHeader() {
@ -4221,9 +4236,9 @@ var CFFPrivateDict = (function CFFPrivateDictClosure() {
[[12, 17], 'LanguageGroup', 'num', 0],
[[12, 18], 'ExpansionFactor', 'num', 0.06],
[[12, 19], 'initialRandomSeed', 'num', 0],
[19, 'Subrs', 'offset', null],
[20, 'defaultWidthX', 'num', 0],
[21, 'nominalWidthX', 'num', 0]
[21, 'nominalWidthX', 'num', 0],
[19, 'Subrs', 'offset', null]
];
var tables = null;
function CFFPrivateDict(strings) {

View File

@ -298,7 +298,7 @@ var Catalog = (function CatalogClosure() {
})();
var XRef = (function XRefClosure() {
function XRef(stream, startXRef, mainXRefEntriesOffset) {
function XRef(stream, startXRef, mainXRefEntriesOffset, password) {
this.stream = stream;
this.entries = [];
this.xrefstms = {};
@ -311,8 +311,7 @@ var XRef = (function XRefClosure() {
var encrypt = trailerDict.get('Encrypt');
if (encrypt) {
var fileId = trailerDict.get('ID');
this.encrypt = new CipherTransformFactory(encrypt,
fileId[0] /*, password */);
this.encrypt = new CipherTransformFactory(encrypt, fileId[0], password);
}
// get the root dictionary (catalog) object

View File

@ -264,8 +264,16 @@ var Parser = (function ParserClosure() {
})();
var Lexer = (function LexerClosure() {
function Lexer(stream) {
function Lexer(stream, knownCommands) {
this.stream = stream;
// The PDFs might have "glued" commands with other commands, operands or
// literals, e.g. "q1". The knownCommands is a dictionary of the valid
// commands and their prefixes. The prefixes are built the following way:
// if there a command that is a prefix of the other valid command or
// literal (e.g. 'f' and 'false') the following prefixes must be included,
// 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
// other commands or literals as a prefix. The knowCommands is optional.
this.knownCommands = knownCommands;
}
Lexer.isSpace = function Lexer_isSpace(ch) {
@ -529,12 +537,18 @@ var Lexer = (function LexerClosure() {
// command
var str = ch;
var knownCommands = this.knownCommands;
var knownCommandFound = knownCommands && (str in knownCommands);
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
// stop if known command is found and next character does not make
// the str a command
if (knownCommandFound && !((str + ch) in knownCommands))
break;
stream.skip();
if (str.length == 128)
error('Command token too long: ' + str.length);
str += ch;
knownCommandFound = knownCommands && (str in knownCommands);
}
if (str == 'true')
return true;

View File

@ -88,6 +88,19 @@ function shadow(obj, prop, value) {
return value;
}
var PasswordException = (function PasswordExceptionClosure() {
function PasswordException(msg, code) {
this.name = 'PasswordException';
this.message = msg;
this.code = code;
}
PasswordException.prototype = new Error();
PasswordException.constructor = PasswordException;
return PasswordException;
})();
function bytesToString(bytes) {
var str = '';
var length = bytes.length;
@ -486,7 +499,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
}
this.isResolved = true;
this.data = data || null;
this.data = (typeof data !== 'undefined') ? data : null;
var callbacks = this.callbacks;
for (var i = 0, ii = callbacks.length; i < ii; i++) {
@ -501,7 +514,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
}
},
reject: function Promise_reject(reason) {
reject: function Promise_reject(reason, exception) {
if (this.isRejected) {
error('A Promise can be rejected only once ' + this.name);
}
@ -514,7 +527,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() {
var errbacks = this.errbacks;
for (var i = 0, ii = errbacks.length; i < ii; i++) {
errbacks[i].call(null, reason);
errbacks[i].call(null, reason, exception);
}
},

View File

@ -91,14 +91,35 @@ var WorkerMessageHandler = {
handler.on('GetDocRequest', function wphSetupDoc(data) {
// Create only the model of the PDFDoc, which is enough for
// processing the content of the pdf.
pdfModel = new PDFDocument(new Stream(data));
var pdfData = data.data;
var pdfPassword = data.params.password;
try {
pdfModel = new PDFDocument(new Stream(pdfData), pdfPassword);
} catch (e) {
if (e instanceof PasswordException) {
if (e.code === 'needpassword') {
handler.send('NeedPassword', {
exception: e
});
} else if (e.code === 'incorrectpassword') {
handler.send('IncorrectPassword', {
exception: e
});
}
return;
} else {
throw e;
}
}
var doc = {
numPages: pdfModel.numPages,
fingerprint: pdfModel.getFingerprint(),
destinations: pdfModel.catalog.destinations,
outline: pdfModel.catalog.documentOutline,
info: pdfModel.getDocumentInfo(),
metadata: pdfModel.catalog.metadata
metadata: pdfModel.catalog.metadata,
encrypted: !!pdfModel.xref.encrypt
};
handler.send('GetDoc', {pdfInfo: doc});
});

View File

@ -0,0 +1,21 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = browser/extensions/pdfjs/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
head.js \
browser_pdfjs_main.js \
file_pdfjs_test.pdf \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,102 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const RELATIVE_DIR = "browser/extensions/pdfjs/test/";
const TESTROOT = "http://example.com/browser/" + RELATIVE_DIR;
function test() {
waitForExplicitFinish();
var tab = gBrowser.addTab(TESTROOT + "file_pdfjs_test.pdf");
var newTabBrowser = gBrowser.getBrowserForTab(tab);
newTabBrowser.addEventListener("pagechange", function onPageChange() {
newTabBrowser.removeEventListener("pagechange", onPageChange, true);
var document = newTabBrowser.contentDocument,
window = newTabBrowser.contentWindow;
//
// Overall sanity tests
//
ok(document.querySelector('div#viewer'), "document content has viewer UI");
ok('PDFJS' in window.wrappedJSObject, "window content has PDFJS object");
//
// Sidebar: open
//
var sidebar = document.querySelector('button#sidebarToggle'),
outerContainer = document.querySelector('div#outerContainer');
sidebar.click();
ok(outerContainer.classList.contains('sidebarOpen'), 'sidebar opens on click');
// Thumbnails are created asynchronously - wait for them
waitForElement(document, 'canvas#thumbnail2', function(error) {
if (error)
finish();
//
// Page change from thumbnail click
//
var pageNumber = document.querySelector('input#pageNumber');
is(parseInt(pageNumber.value), 1, 'initial page is 1');
var thumbnail = document.querySelector('canvas#thumbnail2');
ok(thumbnail, 'thumbnail2 is available');
if (thumbnail) {
thumbnail.click();
is(parseInt(pageNumber.value), 2, 'clicking on thumbnail changes page');
}
//
// Sidebar: close
//
sidebar.click();
ok(!outerContainer.classList.contains('sidebarOpen'), 'sidebar closes on click');
//
// Page change from prev/next buttons
//
var prevPage = document.querySelector('button#previous'),
nextPage = document.querySelector('button#next');
nextPage.click();
is(parseInt(pageNumber.value), 2, 'page increases after clicking on next');
prevPage.click();
is(parseInt(pageNumber.value), 1, 'page decreases after clicking on previous');
//
// Bookmark button
//
var viewBookmark = document.querySelector('a#viewBookmark');
viewBookmark.click();
ok(viewBookmark.href.length > 0, 'viewBookmark button has href');
//
// Zoom in/out
//
var zoomOut = document.querySelector('button.zoomOut'),
zoomIn = document.querySelector('button.zoomIn');
// Zoom in
var oldWidth = document.querySelector('canvas#page1').width;
zoomIn.click();
var newWidth = document.querySelector('canvas#page1').width;
ok(oldWidth < newWidth, 'zooming in increases page width (old: '+oldWidth+', new: '+newWidth+')');
// Zoom out
var oldWidth = document.querySelector('canvas#page1').width;
zoomOut.click();
var newWidth = document.querySelector('canvas#page1').width;
ok(oldWidth > newWidth, 'zooming out decreases page width (old: '+oldWidth+', new: '+newWidth+')');
finish();
});
}, true, true);
registerCleanupFunction(function() {
gBrowser.removeTab(tab);
});
}

Binary file not shown.

21
test/mozcentral/head.js Normal file
View File

@ -0,0 +1,21 @@
// Waits for element 'el' to exist in the DOM of 'doc' before executing 'callback'
// Useful when elements are created asynchronously, e.g. after a Web Worker task
function waitForElement(doc, el, callback) {
var time = 0,
interval = 10,
timeout = 5000;
var checkEl = setInterval(function() {
if (doc.querySelector(el)) {
clearInterval(checkEl);
if (callback) callback();
}
time += interval;
if (time > timeout) {
ok(false, 'waitForElement timed out on element: '+el);
clearInterval(checkEl);
if (callback) callback(true);
}
}, interval);
}

View File

@ -0,0 +1 @@
http://is.muni.cz/www/20544/noty/sbm/Taize/Adoramus_te_Christe.pdf

View File

@ -0,0 +1 @@
http://www.mft-online.de/files/medizinerreport_2012.pdf

View File

@ -0,0 +1 @@
http://www.lezarts.org/07oforhom/Faitsdivers/Hadopi/Le%20Rapport%20Hadopi,%20Intox.pdf

View File

@ -402,6 +402,14 @@
"link": true,
"type": "eq"
},
{ "id": "issue1709",
"file": "pdfs/issue1709.pdf",
"md5": "84497bd23b7c82d03d2681a1cb1d9ed0",
"rounds": 1,
"pageLimit": 10,
"link": true,
"type": "eq"
},
{ "id": "issue1015",
"file": "pdfs/issue1015.pdf",
"md5": "b61503d1b445742b665212866afb60e2",
@ -451,6 +459,13 @@
"link": true,
"type": "eq"
},
{ "id": "issue1629",
"file": "pdfs/issue1629.pdf",
"md5": "0f2cbbf268383a377e95e6bbe36c6a9a",
"rounds": 1,
"link": true,
"type": "eq"
},
{ "id": "issue1169",
"file": "pdfs/issue1169.pdf",
"md5": "3df3ed21fd43ac7fdb21e2015c8a7809",
@ -543,6 +558,14 @@
"link": false,
"type": "eq"
},
{ "id": "issue1721",
"file": "pdfs/issue1721.pdf",
"md5": "b47177f9e5197a76ec498733ecab60e6",
"rounds": 1,
"pageLimit": 2,
"link": true,
"type": "eq"
},
{ "id": "issue1243",
"file": "pdfs/issue1243.pdf",
"md5": "130c849b83513d5ac5e03c6421fc7489",

View File

@ -185,3 +185,66 @@ describe('crypto', function() {
});
});
describe('CipherTransformFactory', function() {
function DictMock(map) {
this.map = map;
}
DictMock.prototype = {
get: function(key) {
return this.map[key];
}
};
var map1 = {
Filter: new Name('Standard'),
V: 2,
Length: 128,
O: unescape('%80%C3%04%96%91o%20sl%3A%E6%1B%13T%91%F2%0DV%12%E3%FF%5E%BB%' +
'E9VO%D8k%9A%CA%7C%5D'),
U: unescape('j%0C%8D%3EY%19%00%BCjd%7D%91%BD%AA%00%18%00%00%00%00%00%00%0' +
'0%00%00%00%00%00%00%00%00%00'),
P: -1028,
R: 3
};
var fileID1 = unescape('%F6%C6%AF%17%F3rR%8DRM%9A%80%D1%EF%DF%18');
var map2 = {
Filter: new Name('Standard'),
V: 4,
Length: 128,
O: unescape('sF%14v.y5%27%DB%97%0A5%22%B3%E1%D4%AD%BD%9B%3C%B4%A5%89u%15%' +
'B2Y%F1h%D9%E9%F4'),
U: unescape('%93%04%89%A9%BF%8AE%A6%88%A2%DB%C2%A0%A8gn%00%00%00%00%00%00' +
'%00%00%00%00%00%00%00%00%00%00'),
P: -1084,
R: 4
};
var fileID2 = unescape('%3CL_%3AD%96%AF@%9A%9D%B3%3Cx%1Cv%AC');
describe('#ctor', function() {
it('should accept user password', function() {
var factory = new CipherTransformFactory(new DictMock(map1), fileID1,
'123456');
});
it('should accept owner password', function() {
var factory = new CipherTransformFactory(new DictMock(map1), fileID1,
'654321');
});
it('should not accept wrong password', function() {
var thrown = false;
try {
var factory = new CipherTransformFactory(new DictMock(map1), fileID1,
'wrong');
} catch (e) {
thrown = true;
}
expect(thrown).toEqual(true);
});
it('should accept no password', function() {
var factory = new CipherTransformFactory(new DictMock(map2), fileID2);
});
});
});

View File

@ -78,6 +78,54 @@ describe('evaluator', function() {
expect(result.fnArray[1]).toEqual('save');
expect(result.fnArray[2]).toEqual('save');
});
it('should handle three glued operations #2', function() {
var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
'prefix');
var resources = new ResourcesMock();
resources.Res1 = {};
var stream = new StringStream('B*BBMC');
var result = evaluator.getOperatorList(stream, resources, []);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual('eoFillStroke');
expect(result.fnArray[1]).toEqual('fillStroke');
expect(result.fnArray[2]).toEqual('beginMarkedContent');
});
it('should handle glued operations and operands', function() {
var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
'prefix');
var stream = new StringStream('q5 Ts');
var result = evaluator.getOperatorList(stream, new ResourcesMock(), []);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(2);
expect(result.fnArray[0]).toEqual('save');
expect(result.fnArray[1]).toEqual('setTextRise');
expect(result.argsArray.length).toEqual(2);
expect(result.argsArray[1].length).toEqual(1);
expect(result.argsArray[1][0]).toEqual(5);
});
it('should handle glued operations and literals', function() {
var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(),
'prefix');
var stream = new StringStream('trueifalserinulli');
var result = evaluator.getOperatorList(stream, new ResourcesMock(), []);
expect(!!result.fnArray && !!result.argsArray).toEqual(true);
expect(result.fnArray.length).toEqual(3);
expect(result.fnArray[0]).toEqual('setFlatness');
expect(result.fnArray[1]).toEqual('setRenderingIntent');
expect(result.fnArray[2]).toEqual('setFlatness');
expect(result.argsArray.length).toEqual(3);
expect(result.argsArray[0].length).toEqual(1);
expect(result.argsArray[0][0]).toEqual(true);
expect(result.argsArray[1].length).toEqual(1);
expect(result.argsArray[1][0]).toEqual(false);
});
});
});

View File

@ -120,6 +120,9 @@
return new Uint8Array(new VBArray(this.responseBody).toArray());
}
});
Object.defineProperty(xhrPrototype, 'overrideMimeType', {
value: function xmlHttpRequestOverrideMimeType(mimeType) {}
});
return;
}
@ -217,15 +220,84 @@
var div = document.createElement('div');
if ('dataset' in div)
return; // dataset property exists
var oldCreateElement = document.createElement;
document.createElement = function newCreateElement() {
var result = oldCreateElement.apply(document, arguments);
if (arguments[0] === 'div') {
// creating dataset property for the div elements
result.dataset = {};
Object.defineProperty(HTMLElement.prototype, 'dataset', {
get: function() {
if (this._dataset)
return this._dataset;
var dataset = {};
for (var j = 0, jj = this.attributes.length; j < jj; j++) {
var attribute = this.attributes[j];
if (attribute.name.substring(0, 5) != 'data-')
continue;
var key = attribute.name.substring(5).replace(/\-([a-z])/g,
function(all, ch) { return ch.toUpperCase(); });
dataset[key] = attribute.value;
}
Object.defineProperty(this, '_dataset', {
value: dataset,
writable: false,
enumerable: false
});
return dataset;
},
enumerable: true
});
})();
// HTMLElement classList property
(function checkClassListProperty() {
var div = document.createElement('div');
if ('classList' in div)
return; // classList property exists
function changeList(element, itemName, add, remove) {
var s = element.className || '';
var list = s.split(/\s+/g);
if (list[0] == '') list.shift();
var index = list.indexOf(itemName);
if (index < 0 && add)
list.push(itemName);
if (index >= 0 && remove)
list.splice(index, 1);
element.className = list.join(' ');
}
var classListPrototype = {
add: function(name) {
changeList(this.element, name, true, false);
},
remove: function(name) {
changeList(this.element, name, false, true);
},
toggle: function(name) {
changeList(this.element, name, true, true);
}
return result;
};
Object.defineProperty(HTMLElement.prototype, 'classList', {
get: function() {
if (this._classList)
return this._classList;
var classList = Object.create(classListPrototype, {
element: {
value: this,
writable: false,
enumerable: true
}
});
Object.defineProperty(this, '_classList', {
value: classList,
writable: false,
enumerable: false
});
return classList;
},
enumerable: true
});
})();
// Check console compatability
@ -252,3 +324,17 @@
document.addEventListener('click', ignoreIfTargetDisabled, true);
}
})();
// Checks if navigator.language is supported
(function checkNavigatorLanguage() {
if ('language' in navigator)
return;
Object.defineProperty(navigator, 'language', {
get: function navigatorLanguage() {
var language = navigator.userLanguage || 'en-US';
return language.substring(0, 2).toLowerCase() +
language.substring(2).toUpperCase();
},
enumerable: true
});
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

View File

@ -424,6 +424,10 @@ html[dir='rtl'] .dropdownToolbarButton {
background: transparent;
}
.dropdownToolbarButton > select > option {
background: hsl(0,0%,24%);
}
#customScaleOption {
display: none;
}
@ -497,6 +501,11 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
content: url(images/toolbarButton-print.png);
}
.toolbarButton.openFile::before {
display: inline-block;
content: url(images/toolbarButton-openFile.png);
}
.toolbarButton.download::before {
display: inline-block;
content: url(images/toolbarButton-download.png);
@ -927,3 +936,52 @@ canvas {
#PDFBug table {
font-size: 10px;
}
@media all and (max-width: 950px) {
html[dir='ltr'] #outerContainer.sidebarMoving .outerCenter,
html[dir='ltr'] #outerContainer.sidebarOpen .outerCenter {
float: left;
left: 180px;
}
html[dir='rtl'] #outerContainer.sidebarMoving .outerCenter,
html[dir='rtl'] #outerContainer.sidebarOpen .outerCenter {
float: right;
right: 180px;
}
}
@media all and (max-width: 770px) {
#sidebarContainer {
top: 33px;
z-index: 100;
}
#sidebarContent {
top: 32px;
background-color: hsla(0,0%,0%,.7);
}
#thumbnailView, #outlineView {
top: 66px;
}
html[dir='ltr'] #outerContainer.sidebarOpen > #mainContainer {
left: 0px;
}
html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
right: 0px;
}
html[dir='ltr'] .outerCenter {
float: left;
left: 180px;
}
html[dir='rtl'] .outerCenter {
float: right;
right: 180px;
}
}
@media all and (max-width: 600px) {
#toolbarViewerRight {
display: none;
}
}

View File

@ -81,20 +81,16 @@
<span data-l10n-id="next_label">Next</span>
</button>
</div>
<label class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
<label id="pageNumberLabel" class="toolbarLabel" for="pageNumber" data-l10n-id="page_label">Page: </label>
<input type="number" id="pageNumber" class="toolbarField pageNumber" onchange="PDFView.page = this.value;" value="1" size="4" min="1" tabindex="6">
</input>
<span id="numPages" class="toolbarLabel"></span>
</div>
<div id="toolbarViewerRight">
<input id="fileInput" class="fileInput" type="file" oncontextmenu="return false;" tabindex="10" />
<!--
<input id="fileInput" class="fileInput" type="file" oncontextmenu="return false;" style="visibility: hidden; position: fixed; right: 0; top: 0" />
<button id="openFile" class="toolbarButton print" title="Open File" tabindex="10" data-l10n-id="open_file" onclick="document.getElementById('fileInput').click()">
<button id="openFile" class="toolbarButton openFile" title="Open File" tabindex="10" data-l10n-id="open_file" onclick="document.getElementById('fileInput').click()">
<span data-l10n-id="open_file_label">Open</span>
</button>
-->
<!--
<button id="print" class="toolbarButton print" title="Print" tabindex="11" data-l10n-id="print" onclick="window.print()">
@ -119,7 +115,7 @@
<span data-l10n-id="zoom_in_label">Zoom In</span>
</button>
</div>
<span class="dropdownToolbarButton">
<span id="scaleSelectContainer" class="dropdownToolbarButton">
<select id="scaleSelect" onchange="PDFView.parseScale(this.value);" title="Zoom" oncontextmenu="return false;" tabindex="9" data-l10n-id="zoom">
<option id="pageAutoOption" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
<option id="pageActualOption" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>

View File

@ -332,10 +332,15 @@ var PDFView = {
return currentPageNumber;
},
open: function pdfViewOpen(url, scale) {
this.url = url;
document.title = decodeURIComponent(getFileName(url)) || url;
open: function pdfViewOpen(url, scale, password) {
var parameters = {password: password};
if (typeof url === 'string') { // URL
this.url = url;
document.title = decodeURIComponent(getFileName(url)) || url;
parameters.url = url;
} else if (url && 'byteLength' in url) { // ArrayBuffer
parameters.data = url;
}
if (!PDFView.loadingBar) {
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
@ -343,12 +348,23 @@ var PDFView = {
var self = this;
self.loading = true;
PDFJS.getDocument(url).then(
PDFJS.getDocument(parameters).then(
function getDocumentCallback(pdfDocument) {
self.load(pdfDocument, scale);
self.loading = false;
},
function getDocumentError(message, exception) {
if (exception.name === 'PasswordException') {
if (exception.code === 'needpassword') {
var promptString = mozL10n.get('request_password', null,
'PDF is protected by a password:');
password = prompt(promptString);
if (password && password.length > 0) {
return PDFView.open(url, scale, password);
}
}
}
var loadingIndicator = document.getElementById('loading');
loadingIndicator.textContent = mozL10n.get('loading_error_indicator',
null, 'Error');
@ -1366,7 +1382,7 @@ window.addEventListener('load', function webViewerLoad(evt) {
if (PDFJS.isFirefoxExtension || !window.File || !window.FileReader ||
!window.FileList || !window.Blob) {
document.getElementById('fileInput').setAttribute('hidden', 'true');
document.getElementById('openFile').setAttribute('hidden', 'true');
} else {
document.getElementById('fileInput').value = null;
}
@ -1555,10 +1571,7 @@ window.addEventListener('change', function webViewerChange(evt) {
for (var i = 0; i < data.length; i++)
uint8Array[i] = data.charCodeAt(i);
// TODO using blob instead?
PDFJS.getDocument(uint8Array).then(function(pdfDocument) {
PDFView.load(pdfDocument);
});
PDFView.open(uint8Array, 0);
};
// Read as a binary string since "readAsArrayBuffer" is not yet