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 000000000..0c8c151da Binary files /dev/null and b/test/pdfs/shading_extend.pdf differ