From 5d8f463162c45c3109d7e32a4350e80dee9c730a Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 7 Jun 2012 16:00:07 -0700 Subject: [PATCH 1/6] Adds support for the extend option for linear and radial shadings. --- src/pattern.js | 33 +++++++++++++++++++++++++++++---- test/pdfs/.gitignore | 1 + test/pdfs/shading_extend.pdf | Bin 0 -> 9514 bytes 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 test/pdfs/shading_extend.pdf diff --git a/src/pattern.js b/src/pattern.js index 8d69d3a92..a0aa9a8b2 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -46,6 +46,11 @@ var Pattern = (function PatternClosure() { var Shadings = {}; +// A small number to offset the first/last color stops so we can insert ones to +// support extend. Number.MIN_VALUE appears to be too small and breaks the +// extend. +Shadings.SMALL_NUMBER = 1e-7; + // Radial and axial shading have very similar implementations // If needed, the implementations can be broken into two classes Shadings.RadialAxial = (function RadialAxialClosure() { @@ -54,7 +59,6 @@ Shadings.RadialAxial = (function RadialAxialClosure() { this.coordsArr = dict.get('Coords'); this.shadingType = dict.get('ShadingType'); this.type = 'Pattern'; - this.ctx = ctx; var cs = dict.get('ColorSpace', 'CS'); cs = ColorSpace.parse(cs, xref, res); @@ -72,7 +76,6 @@ Shadings.RadialAxial = (function RadialAxialClosure() { var extendArr = dict.get('Extend'); extendStart = extendArr[0]; extendEnd = extendArr[1]; - TODO('Support extend'); } this.extendStart = extendStart; @@ -88,16 +91,38 @@ Shadings.RadialAxial = (function RadialAxialClosure() { // 10 samples seems good enough for now, but probably won't work // if there are sharp color changes. Ideally, we would implement // the spec faithfully and add lossless optimizations. - var step = (t1 - t0) / 10; var diff = t1 - t0; + var step = diff / 10; + + var colorStops = this.colorStops = []; + + // Protect against bad domains so we don't end up in an infinte loop below. + if (t0 >= t1 || step <= 0) { + // Acrobat doesn't seem to handle these cases so we'll ignore for + // now. + info('Bad shading domain.'); + return; + } - var colorStops = []; for (var i = t0; i <= t1; i += step) { var rgbColor = cs.getRgb(fn([i])); var cssColor = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]); colorStops.push([(i - t0) / diff, cssColor]); } + // XXX: Extend start and end does work in Chrome. Tested in v21. + if (!extendStart) { + // Insert a color stop at the front and offset the first real color stop + // so it doesn't conflict with the one we insert. + colorStops.unshift([0, 'rgba(255,255,255,0)']); + colorStops[1][0] += Shadings.SMALL_NUMBER; + } + if (!extendEnd) { + // Same idea as above in extendStart but for the end. + colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER; + colorStops.push([1, 'rgba(255,255,255,0)']); + } + this.colorStops = colorStops; } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 7f2911983..60793fa31 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -34,3 +34,4 @@ !gradientfill.pdf !basicapi.pdf !mixedfonts.pdf +!shading_extend.pdf diff --git a/test/pdfs/shading_extend.pdf b/test/pdfs/shading_extend.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0c8c151da6170412f979805766010cee5531427e GIT binary patch literal 9514 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 Z&@Zl#r8S*eZ@?dHYM458c4u3|e*wJgEujDa literal 0 HcmV?d00001 From 164931d2fce96bc2f767675235f7e505b1f5beba Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Mon, 10 Sep 2012 13:23:07 -0700 Subject: [PATCH 2/6] Adds background support for gradient. Warns on case when we don't handle radial gradients correctly. Fixes chrome extend gradients. --- src/pattern.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/pattern.js b/src/pattern.js index a0aa9a8b2..f65a182d9 100644 --- a/src/pattern.js +++ b/src/pattern.js @@ -48,8 +48,9 @@ var Shadings = {}; // A small number to offset the first/last color stops so we can insert ones to // support extend. Number.MIN_VALUE appears to be too small and breaks the -// extend. -Shadings.SMALL_NUMBER = 1e-7; +// extend. 1e-7 works in FF but chrome seems to use an even smaller sized number +// internally so we have to go bigger. +Shadings.SMALL_NUMBER = 1e-2; // Radial and axial shading have very similar implementations // If needed, the implementations can be broken into two classes @@ -78,6 +79,23 @@ Shadings.RadialAxial = (function RadialAxialClosure() { extendEnd = extendArr[1]; } + if (this.shadingType === PatternType.RADIAL && + (!extendStart || !extendEnd)) { + // Radial gradient only currently works if either circle is fully within + // the other circle. + var x1 = this.coordsArr[0]; + var y1 = this.coordsArr[1]; + var r1 = this.coordsArr[2]; + var x2 = this.coordsArr[3]; + var y2 = this.coordsArr[4]; + var r2 = this.coordsArr[5]; + var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + if (r1 <= r2 + distance && + r2 <= r1 + distance) { + warn('Unsupported radial gradient.'); + } + } + this.extendStart = extendStart; this.extendEnd = extendEnd; @@ -110,17 +128,22 @@ Shadings.RadialAxial = (function RadialAxialClosure() { colorStops.push([(i - t0) / diff, cssColor]); } - // XXX: Extend start and end does work in Chrome. Tested in v21. + var background = 'transparent'; + if (dict.has('Background')) { + var rgbColor = cs.getRgb(dict.get('Background')); + background = Util.makeCssRgb(rgbColor[0], rgbColor[1], rgbColor[2]); + } + if (!extendStart) { // Insert a color stop at the front and offset the first real color stop // so it doesn't conflict with the one we insert. - colorStops.unshift([0, 'rgba(255,255,255,0)']); + colorStops.unshift([0, background]); colorStops[1][0] += Shadings.SMALL_NUMBER; } if (!extendEnd) { // Same idea as above in extendStart but for the end. colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER; - colorStops.push([1, 'rgba(255,255,255,0)']); + colorStops.push([1, background]); } this.colorStops = colorStops; From 4c21197963e4229a6cbd88993de1ac5fdbbf99c8 Mon Sep 17 00:00:00 2001 From: Artur Adib Date: Tue, 11 Sep 2012 16:08:07 -0700 Subject: [PATCH 3/6] fix gh-pages bloat --- make.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) mode change 100755 => 100644 make.js diff --git a/make.js b/make.js old mode 100755 new mode 100644 index e33a597e0..4ce67a6ce --- a/make.js +++ b/make.js @@ -255,21 +255,19 @@ target.bundle = function() { target.pagesrepo = function() { cd(ROOT_DIR); echo(); - echo('### Creating fresh clone of gh-pages'); + echo('### Creating a fresh git repo for gh-pages'); - if (!test('-d', BUILD_DIR)) - mkdir(BUILD_DIR); + if (test('-d', GH_PAGES_DIR)) + rm('-rf', GH_PAGES_DIR); - if (!test('-d', GH_PAGES_DIR)) { - echo(); - echo('Cloning project repo...'); - echo('(This operation can take a while, depending on network conditions)'); - exec('git clone -b gh-pages --depth=1 ' + REPO + ' ' + GH_PAGES_DIR, - {silent: true}); - echo('Done.'); - } + mkdir('-p', GH_PAGES_DIR); + var oldDir = pwd(); + cd(GH_PAGES_DIR); + exec('git init'); + exec('git remote add origin ' + REPO); + exec('git checkout --orphan gh-pages'); + cd(oldDir); - rm('-rf', GH_PAGES_DIR + '/*'); mkdir('-p', GH_PAGES_DIR + '/web'); mkdir('-p', GH_PAGES_DIR + '/web/images'); mkdir('-p', GH_PAGES_DIR + BUILD_DIR); From 790f60830b677d49b913a6f927faac62a53accbf Mon Sep 17 00:00:00 2001 From: Artur Adib Date: Wed, 12 Sep 2012 09:10:30 -0700 Subject: [PATCH 4/6] remove target.pagesrepo, commit here (not bot) --- make.js | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/make.js b/make.js index 4ce67a6ce..27afbef25 100644 --- a/make.js +++ b/make.js @@ -104,12 +104,19 @@ target.generic = function() { target.web = function() { target.generic(); target.extension(); - target.pagesrepo(); - cd(ROOT_DIR); echo(); echo('### Creating web site'); + if (test('-d', GH_PAGES_DIR)) + rm('-rf', GH_PAGES_DIR); + + mkdir('-p', GH_PAGES_DIR + '/web'); + mkdir('-p', GH_PAGES_DIR + '/web/images'); + mkdir('-p', GH_PAGES_DIR + BUILD_DIR); + mkdir('-p', GH_PAGES_DIR + EXTENSION_SRC_DIR + '/firefox'); + mkdir('-p', GH_PAGES_DIR + EXTENSION_SRC_DIR + '/chrome'); + cp('-R', GENERIC_DIR + '/*', GH_PAGES_DIR); cp(FIREFOX_BUILD_DIR + '/*.xpi', FIREFOX_BUILD_DIR + '/*.rdf', GH_PAGES_DIR + EXTENSION_SRC_DIR + 'firefox/'); @@ -118,12 +125,14 @@ target.web = function() { cp('web/index.html.template', GH_PAGES_DIR + '/index.html'); cd(GH_PAGES_DIR); + exec('git init'); + exec('git remote add origin ' + REPO); exec('git add -A'); + exec('git commit -am "gh-pages site created via make.js script"'); + exec('git branch -m gh-pages'); echo(); echo('Website built in ' + GH_PAGES_DIR); - echo('Don\'t forget to cd into ' + GH_PAGES_DIR + - ' and issue \'git commit\' to push changes.'); }; // @@ -245,36 +254,6 @@ target.bundle = function() { }; -// -// make pagesrepo -// -// This target clones the gh-pages repo into the build directory. It deletes -// the current contents of the repo, since we overwrite everything with data -// from the master repo. The 'make web' target then uses 'git add -A' to track -// additions, modifications, moves, and deletions. -target.pagesrepo = function() { - cd(ROOT_DIR); - echo(); - echo('### Creating a fresh git repo for gh-pages'); - - if (test('-d', GH_PAGES_DIR)) - rm('-rf', GH_PAGES_DIR); - - mkdir('-p', GH_PAGES_DIR); - var oldDir = pwd(); - cd(GH_PAGES_DIR); - exec('git init'); - exec('git remote add origin ' + REPO); - exec('git checkout --orphan gh-pages'); - cd(oldDir); - - mkdir('-p', GH_PAGES_DIR + '/web'); - mkdir('-p', GH_PAGES_DIR + '/web/images'); - mkdir('-p', GH_PAGES_DIR + BUILD_DIR); - mkdir('-p', GH_PAGES_DIR + EXTENSION_SRC_DIR + '/firefox'); - mkdir('-p', GH_PAGES_DIR + EXTENSION_SRC_DIR + '/chrome'); -}; - /////////////////////////////////////////////////////////////////////////////////////////// // From 3fed93d80894befa9ae4ec42a45bc35c29ba5c59 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Tue, 11 Sep 2012 16:04:01 -0700 Subject: [PATCH 5/6] Adds text layer testing --- test/driver.js | 65 ++++++++++++++++++++++++++++++++++------- test/test.py | 7 +++-- test/test_manifest.json | 12 ++++++++ 3 files changed, 71 insertions(+), 13 deletions(-) diff --git a/test/driver.js b/test/driver.js index 54179f6cb..d1a8a17a7 100644 --- a/test/driver.js +++ b/test/driver.js @@ -26,7 +26,7 @@ // "firefox-bin: Fatal IO error 12 (Cannot allocate memory) on X server :1." // PDFJS.disableWorker = true; -var appPath, browser, canvas, currentTaskIdx, manifest, stdout; +var appPath, browser, canvas, dummyCanvas, currentTaskIdx, manifest, stdout; var inFlightRequests = 0; function queryParams() { @@ -148,6 +148,46 @@ function canvasToDataURL() { return canvas.toDataURL('image/png'); } +function NullTextLayerBuilder() { +} +NullTextLayerBuilder.prototype = { + beginLayout: function NullTextLayerBuilder_BeginLayout() {}, + endLayout: function NullTextLayerBuilder_EndLayout() {}, + appendText: function NullTextLayerBuilder_AppendText() {} +}; + +function SimpleTextLayerBuilder(ctx, viewport) { + this.ctx = ctx; + this.viewport = viewport; +} +SimpleTextLayerBuilder.prototype = { + beginLayout: function SimpleTextLayerBuilder_BeginLayout() { + this.ctx.save(); + }, + endLayout: function SimpleTextLayerBuilder_EndLayout() { + this.ctx.restore(); + }, + appendText: function SimpleTextLayerBuilder_AppendText(text, fontName, + fontSize) { + var ctx = this.ctx, viewport = this.viewport; + // vScale and hScale already contain the scaling to pixel units + var fontHeight = fontSize * text.geom.vScale; + ctx.beginPath(); + ctx.strokeStyle = 'red'; + ctx.fillStyle = 'yellow'; + ctx.rect(text.geom.x, text.geom.y - fontHeight, + text.canvasWidth * text.geom.hScale, fontHeight); + ctx.stroke(); + ctx.fill(); + + var textContent = bidi(text, -1); + ctx.font = fontHeight + 'px sans-serif'; + ctx.fillStyle = 'black'; + ctx.fillText(textContent, text.geom.x, text.geom.y); + } +}; + + function nextPage(task, loadError) { var failure = loadError || ''; @@ -196,16 +236,21 @@ function nextPage(task, loadError) { canvas.height = viewport.height; clear(ctx); - // using the text layer builder that does nothing to test - // text layer creation operations - var textLayerBuilder = { - beginLayout: function nullTextLayerBuilderBeginLayout() {}, - endLayout: function nullTextLayerBuilderEndLayout() {}, - appendText: function nullTextLayerBuilderAppendText(text, fontName, - fontSize) {} - }; + var drawContext, textLayerBuilder; + if (task.type == 'text') { + // using dummy canvas for pdf context drawing operations + if (!dummyCanvas) { + dummyCanvas = document.createElement('canvas'); + } + drawContext = dummyCanvas.getContext('2d'); + // ... text builder will draw its content on the test canvas + textLayerBuilder = new SimpleTextLayerBuilder(ctx, viewport); + } else { + drawContext = ctx; + textLayerBuilder = new NullTextLayerBuilder(); + } var renderContext = { - canvasContext: ctx, + canvasContext: drawContext, textLayer: textLayerBuilder, viewport: viewport }; diff --git a/test/test.py b/test/test.py index b5e3241b9..0e62aa9fe 100644 --- a/test/test.py +++ b/test/test.py @@ -514,7 +514,7 @@ def check(task, results, browser, masterMode): return kind = task['type'] - if 'eq' == kind: + if 'eq' == kind or 'text' == kind: checkEq(task, results, browser, masterMode) elif 'fbf' == kind: checkFBF(task, results, browser) @@ -528,6 +528,7 @@ def checkEq(task, results, browser, masterMode): pfx = os.path.join(REFDIR, sys.platform, browser, task['id']) results = results[0] taskId = task['id'] + taskType = task['type'] passed = True for page in xrange(len(results)): @@ -547,7 +548,7 @@ def checkEq(task, results, browser, masterMode): eq = (ref == snapshot) if not eq: - print 'TEST-UNEXPECTED-FAIL | eq', taskId, '| in', browser, '| rendering of page', page + 1, '!= reference rendering' + print 'TEST-UNEXPECTED-FAIL | ', taskType, taskId, '| in', browser, '| rendering of page', page + 1, '!= reference rendering' if not State.eqLog: State.eqLog = open(EQLOG_FILE, 'w') @@ -576,7 +577,7 @@ def checkEq(task, results, browser, masterMode): of.close() if passed: - print 'TEST-PASS | eq test', task['id'], '| in', browser + print 'TEST-PASS | ', taskType, ' test', task['id'], '| in', browser def checkFBF(task, results, browser): round0, round1 = results[0], results[1] diff --git a/test/test_manifest.json b/test/test_manifest.json index d19633947..e7575f41f 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -11,6 +11,12 @@ "rounds": 2, "type": "fbf" }, + { "id": "tracemonkey-text", + "file": "pdfs/tracemonkey.pdf", + "md5": "9a192d8b1a7dc652a19835f6f08098bd", + "rounds": 1, + "type": "text" + }, { "id": "html5-canvas-cheat-sheet-load", "file": "pdfs/canvas.pdf", "md5": "59510028561daf62e00bf9f6f066b033", @@ -89,6 +95,12 @@ "rounds": 1, "type": "eq" }, + { "id": "thuluthfont-text", + "file": "pdfs/ThuluthFeatures.pdf", + "md5": "b7e18bf7a3d6a9c82aefa12d721072fc", + "rounds": 1, + "type": "text" + }, { "id": "freeculture", "file": "pdfs/freeculture.pdf", "md5": "dcdf3a8268e6a18938a42d5149efcfca", From 9fba150dd214d4a14e5d9ebdf268202ddc6f3512 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Wed, 12 Sep 2012 17:31:04 -0700 Subject: [PATCH 6/6] Move font translation to the worker --- src/api.js | 19 +++++-------------- src/evaluator.js | 29 ++++++++++++++--------------- src/fonts.js | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/src/api.js b/src/api.js index d6d13a095..169faea0d 100644 --- a/src/api.js +++ b/src/api.js @@ -575,24 +575,15 @@ var WorkerTransport = (function WorkerTransportClosure() { this.objs.resolve(id, imageData); break; case 'Font': - var name = data[2]; - var file = data[3]; - var properties = data[4]; - - if (file) { - // Rewrap the ArrayBuffer in a stream. - var fontFileDict = new Dict(); - file = new Stream(file, 0, file.length, fontFileDict); - } + var exportedData = data[2]; // At this point, only the font object is created but the font is // not yet attached to the DOM. This is done in `FontLoader.bind`. var font; - try { - font = new Font(name, file, properties); - } catch (e) { - font = new ErrorFont(e); - } + if ('error' in exportedData) + font = new ErrorFont(exportedData.error); + else + font = new Font(exportedData); this.objs.resolve(id, font); break; default: diff --git a/src/evaluator.js b/src/evaluator.js index 621dd613f..704091149 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -171,31 +171,30 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { ++self.objIdCounter; if (!font.loadedName) { - font.translated = self.translateFont(font, xref, resources, - dependency); - if (font.translated) { + var translated = self.translateFont(font, xref, resources, + dependency); + if (translated) { // keep track of each font we translated so the caller can // load them asynchronously before calling display on a page loadedName = 'font_' + uniquePrefix + self.objIdCounter; - font.translated.properties.loadedName = loadedName; + translated.properties.loadedName = loadedName; font.loadedName = loadedName; + font.translated = translated; - var translated = font.translated; - // Convert the file to an ArrayBuffer which will be turned back into - // a Stream in the main thread. - if (translated.file) - translated.file = translated.file.getBytes(); - if (translated.properties.file) { - translated.properties.file = - translated.properties.file.getBytes(); + var data; + try { + var fontObj = new Font(translated.name, + translated.file, + translated.properties); + data = fontObj.export(); + } catch (e) { + data = { error: e }; } handler.send('obj', [ loadedName, 'Font', - translated.name, - translated.file, - translated.properties + data ]); } } diff --git a/src/fonts.js b/src/fonts.js index 15af2fa39..820ada8a0 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -1526,6 +1526,15 @@ function fontCharsToUnicode(charCodes, fontProperties) { */ var Font = (function FontClosure() { function Font(name, file, properties) { + if (arguments.length === 1) { + // importing translated data + var data = arguments[0]; + for (var i in data) { + this[i] = data[i]; + } + return; + } + this.name = name; this.coded = properties.coded; this.charProcOperatorList = properties.charProcOperatorList; @@ -2036,6 +2045,15 @@ var Font = (function FontClosure() { mimetype: null, encoding: null, + export: function Font_export() { + var data = {}; + for (var i in this) { + if (this.hasOwnProperty(i)) + data[i] = this[i]; + } + return data; + }, + checkAndRepair: function Font_checkAndRepair(name, font, properties) { function readTableEntry(file) { var tag = file.getBytes(4);