Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring of printing code and mozPrintCallback polyfill #7697

Merged
merged 3 commits into from
Oct 11, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ function createWebBundle(defines) {
template = 'web/viewer.js';
files = ['app.js'];
if (defines.FIREFOX || defines.MOZCENTRAL) {
files.push('firefoxcom.js');
files.push('firefoxcom.js', 'firefox_print_service.js');
} else if (defines.CHROME) {
files.push('chromecom.js', 'mozPrintCallback_polyfill.js');
files.push('chromecom.js', 'pdf_print_service.js');
} else if (defines.GENERIC) {
files.push('mozPrintCallback_polyfill.js');
files.push('pdf_print_service.js');
}
}

Expand Down
6 changes: 6 additions & 0 deletions l10n/en-US/viewer.properties
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ document_properties_version=PDF Version:
document_properties_page_count=Page Count:
document_properties_close=Close

print_progress_message=Preparing document for printing…
# LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by
# a numerical per cent value.
print_progress_percent={{progress}}%
print_progress_close=Cancel

# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
Expand Down
96 changes: 36 additions & 60 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ var PDFViewerApplication = {
appConfig: null,
pdfDocument: null,
pdfLoadingTask: null,
printing: false,
printService: null,
/** @type {PDFViewer} */
pdfViewer: null,
/** @type {PDFThumbnailViewer} */
Expand Down Expand Up @@ -428,11 +428,12 @@ var PDFViewerApplication = {
return this.pdfViewer.currentPageNumber;
},

get supportsPrinting() {
var canvas = document.createElement('canvas');
var value = 'mozPrintCallback' in canvas;
get printing() {
return !!this.printService;
},

return pdfjsLib.shadow(this, 'supportsPrinting', value);
get supportsPrinting() {
return PDFPrintServiceFactory.instance.supportsPrinting;
},

get supportsFullscreen() {
Expand Down Expand Up @@ -1099,66 +1100,37 @@ var PDFViewerApplication = {
},

beforePrint: function pdfViewSetupBeforePrint() {
if (this.printService) {
// There is no way to suppress beforePrint/afterPrint events,
// but PDFPrintService may generate double events -- this will ignore
// the second event that will be coming from native window.print().
return;
}

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 alertNotReady = false;
var i, ii;
if (!this.pdfDocument || !this.pagesCount) {
alertNotReady = true;
} else {
for (i = 0, ii = this.pagesCount; i < ii; ++i) {
if (!this.pdfViewer.getPageView(i).pdfPage) {
alertNotReady = true;
break;
}
}
}
if (alertNotReady) {
// The beforePrint is a sync method and we need to know layout before
// returning from this method. Ensure that we can get sizes of the pages.
if (!this.pdfViewer.pageViewsReady) {
var notReadyMessage = mozL10n.get('printing_not_ready', null,
'Warning: The PDF is not fully loaded for printing.');
window.alert(notReadyMessage);
return;
}

this.printing = true;
var pagesOverview = this.pdfViewer.getPagesOverview();
var printContainer = this.appConfig.printContainer;
var printService = PDFPrintServiceFactory.instance.createPrintService(
this.pdfDocument, pagesOverview, printContainer);
this.printService = printService;
this.forceRendering();

var printContainer = this.appConfig.printContainer;
var body = document.querySelector('body');
body.setAttribute('data-mozPrintCallback', true);

if (!this.hasEqualPageSizes) {
console.warn('Not all pages have the same size. The printed result ' +
'may be incorrect!');
}

// Insert a @page + size rule to make sure that the page size is correctly
// set. Note that we assume that all pages have the same size, because
// variable-size pages are not supported yet (at least in Chrome & Firefox).
// TODO(robwu): Use named pages when size calculation bugs get resolved
// (e.g. https://crbug.com/355116) AND when support for named pages is
// added (http://www.w3.org/TR/css3-page/#using-named-pages).
// In browsers where @page + size is not supported (such as Firefox,
// https://bugzil.la/851441), the next stylesheet will be ignored and the
// user has to select the correct paper size in the UI if wanted.
this.pageStyleSheet = document.createElement('style');
var pageSize = this.pdfViewer.getPageView(0).pdfPage.getViewport(1);
this.pageStyleSheet.textContent =
// "size:<width> <height>" is what we need. But also add "A4" because
// Firefox incorrectly reports support for the other value.
'@supports ((size:A4) and (size:1pt 1pt)) {' +
'@page { size: ' + pageSize.width + 'pt ' + pageSize.height + 'pt;}' +
'}';
body.appendChild(this.pageStyleSheet);

for (i = 0, ii = this.pagesCount; i < ii; ++i) {
this.pdfViewer.getPageView(i).beforePrint(printContainer);
}
printService.layout();

//#if !PRODUCTION
if (true) {
Expand Down Expand Up @@ -1186,17 +1158,10 @@ var PDFViewerApplication = {
},

afterPrint: function pdfViewSetupAfterPrint() {
var div = this.appConfig.printContainer;
while (div.hasChildNodes()) {
div.removeChild(div.lastChild);
}

if (this.pageStyleSheet && this.pageStyleSheet.parentNode) {
this.pageStyleSheet.parentNode.removeChild(this.pageStyleSheet);
this.pageStyleSheet = null;
if (this.printService) {
this.printService.destroy();
this.printService = null;
}

this.printing = false;
this.forceRendering();
},

Expand Down Expand Up @@ -2330,6 +2295,17 @@ window.addEventListener('afterprint', function afterPrint(evt) {
});
})();

/* Abstract factory for the print service. */
var PDFPrintServiceFactory = {
instance: {
supportsPrinting: false,
createPrintService: function () {
throw new Error('Not implemented: createPrintService');
}
}
};

exports.PDFViewerApplication = PDFViewerApplication;
exports.DefaultExernalServices = DefaultExernalServices;
exports.PDFPrintServiceFactory = PDFPrintServiceFactory;
}));
122 changes: 122 additions & 0 deletions web/firefox_print_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define('pdfjs-web/firefox_print_service', ['exports', 'pdfjs-web/ui_utils',
'pdfjs-web/app', 'pdfjs-web/pdfjs'], factory);
} else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'), require('./app.js'),
require('./pdfjs.js'));
} else {
factory((root.pdfjsWebFirefoxPrintService = {}), root.pdfjsWebUIUtils,
root.pdfjsWebApp, root.pdfjsWebPDFJS);
}
}(this, function (exports, uiUtils, app, pdfjsLib) {
var CSS_UNITS = uiUtils.CSS_UNITS;
var PDFPrintServiceFactory = app.PDFPrintServiceFactory;

// Creates a placeholder with div and canvas with right size for the page.
function composePage(pdfDocument, pageNumber, size, printContainer) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called renderPage in pdf_print_service.js. Can we name it renderPage here too for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I added a comments to pdf_print_service

var canvas = document.createElement('canvas');

// The size of the canvas in pixels for printing.
var PRINT_RESOLUTION = 150;
var PRINT_UNITS = PRINT_RESOLUTION / 72.0;
canvas.width = Math.floor(size.width * PRINT_UNITS);
canvas.height = Math.floor(size.height * PRINT_UNITS);

// The physical size of the canvas as specified by the PDF document.
canvas.style.width = Math.floor(size.width * CSS_UNITS) + 'px';
canvas.style.height = Math.floor(size.height * CSS_UNITS) + 'px';

var canvasWrapper = document.createElement('div');
canvasWrapper.appendChild(canvas);
printContainer.appendChild(canvasWrapper);

canvas.mozPrintCallback = function(obj) {
// Printing/rendering the page.
var ctx = obj.context;

ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();

pdfDocument.getPage(pageNumber).then(function (pdfPage) {
var renderContext = {
canvasContext: ctx,
transform: [PRINT_UNITS, 0, 0, PRINT_UNITS, 0, 0],
viewport: pdfPage.getViewport(1),
intent: 'print'
};
return pdfPage.render(renderContext).promise;
}).then(function() {
// Tell the printEngine that rendering this canvas/page has finished.
obj.done();
}, function(error) {
console.error(error);
// Tell the printEngine that rendering this canvas/page has failed.
// This will make the print process stop.
if ('abort' in obj) {
obj.abort();
} else {
obj.done();
}
});
};
}

function FirefoxPrintService(pdfDocument, pagesOverview, printContainer) {
this.pdfDocument = pdfDocument;
this.pagesOverview = pagesOverview;
this.printContainer = printContainer;
}

FirefoxPrintService.prototype = {
layout: function () {
var pdfDocument = this.pdfDocument;
var printContainer = this.printContainer;
var body = document.querySelector('body');
body.setAttribute('data-pdfjsprinting', true);

for (var i = 0, ii = this.pagesOverview.length; i < ii; ++i) {
composePage(pdfDocument, i + 1, this.pagesOverview[i], printContainer);
}
},

destroy: function () {
this.printContainer.textContent = '';
}
};

PDFPrintServiceFactory.instance = {
get supportsPrinting() {
var canvas = document.createElement('canvas');
var value = 'mozPrintCallback' in canvas;

return pdfjsLib.shadow(this, 'supportsPrinting', value);
},

createPrintService: function (pdfDocument, pagesOverview, printContainer) {
return new FirefoxPrintService(pdfDocument, pagesOverview,
printContainer);
}
};

exports.FirefoxPrintService = FirefoxPrintService;
}));
Loading