From 9f384bbb41f780b258d832d1c7170b570aedac95 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Mon, 29 Sep 2014 11:05:28 -0500 Subject: [PATCH] Creates AnnotationsLayerBuilder. --- web/annotations_layer_builder.js | 156 +++++++++++++++++++++++++++++++ web/interfaces.js | 13 +++ web/pdf_page_view.js | 132 ++++---------------------- web/pdf_viewer.js | 21 ++++- web/viewer.html | 1 + 5 files changed, 208 insertions(+), 115 deletions(-) create mode 100644 web/annotations_layer_builder.js diff --git a/web/annotations_layer_builder.js b/web/annotations_layer_builder.js new file mode 100644 index 000000000..309f7c033 --- /dev/null +++ b/web/annotations_layer_builder.js @@ -0,0 +1,156 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2014 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*globals PDFJS, CustomStyle, mozL10n */ + +'use strict'; + +/** + * @typedef {Object} AnnotationsLayerBuilderOptions + * @property {HTMLDivElement} pageDiv + * @property {PDFPage} pdfPage + * @property {IPDFLinkService} linkService + */ + +/** + * @class + */ +var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() { + /** + * @param {AnnotationsLayerBuilderOptions} options + * @constructs AnnotationsLayerBuilder + */ + function AnnotationsLayerBuilder(options) { + this.pageDiv = options.pageDiv; + this.pdfPage = options.pdfPage; + this.linkService = options.linkService; + + this.div = null; + } + AnnotationsLayerBuilder.prototype = + /** @lends AnnotationsLayerBuilder.prototype */ { + + /** + * @param {PageViewport} viewport + */ + setupAnnotations: + function AnnotationsLayerBuilder_setupAnnotations(viewport) { + function bindLink(link, dest) { + link.href = linkService.getDestinationHash(dest); + link.onclick = function annotationsLayerBuilderLinksOnclick() { + if (dest) { + linkService.navigateTo(dest); + } + return false; + }; + if (dest) { + link.className = 'internalLink'; + } + } + + function bindNamedAction(link, action) { + link.href = linkService.getAnchorUrl(''); + link.onclick = function annotationsLayerBuilderNamedActionOnClick() { + linkService.executeNamedAction(action); + return false; + }; + link.className = 'internalLink'; + } + + var linkService = this.linkService; + var pdfPage = this.pdfPage; + var self = this; + + pdfPage.getAnnotations().then(function (annotationsData) { + viewport = viewport.clone({ dontFlip: true }); + var transform = viewport.transform; + var transformStr = 'matrix(' + transform.join(',') + ')'; + var data, element, i, ii; + + if (self.div) { + // If an annotationLayer already exists, refresh its children's + // transformation matrices + for (i = 0, ii = annotationsData.length; i < ii; i++) { + data = annotationsData[i]; + element = self.div.querySelector( + '[data-annotation-id="' + data.id + '"]'); + if (element) { + CustomStyle.setProp('transform', element, transformStr); + } + } + // See PDFPageView.reset() + self.div.removeAttribute('hidden'); + } else { + for (i = 0, ii = annotationsData.length; i < ii; i++) { + data = annotationsData[i]; + if (!data || !data.hasHtml) { + continue; + } + + element = PDFJS.AnnotationUtils.getHtmlElement(data, + pdfPage.commonObjs); + element.setAttribute('data-annotation-id', data.id); + mozL10n.translate(element); + + 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'; + + CustomStyle.setProp('transform', element, transformStr); + var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px'; + CustomStyle.setProp('transformOrigin', element, transformOriginStr); + + if (data.subtype === 'Link' && !data.url) { + var link = element.getElementsByTagName('a')[0]; + if (link) { + if (data.action) { + bindNamedAction(link, data.action); + } else { + bindLink(link, ('dest' in data) ? data.dest : null); + } + } + } + + if (!self.div) { + var annotationLayerDiv = document.createElement('div'); + annotationLayerDiv.className = 'annotationLayer'; + self.pageDiv.appendChild(annotationLayerDiv); + self.div = annotationLayerDiv; + } + + self.div.appendChild(element); + } + } + }); + }, + + hide: function () { + if (!this.div) { + return; + } + this.div.setAttribute('hidden', 'true'); + } + }; + return AnnotationsLayerBuilder; +})(); diff --git a/web/interfaces.js b/web/interfaces.js index 91ac65d9b..1cf9ee8d7 100644 --- a/web/interfaces.js +++ b/web/interfaces.js @@ -97,3 +97,16 @@ IPDFTextLayerFactory.prototype = { */ createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {} }; + +/** + * @interface + */ +function IPDFAnnotationsLayerFactory() {} +IPDFAnnotationsLayerFactory.prototype = { + /** + * @param {HTMLDivElement} pageDiv + * @param {PDFPage} pdfPage + * @returns {AnnotationsLayerBuilder} + */ + createAnnotationsLayerBuilder: function (pageDiv, pdfPage) {} +}; diff --git a/web/pdf_page_view.js b/web/pdf_page_view.js index 38556efc6..87228c3e5 100644 --- a/web/pdf_page_view.js +++ b/web/pdf_page_view.js @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals RenderingStates, PDFJS, mozL10n, CustomStyle, getOutputScale, Stats, - CSS_UNITS */ +/* globals RenderingStates, PDFJS, CustomStyle, CSS_UNITS, getOutputScale, + Stats */ 'use strict'; @@ -25,10 +25,10 @@ * @property {number} id - The page unique ID (normally its number). * @property {number} scale - The page scale display. * @property {PageViewport} defaultViewport - The page viewport. - * @property {IPDFLinkService} linkService - The navigation/linking service. * @property {PDFRenderingQueue} renderingQueue - The rendering queue object. * @property {Cache} cache - The page cache. * @property {IPDFTextLayerFactory} textLayerFactory + * @property {IPDFAnnotationsLayerFactory} annotationsLayerFactory */ /** @@ -45,10 +45,10 @@ var PDFPageView = (function PDFPageViewClosure() { var id = options.id; var scale = options.scale; var defaultViewport = options.defaultViewport; - var linkService = options.linkService; var renderingQueue = options.renderingQueue; var cache = options.cache; var textLayerFactory = options.textLayerFactory; + var annotationsLayerFactory = options.annotationsLayerFactory; this.id = id; this.renderingId = 'page' + id; @@ -59,10 +59,10 @@ var PDFPageView = (function PDFPageViewClosure() { this.pdfPageRotate = defaultViewport.rotation; this.hasRestrictedScaling = false; - this.linkService = linkService; this.renderingQueue = renderingQueue; this.cache = cache; this.textLayerFactory = textLayerFactory; + this.annotationsLayerFactory = annotationsLayerFactory; this.renderingState = RenderingStates.INITIAL; this.resume = null; @@ -119,10 +119,12 @@ var PDFPageView = (function PDFPageViewClosure() { div.style.height = Math.floor(this.viewport.height) + 'px'; var childNodes = div.childNodes; + var currentZoomLayer = this.zoomLayer || null; + var currentAnnotationNode = (keepAnnotations && this.annotationLayer && + this.annotationLayer.div) || null; for (var i = div.childNodes.length - 1; i >= 0; i--) { var node = childNodes[i]; - if ((this.zoomLayer && this.zoomLayer === node) || - (keepAnnotations && this.annotationLayer === node)) { + if (currentZoomLayer === node || currentAnnotationNode === node) { continue; } div.removeChild(node); @@ -133,7 +135,7 @@ var PDFPageView = (function PDFPageViewClosure() { if (this.annotationLayer) { // Hide annotationLayer until all elements are resized // so they are not displayed on the already-resized page - this.annotationLayer.setAttribute('hidden', 'true'); + this.annotationLayer.hide(); } } else { this.annotationLayer = null; @@ -258,7 +260,7 @@ var PDFPageView = (function PDFPageViewClosure() { } if (redrawAnnotations && this.annotationLayer) { - this.setupAnnotations(); + this.annotationLayer.setupAnnotations(this.viewport); } }, @@ -270,106 +272,6 @@ var PDFPageView = (function PDFPageViewClosure() { return this.viewport.height; }, - setupAnnotations: function PDFPageView_setupAnnotations() { - function bindLink(link, dest) { - link.href = linkService.getDestinationHash(dest); - link.onclick = function pageViewSetupLinksOnclick() { - if (dest) { - linkService.navigateTo(dest); - } - return false; - }; - if (dest) { - link.className = 'internalLink'; - } - } - - function bindNamedAction(link, action) { - link.href = linkService.getAnchorUrl(''); - link.onclick = function pageViewSetupNamedActionOnClick() { - linkService.executeNamedAction(action); - return false; - }; - link.className = 'internalLink'; - } - - var linkService = this.linkService; - var pageDiv = this.div; - var pdfPage = this.pdfPage; - var viewport = this.viewport; - var self = this; - - pdfPage.getAnnotations().then(function(annotationsData) { - viewport = viewport.clone({ dontFlip: true }); - var transform = viewport.transform; - var transformStr = 'matrix(' + transform.join(',') + ')'; - var data, element, i, ii; - - if (self.annotationLayer) { - // If an annotationLayer already exists, refresh its children's - // transformation matrices - for (i = 0, ii = annotationsData.length; i < ii; i++) { - data = annotationsData[i]; - element = self.annotationLayer.querySelector( - '[data-annotation-id="' + data.id + '"]'); - if (element) { - CustomStyle.setProp('transform', element, transformStr); - } - } - // See this.reset() - self.annotationLayer.removeAttribute('hidden'); - } else { - for (i = 0, ii = annotationsData.length; i < ii; i++) { - data = annotationsData[i]; - if (!data || !data.hasHtml) { - continue; - } - - element = PDFJS.AnnotationUtils.getHtmlElement(data, - pdfPage.commonObjs); - element.setAttribute('data-annotation-id', data.id); - mozL10n.translate(element); - - 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'; - - CustomStyle.setProp('transform', element, transformStr); - var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px'; - CustomStyle.setProp('transformOrigin', element, transformOriginStr); - - if (data.subtype === 'Link' && !data.url) { - var link = element.getElementsByTagName('a')[0]; - if (link) { - if (data.action) { - bindNamedAction(link, data.action); - } else { - bindLink(link, ('dest' in data) ? data.dest : null); - } - } - } - - if (!self.annotationLayer) { - var annotationLayerDiv = document.createElement('div'); - annotationLayerDiv.className = 'annotationLayer'; - pageDiv.appendChild(annotationLayerDiv); - self.annotationLayer = annotationLayerDiv; - } - - self.annotationLayer.appendChild(element); - } - } - }); - }, - getPagePoint: function PDFPageView_getPagePoint(x, y) { return this.viewport.convertToPdfPoint(x, y); }, @@ -396,7 +298,7 @@ var PDFPageView = (function PDFPageViewClosure() { canvasWrapper.appendChild(canvas); if (this.annotationLayer) { // annotationLayer needs to stay on top - div.insertBefore(canvasWrapper, this.annotationLayer); + div.insertBefore(canvasWrapper, this.annotationLayer.div); } else { div.appendChild(canvasWrapper); } @@ -443,7 +345,7 @@ var PDFPageView = (function PDFPageViewClosure() { textLayerDiv.style.height = canvas.style.height; if (this.annotationLayer) { // annotationLayer needs to stay on top - div.insertBefore(textLayerDiv, this.annotationLayer); + div.insertBefore(textLayerDiv, this.annotationLayer.div); } else { div.appendChild(textLayerDiv); } @@ -538,7 +440,13 @@ var PDFPageView = (function PDFPageViewClosure() { } ); - this.setupAnnotations(); + if (this.annotationsLayerFactory) { + if (!this.annotationLayer) { + this.annotationLayer = this.annotationsLayerFactory. + createAnnotationsLayerBuilder(div, this.pdfPage); + } + this.annotationLayer.setupAnnotations(this.viewport); + } div.setAttribute('data-loaded', true); // Add the page to the cache at the start of drawing. That way it can be diff --git a/web/pdf_viewer.js b/web/pdf_viewer.js index 6441eae9e..84483224c 100644 --- a/web/pdf_viewer.js +++ b/web/pdf_viewer.js @@ -17,7 +17,8 @@ /*globals watchScroll, Cache, DEFAULT_CACHE_SIZE, PDFPageView, UNKNOWN_SCALE, SCROLLBAR_PADDING, VERTICAL_PADDING, MAX_AUTO_SCALE, CSS_UNITS, DEFAULT_SCALE, scrollIntoView, getVisibleElements, RenderingStates, - PDFJS, Promise, TextLayerBuilder, PDFRenderingQueue */ + PDFJS, Promise, TextLayerBuilder, PDFRenderingQueue, + AnnotationsLayerBuilder */ 'use strict'; @@ -33,6 +34,7 @@ var IGNORE_CURRENT_POSITION_ON_ZOOM = false; //#include pdf_rendering_queue.js //#include pdf_page_view.js //#include text_layer_builder.js +//#include annotations_layer_builder.js /** * @typedef {Object} PDFViewerOptions @@ -244,10 +246,10 @@ var PDFViewer = (function pdfViewer() { id: pageNum, scale: scale, defaultViewport: viewport.clone(), - linkService: this.linkService, renderingQueue: this.renderingQueue, cache: this.cache, - textLayerFactory: textLayerFactory + textLayerFactory: textLayerFactory, + annotationsLayerFactory: this }); bindOnAfterDraw(pageView); this.pages.push(pageView); @@ -675,6 +677,19 @@ var PDFViewer = (function pdfViewer() { }); }, + /** + * @param {HTMLDivElement} pageDiv + * @param {PDFPage} pdfPage + * @returns {AnnotationsLayerBuilder} + */ + createAnnotationsLayerBuilder: function (pageDiv, pdfPage) { + return new AnnotationsLayerBuilder({ + pageDiv: pageDiv, + pdfPage: pdfPage, + linkService: this.linkService + }); + }, + setFindController: function (findController) { this.findController = findController; }, diff --git a/web/viewer.html b/web/viewer.html index c2d3dff69..d6588d940 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -71,6 +71,7 @@ http://sourceforge.net/adobe/cmap/wiki/License/ +