diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index de6fd95db..1c4dd1cde 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -87,3 +87,5 @@ loading_error=An error occurred while loading the PDF. # Some common types are e.g.: "Check", "Text", "Comment", "Note" text_annotation_type=[{{type}} Annotation] request_password=PDF is protected by a password: + +printing_not_supported=Warning: Printing is not fully supported by this browser. diff --git a/web/viewer.css b/web/viewer.css index b8e86f2c8..80a8c5a40 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -1113,7 +1113,16 @@ canvas { font-size: 10px; } +@page { + margin: 0; +} + +#printContainer { + display: none; +} + @media print { + /* Rules for browsers that don't support mozPrintCallback. */ #sidebarContainer, .toolbar, #loadingBox, #errorWrapper, .textLayer { display: none; } @@ -1135,6 +1144,19 @@ canvas { .page[data-loaded] { display: block; } + + /* Rules for browsers that support mozPrintCallback */ + body[data-mozPrintCallback] #outerContainer { + display: none; + } + body[data-mozPrintCallback] #printContainer { + display: block; + } + #printContainer canvas { + position: relative; + top: 0; + left: 0; + } } @media all and (max-width: 950px) { diff --git a/web/viewer.html b/web/viewer.html index c59d9fcf3..28e57f700 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -102,11 +102,9 @@ <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()"> <span data-l10n-id="print_label">Print</span> </button> - --> <button id="download" class="toolbarButton download" title="Download" onclick="PDFView.download();" tabindex="12" data-l10n-id="download"> <span data-l10n-id="download_label">Download</span> @@ -176,5 +174,6 @@ </div> <!-- mainContainer --> </div> <!-- outerContainer --> + <div id="printContainer"></div> </body> </html> diff --git a/web/viewer.js b/web/viewer.js index 516081f6f..cbe20bb66 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -379,6 +379,17 @@ var PDFView = { return currentPageNumber; }, + get supportsPrinting() { + var canvas = document.createElement('canvas'); + var value = 'mozPrintCallback' in canvas; + // shadow + Object.defineProperty(this, 'supportsPrinting', { value: value, + enumerable: true, + configurable: true, + writable: false }); + return value; + }, + open: function pdfViewOpen(url, scale, password) { var parameters = {password: password}; if (typeof url === 'string') { // URL @@ -1041,6 +1052,26 @@ var PDFView = { params[unescape(key)] = unescape(value); } return params; + }, + + beforePrint: function pdfViewSetupBeforePrint() { + if (!this.supportsPrinting) { + var printMessage = mozL10n.get('printing_not_supported', null, + 'Warning: Printing is not fully supported by this browser.'); + this.error(printMessage); + return; + } + var body = document.querySelector('body'); + body.setAttribute('data-mozPrintCallback', true); + for (var i = 0, ii = this.pages.length; i < ii; ++i) { + this.pages[i].beforePrint(); + } + }, + + afterPrint: function pdfViewSetupAfterPrint() { + var div = document.getElementById('printContainer'); + while (div.hasChildNodes()) + div.removeChild(div.lastChild); } }; @@ -1360,6 +1391,44 @@ var PageView = function pageView(container, pdfPage, id, scale, div.setAttribute('data-loaded', true); }; + this.beforePrint = function pageViewBeforePrint() { + var pdfPage = this.pdfPage; + var viewport = pdfPage.getViewport(1); + + var canvas = this.canvas = document.createElement('canvas'); + canvas.width = viewport.width; + canvas.height = viewport.height; + canvas.style.width = viewport.width + 'pt'; + canvas.style.height = viewport.height + 'pt'; + + var printContainer = document.getElementById('printContainer'); + printContainer.appendChild(canvas); + + var self = this; + canvas.mozPrintCallback = function(obj) { + var ctx = obj.context; + var renderContext = { + canvasContext: ctx, + viewport: viewport + }; + + pdfPage.render(renderContext).then(function() { + // Tell the printEngine that rendering this canvas/page has finished. + obj.done(); + self.pdfPage.destroy(); + }, function(error) { + console.error(error); + // Tell the printEngine that rendering this canvas/page has failed. + // This will make the print proces stop. + if ('abort' in object) + obj.abort(); + else + obj.done(); + self.pdfPage.destroy(); + }); + }; + }; + this.updateStats = function pageViewUpdateStats() { if (PDFJS.pdfBug && Stats.enabled) { var stats = this.stats; @@ -1706,6 +1775,10 @@ window.addEventListener('load', function webViewerLoad(evt) { document.querySelector('#viewSearch').classList.remove('hidden'); } + if (!PDFView.supportsPrinting) { + document.getElementById('print').classList.add('hidden'); + } + // Listen for warnings to trigger the fallback UI. Errors should be caught // and call PDFView.error() so we don't need to listen for those. PDFJS.LogManager.addLogger({ @@ -1960,3 +2033,11 @@ window.addEventListener('keydown', function keydown(evt) { evt.preventDefault(); } }); + +window.addEventListener('beforeprint', function beforePrint(evt) { + PDFView.beforePrint(); +}); + +window.addEventListener('afterprint', function afterPrint(evt) { + PDFView.afterPrint(); +});