diff --git a/examples/acroforms/index.html b/examples/acroforms/index.html
index 0b12a53d8..4d61bad41 100644
--- a/examples/acroforms/index.html
+++ b/examples/acroforms/index.html
@@ -12,6 +12,7 @@
+
diff --git a/examples/helloworld/index.html b/examples/helloworld/index.html
index 778f40682..6cf34aaf1 100644
--- a/examples/helloworld/index.html
+++ b/examples/helloworld/index.html
@@ -12,6 +12,7 @@
+
diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js
index 9cb97428f..ff9192ba0 100644
--- a/extensions/firefox/tools/l10n.js
+++ b/extensions/firefox/tools/l10n.js
@@ -105,7 +105,10 @@
// Arabic, Hebrew, Farsi, Pashto, Urdu
var rtlList = ['ar', 'he', 'fa', 'ps', 'ur'];
return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr';
- }
+ },
+
+ // translate an element or document fragment
+ translate: translateFragment
};
})(this);
diff --git a/l10n/ar/viewer.properties b/l10n/ar/viewer.properties
index 988abecec..6d22d27cb 100644
--- a/l10n/ar/viewer.properties
+++ b/l10n/ar/viewer.properties
@@ -98,11 +98,11 @@ page_scale_actual=الحجم الحقيقي
loading_error_indicator=خطأ
loading_error=حدث خطأ أثناء تحميل وثيقه الـPDF
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[ملاحظة {{type}}]
+text_annotation_type.alt=[ملاحظة {{type}}]
request_password=الـPDF محمي بكلمة مرور:
printing_not_supported=تحذير: الطباعة ليست مدعومة كليًا في هذا المتصفح.
diff --git a/l10n/ca/viewer.properties b/l10n/ca/viewer.properties
index 84b515d69..1bbddebcd 100644
--- a/l10n/ca/viewer.properties
+++ b/l10n/ca/viewer.properties
@@ -114,11 +114,11 @@ loading_error_indicator=Error
loading_error=Ha ocorregut un error mentres es carregava el PDF.
invalid_file_error=Invàlid o fitxer PDF corrupte.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[Anotació {{type}}]
+text_annotation_type.alt=[Anotació {{type}}]
request_password=El PDF està protegit amb una contrasenya:
printing_not_supported=Avís: La impressió no és compatible totalment en aquest navegador.
diff --git a/l10n/cs/viewer.properties b/l10n/cs/viewer.properties
index 83f12b266..beac468ac 100644
--- a/l10n/cs/viewer.properties
+++ b/l10n/cs/viewer.properties
@@ -41,7 +41,7 @@ rendering_error=Došlo k chybě při vykreslování stránky.
page_label=Stránka:
page_of=z{{pageCount}}
open_file.title=Otevřít soubor
-text_annotation_type=[{{type}}Anotace]
+text_annotation_type.alt=[{{type}}Anotace]
toggle_slider_label=Přepnout posuvník
thumbs_label=Náhledy
outline_label=Přehled dokumentu
diff --git a/l10n/da/viewer.properties b/l10n/da/viewer.properties
index 0c566b96e..e1d43ee43 100644
--- a/l10n/da/viewer.properties
+++ b/l10n/da/viewer.properties
@@ -114,7 +114,7 @@ missing_file_error=Manglende PDF-fil
# "{{type}}" vil blive ersattet af en kommentar type fra en liste
# defineret i PDF specifikationen (32000-1:2008 Table 169 – Annotation types).
# Nogle almindelige typer er f.eks.: "Check", "Text", "Comment" og "Note"
-text_annotation_type=[{{type}} Kommentar]
+text_annotation_type.alt=[{{type}} Kommentar]
request_password=PDF filen er beskyttet med et kodeord:
invalid_password=Ugyldigt kodeord.
diff --git a/l10n/de/viewer.properties b/l10n/de/viewer.properties
index d1be81f6c..c38fb6a67 100644
--- a/l10n/de/viewer.properties
+++ b/l10n/de/viewer.properties
@@ -109,11 +109,11 @@ loading_error_indicator=Fehler
loading_error=Das PDF konnte nicht geladen werden.
invalid_file_error=Ungültige oder beschädigte PDF-Datei.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Annotation]
+text_annotation_type.alt=[{{type}} Annotation]
request_password=Das PDF ist passwortgeschützt:
printing_not_supported=Warnung: Drucken wird durch diesen Browser nicht vollständig unterstützt.
diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties
index 987c90431..ffc025362 100644
--- a/l10n/en-US/viewer.properties
+++ b/l10n/en-US/viewer.properties
@@ -110,11 +110,11 @@ loading_error=An error occurred while loading the PDF.
invalid_file_error=Invalid or corrupted PDF file.
missing_file_error=Missing PDF file.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Annotation]
+text_annotation_type.alt=[{{type}} Annotation]
request_password=PDF is protected by a password:
invalid_password=Invalid Password.
diff --git a/l10n/es/viewer.properties b/l10n/es/viewer.properties
index 059eed69a..eda8354fb 100644
--- a/l10n/es/viewer.properties
+++ b/l10n/es/viewer.properties
@@ -114,7 +114,7 @@ missing_file_error=Falta el archivo PDF.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[Anotación {{type}}]
+text_annotation_type.alt=[Anotación {{type}}]
request_password=El archivo PDF está protegido por una contraseña:
printing_not_supported=Aviso: Este navegador no es compatible completamente con la impresión.
diff --git a/l10n/fi/viewer.properties b/l10n/fi/viewer.properties
index f8cb93f0b..d032bcc10 100644
--- a/l10n/fi/viewer.properties
+++ b/l10n/fi/viewer.properties
@@ -110,11 +110,11 @@ loading_error=Virhe on tapahtunut PDF:ää ladattaessa.
invalid_file_error=Virheellinen tai vioittunut PDF tiedosto.
missing_file_error=PDF tiedostoa ei löytynyt.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Selite]
+text_annotation_type.alt=[{{type}} Selite]
request_password=PDF on salasanasuojattu:
printing_not_supported=Varoitus: Tämä selain ei täysin tue tulostusta.
diff --git a/l10n/fr/viewer.properties b/l10n/fr/viewer.properties
index cdd1989aa..2a0094b2b 100644
--- a/l10n/fr/viewer.properties
+++ b/l10n/fr/viewer.properties
@@ -114,7 +114,7 @@ missing_file_error=Fichier PDF manquant.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[Annotation {{type}}]
+text_annotation_type.alt=[Annotation {{type}}]
request_password=Le PDF est protégé par un mot de passe :
printing_not_supported=Attention : l'impression n'est pas totalement prise en charge par ce navigateur.
diff --git a/l10n/he/viewer.properties b/l10n/he/viewer.properties
index ca3741cff..38f280c0d 100644
--- a/l10n/he/viewer.properties
+++ b/l10n/he/viewer.properties
@@ -41,7 +41,7 @@ rendering_error=אירעה שגיאה בעת עיבוד הדף.
page_label=דף:
page_of=מתוך {{pageCount}}
open_file.title=פתיחת קובץ
-text_annotation_type=[{{type}} Annotation]
+text_annotation_type.alt=[{{type}} Annotation]
toggle_slider_label=מתג החלקה
thumbs_label=תמונות ממוזערות
outline_label=מתאר מסמך
diff --git a/l10n/it/viewer.properties b/l10n/it/viewer.properties
index 962226446..79331b452 100644
--- a/l10n/it/viewer.properties
+++ b/l10n/it/viewer.properties
@@ -41,4 +41,4 @@ rendering_error=
page_label=Pagina:
page_of=di {{pageCount}}
open_file.title=Apri File
-text_annotation_type=[{{type}} Annotazione]
+text_annotation_type.alt=[{{type}} Annotazione]
diff --git a/l10n/ja/viewer.properties b/l10n/ja/viewer.properties
index e5c6e81dc..b92176fea 100644
--- a/l10n/ja/viewer.properties
+++ b/l10n/ja/viewer.properties
@@ -110,11 +110,11 @@ loading_error=PDF の読み込み中にエラーが発生しました
invalid_file_error=無効または破損した PDF ファイル
missing_file_error=PDF ファイルが見つかりません。
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} 注釈]
+text_annotation_type.alt=[{{type}} 注釈]
request_password=PDF はパスワードによって保護されています
invalid_password=無効なパスワードです
diff --git a/l10n/lt/viewer.properties b/l10n/lt/viewer.properties
index 2ad6406e4..c2e457712 100644
--- a/l10n/lt/viewer.properties
+++ b/l10n/lt/viewer.properties
@@ -110,11 +110,11 @@ loading_error=PDF bylos įkelimo metu įvyko klaida.
invalid_file_error=Neteisinga arba pažeista PDF byla.
missing_file_error=Trūksta PDF bylos.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Pastaba]
+text_annotation_type.alt=[{{type}} Pastaba]
request_password=PDF byla yra apsaugota slaptažodžiu:
printing_not_supported=Dėmesio: Naršyklė pilnai nepalaiko spausdinimo.
diff --git a/l10n/nl/viewer.properties b/l10n/nl/viewer.properties
index 73aafa8af..a731a76f1 100644
--- a/l10n/nl/viewer.properties
+++ b/l10n/nl/viewer.properties
@@ -110,11 +110,11 @@ loading_error=Er is een fout opgetreden bij het laden van het PDF-bestand.
invalid_file_error=Ongeldig of corrupt PDF-bestand.
missing_file_error=Ontbrekend PDF-bestand.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}}-aantekening]
+text_annotation_type.alt=[{{type}}-aantekening]
request_password=Dit PDF-bestand is beveiligd met een wachtwoord:
printing_not_supported=Waarschuwing: afdrukken wordt niet volledig ondersteund door deze browser.
diff --git a/l10n/pl/viewer.properties b/l10n/pl/viewer.properties
index 9aa576f3a..dd9b3162b 100644
--- a/l10n/pl/viewer.properties
+++ b/l10n/pl/viewer.properties
@@ -110,11 +110,11 @@ loading_error=Wystąpił błąd podczas wczytywania pliku PDF.
invalid_file_error=Błędny lub uszkodzony plik PDF.
missing_file_error=Nie znaleziono pliku PDF.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 - Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[Komentarz {{type}}]
+text_annotation_type.alt=[Komentarz {{type}}]
request_password=Plik PDF jest chroniony przez hasło:
printing_not_supported=Ostrzeżenie: Drukowanie nie jest w pełni obsługiwane przez tę przeglądarkę.
diff --git a/l10n/pt-BR/viewer.properties b/l10n/pt-BR/viewer.properties
index 9f47b9cee..edea5f11c 100644
--- a/l10n/pt-BR/viewer.properties
+++ b/l10n/pt-BR/viewer.properties
@@ -41,4 +41,4 @@ rendering_error=Um erro ocorreu ao apresentar a página.
page_label=Página:
page_of=de {{pageCount}}
open_file.title=Abrir arquivo
-text_annotation_type=[{{type}} Anotações]
+text_annotation_type.alt=[{{type}} Anotações]
diff --git a/l10n/ro/viewer.properties b/l10n/ro/viewer.properties
index 985be8d69..ae37ec72d 100644
--- a/l10n/ro/viewer.properties
+++ b/l10n/ro/viewer.properties
@@ -41,7 +41,7 @@ rendering_error=S-a produs o eroare în timpul procesării paginii.
page_label=Pagina:
page_of=din {{pageCount}}
open_file.title=Deschide fișier
-text_annotation_type=[Adnotare {{type}}]
+text_annotation_type.alt=[Adnotare {{type}}]
toggle_slider_label=Vedere de ansamblu
thumbs_label=Miniaturi
outline_label=Cuprins
diff --git a/l10n/ru/viewer.properties b/l10n/ru/viewer.properties
index 0465fd8a8..f86b601a2 100644
--- a/l10n/ru/viewer.properties
+++ b/l10n/ru/viewer.properties
@@ -41,7 +41,7 @@ rendering_error=Произошла ошибка во время создания
page_label=Страница:
page_of=из {{pageCount}}
open_file.title=Открыть файл
-text_annotation_type=[Аннотация {{type}}]
+text_annotation_type.alt=[Аннотация {{type}}]
toggle_slider_label=Вспомогательная панель
thumbs_label=Уменьшенные изображения
outline_label=Содержание документа
diff --git a/l10n/sr/viewer.properties b/l10n/sr/viewer.properties
index 7ec9bfd7c..9fe3666e2 100644
--- a/l10n/sr/viewer.properties
+++ b/l10n/sr/viewer.properties
@@ -41,7 +41,7 @@ rendering_error=Дошло је до грешке приликом приказ
page_label=Страна:
page_of=од {{pageCount}}
open_file.title=Отвори датотеку
-text_annotation_type=[{{type}} Annotation]
+text_annotation_type.alt=[{{type}} Annotation]
toggle_slider_label=Клизач
thumbs_label=Сличице
outline_label=Документи у линијама
diff --git a/l10n/sv/viewer.properties b/l10n/sv/viewer.properties
index 8ecc1f7ab..24320bb9c 100644
--- a/l10n/sv/viewer.properties
+++ b/l10n/sv/viewer.properties
@@ -110,11 +110,11 @@ loading_error=Ett fel inträffade när PDF-filen laddades.
invalid_file_error=Ogiltig eller korrupt PDF-fil.
missing_file_error=PDF-filen saknas.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}}-anteckning]
+text_annotation_type.alt=[{{type}}-anteckning]
request_password=PDF-filen är lösenordsskyddad:
invalid_password=Felaktigt lösenord.
diff --git a/l10n/tr/viewer.properties b/l10n/tr/viewer.properties
index a9d69dd94..ecd51c6cc 100644
--- a/l10n/tr/viewer.properties
+++ b/l10n/tr/viewer.properties
@@ -110,11 +110,11 @@ loading_error=PDF yüklenirken hata.
invalid_file_error=Geçersiz yada bozuk dosya.
missing_file_error=PDF dosyası bulunamadı.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Not]
+text_annotation_type.alt=[{{type}} Not]
request_password=PDF Şifre ile korunmakta:
printing_not_supported=Uyarı: Yazdırma işlemi bu tarayıcı ile tam desteklenmiyor.
diff --git a/l10n/zh-CN/viewer.properties b/l10n/zh-CN/viewer.properties
index 5b045b250..c27e60973 100644
--- a/l10n/zh-CN/viewer.properties
+++ b/l10n/zh-CN/viewer.properties
@@ -110,11 +110,11 @@ loading_error=加载 PDF 文件时出错。
invalid_file_error=PDF 文件无效或已损坏。
missing_file_error=缺失 PDF 文件。
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} 注解]
+text_annotation_type.alt=[{{type}} 注解]
request_password=该 PDF 文档受密码保护:
printing_not_supported=警告:该浏览器不能完全支持打印。
diff --git a/l10n/zh-TW/viewer.properties b/l10n/zh-TW/viewer.properties
index 7fd6aafa4..7196242ee 100644
--- a/l10n/zh-TW/viewer.properties
+++ b/l10n/zh-TW/viewer.properties
@@ -104,7 +104,7 @@ missing_file_error=遺失PDF檔案。
# 其他標籤和訊息
# "{{type}}" 用來表示PDF格式規範 (32000-1:2008 Table 169 – Annotation types) 入面所定義的註解種類。
# 一些常見的類型有: "Check"、 "Text"、 "Comment"、 "Note"
-text_annotation_type=[{{type}} 註解]
+text_annotation_type.alt=[{{type}} 註解]
request_password=PDF檔案受密碼保護:
invalid_password=密碼無效。
diff --git a/make.js b/make.js
index 7e1d565ee..fbdd137cc 100644
--- a/make.js
+++ b/make.js
@@ -239,6 +239,7 @@ target.bundle = function(args) {
'api.js',
'canvas.js',
'obj.js',
+ 'annotation.js',
'function.js',
'charsets.js',
'cidmaps.js',
diff --git a/src/annotation.js b/src/annotation.js
new file mode 100644
index 000000000..467cbf9f8
--- /dev/null
+++ b/src/annotation.js
@@ -0,0 +1,508 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* Copyright 2012 Mozilla Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* globals Util, isDict, isName, stringToPDFString, TODO, Dict, Stream,
+ stringToBytes, PDFJS, isWorker, assert, NotImplementedException,
+ Promise */
+
+'use strict';
+
+var Annotation = (function AnnotationClosure() {
+ // 12.5.5: Algorithm: Appearance streams
+ function getTransformMatrix(rect, bbox, matrix) {
+ var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
+ var minX = bounds[0];
+ var minY = bounds[1];
+ var maxX = bounds[2];
+ var maxY = bounds[3];
+
+ if (minX === maxX || minY === maxY) {
+ // From real-life file, bbox was [0, 0, 0, 0]. In this case,
+ // just apply the transform for rect
+ return [1, 0, 0, 1, rect[0], rect[1]];
+ }
+
+ var xRatio = (rect[2] - rect[0]) / (maxX - minX);
+ var yRatio = (rect[3] - rect[1]) / (maxY - minY);
+ return [
+ xRatio,
+ 0,
+ 0,
+ yRatio,
+ rect[0] - minX * xRatio,
+ rect[1] - minY * yRatio
+ ];
+ }
+
+ function getDefaultAppearance(dict) {
+ var appearanceState = dict.get('AP');
+ if (!isDict(appearanceState)) {
+ return;
+ }
+
+ var appearance;
+ var appearances = appearanceState.get('N');
+ if (isDict(appearances)) {
+ var as = dict.get('AS');
+ if (as && appearances.has(as.name)) {
+ appearance = appearances.get(as.name);
+ }
+ } else {
+ appearance = appearances;
+ }
+ return appearance;
+ }
+
+ function Annotation(params) {
+ if (params.data) {
+ this.data = params.data;
+ return;
+ }
+
+ var dict = params.dict;
+ var data = this.data = {};
+
+ data.subtype = dict.get('Subtype').name;
+ var rect = dict.get('Rect');
+ data.rect = Util.normalizeRect(rect);
+ data.annotationFlags = dict.get('F');
+
+ var border = dict.get('BS');
+ if (isDict(border)) {
+ var borderWidth = border.has('W') ? border.get('W') : 1;
+ data.border = {
+ width: borderWidth,
+ type: border.get('S') || 'S',
+ rgb: dict.get('C') || [0, 0, 1]
+ };
+ }
+
+ this.appearance = getDefaultAppearance(dict);
+ }
+
+ Annotation.prototype = {
+
+ getData: function Annotation_getData() {
+ return this.data;
+ },
+
+ hasHtml: function Annotation_hasHtml() {
+ return false;
+ },
+
+ getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
+ throw new NotImplementedException(
+ 'getHtmlElement() should be implemented in subclass');
+ },
+
+ getEmptyContainer: function Annotaiton_getEmptyContainer(tagName, rect) {
+ assert(!isWorker,
+ 'getEmptyContainer() should be called from main thread');
+
+ rect = rect || this.data.rect;
+ var element = document.createElement(tagName);
+ element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
+ element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
+ return element;
+ },
+
+ isViewable: function Annotation_isViewable() {
+ var data = this.data;
+ return !!(
+ data &&
+ (!data.annotationFlags ||
+ !(data.annotationFlags & 0x22)) && // Hidden or NoView
+ data.rect // rectangle is nessessary
+ );
+ },
+
+ getOperatorList: function Annotation_appendToOperatorList(evaluator) {
+
+ var promise = new Promise();
+
+ if (!this.appearance) {
+ promise.resolve({
+ queue: {
+ fnArray: [],
+ argsArray: []
+ },
+ dependency: {}
+ });
+ return promise;
+ }
+
+ var data = this.data;
+
+ var appearanceDict = this.appearance.dict;
+ var resources = appearanceDict.get('Resources');
+ var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
+ var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
+ var transform = getTransformMatrix(data.rect, bbox, matrix);
+
+ var border = data.border;
+
+ var listPromise = evaluator.getOperatorList(this.appearance, resources);
+ listPromise.then(function(appearanceStreamData) {
+ var fnArray = appearanceStreamData.queue.fnArray;
+ var argsArray = appearanceStreamData.queue.argsArray;
+
+ fnArray.unshift('beginAnnotation');
+ argsArray.unshift([data.rect, transform, matrix]);
+
+ fnArray.push('endAnnotation');
+ argsArray.push([]);
+
+ promise.resolve(appearanceStreamData);
+ });
+
+ return promise;
+ }
+ };
+
+ Annotation.getConstructor =
+ function Annotation_getConstructor(subtype, fieldType) {
+
+ if (!subtype) {
+ return;
+ }
+
+ // TODO(mack): Implement FreeText annotations
+ if (subtype === 'Link') {
+ return LinkAnnotation;
+ } else if (subtype === 'Text') {
+ return TextAnnotation;
+ } else if (subtype === 'Widget') {
+ if (!fieldType) {
+ return;
+ }
+
+ return WidgetAnnotation;
+ } else {
+ return Annotation;
+ }
+ };
+
+ // TODO(mack): Support loading annotation from data
+ Annotation.fromData = function Annotation_fromData(data) {
+ var subtype = data.subtype;
+ var fieldType = data.fieldType;
+ var Constructor = Annotation.getConstructor(subtype, fieldType);
+ if (Constructor) {
+ return new Constructor({ data: data });
+ }
+ };
+
+ Annotation.fromRef = function Annotation_fromRef(xref, ref) {
+
+ var dict = xref.fetchIfRef(ref);
+ if (!isDict(dict)) {
+ return;
+ }
+
+ var subtype = dict.get('Subtype');
+ subtype = isName(subtype) ? subtype.name : '';
+ if (!subtype) {
+ return;
+ }
+
+ var fieldType = Util.getInheritableProperty(dict, 'FT');
+ fieldType = isName(fieldType) ? fieldType.name : '';
+
+ var Constructor = Annotation.getConstructor(subtype, fieldType);
+ if (!Constructor) {
+ return;
+ }
+
+ var params = {
+ dict: dict,
+ ref: ref,
+ };
+
+ var annotation = new Constructor(params);
+
+ if (annotation.isViewable()) {
+ return annotation;
+ } else {
+ TODO('unimplemented annotation type: ' + subtype);
+ }
+ };
+
+ return Annotation;
+})();
+PDFJS.Annotation = Annotation;
+
+
+var WidgetAnnotation = (function WidgetAnnotationClosure() {
+
+ function WidgetAnnotation(params) {
+ Annotation.call(this, params);
+
+ if (params.data) {
+ return;
+ }
+
+ var dict = params.dict;
+ var data = this.data;
+
+ data.fieldValue = stringToPDFString(
+ Util.getInheritableProperty(dict, 'V') || '');
+ data.alternativeText = stringToPDFString(dict.get('TU') || '');
+ data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
+ var fieldType = Util.getInheritableProperty(dict, 'FT');
+ data.fieldType = isName(fieldType) ? fieldType.name : '';
+ data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
+ this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
+
+ // Building the full field name by collecting the field and
+ // its ancestors 'T' data and joining them using '.'.
+ var fieldName = [];
+ var namedItem = dict;
+ var ref = params.ref;
+ while (namedItem) {
+ var parent = namedItem.get('Parent');
+ var parentRef = namedItem.getRaw('Parent');
+ var name = namedItem.get('T');
+ if (name) {
+ fieldName.unshift(stringToPDFString(name));
+ } else {
+ // The field name is absent, that means more than one field
+ // with the same name may exist. Replacing the empty name
+ // with the '`' plus index in the parent's 'Kids' array.
+ // This is not in the PDF spec but necessary to id the
+ // the input controls.
+ var kids = parent.get('Kids');
+ var j, jj;
+ for (j = 0, jj = kids.length; j < jj; j++) {
+ var kidRef = kids[j];
+ if (kidRef.num == ref.num && kidRef.gen == ref.gen)
+ break;
+ }
+ fieldName.unshift('`' + j);
+ }
+ namedItem = parent;
+ ref = parentRef;
+ }
+ data.fullName = fieldName.join('.');
+ }
+
+ var parent = Annotation.prototype;
+ Util.inherit(WidgetAnnotation, Annotation, {
+ isViewable: function WidgetAnnotation_isViewable() {
+ if (this.data.fieldType === 'Sig') {
+ TODO('unimplemented annotation type: Widget signature');
+ return false;
+ }
+
+ return parent.isViewable.call(this);
+ }
+ });
+
+ return WidgetAnnotation;
+})();
+
+var TextAnnotation = (function TextAnnotationClosure() {
+ function TextAnnotation(params) {
+ Annotation.call(this, params);
+
+ if (params.data) {
+ return;
+ }
+
+ var dict = params.dict;
+ var data = this.data;
+
+ var content = dict.get('Contents');
+ var title = dict.get('T');
+ data.content = stringToPDFString(content || '');
+ data.title = stringToPDFString(title || '');
+ data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name;
+ }
+
+ var ANNOT_MIN_SIZE = 10;
+ var IMAGE_DIR = './images/';
+
+ Util.inherit(TextAnnotation, Annotation, {
+
+ getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
+ var promise = new Promise();
+ promise.resolve({
+ queue: {
+ fnArray: [],
+ argsArray: []
+ },
+ dependency: {}
+ });
+ return promise;
+ },
+
+ hasHtml: function TextAnnotation_hasHtml() {
+ return true;
+ },
+
+ getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
+ assert(!isWorker, 'getHtmlElement() shall be called from main thread');
+
+ var item = this.data;
+ var rect = item.rect;
+
+ // sanity check because of OOo-generated PDFs
+ if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
+ rect[3] = rect[1] + ANNOT_MIN_SIZE;
+ }
+ if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
+ rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
+ }
+
+ var container = this.getEmptyContainer('section', rect);
+ container.className = 'annotText';
+
+ var image = document.createElement('img');
+ image.style.width = container.style.width;
+ image.style.height = container.style.height;
+ var iconName = item.name;
+ image.src = IMAGE_DIR + 'annotation-' +
+ iconName.toLowerCase() + '.svg';
+ image.alt = '[{{type}} Annotation]';
+ image.dataset.l10nId = 'text_annotation_type';
+ image.dataset.l10nArgs = JSON.stringify({type: iconName});
+ var content = document.createElement('div');
+ content.setAttribute('hidden', true);
+ var title = document.createElement('h1');
+ var text = document.createElement('p');
+ content.style.left = Math.floor(rect[2] - rect[0]) + 'px';
+ content.style.top = '0px';
+ title.textContent = item.title;
+
+ if (!item.content && !item.title) {
+ content.setAttribute('hidden', true);
+ } else {
+ var e = document.createElement('span');
+ var lines = item.content.split(/(?:\r\n?|\n)/);
+ for (var i = 0, ii = lines.length; i < ii; ++i) {
+ var line = lines[i];
+ e.appendChild(document.createTextNode(line));
+ if (i < (ii - 1))
+ e.appendChild(document.createElement('br'));
+ }
+ text.appendChild(e);
+ image.addEventListener('mouseover', function annotationImageOver() {
+ container.style.zIndex += 1;
+ content.removeAttribute('hidden');
+ }, false);
+
+ image.addEventListener('mouseout', function annotationImageOut() {
+ container.style.zIndex -= 1;
+ content.setAttribute('hidden', true);
+ }, false);
+ }
+
+ content.appendChild(title);
+ content.appendChild(text);
+ container.appendChild(image);
+ container.appendChild(content);
+
+ return container;
+ }
+ });
+
+ return TextAnnotation;
+})();
+
+var LinkAnnotation = (function LinkAnnotationClosure() {
+ function isValidUrl(url) {
+ if (!url)
+ return false;
+ var colon = url.indexOf(':');
+ if (colon < 0)
+ return false;
+ var protocol = url.substr(0, colon);
+ switch (protocol) {
+ case 'http':
+ case 'https':
+ case 'ftp':
+ case 'mailto':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ function LinkAnnotation(params) {
+ Annotation.call(this, params);
+
+ if (params.data) {
+ return;
+ }
+
+ var dict = params.dict;
+ var data = this.data;
+
+ var action = dict.get('A');
+ if (action) {
+ var linkType = action.get('S').name;
+ if (linkType === 'URI') {
+ var url = action.get('URI');
+ // TODO: pdf spec mentions urls can be relative to a Base
+ // entry in the dictionary.
+ if (!isValidUrl(url)) {
+ url = '';
+ }
+ data.url = url;
+ } else if (linkType === 'GoTo') {
+ data.dest = action.get('D');
+ } else if (linkType === 'GoToR') {
+ var urlDict = action.get('F');
+ if (isDict(urlDict)) {
+ // We assume that the 'url' is a Filspec dictionary
+ // and fetch the url without checking any further
+ url = urlDict.get('F') || '';
+ }
+
+ // TODO: pdf reference says that GoToR
+ // can also have 'NewWindow' attribute
+ if (!isValidUrl(url)) {
+ url = '';
+ }
+ data.url = url;
+ data.dest = action.get('D');
+ } else {
+ TODO('unrecognized link type: ' + linkType);
+ }
+ } else if (dict.has('Dest')) {
+ // simple destination link
+ var dest = dict.get('Dest');
+ data.dest = isName(dest) ? dest.name : dest;
+ }
+ }
+
+ Util.inherit(LinkAnnotation, Annotation, {
+ hasOperatorList: function LinkAnnotation_hasOperatorList() {
+ return false;
+ },
+
+ hasHtml: function LinkAnnotation_hasHtml() {
+ return true;
+ },
+
+ getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
+ var element = this.getEmptyContainer('a');
+ element.href = this.data.url || '';
+ return element;
+ }
+ });
+
+ return LinkAnnotation;
+})();
diff --git a/src/canvas.js b/src/canvas.js
index 395c4fa1a..63019dd02 100644
--- a/src/canvas.js
+++ b/src/canvas.js
@@ -1495,24 +1495,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
- matrix, border) {
+ matrix) {
this.save();
if (rect && isArray(rect) && 4 == rect.length) {
var width = rect[2] - rect[0];
var height = rect[3] - rect[1];
-
- if (border) {
- // TODO(mack): Support different border styles
- this.save();
- var rgb = border.rgb;
- this.setStrokeRGBColor(rgb[0], rgb[1], rgb[2]);
- this.setLineWidth(border.width);
- this.rectangle(rect[0], rect[1], width, height);
- this.stroke();
- this.restore();
- }
-
this.rectangle(rect[0], rect[1], width, height);
this.clip();
this.endPath();
diff --git a/src/core.js b/src/core.js
index e6391610c..4c262b2d7 100644
--- a/src/core.js
+++ b/src/core.js
@@ -18,7 +18,7 @@
isArrayBuffer, isDict, isName, isStream, isString, Lexer,
Linearization, NullStream, PartialEvaluator, shadow, Stream,
StreamsSequenceStream, stringToPDFString, TODO, Util, warn, XRef,
- MissingDataException, Promise */
+ MissingDataException, Promise, Annotation */
'use strict';
@@ -41,25 +41,6 @@ globalScope.PDFJS.pdfBug = false;
var Page = (function PageClosure() {
- function getDefaultAnnotationAppearance(annotationDict) {
- var appearanceState = annotationDict.get('AP');
- if (!isDict(appearanceState)) {
- return;
- }
-
- var appearance;
- var appearances = appearanceState.get('N');
- if (isDict(appearances)) {
- var as = annotationDict.get('AS');
- if (as && appearances.has(as.name)) {
- appearance = appearances.get(as.name);
- }
- } else {
- appearance = appearances;
- }
- return appearance;
- }
-
function Page(pdfManager, xref, pageIndex, pageDict, ref) {
this.pdfManager = pdfManager;
this.pageIndex = pageIndex;
@@ -116,8 +97,8 @@ var Page = (function PageClosure() {
return shadow(this, 'view', cropBox);
},
- get annotations() {
- return shadow(this, 'annotations', this.inheritPageProp('Annots'));
+ get annotationRefs() {
+ return shadow(this, 'annotationRefs', this.inheritPageProp('Annots'));
},
get rotate() {
var rotate = this.inheritPageProp('Rotate') || 0;
@@ -157,7 +138,6 @@ var Page = (function PageClosure() {
var promise = new Promise();
var pageListPromise = new Promise();
- var annotationListPromise = new Promise();
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
@@ -185,37 +165,41 @@ var Page = (function PageClosure() {
);
});
- pdfManager.ensure(this, 'getAnnotationsForDraw', []).then(
- function(annotations) {
- pdfManager.ensure(partialEvaluator, 'getAnnotationsOperatorList',
- [annotations]).then(
- function(opListPromise) {
- opListPromise.then(function(data) {
- annotationListPromise.resolve(data);
- });
+ var annotationsPromise = pdfManager.ensure(this, 'annotations');
+ Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
+ var pageData = datas[0];
+ var pageQueue = pageData.queue;
+ var annotations = datas[1];
+
+ var ensurePromises = [];
+ for (var i = 0, n = annotations.length; i < n; ++i) {
+ var ensurePromise = pdfManager.ensure(annotations[i],
+ 'getOperatorList',
+ [partialEvaluator]);
+ ensurePromises.push(ensurePromise);
+ }
+
+ Promise.all(ensurePromises).then(function(listPromises) {
+ Promise.all(listPromises).then(function(datas) {
+ for (var i = 0, n = datas.length; i < n; ++i) {
+ var annotationData = datas[i];
+ var annotationQueue = annotationData.queue;
+ Util.concatenateToArray(pageQueue.fnArray,
+ annotationQueue.fnArray);
+ Util.concatenateToArray(pageQueue.argsArray,
+ annotationQueue.argsArray);
+ Util.extendObj(pageData.dependencies,
+ annotationData.dependencies);
}
- );
- }
- );
- Promise.all([pageListPromise, annotationListPromise]).then(
- function(datas) {
- var pageData = datas[0];
- var pageQueue = pageData.queue;
- var annotationData = datas[1];
- var annotationQueue = annotationData.queue;
- Util.concatenateToArray(pageQueue.fnArray, annotationQueue.fnArray);
- Util.concatenateToArray(pageQueue.argsArray,
- annotationQueue.argsArray);
- PartialEvaluator.optimizeQueue(pageQueue);
- Util.extendObj(pageData.dependencies, annotationData.dependencies);
+ PartialEvaluator.optimizeQueue(pageQueue);
- promise.resolve(pageData);
- }
- );
+ promise.resolve(pageData);
+ });
+ });
+ });
return promise;
-
},
extractTextContent: function Page_extractTextContent() {
var handler = {
@@ -259,230 +243,27 @@ var Page = (function PageClosure() {
return textContentPromise;
},
- getLinks: function Page_getLinks() {
- var links = [];
- var annotations = this.getAnnotations();
- var i, n = annotations.length;
- for (i = 0; i < n; ++i) {
- if (annotations[i].type != 'Link')
- continue;
- links.push(annotations[i]);
+
+ getAnnotationsData: function Page_getAnnotationsData() {
+ var annotations = this.annotations;
+ var annotationsData = [];
+ for (var i = 0, n = annotations.length; i < n; ++i) {
+ annotationsData.push(annotations[i].getData());
}
- return links;
+ return annotationsData;
},
- getAnnotations: function Page_getAnnotations() {
- var annotations = this.getAnnotationsBase();
- var items = [];
- for (var i = 0, length = annotations.length; i < length; ++i) {
- items.push(annotations[i].item);
- }
- return items;
- },
-
- getAnnotationsForDraw: function Page_getAnnotationsForDraw() {
- var annotations = this.getAnnotationsBase();
- var items = [];
- for (var i = 0, length = annotations.length; i < length; ++i) {
- var item = annotations[i].item;
- var annotationDict = annotations[i].dict;
-
- item.annotationFlags = annotationDict.get('F');
-
- var appearance = getDefaultAnnotationAppearance(annotationDict);
- if (appearance &&
- // TODO(mack): The proper implementation requires that the
- // appearance stream overrides Name, but we're currently
- // doing it the other way around for 'Text' annotations since we
- // have special rendering for it
- item.type !== 'Text') {
-
- item.appearance = appearance;
- var appearanceDict = appearance.dict;
- item.resources = appearanceDict.get('Resources');
- item.bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
- item.matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
- }
-
- var border = annotationDict.get('BS');
- if (isDict(border) && !item.appearance) {
- var borderWidth = border.has('W') ? border.get('W') : 1;
- if (borderWidth !== 0) {
- item.border = {
- width: borderWidth,
- type: border.get('S') || 'S',
- rgb: annotationDict.get('C') || [0, 0, 1]
- };
- }
- }
-
- items.push(item);
- }
-
- return items;
- },
-
- getAnnotationsBase: function Page_getAnnotationsBase() {
- var xref = this.xref;
- function getInheritableProperty(annotation, name) {
- var item = annotation;
- while (item && !item.has(name)) {
- item = item.get('Parent');
- }
- if (!item)
- return null;
- return item.get(name);
- }
- function isValidUrl(url) {
- if (!url)
- return false;
- var colon = url.indexOf(':');
- if (colon < 0)
- return false;
- var protocol = url.substr(0, colon);
- switch (protocol) {
- case 'http':
- case 'https':
- case 'ftp':
- case 'mailto':
- return true;
- default:
- return false;
+ get annotations() {
+ var annotations = [];
+ var annotationRefs = this.annotationRefs || [];
+ for (var i = 0, n = annotationRefs.length; i < n; ++i) {
+ var annotationRef = annotationRefs[i];
+ var annotation = Annotation.fromRef(this.xref, annotationRef);
+ if (annotation) {
+ annotations.push(annotation);
}
}
-
- var annotations = this.annotations || [];
- var i, n = annotations.length;
- var items = [];
- for (i = 0; i < n; ++i) {
- var annotationRef = annotations[i];
- var annotation = xref.fetchIfRef(annotationRef);
- if (!isDict(annotation))
- continue;
- var subtype = annotation.get('Subtype');
- if (!isName(subtype))
- continue;
-
- var item = {};
- item.type = subtype.name;
- var rect = annotation.get('Rect');
- item.rect = Util.normalizeRect(rect);
-
- var includeAnnotation = true;
- switch (subtype.name) {
- case 'Link':
- var a = annotation.get('A');
- if (a) {
- switch (a.get('S').name) {
- case 'URI':
- var url = a.get('URI');
- // TODO: pdf spec mentions urls can be relative to a Base
- // entry in the dictionary.
- if (!isValidUrl(url))
- url = '';
- item.url = url;
- break;
- case 'GoTo':
- item.dest = a.get('D');
- break;
- case 'GoToR':
- var url = a.get('F');
- if (isDict(url)) {
- // We assume that the 'url' is a Filspec dictionary
- // and fetch the url without checking any further
- url = url.get('F') || '';
- }
-
- // TODO: pdf reference says that GoToR
- // can also have 'NewWindow' attribute
- if (!isValidUrl(url))
- url = '';
- item.url = url;
- item.dest = a.get('D');
- break;
- default:
- TODO('unrecognized link type: ' + a.get('S').name);
- }
- } else if (annotation.has('Dest')) {
- // simple destination link
- var dest = annotation.get('Dest');
- item.dest = isName(dest) ? dest.name : dest;
- }
- break;
- case 'Widget':
- var fieldType = getInheritableProperty(annotation, 'FT');
- if (!isName(fieldType))
- break;
-
- // Do not display digital signatures since we do not currently
- // validate them.
- if (fieldType.name === 'Sig') {
- includeAnnotation = false;
- break;
- }
-
- item.fieldType = fieldType.name;
- // Building the full field name by collecting the field and
- // its ancestors 'T' properties and joining them using '.'.
- var fieldName = [];
- var namedItem = annotation, ref = annotationRef;
- while (namedItem) {
- var parent = namedItem.get('Parent');
- var parentRef = namedItem.getRaw('Parent');
- var name = namedItem.get('T');
- if (name) {
- fieldName.unshift(stringToPDFString(name));
- } else {
- // The field name is absent, that means more than one field
- // with the same name may exist. Replacing the empty name
- // with the '`' plus index in the parent's 'Kids' array.
- // This is not in the PDF spec but necessary to id the
- // the input controls.
- var kids = parent.get('Kids');
- var j, jj;
- for (j = 0, jj = kids.length; j < jj; j++) {
- var kidRef = kids[j];
- if (kidRef.num == ref.num && kidRef.gen == ref.gen)
- break;
- }
- fieldName.unshift('`' + j);
- }
- namedItem = parent;
- ref = parentRef;
- }
- item.fullName = fieldName.join('.');
- var alternativeText = stringToPDFString(annotation.get('TU') || '');
- item.alternativeText = alternativeText;
- var da = getInheritableProperty(annotation, 'DA') || '';
- var m = /([\d\.]+)\sTf/.exec(da);
- if (m)
- item.fontSize = parseFloat(m[1]);
- item.textAlignment = getInheritableProperty(annotation, 'Q');
- item.flags = getInheritableProperty(annotation, 'Ff') || 0;
- break;
- case 'Text':
- var content = annotation.get('Contents');
- var title = annotation.get('T');
- item.content = stringToPDFString(content || '');
- item.title = stringToPDFString(title || '');
- item.name = !annotation.has('Name') ? 'Note' :
- annotation.get('Name').name;
- break;
- default:
- var appearance = getDefaultAnnotationAppearance(annotation);
- if (!appearance) {
- TODO('unimplemented annotation type: ' + subtype.name);
- }
- break;
- }
- if (includeAnnotation) {
- items.push({
- item: item,
- dict: annotation
- });
- }
- }
- return items;
+ return shadow(this, 'annotations', annotations);
}
};
diff --git a/src/evaluator.js b/src/evaluator.js
index 830d38c05..d082feee3 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -504,10 +504,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var promise = new Promise();
var fontRes = resources.get('Font');
+ if (!fontRes) {
+ warn('fontRes not available');
+ }
- assert(fontRes, 'fontRes not available');
-
- font = xref.fetchIfRef(font) || fontRes.get(fontName);
+ font = xref.fetchIfRef(font) || (fontRes && fontRes.get(fontName));
if (!isDict(font)) {
++this.idCounters.font;
promise.resolve({
@@ -828,93 +829,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return promise;
},
- getAnnotationsOperatorList:
- function PartialEvaluator_getAnnotationsOperatorList(annotations,
- dependency) {
- var promise = new Promise();
-
- // 12.5.5: Algorithm: Appearance streams
- function getTransformMatrix(rect, bbox, matrix) {
- var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
- var minX = bounds[0];
- var minY = bounds[1];
- var maxX = bounds[2];
- var maxY = bounds[3];
- var width = rect[2] - rect[0];
- var height = rect[3] - rect[1];
- var xRatio = width / (maxX - minX);
- var yRatio = height / (maxY - minY);
- return [
- xRatio,
- 0,
- 0,
- yRatio,
- rect[0] - minX * xRatio,
- rect[1] - minY * yRatio
- ];
- }
-
- var opListPromises = [];
- var includedAnnotations = [];
-
- // deal with annotations
- for (var i = 0, length = annotations.length; i < length; ++i) {
- var annotation = annotations[i];
-
- // check whether we can visualize annotation
- if (!annotation ||
- !annotation.annotationFlags ||
- (annotation.annotationFlags & 0x0022) || // Hidden or NoView
- !annotation.rect || // rectangle is nessessary
- !annotation.appearance) { // appearance is nessessary
- continue;
- }
-
- includedAnnotations.push(annotation);
-
- if (annotation.appearance) {
- var opListPromise = this.getOperatorList(annotation.appearance,
- annotation.resources);
- opListPromises.push(opListPromise);
- } else {
- var opListPromise = new Promise();
- opListPromise.resolve(createOperatorList());
- opListPromises.push(opListPromise);
- }
- }
-
- Promise.all(opListPromises).then(function(datas) {
- var fnArray = [];
- var argsArray = [];
- var dependencies = {};
- for (var i = 0, n = datas.length; i < n; ++i) {
- var annotation = includedAnnotations[i];
- var data = datas[i];
-
- // apply rectangle
- var rect = annotation.rect;
- var bbox = annotation.bbox;
- var matrix = annotation.matrix;
- var transform = getTransformMatrix(rect, bbox, matrix);
- var border = annotation.border;
-
- fnArray.push('beginAnnotation');
- argsArray.push([rect, transform, matrix, border]);
-
- Util.concatenateToArray(fnArray, data.queue.fnArray);
- Util.concatenateToArray(argsArray, data.queue.argsArray);
- Util.extendObj(dependencies, data.dependencies);
-
- fnArray.push('endAnnotation');
- argsArray.push([]);
- }
-
- promise.resolve(createOperatorList(fnArray, argsArray, dependencies));
- });
-
- return promise;
- },
-
getTextContent: function PartialEvaluator_getTextContent(
stream, resources) {
diff --git a/src/util.js b/src/util.js
index 4094c3350..0ee9ef6ed 100644
--- a/src/util.js
+++ b/src/util.js
@@ -424,11 +424,30 @@ var Util = PDFJS.Util = (function UtilClosure() {
}
};
+ Util.getInheritableProperty = function Util_getInheritableProperty(dict,
+ name) {
+ while (dict && !dict.has(name)) {
+ dict = dict.get('Parent');
+ }
+ if (!dict) {
+ return null;
+ }
+ return dict.get(name);
+ };
+
+ Util.inherit = function Util_inherit(sub, base, prototype) {
+ sub.prototype = Object.create(base.prototype);
+ sub.prototype.constructor = sub;
+ for (var prop in prototype) {
+ sub.prototype[prop] = prototype[prop];
+ }
+ };
+
return Util;
})();
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
- function PageViewport(viewBox, scale, rotation, offsetX, offsetY) {
+ function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
this.viewBox = viewBox;
this.scale = scale;
this.rotation = rotation;
@@ -440,25 +459,28 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
var centerX = (viewBox[2] + viewBox[0]) / 2;
var centerY = (viewBox[3] + viewBox[1]) / 2;
var rotateA, rotateB, rotateC, rotateD;
- switch (rotation % 360) {
- case -180:
+ rotation = rotation % 360;
+ rotation = rotation < 0 ? rotation + 360 : rotation;
+ switch (rotation) {
case 180:
rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
break;
- case -270:
case 90:
rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
break;
- case -90:
case 270:
rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
break;
- //case 360:
//case 0:
default:
rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
break;
}
+
+ if (dontFlip) {
+ rotateC = -rotateC; rotateD = -rotateD;
+ }
+
var offsetCanvasX, offsetCanvasY;
var width, height;
if (rotateA === 0) {
@@ -494,7 +516,7 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
var scale = 'scale' in args ? args.scale : this.scale;
var rotation = 'rotation' in args ? args.rotation : this.rotation;
return new PageViewport(this.viewBox.slice(), scale, rotation,
- this.offsetX, this.offsetY);
+ this.offsetX, this.offsetY, args.dontFlip);
},
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform);
diff --git a/src/worker.js b/src/worker.js
index a77387385..5209c6015 100644
--- a/src/worker.js
+++ b/src/worker.js
@@ -350,11 +350,11 @@ var WorkerMessageHandler = {
handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
pdfManager.getPage(data.pageIndex).then(function(page) {
- pdfManager.ensure(page, 'getAnnotations',[]).then(
- function(annotations) {
+ pdfManager.ensure(page, 'getAnnotationsData', []).then(
+ function(annotationsData) {
handler.send('GetAnnotations', {
pageIndex: data.pageIndex,
- annotations: annotations
+ annotations: annotationsData
});
}
);
diff --git a/src/worker_loader.js b/src/worker_loader.js
index ca464b03b..9f28b62cc 100644
--- a/src/worker_loader.js
+++ b/src/worker_loader.js
@@ -26,6 +26,7 @@ var files = [
'util.js',
'canvas.js',
'obj.js',
+ 'annotation.js',
'function.js',
'charsets.js',
'cidmaps.js',
diff --git a/test/font/font_test.html b/test/font/font_test.html
index 9321ce5af..976216102 100644
--- a/test/font/font_test.html
+++ b/test/font/font_test.html
@@ -20,6 +20,7 @@
+
diff --git a/test/test_slave.html b/test/test_slave.html
index 3268111b7..0424f7817 100644
--- a/test/test_slave.html
+++ b/test/test_slave.html
@@ -27,6 +27,7 @@ limitations under the License.
+
diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html
index 1c5ac6712..26ffbeba5 100644
--- a/test/unit/unit_test.html
+++ b/test/unit/unit_test.html
@@ -19,6 +19,7 @@
+
diff --git a/web/viewer.html b/web/viewer.html
index e7ac263f2..6f515729e 100644
--- a/web/viewer.html
+++ b/web/viewer.html
@@ -47,6 +47,7 @@ limitations under the License.
+
diff --git a/web/viewer.js b/web/viewer.js
index 56023cf32..81f19e42a 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -28,9 +28,7 @@ var SCROLLBAR_PADDING = 40;
var VERTICAL_PADDING = 5;
var MIN_SCALE = 0.25;
var MAX_SCALE = 4.0;
-var IMAGE_DIR = './images/';
var SETTINGS_MEMORY = 20;
-var ANNOT_MIN_SIZE = 10;
var RenderingStates = {
INITIAL: 0,
RUNNING: 1,
@@ -2115,7 +2113,8 @@ var PageView = function pageView(container, id, scale,
enumerable: true
});
- function setupAnnotations(pdfPage, viewport) {
+ function setupAnnotations(annotationsDiv, pdfPage, viewport) {
+
function bindLink(link, dest) {
link.href = PDFView.getDestinationHash(dest);
link.onclick = function pageViewSetupLinksOnclick() {
@@ -2125,91 +2124,43 @@ var PageView = function pageView(container, id, scale,
};
link.className = 'internalLink';
}
- function createElementWithStyle(tagName, item, rect) {
- if (!rect) {
- rect = viewport.convertToViewportRectangle(item.rect);
- rect = PDFJS.Util.normalizeRect(rect);
- }
- var element = document.createElement(tagName);
- element.style.left = Math.floor(rect[0]) + 'px';
- element.style.top = Math.floor(rect[1]) + 'px';
- element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
- element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
- return element;
- }
- function createTextAnnotation(item) {
- var container = document.createElement('section');
- container.className = 'annotText';
- var rect = viewport.convertToViewportRectangle(item.rect);
- rect = PDFJS.Util.normalizeRect(rect);
- // sanity check because of OOo-generated PDFs
- if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
- rect[3] = rect[1] + ANNOT_MIN_SIZE;
- }
- if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
- rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
- }
- var image = createElementWithStyle('img', item, rect);
- var iconName = item.name;
- image.src = IMAGE_DIR + 'annotation-' +
- iconName.toLowerCase() + '.svg';
- image.alt = mozL10n.get('text_annotation_type', {type: iconName},
- '[{{type}} Annotation]');
- var content = document.createElement('div');
- content.setAttribute('hidden', true);
- var title = document.createElement('h1');
- var text = document.createElement('p');
- content.style.left = Math.floor(rect[2]) + 'px';
- content.style.top = Math.floor(rect[1]) + 'px';
- title.textContent = item.title;
-
- if (!item.content && !item.title) {
- content.setAttribute('hidden', true);
- } else {
- var e = document.createElement('span');
- var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
- var line = lines[i];
- e.appendChild(document.createTextNode(line));
- if (i < (ii - 1))
- e.appendChild(document.createElement('br'));
+ pdfPage.getAnnotations().then(function(annotationsData) {
+ viewport = viewport.clone({ dontFlip: true });
+ for (var i = 0; i < annotationsData.length; i++) {
+ var data = annotationsData[i];
+ var annotation = PDFJS.Annotation.fromData(data);
+ if (!annotation || !annotation.hasHtml()) {
+ continue;
}
- text.appendChild(e);
- image.addEventListener('mouseover', function annotationImageOver() {
- content.removeAttribute('hidden');
- }, false);
- image.addEventListener('mouseout', function annotationImageOut() {
- content.setAttribute('hidden', true);
- }, false);
- }
+ var element = annotation.getHtmlElement(pdfPage.commonObjs);
+ mozL10n.translate(element);
- content.appendChild(title);
- content.appendChild(text);
- container.appendChild(image);
- container.appendChild(content);
+ data = annotation.getData();
+ var rect = data.rect;
+ var view = pdfPage.view;
+ rect = PDFJS.Util.normalizeRect([
+ rect[0],
+ view[3] - rect[1] + view[1],
+ rect[2],
+ view[3] - rect[3] + view[1]
+ ]);
+ element.style.left = rect[0] + 'px';
+ element.style.top = rect[1] + 'px';
+ element.style.position = 'absolute';
- return container;
- }
+ var transform = viewport.transform;
+ var transformStr = 'matrix(' + transform.join(',') + ')';
+ CustomStyle.setProp('transform', element, transformStr);
+ var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
+ CustomStyle.setProp('transformOrigin', element, transformOriginStr);
- pdfPage.getAnnotations().then(function(items) {
- for (var i = 0; i < items.length; i++) {
- var item = items[i];
- switch (item.type) {
- case 'Link':
- var link = createElementWithStyle('a', item);
- link.href = item.url || '';
- if (!item.url)
- bindLink(link, ('dest' in item) ? item.dest : null);
- div.appendChild(link);
- break;
- case 'Text':
- var textAnnotation = createTextAnnotation(item);
- if (textAnnotation)
- div.appendChild(textAnnotation);
- break;
+ if (data.subtype === 'Link' && !data.url) {
+ bindLink(element, ('dest' in data) ? data.dest : null);
}
+
+ annotationsDiv.appendChild(element);
}
});
}
@@ -2457,7 +2408,7 @@ var PageView = function pageView(container, id, scale,
);
}
- setupAnnotations(this.pdfPage, this.viewport);
+ setupAnnotations(div, pdfPage, this.viewport);
div.setAttribute('data-loaded', true);
};