diff --git a/src/core/evaluator.js b/src/core/evaluator.js index 56f947c91..c5e589824 100644 --- a/src/core/evaluator.js +++ b/src/core/evaluator.js @@ -19,8 +19,9 @@ info, isArray, isCmd, isDict, isEOF, isName, isNum, isStream, isString, JpegStream, Lexer, Metrics, Name, Parser, Pattern, PDFImage, PDFJS, serifFonts, stdFontMap, symbolsFonts, - TilingPattern, TODO, warn, Util, Promise, - RefSetCache, isRef, TextRenderingMode, CMapFactory, OPS */ + TilingPattern, warn, Util, Promise, UnsupportedManager, + RefSetCache, isRef, TextRenderingMode, CMapFactory, OPS, + UNSUPPORTED_FEATURES */ 'use strict'; @@ -407,9 +408,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { gStateObj.push([key, value]); break; case 'SMask': - // We support the default so don't trigger the TODO. + // We support the default so don't trigger a warning bar. if (!isName(value) || value.name != 'None') - TODO('graphic state operator ' + key); + UnsupportedManager.notify(UNSUPPORTED_FEATURES.smask); break; // Only generate info log messages for the following since // they are unlikey to have a big impact on the rendering. @@ -499,6 +500,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { try { translated = this.translateFont(font, xref); } catch (e) { + UnsupportedManager.notify(UNSUPPORTED_FEATURES.font); translated = new ErrorFont(e instanceof Error ? e.message : e); } font.translated = translated; diff --git a/src/core/fonts.js b/src/core/fonts.js index dae633038..67236c3fe 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -17,7 +17,7 @@ /* globals assert, bytesToString, CIDToUnicodeMaps, error, ExpertCharset, ExpertSubsetCharset, FileReaderSync, GlyphsUnicode, info, isArray, isNum, ISOAdobeCharset, Stream, - stringToBytes, TextDecoder, TODO, warn, Lexer, Util, + stringToBytes, TextDecoder, warn, Lexer, Util, FONT_IDENTITY_MATRIX, FontRendererFactory, shadow, isString */ 'use strict'; @@ -495,7 +495,7 @@ function sjis83pvToUnicode(str) { // TODO: 83pv has incompatible mappings in ed40..ee9c range. return decodeBytes(bytes, 'shift_jis', true); } catch (e) { - TODO('Unsupported 83pv character found'); + warn('Unsupported 83pv character found'); // Just retry without checking errors for now. return decodeBytes(bytes, 'shift_jis'); } @@ -507,7 +507,7 @@ function sjis90pvToUnicode(str) { // TODO: 90pv has incompatible mappings in 8740..879c and eb41..ee9c. return decodeBytes(bytes, 'shift_jis', true); } catch (e) { - TODO('Unsupported 90pv character found'); + warn('Unsupported 90pv character found'); // Just retry without checking errors for now. return decodeBytes(bytes, 'shift_jis'); } @@ -4339,7 +4339,7 @@ var Font = (function FontClosure() { var cidEncoding = properties.cidEncoding; if (properties.toUnicode) { if (cidEncoding && cidEncoding.indexOf('Identity-') !== 0) { - TODO('Need to create a reverse mapping from \'ToUnicode\' CMap'); + warn('Need to create a reverse mapping from \'ToUnicode\' CMap'); } return; // 'ToUnicode' CMap will be used } diff --git a/src/core/image.js b/src/core/image.js index ceeee3923..ca50f8dde 100644 --- a/src/core/image.js +++ b/src/core/image.js @@ -15,7 +15,7 @@ * limitations under the License. */ /* globals ColorSpace, error, isArray, isStream, JpegStream, Name, Promise, - Stream, TODO, warn */ + Stream, warn */ 'use strict'; @@ -54,7 +54,7 @@ var PDFImage = (function PDFImageClosure() { if (image.getParams) { // JPX/JPEG2000 streams directly contain bits per component // and color space mode information. - TODO('get params from actual stream'); + warn('get params from actual stream'); // var bits = ... // var colorspace = ... } @@ -87,7 +87,7 @@ var PDFImage = (function PDFImageClosure() { if (!this.imageMask) { var colorSpace = dict.get('ColorSpace', 'CS'); if (!colorSpace) { - TODO('JPX images (which don"t require color spaces'); + warn('JPX images (which don"t require color spaces'); colorSpace = new Name('DeviceRGB'); } this.colorSpace = ColorSpace.parse(colorSpace, xref, res); diff --git a/src/core/worker.js b/src/core/worker.js index 0db5b5a9b..a2b405b69 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -429,15 +429,12 @@ var workerConsole = { if (typeof window === 'undefined') { globalScope.console = workerConsole; - // Add a logger so we can pass warnings on to the main thread, errors will - // throw an exception which will be forwarded on automatically. - PDFJS.LogManager.addLogger({ - warn: function(msg) { - globalScope.postMessage({ - action: '_warn', - data: msg - }); - } + // Listen for unsupported features so we can pass them on to the main thread. + PDFJS.UnsupportedManager.listen(function (msg) { + globalScope.postMessage({ + action: '_unsupported_feature', + data: msg + }); }); var handler = new MessageHandler('worker_processor', this); diff --git a/src/display/canvas.js b/src/display/canvas.js index 026849298..a918b7bb5 100644 --- a/src/display/canvas.js +++ b/src/display/canvas.js @@ -16,7 +16,7 @@ */ /* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageData, isArray, isNum, - Pattern, TilingPattern, TODO, Util, warn, assert, info, + Pattern, TilingPattern, Util, warn, assert, info, TextRenderingMode, OPS */ 'use strict'; @@ -1460,7 +1460,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { // TODO knockout - supposedly possible with the clever use of compositing // modes. if (group.knockout) { - TODO('Support knockout groups.'); + warn('Knockout groups not supported.'); } var currentTransform = currentCtx.mozCurrentTransform; diff --git a/src/shared/annotation.js b/src/shared/annotation.js index 67365f22f..eae51c980 100644 --- a/src/shared/annotation.js +++ b/src/shared/annotation.js @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* globals Util, isDict, isName, stringToPDFString, TODO, Dict, Stream, +/* globals Util, isDict, isName, stringToPDFString, warn, Dict, Stream, stringToBytes, PDFJS, isWorker, assert, NotImplementedException, Promise, isArray, ObjectLoader, isValidUrl, OperatorList, OPS */ @@ -266,7 +266,7 @@ var Annotation = (function AnnotationClosure() { if (annotation.isViewable()) { return annotation; } else { - TODO('unimplemented annotation type: ' + subtype); + warn('unimplemented annotation type: ' + subtype); } }; @@ -358,7 +358,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() { Util.inherit(WidgetAnnotation, Annotation, { isViewable: function WidgetAnnotation_isViewable() { if (this.data.fieldType === 'Sig') { - TODO('unimplemented annotation type: Widget signature'); + warn('unimplemented annotation type: Widget signature'); return false; } @@ -643,7 +643,7 @@ var LinkAnnotation = (function LinkAnnotationClosure() { } else if (linkType === 'Named') { data.action = action.get('N').name; } else { - TODO('unrecognized link type: ' + linkType); + warn('unrecognized link type: ' + linkType); } } else if (dict.has('Dest')) { // simple destination link diff --git a/src/shared/colorspace.js b/src/shared/colorspace.js index 62f7a4d4f..9eedfc8e7 100644 --- a/src/shared/colorspace.js +++ b/src/shared/colorspace.js @@ -15,7 +15,7 @@ * limitations under the License. */ /* globals error, info, isArray, isDict, isName, isStream, isString, - PDFFunction, warn, shadow, TODO */ + PDFFunction, warn, shadow */ 'use strict'; @@ -671,7 +671,7 @@ var CalGrayCS = (function CalGrayCSClosure() { } if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) { - TODO(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + + warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB + ', ZB: ' + this.ZB + ', only default values are supported.'); } diff --git a/src/shared/function.js b/src/shared/function.js index 0606bac46..15b153957 100644 --- a/src/shared/function.js +++ b/src/shared/function.js @@ -1,6 +1,5 @@ /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* globals EOF, error, isArray, isBool, Lexer, TODO */ /* Copyright 2012 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* globals EOF, error, isArray, isBool, Lexer, info */ 'use strict'; @@ -122,7 +122,7 @@ var PDFFunction = (function PDFFunctionClosure() { if (order !== 1) { // No description how cubic spline interpolation works in PDF32000:2008 // As in poppler, ignoring order, linear interpolation may work as good - TODO('No support for cubic spline interpolation: ' + order); + info('No support for cubic spline interpolation: ' + order); } var encode = dict.get('Encode'); diff --git a/src/shared/pattern.js b/src/shared/pattern.js index b2c5456fb..f0fa153a8 100644 --- a/src/shared/pattern.js +++ b/src/shared/pattern.js @@ -15,8 +15,8 @@ * limitations under the License. */ /* globals CanvasGraphics, ColorSpace, DeviceRgbCS, error, - info, isArray, isPDFFunction, isStream, PDFFunction, TODO, Util, - warn, CachedCanvases */ + info, isArray, isPDFFunction, isStream, PDFFunction, Util, + warn, CachedCanvases, UnsupportedManager, UNSUPPORTED_FEATURES */ 'use strict'; @@ -55,7 +55,7 @@ var Pattern = (function PatternClosure() { // Both radial and axial shadings are handled by RadialAxial shading. return new Shadings.RadialAxial(dict, matrix, xref, res); default: - TODO('Unsupported shading type: ' + type); + UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern); return new Shadings.Dummy(); } }; @@ -315,7 +315,7 @@ var TilingPattern = (function TilingPatternClosure() { var commonObjs = this.commonObjs; var ctx = this.ctx; - TODO('TilingType: ' + tilingType); + info('TilingType: ' + tilingType); var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; diff --git a/src/shared/util.js b/src/shared/util.js index 598674990..00b62a0d2 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -156,21 +156,19 @@ var log = (function() { } })(); -// A notice for devs that will not trigger the fallback UI. These are good -// for things that are helpful to devs, such as warning that Workers were -// disabled, which is important to devs but not end users. +// A notice for devs. These are good for things that are helpful to devs, such +// as warning that Workers were disabled, which is important to devs but not +// end users. function info(msg) { if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) { log('Info: ' + msg); - PDFJS.LogManager.notify('info', msg); } } -// Non-fatal warnings that should trigger the fallback UI. +// Non-fatal warnings. function warn(msg) { if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) { log('Warning: ' + msg); - PDFJS.LogManager.notify('warn', msg); } } @@ -188,15 +186,10 @@ function error(msg) { log('Error: ' + msg); } log(backtrace()); - PDFJS.LogManager.notify('error', msg); + UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown); throw new Error(msg); } -// Missing features that should trigger the fallback UI. -function TODO(what) { - warn('TODO: ' + what); -} - function backtrace() { try { throw new Error(); @@ -210,6 +203,31 @@ function assert(cond, msg) { error(msg); } +var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = { + unknown: 'unknown', + forms: 'forms', + javaScript: 'javaScript', + smask: 'smask', + shadingPattern: 'shadingPattern', + font: 'font' +}; + +var UnsupportedManager = PDFJS.UnsupportedManager = + (function UnsupportedManagerClosure() { + var listeners = []; + return { + listen: function (cb) { + listeners.push(cb); + }, + notify: function (featureId) { + warn('Unsupported feature "' + featureId + '"'); + for (var i = 0, ii = listeners.length; i < ii; i++) { + listeners[i](featureId); + } + } + }; +})(); + // Combines two URLs. The baseUrl shall be absolute URL. If the url is an // absolute URL, it will be returned as is. function combineUrl(baseUrl, url) { @@ -263,22 +281,6 @@ function assertWellFormed(cond, msg) { error(msg); } -var LogManager = PDFJS.LogManager = (function LogManagerClosure() { - var loggers = []; - return { - addLogger: function logManager_addLogger(logger) { - loggers.push(logger); - }, - notify: function(type, message) { - for (var i = 0, ii = loggers.length; i < ii; i++) { - var logger = loggers[i]; - if (logger[type]) - logger[type](message); - } - } - }; -})(); - function shadow(obj, prop, value) { Object.defineProperty(obj, prop, { value: value, enumerable: true, @@ -1152,8 +1154,8 @@ function MessageHandler(name, comObj) { log.apply(null, data); }]; } - ah['_warn'] = [function ah_Warn(data) { - warn(data); + ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) { + UnsupportedManager.notify(data); }]; comObj.onmessage = function messageHandlerComObjOnMessage(event) { diff --git a/web/viewer.js b/web/viewer.js index 1ded06cf9..f753e3da4 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -599,7 +599,7 @@ var PDFView = { ).then(null, noData); }, - fallback: function pdfViewFallback() { + fallback: function pdfViewFallback(featureId) { //#if !(FIREFOX || MOZCENTRAL) // return; //#else @@ -935,7 +935,7 @@ var PDFView = { pdfDocument.getJavaScript().then(function(javaScript) { if (javaScript.length) { console.warn('Warning: JavaScript is not supported'); - PDFView.fallback(); + PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.javaScript); } // Hack to support auto printing. var regex = /\bprint\s*\(/g; @@ -1000,7 +1000,7 @@ var PDFView = { if (info.IsAcroFormPresent) { console.warn('Warning: AcroForm/XFA is not supported'); - PDFView.fallback(); + PDFView.fallback(PDFJS.UNSUPPORTED_FEATURES.forms); } //#if (FIREFOX || MOZCENTRAL) @@ -1661,13 +1661,8 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { document.getElementById('viewFind').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({ - warn: function() { - PDFView.fallback(); - } - }); + // Listen for unsuporrted features to trigger the fallback UI. + PDFJS.UnsupportedManager.listen(PDFView.fallback.bind(PDFView)); // Suppress context menus for some controls document.getElementById('scaleSelect').oncontextmenu = noContextMenuHandler;