From fcdd7e384554dbe2ac24e2217f2fcd2cc6ba5a64 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 9 May 2011 20:16:06 -0500 Subject: [PATCH 1/5] Implement "n" (end path), add stubs for NYI operators --- pdf.js | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 107 insertions(+), 7 deletions(-) diff --git a/pdf.js b/pdf.js index 9da8848db..bb8ec8305 100644 --- a/pdf.js +++ b/pdf.js @@ -1003,6 +1003,8 @@ var Interpreter = (function() { J: gfx.setLineCap, j: gfx.setLineJoin, d: gfx.setDash, + ri: gfx.setRenderingIntent, + i: gfx.setFlatness, q: gfx.save, Q: gfx.restore, cm: gfx.transform, @@ -1017,6 +1019,7 @@ var Interpreter = (function() { f: gfx.fill, B: gfx.fillStroke, b: gfx.closeFillStroke, + n: gfx.endPath, // Clipping @@ -1028,12 +1031,17 @@ var Interpreter = (function() { gfx.setFont(font, size); }, Td: gfx.moveText, + Tm: gfx.setTextMatrix, Tj: gfx.showText, TJ: gfx.showSpacedText, // Type3 fonts // Color + CS: gfx.setStrokeColorSpace, + cs: gfx.setFillColorSpace, + SC: gfx.setStrokeColor, + sc: gfx.setFillColor, g: gfx.setFillGray, RG: gfx.setStrokeRGBColor, rg: gfx.setFillRGBColor, @@ -1041,6 +1049,8 @@ var Interpreter = (function() { // Shading // Images // XObjects + Do: gfx.paintXObject, + // Marked content // Compatibility }; @@ -1064,11 +1074,10 @@ var Interpreter = (function() { if (IsCmd(obj)) { var cmd = obj.cmd; var fn = map[cmd]; - if (fn) { - if (fn.length != args.length) - this.error("Invalid number of arguments '" + cmd + "'"); + if (fn) + // TODO figure out how to type-check vararg functions fn.apply(gfx, args); - } else + else this.error("Unknown command '" + cmd + "'"); args.length = 0; } else { @@ -1116,6 +1125,12 @@ var EchoGraphics = (function() { setDash: function(dashArray, dashPhase) { this.printdentln(""+ dashArray +" "+ dashPhase +" d"); }, + setRenderingIntent: function(intent) { + this.printdentln("/"+ intent.name + " ri"); + }, + setFlatness: function(flatness) { + this.printdentln(""+ flatness +" i"); + }, save: function() { this.printdentln("q"); }, @@ -1157,6 +1172,9 @@ var EchoGraphics = (function() { closeFillStroke: function() { this.printdentln("b"); }, + endPath: function() { + this.printdentln("n"); + }, // Clipping @@ -1175,6 +1193,10 @@ var EchoGraphics = (function() { moveText: function (x, y) { this.printdentln(""+ x +" "+ y +" Td"); }, + setTextMatrix: function(a, b, c, d, e, f) { + this.printdentln(""+ a +" "+ b +" "+ c + + " "+d +" "+ e +" "+ f + " Tm"); + }, showText: function(text) { this.printdentln("( "+ text +" ) Tj"); }, @@ -1185,6 +1207,24 @@ var EchoGraphics = (function() { // Type3 fonts // Color + setStrokeColorSpace: function(space) { + this.printdentln("/"+ space.name +" CS"); + }, + setFillColorSpace: function(space) { + this.printdentln("/"+ space.name +" cs"); + }, + setStrokeColor: function(/*...*/) { + this.printdent(""); + for (var i = 0; i < arguments.length; ++i) + this.print(""+ arguments[i] +" "); + this.printdentln("SC"); + }, + setFillColor: function(/*...*/) { + this.printdent(""); + for (var i = 0; i < arguments.length; ++i) + this.print(""+ arguments[i] +" "); + this.printdentln("sc"); + }, setFillGray: function(gray) { this.printdentln(""+ gray +" g"); }, @@ -1198,6 +1238,10 @@ var EchoGraphics = (function() { // Shading // Images // XObjects + paintXObject: function(obj) { + this.printdentln("/"+ obj.name +" Do"); + }, + // Marked content // Compatibility @@ -1209,9 +1253,13 @@ var EchoGraphics = (function() { this.print(str); this.out += "\n"; }, - printdentln: function(str) { + printdent: function(str) { this.print(this.indentationStr); - this.println(str); + this.print(str); + }, + printdentln: function(str) { + this.printdent(str); + this.println(""); }, indent: function() { this.indentation += 2; @@ -1277,6 +1325,12 @@ var CanvasGraphics = (function() { setDash: function(dashArray, dashPhase) { // TODO }, + setRenderingIntent: function(intent) { + // TODO + }, + setFlatness: function(flatness) { + // TODO + }, save: function() { this.ctx.save(); this.stateStack.push(this.current); @@ -1322,6 +1376,9 @@ var CanvasGraphics = (function() { closeFillStroke: function() { return this.fillStroke(); }, + endPath: function() { + this.consumePath(); + }, // Clipping @@ -1339,10 +1396,13 @@ var CanvasGraphics = (function() { moveText: function (x, y) { this.current.lineX += x; this.current.lineY += y; - // XXX transform + // TODO transform this.current.curX = this.current.lineX; this.current.curY = this.current.lineY; }, + setTextMatrix: function(a, b, c, d, e, f) { + // TODO + }, showText: function(text) { this.ctx.save(); this.ctx.translate(0, 2 * this.current.curY); @@ -1369,6 +1429,18 @@ var CanvasGraphics = (function() { // Type3 fonts // Color + setStrokeColorSpace: function(space) { + // TODO + }, + setFillColorSpace: function(space) { + // TODO + }, + setStrokeColor: function(/*...*/) { + // TODO + }, + setFillColor: function(/*...*/) { + // TODO + }, setFillGray: function(gray) { this.setFillRGBColor(gray, gray, gray); }, @@ -1379,6 +1451,12 @@ var CanvasGraphics = (function() { this.ctx.fillStyle = this.makeCssRgb(r, g, b); }, + // XObjects + paintXObject: function(obj) { + // TODO + }, + + // Helper functions consumePath: function() { @@ -1499,6 +1577,13 @@ var tests = [ int(-72), int(0), cmd("l"), int(4), cmd("w"), cmd("h"), cmd("S"), + int(100), int(72), cmd("m"), + int(172), int(0), cmd("l"), + int(100), int(-72), cmd("l"), + int(-172), int(0), cmd("l"), + int(4), cmd("w"), + cmd("n"), + cmd("S"), eof() ] }, @@ -1579,6 +1664,21 @@ var tests = [ eof() ], }, + { name: "NYI", // check that NYI commands are no-ops + res: { }, + mediaBox: [ 0, 0, 612, 792 ], + objs: [ + name("Perceptual"), cmd("ri"), + int(2), cmd("i"), + int(1), int(0), int(0), int(1), int(80), int(80), cmd("Tm"), + name("DeviceRGB"), cmd("CS"), + name("DeviceGray"), cmd("cs"), + int(1), int(0), int(0), cmd("SC"), + int(1), cmd("sc"), + name("object"), cmd("Do"), + eof() + ], + }, ]; From e820a20b63c03244f4155cf1b49bd9df28e3e1dc Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 9 May 2011 21:05:33 -0500 Subject: [PATCH 2/5] Clipping (non-zero winding) --- pdf.js | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/pdf.js b/pdf.js index e592b3ca5..23784ac7a 100644 --- a/pdf.js +++ b/pdf.js @@ -1597,6 +1597,8 @@ var Interpreter = (function() { n: gfx.endPath, // Clipping + W: gfx.clip, + "W*": gfx.eoClip, // Text BT: gfx.beginText, @@ -1749,6 +1751,12 @@ var EchoGraphics = (function() { }, // Clipping + clip: function() { + this.printdentln("W"); + }, + eoClip: function() { + this.printdentln("W*"); + }, // Text beginText: function() { @@ -1868,10 +1876,13 @@ var CanvasGraphics = (function() { this.ctx = canvasCtx; this.current = new CanvasExtraState(); this.stateStack = [ ]; + this.pendingClip = null; } var LINE_CAP_STYLES = [ "butt", "round", "square" ]; var LINE_JOIN_STYLES = [ "miter", "round", "bevel" ]; + var NORMAL_CLIP = {}; + var EO_CLIP = {}; constructor.prototype = { beginDrawing: function(mediaBox) { @@ -1953,6 +1964,12 @@ var CanvasGraphics = (function() { }, // Clipping + clip: function() { + this.pendingClip = NORMAL_CLIP; + }, + eoClip: function() { + this.pendingClip = EO_CLIP; + }, // Text beginText: function() { @@ -2028,10 +2045,14 @@ var CanvasGraphics = (function() { // TODO }, - // Helper functions consumePath: function() { + if (this.pendingClip) { + // TODO: needs to support even-odd winding rule + this.ctx.clip(); + this.pendingClip = null; + } this.ctx.beginPath(); }, makeCssRgb: function(r, g, b) { @@ -2149,13 +2170,6 @@ var tests = [ int(-72), int(0), cmd("l"), int(4), cmd("w"), cmd("h"), cmd("S"), - int(100), int(72), cmd("m"), - int(172), int(0), cmd("l"), - int(100), int(-72), cmd("l"), - int(-172), int(0), cmd("l"), - int(4), cmd("w"), - cmd("n"), - cmd("S"), eof() ] }, @@ -2251,6 +2265,28 @@ var tests = [ eof() ], }, + { name: "Broken heart", + res: { }, + mediaBox: [ 0, 0, 612, 792 ], + objs: [ + cmd("q"), + int(20), int(20), int(60), int(60), cmd("re"), + int(60), int(60), int(60), int(60), cmd("re"), + cmd("W"), cmd("n"), + + real(0.9), real(0.0), real(0.0), cmd("rg"), + int(75), int(40), cmd("m"), + int(75), int(37), int(70), int(25), int(50), int(25), cmd("c"), + int(20), int(25), int(20), real(62.5), int(20), real(62.5), cmd("c"), + int(20), int(80), int(40), int(102), int(75), int(120), cmd("c"), + int(110), int(102), int(130), int(80), int(130), real(62.5), cmd("c"), + int(130), real(62.5), int(130), int(25), int(100), int(25), cmd("c"), + int(85), int(25), int(75), int(37), int(75), int(40), cmd("c"), + cmd("f"), + cmd("Q"), + eof() + ] + }, ]; From c1758ea66fc62e1d84a2f298da339d35c6716950 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 9 May 2011 21:08:21 -0500 Subject: [PATCH 3/5] Placeholder even-odd fill --- pdf.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pdf.js b/pdf.js index 23784ac7a..b967f177f 100644 --- a/pdf.js +++ b/pdf.js @@ -1592,6 +1592,7 @@ var Interpreter = (function() { re: gfx.rectangle, S: gfx.stroke, f: gfx.fill, + "f*": gfx.eoFill, B: gfx.fillStroke, b: gfx.closeFillStroke, n: gfx.endPath, @@ -1740,6 +1741,9 @@ var EchoGraphics = (function() { fill: function() { this.printdentln("f"); }, + eoFill: function() { + this.printdentln("f*"); + }, fillStroke: function() { this.printdentln("B"); }, @@ -1951,6 +1955,10 @@ var CanvasGraphics = (function() { this.ctx.fill(); this.consumePath(); }, + eoFill: function() { + // TODO: needs to support even-odd winding rule + this.fill(); + }, fillStroke: function() { this.ctx.fill(); this.ctx.stroke(); From 3674f38fdd1808bb5e94f65b0697e2ccc0446e20 Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 9 May 2011 21:14:09 -0500 Subject: [PATCH 4/5] shadingFill placeholder --- pdf.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pdf.js b/pdf.js index b967f177f..834dfd8e6 100644 --- a/pdf.js +++ b/pdf.js @@ -1625,6 +1625,8 @@ var Interpreter = (function() { rg: gfx.setFillRGBColor, // Shading + sh: gfx.shadingFill, + // Images // XObjects Do: gfx.paintXObject, @@ -1820,6 +1822,10 @@ var EchoGraphics = (function() { }, // Shading + shadingFill: function(entry) { + this.printdentln("/"+ entry.name +" sh"); + }, + // Images // XObjects paintXObject: function(obj) { @@ -2048,6 +2054,11 @@ var CanvasGraphics = (function() { this.ctx.fillStyle = this.makeCssRgb(r, g, b); }, + // Shading + shadingFill: function(entry) { + // TODO + }, + // XObjects paintXObject: function(obj) { // TODO @@ -2270,6 +2281,7 @@ var tests = [ int(1), int(0), int(0), cmd("SC"), int(1), cmd("sc"), name("object"), cmd("Do"), + name("shading"), cmd("sh"), eof() ], }, From 99972ad26a5f0309a04e25c84e868189564fbf6e Mon Sep 17 00:00:00 2001 From: Chris Jones Date: Mon, 9 May 2011 21:19:26 -0500 Subject: [PATCH 5/5] placeholders for scn/SCN --- pdf.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pdf.js b/pdf.js index 834dfd8e6..167de228f 100644 --- a/pdf.js +++ b/pdf.js @@ -1619,7 +1619,9 @@ var Interpreter = (function() { CS: gfx.setStrokeColorSpace, cs: gfx.setFillColorSpace, SC: gfx.setStrokeColor, + SCN: gfx.setStrokeColorN, sc: gfx.setFillColor, + scn: gfx.setFillColorN, g: gfx.setFillGray, RG: gfx.setStrokeRGBColor, rg: gfx.setFillRGBColor, @@ -1805,12 +1807,24 @@ var EchoGraphics = (function() { this.print(""+ arguments[i] +" "); this.printdentln("SC"); }, + setStrokeColorN: function(/*...*/) { + this.printdent(""); + for (var i = 0; i < arguments.length; ++i) + this.print(""+ arguments[i] +" "); + this.printdentln("SCN"); + }, setFillColor: function(/*...*/) { this.printdent(""); for (var i = 0; i < arguments.length; ++i) this.print(""+ arguments[i] +" "); this.printdentln("sc"); }, + setFillColorN: function(/*...*/) { + this.printdent(""); + for (var i = 0; i < arguments.length; ++i) + this.print(""+ arguments[i] +" "); + this.printdentln("scn"); + }, setFillGray: function(gray) { this.printdentln(""+ gray +" g"); }, @@ -2041,9 +2055,15 @@ var CanvasGraphics = (function() { setStrokeColor: function(/*...*/) { // TODO }, + setStrokeColorN: function(/*...*/) { + // TODO + }, setFillColor: function(/*...*/) { // TODO }, + setFillColorN: function(/*...*/) { + // TODO + }, setFillGray: function(gray) { this.setFillRGBColor(gray, gray, gray); }, @@ -2279,7 +2299,9 @@ var tests = [ name("DeviceRGB"), cmd("CS"), name("DeviceGray"), cmd("cs"), int(1), int(0), int(0), cmd("SC"), + int(1), int(0), int(0), cmd("SCN"), int(1), cmd("sc"), + int(1), cmd("scn"), name("object"), cmd("Do"), name("shading"), cmd("sh"), eof()