2014-05-20 08:53:40 +09:00
|
|
|
/* Copyright 2012 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.
|
|
|
|
*/
|
2017-07-06 22:08:37 +09:00
|
|
|
/* globals __non_webpack_require__ */
|
2014-05-20 08:53:40 +09:00
|
|
|
|
2017-04-02 21:25:33 +09:00
|
|
|
import {
|
2018-01-06 21:10:58 +09:00
|
|
|
createObjectURL, FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageKind, isNum, OPS,
|
2018-08-29 06:42:07 +09:00
|
|
|
TextRenderingMode, Util, warn
|
2017-04-02 21:25:33 +09:00
|
|
|
} from '../shared/util';
|
2017-07-24 07:09:18 +09:00
|
|
|
import { DOMSVGFactory } from './dom_utils';
|
2018-01-06 21:10:58 +09:00
|
|
|
import isNodeJS from '../shared/is_node';
|
2017-04-02 21:25:33 +09:00
|
|
|
|
|
|
|
var SVGGraphics = function() {
|
|
|
|
throw new Error('Not implemented: SVGGraphics');
|
|
|
|
};
|
|
|
|
|
2018-01-18 02:20:00 +09:00
|
|
|
if (typeof PDFJSDev === 'undefined' || PDFJSDev.test('GENERIC')) {
|
2015-11-22 01:32:47 +09:00
|
|
|
|
2014-08-15 06:13:15 +09:00
|
|
|
var SVG_DEFAULTS = {
|
|
|
|
fontStyle: 'normal',
|
|
|
|
fontWeight: 'normal',
|
Fix inconsistent spacing and trailing commas in objects in remaining `src/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 5739f6f2..4216b2d2 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -2071,7 +2071,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var map = [];
for (var i = 0, ii = positions.length; i < ii; i += 2) {
map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height, });
+ positions[i + 1]], x: 0, y: 0, w: width, h: height, });
}
this.paintInlineImageXObjectGroup(imgData, map);
},
diff --git a/src/display/svg.js b/src/display/svg.js
index 9eb05dfa..2aa21482 100644
--- a/src/display/svg.js
+++ b/src/display/svg.js
@@ -458,7 +458,11 @@ SVGGraphics = (function SVGGraphicsClosure() {
for (var x = 0; x < fnArrayLen; x++) {
var fnId = fnArray[x];
- opList.push({ 'fnId': fnId, 'fn': REVOPS[fnId], 'args': argsArray[x], });
+ opList.push({
+ 'fnId': fnId,
+ 'fn': REVOPS[fnId],
+ 'args': argsArray[x],
+ });
}
return opListToTree(opList);
},
```
2017-06-02 18:26:37 +09:00
|
|
|
fillColor: '#000000',
|
2014-08-15 06:13:15 +09:00
|
|
|
};
|
|
|
|
|
2014-08-08 01:30:48 +09:00
|
|
|
var convertImgDataToPng = (function convertImgDataToPngClosure() {
|
2014-08-10 05:53:05 +09:00
|
|
|
var PNG_HEADER =
|
|
|
|
new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
|
|
|
|
|
|
var CHUNK_WRAPPER_SIZE = 12;
|
|
|
|
|
|
|
|
var crcTable = new Int32Array(256);
|
2014-08-08 01:30:48 +09:00
|
|
|
for (var i = 0; i < 256; i++) {
|
|
|
|
var c = i;
|
|
|
|
for (var h = 0; h < 8; h++) {
|
|
|
|
if (c & 1) {
|
|
|
|
c = 0xedB88320 ^ ((c >> 1) & 0x7fffffff);
|
|
|
|
} else {
|
|
|
|
c = (c >> 1) & 0x7fffffff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
crcTable[i] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
function crc32(data, start, end) {
|
|
|
|
var crc = -1;
|
|
|
|
for (var i = start; i < end; i++) {
|
|
|
|
var a = (crc ^ data[i]) & 0xff;
|
|
|
|
var b = crcTable[a];
|
|
|
|
crc = (crc >>> 8) ^ b;
|
|
|
|
}
|
|
|
|
return crc ^ -1;
|
|
|
|
}
|
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
function writePngChunk(type, body, data, offset) {
|
|
|
|
var p = offset;
|
|
|
|
var len = body.length;
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
data[p] = len >> 24 & 0xff;
|
|
|
|
data[p + 1] = len >> 16 & 0xff;
|
|
|
|
data[p + 2] = len >> 8 & 0xff;
|
|
|
|
data[p + 3] = len & 0xff;
|
|
|
|
p += 4;
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
data[p] = type.charCodeAt(0) & 0xff;
|
|
|
|
data[p + 1] = type.charCodeAt(1) & 0xff;
|
|
|
|
data[p + 2] = type.charCodeAt(2) & 0xff;
|
|
|
|
data[p + 3] = type.charCodeAt(3) & 0xff;
|
|
|
|
p += 4;
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
data.set(body, p);
|
|
|
|
p += body.length;
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
var crc = crc32(data, offset + 4, p);
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
data[p] = crc >> 24 & 0xff;
|
|
|
|
data[p + 1] = crc >> 16 & 0xff;
|
|
|
|
data[p + 2] = crc >> 8 & 0xff;
|
|
|
|
data[p + 3] = crc & 0xff;
|
2014-08-08 01:30:48 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
function adler32(data, start, end) {
|
|
|
|
var a = 1;
|
|
|
|
var b = 0;
|
|
|
|
for (var i = start; i < end; ++i) {
|
|
|
|
a = (a + (data[i] & 0xff)) % 65521;
|
|
|
|
b = (b + a) % 65521;
|
|
|
|
}
|
|
|
|
return (b << 16) | a;
|
|
|
|
}
|
|
|
|
|
2017-07-05 02:13:34 +09:00
|
|
|
/**
|
|
|
|
* @param {Uint8Array} literals The input data.
|
|
|
|
* @returns {Uint8Array} The DEFLATE-compressed data stream in zlib format.
|
|
|
|
* This is the required format for compressed streams in the PNG format:
|
|
|
|
* http://www.libpng.org/pub/png/spec/1.2/PNG-Compression.html
|
|
|
|
*/
|
|
|
|
function deflateSync(literals) {
|
2017-07-06 22:08:37 +09:00
|
|
|
if (!isNodeJS()) {
|
|
|
|
// zlib is certainly not available outside of Node.js. We can either use
|
|
|
|
// the pako library for client-side DEFLATE compression, or use the canvas
|
|
|
|
// API of the browser to obtain a more optimal PNG file.
|
|
|
|
return deflateSyncUncompressed(literals);
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
// NOTE: This implementation is far from perfect, but already way better
|
|
|
|
// than not applying any compression.
|
|
|
|
//
|
|
|
|
// A better algorithm will try to choose a good predictor/filter and
|
|
|
|
// then choose a suitable zlib compression strategy (e.g. 3,Z_RLE).
|
|
|
|
//
|
|
|
|
// Node v0.11.12 zlib.deflateSync is introduced (and returns a Buffer).
|
|
|
|
// Node v3.0.0 Buffer inherits from Uint8Array.
|
|
|
|
// Node v8.0.0 zlib.deflateSync accepts Uint8Array as input.
|
|
|
|
var input;
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
if (parseInt(process.versions.node) >= 8) {
|
|
|
|
input = literals;
|
|
|
|
} else {
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
input = new Buffer(literals);
|
|
|
|
}
|
|
|
|
var output = __non_webpack_require__('zlib')
|
|
|
|
.deflateSync(input, { level: 9, });
|
|
|
|
return output instanceof Uint8Array ? output : new Uint8Array(output);
|
|
|
|
} catch (e) {
|
|
|
|
warn('Not compressing PNG because zlib.deflateSync is unavailable: ' + e);
|
|
|
|
}
|
|
|
|
|
2017-07-05 02:13:34 +09:00
|
|
|
return deflateSyncUncompressed(literals);
|
|
|
|
}
|
|
|
|
|
|
|
|
// An implementation of DEFLATE with compression level 0 (Z_NO_COMPRESSION).
|
|
|
|
function deflateSyncUncompressed(literals) {
|
|
|
|
var len = literals.length;
|
|
|
|
var maxBlockLength = 0xFFFF;
|
|
|
|
|
|
|
|
var deflateBlocks = Math.ceil(len / maxBlockLength);
|
|
|
|
var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);
|
|
|
|
var pi = 0;
|
|
|
|
idat[pi++] = 0x78; // compression method and flags
|
|
|
|
idat[pi++] = 0x9c; // flags
|
|
|
|
|
|
|
|
var pos = 0;
|
|
|
|
while (len > maxBlockLength) {
|
|
|
|
// writing non-final DEFLATE blocks type 0 and length of 65535
|
|
|
|
idat[pi++] = 0x00;
|
|
|
|
idat[pi++] = 0xff;
|
|
|
|
idat[pi++] = 0xff;
|
|
|
|
idat[pi++] = 0x00;
|
|
|
|
idat[pi++] = 0x00;
|
|
|
|
idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
|
|
|
|
pi += maxBlockLength;
|
|
|
|
pos += maxBlockLength;
|
|
|
|
len -= maxBlockLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
// writing non-final DEFLATE blocks type 0
|
|
|
|
idat[pi++] = 0x01;
|
|
|
|
idat[pi++] = len & 0xff;
|
|
|
|
idat[pi++] = len >> 8 & 0xff;
|
|
|
|
idat[pi++] = (~len & 0xffff) & 0xff;
|
|
|
|
idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
|
|
|
|
idat.set(literals.subarray(pos), pi);
|
|
|
|
pi += literals.length - pos;
|
|
|
|
|
|
|
|
var adler = adler32(literals, 0, literals.length); // checksum
|
|
|
|
idat[pi++] = adler >> 24 & 0xff;
|
|
|
|
idat[pi++] = adler >> 16 & 0xff;
|
|
|
|
idat[pi++] = adler >> 8 & 0xff;
|
|
|
|
idat[pi++] = adler & 0xff;
|
|
|
|
return idat;
|
|
|
|
}
|
|
|
|
|
2017-11-29 04:24:27 +09:00
|
|
|
function encode(imgData, kind, forceDataSchema, isMask) {
|
2014-08-08 01:30:48 +09:00
|
|
|
var width = imgData.width;
|
|
|
|
var height = imgData.height;
|
2014-08-14 03:31:21 +09:00
|
|
|
var bitDepth, colorType, lineSize;
|
2014-08-08 01:30:48 +09:00
|
|
|
var bytes = imgData.data;
|
2014-08-14 03:31:21 +09:00
|
|
|
|
2014-08-08 01:30:48 +09:00
|
|
|
switch (kind) {
|
|
|
|
case ImageKind.GRAYSCALE_1BPP:
|
|
|
|
colorType = 0;
|
|
|
|
bitDepth = 1;
|
|
|
|
lineSize = (width + 7) >> 3;
|
|
|
|
break;
|
|
|
|
case ImageKind.RGB_24BPP:
|
|
|
|
colorType = 2;
|
|
|
|
bitDepth = 8;
|
|
|
|
lineSize = width * 3;
|
|
|
|
break;
|
|
|
|
case ImageKind.RGBA_32BPP:
|
|
|
|
colorType = 6;
|
|
|
|
bitDepth = 8;
|
|
|
|
lineSize = width * 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Error('invalid format');
|
|
|
|
}
|
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
// prefix every row with predictor 0
|
2014-08-08 01:30:48 +09:00
|
|
|
var literals = new Uint8Array((1 + lineSize) * height);
|
|
|
|
var offsetLiterals = 0, offsetBytes = 0;
|
2014-08-10 05:53:05 +09:00
|
|
|
var y, i;
|
|
|
|
for (y = 0; y < height; ++y) {
|
|
|
|
literals[offsetLiterals++] = 0; // no prediction
|
2014-08-08 01:30:48 +09:00
|
|
|
literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),
|
|
|
|
offsetLiterals);
|
|
|
|
offsetBytes += lineSize;
|
|
|
|
offsetLiterals += lineSize;
|
|
|
|
}
|
2014-08-10 05:53:05 +09:00
|
|
|
|
2017-11-29 04:24:27 +09:00
|
|
|
if (kind === ImageKind.GRAYSCALE_1BPP && isMask) {
|
|
|
|
// inverting for image masks
|
2014-08-10 05:53:05 +09:00
|
|
|
offsetLiterals = 0;
|
|
|
|
for (y = 0; y < height; y++) {
|
|
|
|
offsetLiterals++; // skipping predictor
|
|
|
|
for (i = 0; i < lineSize; i++) {
|
|
|
|
literals[offsetLiterals++] ^= 0xFF;
|
|
|
|
}
|
2014-08-08 01:30:48 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var ihdr = new Uint8Array([
|
|
|
|
width >> 24 & 0xff,
|
|
|
|
width >> 16 & 0xff,
|
|
|
|
width >> 8 & 0xff,
|
|
|
|
width & 0xff,
|
|
|
|
height >> 24 & 0xff,
|
|
|
|
height >> 16 & 0xff,
|
|
|
|
height >> 8 & 0xff,
|
|
|
|
height & 0xff,
|
|
|
|
bitDepth, // bit depth
|
|
|
|
colorType, // color type
|
|
|
|
0x00, // compression method
|
|
|
|
0x00, // filter method
|
|
|
|
0x00 // interlace method
|
|
|
|
]);
|
|
|
|
|
2017-07-05 02:13:34 +09:00
|
|
|
var idat = deflateSync(literals);
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2014-08-10 05:53:05 +09:00
|
|
|
// PNG will consists: header, IHDR+data, IDAT+data, and IEND.
|
2014-08-14 03:31:21 +09:00
|
|
|
var pngLength = PNG_HEADER.length + (CHUNK_WRAPPER_SIZE * 3) +
|
|
|
|
ihdr.length + idat.length;
|
2014-08-10 05:53:05 +09:00
|
|
|
var data = new Uint8Array(pngLength);
|
|
|
|
var offset = 0;
|
|
|
|
data.set(PNG_HEADER, offset);
|
|
|
|
offset += PNG_HEADER.length;
|
|
|
|
writePngChunk('IHDR', ihdr, data, offset);
|
|
|
|
offset += CHUNK_WRAPPER_SIZE + ihdr.length;
|
|
|
|
writePngChunk('IDATA', idat, data, offset);
|
|
|
|
offset += CHUNK_WRAPPER_SIZE + idat.length;
|
|
|
|
writePngChunk('IEND', new Uint8Array(0), data, offset);
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2016-03-29 04:49:22 +09:00
|
|
|
return createObjectURL(data, 'image/png', forceDataSchema);
|
2014-08-08 01:30:48 +09:00
|
|
|
}
|
|
|
|
|
2017-11-29 04:24:27 +09:00
|
|
|
return function convertImgDataToPng(imgData, forceDataSchema, isMask) {
|
2014-08-08 01:30:48 +09:00
|
|
|
var kind = (imgData.kind === undefined ?
|
2014-08-14 03:31:21 +09:00
|
|
|
ImageKind.GRAYSCALE_1BPP : imgData.kind);
|
2017-11-29 04:24:27 +09:00
|
|
|
return encode(imgData, kind, forceDataSchema, isMask);
|
2014-08-08 01:30:48 +09:00
|
|
|
};
|
|
|
|
})();
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
var SVGExtraState = (function SVGExtraStateClosure() {
|
2014-08-14 03:31:21 +09:00
|
|
|
function SVGExtraState() {
|
2014-05-20 08:53:40 +09:00
|
|
|
this.fontSizeScale = 1;
|
2014-08-15 06:13:15 +09:00
|
|
|
this.fontWeight = SVG_DEFAULTS.fontWeight;
|
2014-08-12 01:18:32 +09:00
|
|
|
this.fontSize = 0;
|
2014-07-04 01:03:31 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
this.textMatrix = IDENTITY_MATRIX;
|
|
|
|
this.fontMatrix = FONT_IDENTITY_MATRIX;
|
|
|
|
this.leading = 0;
|
2018-08-29 06:42:07 +09:00
|
|
|
this.textRenderingMode = TextRenderingMode.FILL;
|
2014-08-14 03:31:21 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
// Current point (in user coordinates)
|
|
|
|
this.x = 0;
|
|
|
|
this.y = 0;
|
2014-08-14 03:31:21 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
// Start of text line (in text coordinates)
|
|
|
|
this.lineX = 0;
|
|
|
|
this.lineY = 0;
|
2014-08-14 03:31:21 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
// Character and word spacing
|
|
|
|
this.charSpacing = 0;
|
|
|
|
this.wordSpacing = 0;
|
|
|
|
this.textHScale = 1;
|
|
|
|
this.textRise = 0;
|
2014-08-14 03:31:21 +09:00
|
|
|
|
|
|
|
// Default foreground and background colors
|
2014-08-15 06:13:15 +09:00
|
|
|
this.fillColor = SVG_DEFAULTS.fillColor;
|
2014-05-20 08:53:40 +09:00
|
|
|
this.strokeColor = '#000000';
|
|
|
|
|
|
|
|
this.fillAlpha = 1;
|
|
|
|
this.strokeAlpha = 1;
|
|
|
|
this.lineWidth = 1;
|
|
|
|
this.lineJoin = '';
|
|
|
|
this.lineCap = '';
|
|
|
|
this.miterLimit = 0;
|
2015-02-03 00:12:52 +09:00
|
|
|
|
2014-07-04 01:07:05 +09:00
|
|
|
this.dashArray = [];
|
|
|
|
this.dashPhase = 0;
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
this.dependencies = [];
|
2014-07-04 00:59:04 +09:00
|
|
|
|
|
|
|
// Clipping
|
2016-10-18 06:09:24 +09:00
|
|
|
this.activeClipUrl = null;
|
|
|
|
this.clipGroup = null;
|
2014-08-08 01:30:48 +09:00
|
|
|
|
|
|
|
this.maskId = '';
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
SVGExtraState.prototype = {
|
|
|
|
clone: function SVGExtraState_clone() {
|
|
|
|
return Object.create(this);
|
|
|
|
},
|
|
|
|
setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) {
|
|
|
|
this.x = x;
|
|
|
|
this.y = y;
|
Fix inconsistent spacing and trailing commas in objects in remaining `src/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 5739f6f2..4216b2d2 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -2071,7 +2071,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var map = [];
for (var i = 0, ii = positions.length; i < ii; i += 2) {
map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height, });
+ positions[i + 1]], x: 0, y: 0, w: width, h: height, });
}
this.paintInlineImageXObjectGroup(imgData, map);
},
diff --git a/src/display/svg.js b/src/display/svg.js
index 9eb05dfa..2aa21482 100644
--- a/src/display/svg.js
+++ b/src/display/svg.js
@@ -458,7 +458,11 @@ SVGGraphics = (function SVGGraphicsClosure() {
for (var x = 0; x < fnArrayLen; x++) {
var fnId = fnArray[x];
- opList.push({ 'fnId': fnId, 'fn': REVOPS[fnId], 'args': argsArray[x], });
+ opList.push({
+ 'fnId': fnId,
+ 'fn': REVOPS[fnId],
+ 'args': argsArray[x],
+ });
}
return opListToTree(opList);
},
```
2017-06-02 18:26:37 +09:00
|
|
|
},
|
2014-05-20 08:53:40 +09:00
|
|
|
};
|
|
|
|
return SVGExtraState;
|
|
|
|
})();
|
|
|
|
|
2017-04-02 21:25:33 +09:00
|
|
|
SVGGraphics = (function SVGGraphicsClosure() {
|
2014-08-12 01:18:32 +09:00
|
|
|
function opListToTree(opList) {
|
|
|
|
var opTree = [];
|
|
|
|
var tmp = [];
|
|
|
|
var opListLen = opList.length;
|
|
|
|
|
|
|
|
for (var x = 0; x < opListLen; x++) {
|
|
|
|
if (opList[x].fn === 'save') {
|
Fix inconsistent spacing and trailing commas in objects in remaining `src/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 5739f6f2..4216b2d2 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -2071,7 +2071,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var map = [];
for (var i = 0, ii = positions.length; i < ii; i += 2) {
map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height, });
+ positions[i + 1]], x: 0, y: 0, w: width, h: height, });
}
this.paintInlineImageXObjectGroup(imgData, map);
},
diff --git a/src/display/svg.js b/src/display/svg.js
index 9eb05dfa..2aa21482 100644
--- a/src/display/svg.js
+++ b/src/display/svg.js
@@ -458,7 +458,11 @@ SVGGraphics = (function SVGGraphicsClosure() {
for (var x = 0; x < fnArrayLen; x++) {
var fnId = fnArray[x];
- opList.push({ 'fnId': fnId, 'fn': REVOPS[fnId], 'args': argsArray[x], });
+ opList.push({
+ 'fnId': fnId,
+ 'fn': REVOPS[fnId],
+ 'args': argsArray[x],
+ });
}
return opListToTree(opList);
},
```
2017-06-02 18:26:37 +09:00
|
|
|
opTree.push({ 'fnId': 92, 'fn': 'group', 'items': [], });
|
2014-08-12 01:18:32 +09:00
|
|
|
tmp.push(opTree);
|
|
|
|
opTree = opTree[opTree.length - 1].items;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-01 23:04:21 +09:00
|
|
|
if (opList[x].fn === 'restore') {
|
2014-08-12 01:18:32 +09:00
|
|
|
opTree = tmp.pop();
|
|
|
|
} else {
|
|
|
|
opTree.push(opList[x]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return opTree;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Formats float number.
|
|
|
|
* @param value {number} number to format.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function pf(value) {
|
2017-09-03 19:50:16 +09:00
|
|
|
if (Number.isInteger(value)) {
|
2014-08-12 01:18:32 +09:00
|
|
|
return value.toString();
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
2014-08-12 01:18:32 +09:00
|
|
|
var s = value.toFixed(10);
|
|
|
|
var i = s.length - 1;
|
|
|
|
if (s[i] !== '0') {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
// removing trailing zeros
|
|
|
|
do {
|
|
|
|
i--;
|
|
|
|
} while (s[i] === '0');
|
2018-09-28 18:41:07 +09:00
|
|
|
return s.substring(0, s[i] === '.' ? i : i + 1);
|
2014-08-12 01:18:32 +09:00
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
|
2014-08-12 01:18:32 +09:00
|
|
|
/**
|
|
|
|
* Formats transform matrix. The standard rotation, scale and translate
|
|
|
|
* matrices are replaced by their shorter forms, and for identity matrix
|
|
|
|
* returns empty string to save the memory.
|
|
|
|
* @param m {Array} matrix to format.
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function pm(m) {
|
|
|
|
if (m[4] === 0 && m[5] === 0) {
|
|
|
|
if (m[1] === 0 && m[2] === 0) {
|
|
|
|
if (m[0] === 1 && m[3] === 1) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')';
|
|
|
|
}
|
|
|
|
if (m[0] === m[3] && m[1] === -m[2]) {
|
|
|
|
var a = Math.acos(m[0]) * 180 / Math.PI;
|
|
|
|
return 'rotate(' + pf(a) + ')';
|
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
} else {
|
2014-08-12 01:18:32 +09:00
|
|
|
if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) {
|
|
|
|
return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')';
|
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
2014-08-12 01:18:32 +09:00
|
|
|
return 'matrix(' + pf(m[0]) + ' ' + pf(m[1]) + ' ' + pf(m[2]) + ' ' +
|
|
|
|
pf(m[3]) + ' ' + pf(m[4]) + ' ' + pf(m[5]) + ')';
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
|
|
|
|
2016-03-29 04:49:22 +09:00
|
|
|
function SVGGraphics(commonObjs, objs, forceDataSchema) {
|
2017-07-24 07:09:18 +09:00
|
|
|
this.svgFactory = new DOMSVGFactory();
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
this.current = new SVGExtraState();
|
|
|
|
this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
|
|
|
|
this.transformStack = [];
|
|
|
|
this.extraStack = [];
|
|
|
|
this.commonObjs = commonObjs;
|
2014-06-25 05:24:00 +09:00
|
|
|
this.objs = objs;
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
this.pendingClip = null;
|
2014-05-20 08:53:40 +09:00
|
|
|
this.pendingEOFill = false;
|
2014-08-15 05:11:27 +09:00
|
|
|
|
|
|
|
this.embedFonts = false;
|
2016-01-28 02:04:13 +09:00
|
|
|
this.embeddedFonts = Object.create(null);
|
2014-08-15 05:11:27 +09:00
|
|
|
this.cssStyle = null;
|
2016-03-29 04:49:22 +09:00
|
|
|
this.forceDataSchema = !!forceDataSchema;
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
var XML_NS = 'http://www.w3.org/XML/1998/namespace';
|
2014-06-25 05:24:00 +09:00
|
|
|
var XLINK_NS = 'http://www.w3.org/1999/xlink';
|
2014-05-20 08:53:40 +09:00
|
|
|
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
|
|
|
|
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
|
2014-07-04 00:59:04 +09:00
|
|
|
var clipCount = 0;
|
2014-08-08 01:30:48 +09:00
|
|
|
var maskCount = 0;
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
SVGGraphics.prototype = {
|
|
|
|
save: function SVGGraphics_save() {
|
|
|
|
this.transformStack.push(this.transformMatrix);
|
|
|
|
var old = this.current;
|
|
|
|
this.extraStack.push(old);
|
|
|
|
this.current = old.clone();
|
|
|
|
},
|
|
|
|
|
|
|
|
restore: function SVGGraphics_restore() {
|
|
|
|
this.transformMatrix = this.transformStack.pop();
|
|
|
|
this.current = this.extraStack.pop();
|
2014-06-20 13:18:04 +09:00
|
|
|
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
this.pendingClip = null;
|
2016-10-13 04:22:35 +09:00
|
|
|
this.tgrp = null;
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
group: function SVGGraphics_group(items) {
|
|
|
|
this.save();
|
|
|
|
this.executeOpTree(items);
|
|
|
|
this.restore();
|
|
|
|
},
|
|
|
|
|
|
|
|
loadDependencies: function SVGGraphics_loadDependencies(operatorList) {
|
|
|
|
var fnArray = operatorList.fnArray;
|
|
|
|
var fnArrayLen = fnArray.length;
|
|
|
|
var argsArray = operatorList.argsArray;
|
|
|
|
|
|
|
|
for (var i = 0; i < fnArrayLen; i++) {
|
2014-08-01 19:41:03 +09:00
|
|
|
if (OPS.dependency === fnArray[i]) {
|
2014-05-20 08:53:40 +09:00
|
|
|
var deps = argsArray[i];
|
|
|
|
for (var n = 0, nn = deps.length; n < nn; n++) {
|
|
|
|
var obj = deps[n];
|
|
|
|
var common = obj.substring(0, 2) === 'g_';
|
2014-06-25 05:24:00 +09:00
|
|
|
var promise;
|
2014-05-20 08:53:40 +09:00
|
|
|
if (common) {
|
2017-05-03 23:39:54 +09:00
|
|
|
promise = new Promise((resolve) => {
|
|
|
|
this.commonObjs.get(obj, resolve);
|
2014-05-20 08:53:40 +09:00
|
|
|
});
|
2014-06-25 05:24:00 +09:00
|
|
|
} else {
|
2017-05-03 23:39:54 +09:00
|
|
|
promise = new Promise((resolve) => {
|
|
|
|
this.objs.get(obj, resolve);
|
2014-06-25 05:24:00 +09:00
|
|
|
});
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
|
|
|
this.current.dependencies.push(promise);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Promise.all(this.current.dependencies);
|
|
|
|
},
|
|
|
|
|
|
|
|
transform: function SVGGraphics_transform(a, b, c, d, e, f) {
|
|
|
|
var transformMatrix = [a, b, c, d, e, f];
|
2016-03-29 04:49:22 +09:00
|
|
|
this.transformMatrix = Util.transform(this.transformMatrix,
|
|
|
|
transformMatrix);
|
2016-10-13 04:22:35 +09:00
|
|
|
this.tgrp = null;
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
2014-08-15 02:56:11 +09:00
|
|
|
getSVG: function SVGGraphics_getSVG(operatorList, viewport) {
|
2014-05-20 08:53:40 +09:00
|
|
|
this.viewport = viewport;
|
2014-08-15 02:56:11 +09:00
|
|
|
|
2016-10-16 04:05:57 +09:00
|
|
|
var svgElement = this._initialize(viewport);
|
2017-05-03 23:39:54 +09:00
|
|
|
return this.loadDependencies(operatorList).then(() => {
|
2014-08-15 02:56:11 +09:00
|
|
|
this.transformMatrix = IDENTITY_MATRIX;
|
|
|
|
var opTree = this.convertOpList(operatorList);
|
|
|
|
this.executeOpTree(opTree);
|
2016-10-16 04:05:57 +09:00
|
|
|
return svgElement;
|
2017-05-03 23:39:54 +09:00
|
|
|
});
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
convertOpList: function SVGGraphics_convertOpList(operatorList) {
|
|
|
|
var argsArray = operatorList.argsArray;
|
|
|
|
var fnArray = operatorList.fnArray;
|
Switch to using ESLint, instead of JSHint, for linting
*Please note that most of the necessary code adjustments were made in PR 7890.*
ESLint has a number of advantageous properties, compared to JSHint. Among those are:
- The ability to find subtle bugs, thanks to more rules (e.g. PR 7881).
- Much more customizable in general, and many rules allow fine-tuned behaviour rather than the just the on/off rules in JSHint.
- Many more rules that can help developers avoid bugs, and a lot of rules that can be used to enforce a consistent coding style. The latter should be particularily useful for new contributors (and reduce the amount of stylistic review comments necessary).
- The ability to easily specify exactly what rules to use/not to use, as opposed to JSHint which has a default set. *Note:* in future JSHint version some of the rules we depend on will be removed, according to warnings in http://jshint.com/docs/options/, so we wouldn't be able to update without losing lint coverage.
- More easily disable one, or more, rules temporarily. In JSHint this requires using a numeric code, which isn't very user friendly, whereas in ESLint the rule name is simply used instead.
By default there's no rules enabled in ESLint, but there are some default rule sets available. However, to prevent linting failures if we update ESLint in the future, it seemed easier to just explicitly specify what rules we want.
Obviously this makes the ESLint config file somewhat bigger than the old JSHint config file, but given how rarely that one has been updated over the years I don't think that matters too much.
I've tried, to the best of my ability, to ensure that we enable the same rules for ESLint that we had for JSHint. Furthermore, I've also enabled a number of rules that seemed to make sense, both to catch possible errors *and* various style guide violations.
Despite the ESLint README claiming that it's slower that JSHint, https://github.com/eslint/eslint#how-does-eslint-performance-compare-to-jshint, locally this patch actually reduces the runtime for `gulp` lint (by approximately 20-25%).
A couple of stylistic rules that would have been nice to enable, but where our code currently differs to much to make it feasible:
- `comma-dangle`, controls trailing commas in Objects and Arrays (among others).
- `object-curly-spacing`, controls spacing inside of Objects.
- `spaced-comment`, used to enforce spaces after `//` and `/*. (This is made difficult by the fact that there's still some usage of the old preprocessor left.)
Rules that I indend to look into possibly enabling in follow-ups, if it seems to make sense: `no-else-return`, `no-lonely-if`, `brace-style` with the `allowSingleLine` parameter removed.
Useful links:
- http://eslint.org/docs/user-guide/configuring
- http://eslint.org/docs/rules/
2016-12-15 23:52:29 +09:00
|
|
|
var fnArrayLen = fnArray.length;
|
2014-05-20 08:53:40 +09:00
|
|
|
var REVOPS = [];
|
2014-08-14 03:31:21 +09:00
|
|
|
var opList = [];
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
for (var op in OPS) {
|
|
|
|
REVOPS[OPS[op]] = op;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var x = 0; x < fnArrayLen; x++) {
|
|
|
|
var fnId = fnArray[x];
|
Fix inconsistent spacing and trailing commas in objects in remaining `src/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 5739f6f2..4216b2d2 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -2071,7 +2071,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var map = [];
for (var i = 0, ii = positions.length; i < ii; i += 2) {
map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height, });
+ positions[i + 1]], x: 0, y: 0, w: width, h: height, });
}
this.paintInlineImageXObjectGroup(imgData, map);
},
diff --git a/src/display/svg.js b/src/display/svg.js
index 9eb05dfa..2aa21482 100644
--- a/src/display/svg.js
+++ b/src/display/svg.js
@@ -458,7 +458,11 @@ SVGGraphics = (function SVGGraphicsClosure() {
for (var x = 0; x < fnArrayLen; x++) {
var fnId = fnArray[x];
- opList.push({ 'fnId': fnId, 'fn': REVOPS[fnId], 'args': argsArray[x], });
+ opList.push({
+ 'fnId': fnId,
+ 'fn': REVOPS[fnId],
+ 'args': argsArray[x],
+ });
}
return opListToTree(opList);
},
```
2017-06-02 18:26:37 +09:00
|
|
|
opList.push({
|
|
|
|
'fnId': fnId,
|
|
|
|
'fn': REVOPS[fnId],
|
|
|
|
'args': argsArray[x],
|
|
|
|
});
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
2014-08-14 03:31:21 +09:00
|
|
|
return opListToTree(opList);
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
2015-02-03 00:12:52 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
executeOpTree: function SVGGraphics_executeOpTree(opTree) {
|
|
|
|
var opTreeLen = opTree.length;
|
2016-11-01 23:04:21 +09:00
|
|
|
for (var x = 0; x < opTreeLen; x++) {
|
2014-05-20 08:53:40 +09:00
|
|
|
var fn = opTree[x].fn;
|
|
|
|
var fnId = opTree[x].fnId;
|
|
|
|
var args = opTree[x].args;
|
|
|
|
|
|
|
|
switch (fnId | 0) {
|
|
|
|
case OPS.beginText:
|
2014-08-14 03:31:21 +09:00
|
|
|
this.beginText();
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
2018-04-02 21:29:34 +09:00
|
|
|
case OPS.dependency:
|
|
|
|
// Handled in loadDependencies, warning should not be thrown
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.setLeading:
|
|
|
|
this.setLeading(args);
|
|
|
|
break;
|
|
|
|
case OPS.setLeadingMoveText:
|
|
|
|
this.setLeadingMoveText(args[0], args[1]);
|
|
|
|
break;
|
|
|
|
case OPS.setFont:
|
|
|
|
this.setFont(args);
|
|
|
|
break;
|
|
|
|
case OPS.showText:
|
|
|
|
this.showText(args[0]);
|
|
|
|
break;
|
|
|
|
case OPS.showSpacedText:
|
|
|
|
this.showText(args[0]);
|
|
|
|
break;
|
|
|
|
case OPS.endText:
|
2014-07-25 21:29:10 +09:00
|
|
|
this.endText();
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.moveText:
|
|
|
|
this.moveText(args[0], args[1]);
|
|
|
|
break;
|
|
|
|
case OPS.setCharSpacing:
|
|
|
|
this.setCharSpacing(args[0]);
|
|
|
|
break;
|
|
|
|
case OPS.setWordSpacing:
|
|
|
|
this.setWordSpacing(args[0]);
|
|
|
|
break;
|
2015-03-16 08:37:31 +09:00
|
|
|
case OPS.setHScale:
|
|
|
|
this.setHScale(args[0]);
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.setTextMatrix:
|
|
|
|
this.setTextMatrix(args[0], args[1], args[2],
|
2014-08-14 03:31:21 +09:00
|
|
|
args[3], args[4], args[5]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
2017-08-20 00:21:08 +09:00
|
|
|
case OPS.setTextRise:
|
|
|
|
this.setTextRise(args[0]);
|
|
|
|
break;
|
2018-08-29 06:42:07 +09:00
|
|
|
case OPS.setTextRenderingMode:
|
|
|
|
this.setTextRenderingMode(args[0]);
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.setLineWidth:
|
2014-08-12 01:18:32 +09:00
|
|
|
this.setLineWidth(args[0]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.setLineJoin:
|
2014-08-12 01:18:32 +09:00
|
|
|
this.setLineJoin(args[0]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.setLineCap:
|
2014-08-12 01:18:32 +09:00
|
|
|
this.setLineCap(args[0]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.setMiterLimit:
|
2014-08-12 01:18:32 +09:00
|
|
|
this.setMiterLimit(args[0]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.setFillRGBColor:
|
|
|
|
this.setFillRGBColor(args[0], args[1], args[2]);
|
|
|
|
break;
|
|
|
|
case OPS.setStrokeRGBColor:
|
|
|
|
this.setStrokeRGBColor(args[0], args[1], args[2]);
|
|
|
|
break;
|
|
|
|
case OPS.setDash:
|
|
|
|
this.setDash(args[0], args[1]);
|
|
|
|
break;
|
|
|
|
case OPS.setGState:
|
2014-07-05 17:48:11 +09:00
|
|
|
this.setGState(args[0]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.fill:
|
|
|
|
this.fill();
|
|
|
|
break;
|
|
|
|
case OPS.eoFill:
|
|
|
|
this.eoFill();
|
|
|
|
break;
|
|
|
|
case OPS.stroke:
|
|
|
|
this.stroke();
|
|
|
|
break;
|
|
|
|
case OPS.fillStroke:
|
|
|
|
this.fillStroke();
|
|
|
|
break;
|
2014-07-04 01:03:31 +09:00
|
|
|
case OPS.eoFillStroke:
|
|
|
|
this.eoFillStroke();
|
|
|
|
break;
|
2014-07-04 00:59:04 +09:00
|
|
|
case OPS.clip:
|
|
|
|
this.clip('nonzero');
|
|
|
|
break;
|
|
|
|
case OPS.eoClip:
|
|
|
|
this.clip('evenodd');
|
|
|
|
break;
|
2014-06-25 05:16:50 +09:00
|
|
|
case OPS.paintSolidColorImageMask:
|
|
|
|
this.paintSolidColorImageMask();
|
|
|
|
break;
|
2014-06-25 05:24:00 +09:00
|
|
|
case OPS.paintJpegXObject:
|
|
|
|
this.paintJpegXObject(args[0], args[1], args[2]);
|
|
|
|
break;
|
2014-08-08 01:30:48 +09:00
|
|
|
case OPS.paintImageXObject:
|
|
|
|
this.paintImageXObject(args[0]);
|
|
|
|
break;
|
|
|
|
case OPS.paintInlineImageXObject:
|
|
|
|
this.paintInlineImageXObject(args[0]);
|
|
|
|
break;
|
|
|
|
case OPS.paintImageMaskXObject:
|
|
|
|
this.paintImageMaskXObject(args[0]);
|
|
|
|
break;
|
2014-08-15 05:54:38 +09:00
|
|
|
case OPS.paintFormXObjectBegin:
|
|
|
|
this.paintFormXObjectBegin(args[0], args[1]);
|
|
|
|
break;
|
|
|
|
case OPS.paintFormXObjectEnd:
|
|
|
|
this.paintFormXObjectEnd();
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.closePath:
|
|
|
|
this.closePath();
|
|
|
|
break;
|
|
|
|
case OPS.closeStroke:
|
|
|
|
this.closeStroke();
|
|
|
|
break;
|
|
|
|
case OPS.closeFillStroke:
|
|
|
|
this.closeFillStroke();
|
|
|
|
break;
|
2018-01-10 02:42:12 +09:00
|
|
|
case OPS.closeEOFillStroke:
|
|
|
|
this.closeEOFillStroke();
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.nextLine:
|
|
|
|
this.nextLine();
|
|
|
|
break;
|
|
|
|
case OPS.transform:
|
|
|
|
this.transform(args[0], args[1], args[2], args[3],
|
2014-08-14 03:31:21 +09:00
|
|
|
args[4], args[5]);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.constructPath:
|
|
|
|
this.constructPath(args[0], args[1]);
|
|
|
|
break;
|
2014-07-25 21:29:10 +09:00
|
|
|
case OPS.endPath:
|
|
|
|
this.endPath();
|
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case 92:
|
|
|
|
this.group(opTree[x].items);
|
|
|
|
break;
|
|
|
|
default:
|
2016-10-13 04:22:35 +09:00
|
|
|
warn('Unimplemented operator ' + fn);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) {
|
|
|
|
this.current.wordSpacing = wordSpacing;
|
|
|
|
},
|
|
|
|
|
|
|
|
setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) {
|
|
|
|
this.current.charSpacing = charSpacing;
|
|
|
|
},
|
|
|
|
|
|
|
|
nextLine: function SVGGraphics_nextLine() {
|
|
|
|
this.moveText(0, this.current.leading);
|
|
|
|
},
|
|
|
|
|
|
|
|
setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) {
|
|
|
|
var current = this.current;
|
2014-08-14 03:31:21 +09:00
|
|
|
this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f];
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
this.current.x = this.current.lineX = 0;
|
|
|
|
this.current.y = this.current.lineY = 0;
|
|
|
|
|
|
|
|
current.xcoords = [];
|
2017-07-24 07:09:18 +09:00
|
|
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
2014-05-20 08:53:40 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
2014-08-12 01:18:32 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-size',
|
|
|
|
pf(current.fontSize) + 'px');
|
|
|
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
2014-05-20 08:53:40 +09:00
|
|
|
|
2017-07-24 07:09:18 +09:00
|
|
|
current.txtElement = this.svgFactory.createElement('svg:text');
|
2014-05-20 08:53:40 +09:00
|
|
|
current.txtElement.appendChild(current.tspan);
|
|
|
|
},
|
|
|
|
|
2014-08-14 03:31:21 +09:00
|
|
|
beginText: function SVGGraphics_beginText() {
|
2014-05-20 08:53:40 +09:00
|
|
|
this.current.x = this.current.lineX = 0;
|
|
|
|
this.current.y = this.current.lineY = 0;
|
|
|
|
this.current.textMatrix = IDENTITY_MATRIX;
|
|
|
|
this.current.lineMatrix = IDENTITY_MATRIX;
|
2017-07-24 07:09:18 +09:00
|
|
|
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
|
|
|
this.current.txtElement = this.svgFactory.createElement('svg:text');
|
|
|
|
this.current.txtgrp = this.svgFactory.createElement('svg:g');
|
2014-05-20 08:53:40 +09:00
|
|
|
this.current.xcoords = [];
|
|
|
|
},
|
|
|
|
|
|
|
|
moveText: function SVGGraphics_moveText(x, y) {
|
|
|
|
var current = this.current;
|
|
|
|
this.current.x = this.current.lineX += x;
|
|
|
|
this.current.y = this.current.lineY += y;
|
|
|
|
|
|
|
|
current.xcoords = [];
|
2017-07-24 07:09:18 +09:00
|
|
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
2014-05-20 08:53:40 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
2014-08-12 01:18:32 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-size',
|
|
|
|
pf(current.fontSize) + 'px');
|
|
|
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
showText: function SVGGraphics_showText(glyphs) {
|
|
|
|
var current = this.current;
|
|
|
|
var font = current.font;
|
|
|
|
var fontSize = current.fontSize;
|
|
|
|
|
|
|
|
if (fontSize === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var charSpacing = current.charSpacing;
|
|
|
|
var wordSpacing = current.wordSpacing;
|
|
|
|
var fontDirection = current.fontDirection;
|
|
|
|
var textHScale = current.textHScale * fontDirection;
|
|
|
|
var glyphsLength = glyphs.length;
|
|
|
|
var vertical = font.vertical;
|
|
|
|
var widthAdvanceScale = fontSize * current.fontMatrix[0];
|
|
|
|
|
|
|
|
var x = 0, i;
|
|
|
|
for (i = 0; i < glyphsLength; ++i) {
|
|
|
|
var glyph = glyphs[i];
|
|
|
|
if (glyph === null) {
|
|
|
|
// word break
|
|
|
|
x += fontDirection * wordSpacing;
|
|
|
|
continue;
|
|
|
|
} else if (isNum(glyph)) {
|
|
|
|
x += -glyph * fontSize * 0.001;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
var width = glyph.width;
|
|
|
|
var character = glyph.fontChar;
|
2017-04-27 19:31:06 +09:00
|
|
|
var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
|
|
|
var charWidth = width * widthAdvanceScale + spacing * fontDirection;
|
2014-05-20 08:53:40 +09:00
|
|
|
|
2017-08-17 06:35:39 +09:00
|
|
|
if (!glyph.isInFont && !font.missingFile) {
|
|
|
|
x += charWidth;
|
|
|
|
// TODO: To assist with text selection, we should replace the missing
|
|
|
|
// character with a space character if charWidth is not zero.
|
|
|
|
// But we cannot just do "character = ' '", because the ' ' character
|
|
|
|
// might actually map to a different glyph.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
current.xcoords.push(current.x + x * textHScale);
|
2014-05-20 08:53:40 +09:00
|
|
|
current.tspan.textContent += character;
|
2017-08-17 06:35:39 +09:00
|
|
|
x += charWidth;
|
2014-05-20 08:53:40 +09:00
|
|
|
}
|
|
|
|
if (vertical) {
|
|
|
|
current.y -= x * textHScale;
|
|
|
|
} else {
|
|
|
|
current.x += x * textHScale;
|
|
|
|
}
|
|
|
|
|
2014-08-12 01:18:32 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'x',
|
|
|
|
current.xcoords.map(pf).join(' '));
|
|
|
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
2014-05-20 08:53:40 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
|
2014-08-12 01:18:32 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'font-size',
|
|
|
|
pf(current.fontSize) + 'px');
|
2014-08-15 06:13:15 +09:00
|
|
|
if (current.fontStyle !== SVG_DEFAULTS.fontStyle) {
|
|
|
|
current.tspan.setAttributeNS(null, 'font-style', current.fontStyle);
|
|
|
|
}
|
|
|
|
if (current.fontWeight !== SVG_DEFAULTS.fontWeight) {
|
|
|
|
current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight);
|
|
|
|
}
|
2018-08-29 06:42:07 +09:00
|
|
|
|
|
|
|
const fillStrokeMode = current.textRenderingMode &
|
|
|
|
TextRenderingMode.FILL_STROKE_MASK;
|
|
|
|
|
|
|
|
if (fillStrokeMode === TextRenderingMode.FILL ||
|
|
|
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
|
|
|
if (current.fillColor !== SVG_DEFAULTS.fillColor) {
|
|
|
|
current.tspan.setAttributeNS(null, 'fill', current.fillColor);
|
|
|
|
}
|
|
|
|
if (current.fillAlpha < 1) {
|
|
|
|
current.tspan.setAttributeNS(null, 'fill-opacity', current.fillAlpha);
|
|
|
|
}
|
|
|
|
} else if (current.textRenderingMode === TextRenderingMode.ADD_TO_PATH) {
|
|
|
|
// Workaround for Firefox: We must set fill="transparent" because
|
|
|
|
// fill="none" would generate an empty clipping path.
|
|
|
|
current.tspan.setAttributeNS(null, 'fill', 'transparent');
|
|
|
|
} else {
|
|
|
|
current.tspan.setAttributeNS(null, 'fill', 'none');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fillStrokeMode === TextRenderingMode.STROKE ||
|
|
|
|
fillStrokeMode === TextRenderingMode.FILL_STROKE) {
|
|
|
|
this._setStrokeAttributes(current.tspan);
|
2014-08-15 06:13:15 +09:00
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
|
2017-08-20 00:21:08 +09:00
|
|
|
// Include the text rise in the text matrix since the `pm` function
|
|
|
|
// creates the SVG element's `translate` entry (work on a copy to avoid
|
|
|
|
// altering the original text matrix).
|
|
|
|
let textMatrix = current.textMatrix;
|
|
|
|
if (current.textRise !== 0) {
|
|
|
|
textMatrix = textMatrix.slice();
|
|
|
|
textMatrix[5] += current.textRise;
|
|
|
|
}
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
current.txtElement.setAttributeNS(null, 'transform',
|
2017-08-20 00:21:08 +09:00
|
|
|
pm(textMatrix) + ' scale(1, -1)');
|
2014-05-20 08:53:40 +09:00
|
|
|
current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve');
|
|
|
|
current.txtElement.appendChild(current.tspan);
|
|
|
|
current.txtgrp.appendChild(current.txtElement);
|
|
|
|
|
2016-10-13 04:22:35 +09:00
|
|
|
this._ensureTransformGroup().appendChild(current.txtElement);
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
2014-07-25 21:29:10 +09:00
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) {
|
|
|
|
this.setLeading(-y);
|
|
|
|
this.moveText(x, y);
|
|
|
|
},
|
|
|
|
|
2014-08-15 05:11:27 +09:00
|
|
|
addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
|
|
|
|
if (!this.cssStyle) {
|
2017-07-24 07:09:18 +09:00
|
|
|
this.cssStyle = this.svgFactory.createElement('svg:style');
|
2014-08-15 05:11:27 +09:00
|
|
|
this.cssStyle.setAttributeNS(null, 'type', 'text/css');
|
|
|
|
this.defs.appendChild(this.cssStyle);
|
|
|
|
}
|
|
|
|
|
2016-03-29 04:49:22 +09:00
|
|
|
var url = createObjectURL(fontObj.data, fontObj.mimetype,
|
|
|
|
this.forceDataSchema);
|
2014-08-15 05:11:27 +09:00
|
|
|
this.cssStyle.textContent +=
|
|
|
|
'@font-face { font-family: "' + fontObj.loadedName + '";' +
|
|
|
|
' src: url(' + url + '); }\n';
|
|
|
|
},
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
setFont: function SVGGraphics_setFont(details) {
|
|
|
|
var current = this.current;
|
|
|
|
var fontObj = this.commonObjs.get(details[0]);
|
|
|
|
var size = details[1];
|
|
|
|
this.current.font = fontObj;
|
|
|
|
|
2014-08-15 05:11:27 +09:00
|
|
|
if (this.embedFonts && fontObj.data &&
|
|
|
|
!this.embeddedFonts[fontObj.loadedName]) {
|
|
|
|
this.addFontStyle(fontObj);
|
|
|
|
this.embeddedFonts[fontObj.loadedName] = fontObj;
|
|
|
|
}
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
current.fontMatrix = (fontObj.fontMatrix ?
|
2014-08-14 03:31:21 +09:00
|
|
|
fontObj.fontMatrix : FONT_IDENTITY_MATRIX);
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
|
|
|
|
(fontObj.bold ? 'bold' : 'normal');
|
|
|
|
var italic = fontObj.italic ? 'italic' : 'normal';
|
|
|
|
|
|
|
|
if (size < 0) {
|
|
|
|
size = -size;
|
|
|
|
current.fontDirection = -1;
|
|
|
|
} else {
|
|
|
|
current.fontDirection = 1;
|
|
|
|
}
|
|
|
|
current.fontSize = size;
|
|
|
|
current.fontFamily = fontObj.loadedName;
|
2014-07-04 01:03:31 +09:00
|
|
|
current.fontWeight = bold;
|
|
|
|
current.fontStyle = italic;
|
|
|
|
|
2017-07-24 07:09:18 +09:00
|
|
|
current.tspan = this.svgFactory.createElement('svg:tspan');
|
2014-08-12 01:18:32 +09:00
|
|
|
current.tspan.setAttributeNS(null, 'y', pf(-current.y));
|
2014-07-04 01:03:31 +09:00
|
|
|
current.xcoords = [];
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
2018-08-29 06:42:07 +09:00
|
|
|
endText() {
|
|
|
|
const current = this.current;
|
|
|
|
if ((current.textRenderingMode & TextRenderingMode.ADD_TO_PATH_FLAG) &&
|
|
|
|
current.txtElement && current.txtElement.hasChildNodes()) {
|
|
|
|
// If no glyphs are shown (i.e. no child nodes), no clipping occurs.
|
|
|
|
current.element = current.txtElement;
|
|
|
|
this.clip('nonzero');
|
|
|
|
this.endPath();
|
|
|
|
}
|
|
|
|
},
|
2014-05-20 08:53:40 +09:00
|
|
|
|
|
|
|
// Path properties
|
|
|
|
setLineWidth: function SVGGraphics_setLineWidth(width) {
|
|
|
|
this.current.lineWidth = width;
|
|
|
|
},
|
|
|
|
setLineCap: function SVGGraphics_setLineCap(style) {
|
|
|
|
this.current.lineCap = LINE_CAP_STYLES[style];
|
|
|
|
},
|
|
|
|
setLineJoin: function SVGGraphics_setLineJoin(style) {
|
|
|
|
this.current.lineJoin = LINE_JOIN_STYLES[style];
|
|
|
|
},
|
|
|
|
setMiterLimit: function SVGGraphics_setMiterLimit(limit) {
|
|
|
|
this.current.miterLimit = limit;
|
|
|
|
},
|
2017-06-23 07:24:47 +09:00
|
|
|
setStrokeAlpha: function SVGGraphics_setStrokeAlpha(strokeAlpha) {
|
|
|
|
this.current.strokeAlpha = strokeAlpha;
|
|
|
|
},
|
2014-05-20 08:53:40 +09:00
|
|
|
setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) {
|
2014-10-28 05:30:47 +09:00
|
|
|
var color = Util.makeCssRgb(r, g, b);
|
2014-05-20 08:53:40 +09:00
|
|
|
this.current.strokeColor = color;
|
|
|
|
},
|
2017-06-23 07:19:20 +09:00
|
|
|
setFillAlpha: function SVGGraphics_setFillAlpha(fillAlpha) {
|
|
|
|
this.current.fillAlpha = fillAlpha;
|
|
|
|
},
|
2014-05-20 08:53:40 +09:00
|
|
|
setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
|
2014-10-28 05:30:47 +09:00
|
|
|
var color = Util.makeCssRgb(r, g, b);
|
2014-05-20 08:53:40 +09:00
|
|
|
this.current.fillColor = color;
|
2017-07-24 07:09:18 +09:00
|
|
|
this.current.tspan = this.svgFactory.createElement('svg:tspan');
|
2014-07-04 01:03:31 +09:00
|
|
|
this.current.xcoords = [];
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
|
|
|
|
this.current.dashArray = dashArray;
|
|
|
|
this.current.dashPhase = dashPhase;
|
|
|
|
},
|
|
|
|
|
|
|
|
constructPath: function SVGGraphics_constructPath(ops, args) {
|
|
|
|
var current = this.current;
|
|
|
|
var x = current.x, y = current.y;
|
2017-07-24 07:09:18 +09:00
|
|
|
current.path = this.svgFactory.createElement('svg:path');
|
2014-06-25 04:23:18 +09:00
|
|
|
var d = [];
|
2014-05-20 08:53:40 +09:00
|
|
|
var opLength = ops.length;
|
|
|
|
|
|
|
|
for (var i = 0, j = 0; i < opLength; i++) {
|
|
|
|
switch (ops[i] | 0) {
|
2014-06-24 05:07:31 +09:00
|
|
|
case OPS.rectangle:
|
|
|
|
x = args[j++];
|
|
|
|
y = args[j++];
|
|
|
|
var width = args[j++];
|
|
|
|
var height = args[j++];
|
|
|
|
var xw = x + width;
|
|
|
|
var yh = y + height;
|
2016-12-11 03:58:36 +09:00
|
|
|
d.push('M', pf(x), pf(y), 'L', pf(xw), pf(y), 'L', pf(xw), pf(yh),
|
2014-08-12 01:18:32 +09:00
|
|
|
'L', pf(x), pf(yh), 'Z');
|
2014-06-24 05:07:31 +09:00
|
|
|
break;
|
2014-05-20 08:53:40 +09:00
|
|
|
case OPS.moveTo:
|
|
|
|
x = args[j++];
|
|
|
|
y = args[j++];
|
2014-08-12 01:18:32 +09:00
|
|
|
d.push('M', pf(x), pf(y));
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.lineTo:
|
|
|
|
x = args[j++];
|
|
|
|
y = args[j++];
|
2016-12-11 03:58:36 +09:00
|
|
|
d.push('L', pf(x), pf(y));
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
case OPS.curveTo:
|
|
|
|
x = args[j + 4];
|
|
|
|
y = args[j + 5];
|
2014-08-12 01:18:32 +09:00
|
|
|
d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]),
|
|
|
|
pf(args[j + 3]), pf(x), pf(y));
|
2014-05-20 08:53:40 +09:00
|
|
|
j += 6;
|
|
|
|
break;
|
|
|
|
case OPS.curveTo2:
|
|
|
|
x = args[j + 2];
|
|
|
|
y = args[j + 3];
|
2014-08-12 01:18:32 +09:00
|
|
|
d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]),
|
|
|
|
pf(args[j + 2]), pf(args[j + 3]));
|
2014-05-20 08:53:40 +09:00
|
|
|
j += 4;
|
|
|
|
break;
|
|
|
|
case OPS.curveTo3:
|
|
|
|
x = args[j + 2];
|
|
|
|
y = args[j + 3];
|
2014-08-12 01:18:32 +09:00
|
|
|
d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y),
|
|
|
|
pf(x), pf(y));
|
2014-05-20 08:53:40 +09:00
|
|
|
j += 4;
|
|
|
|
break;
|
|
|
|
case OPS.closePath:
|
2014-06-25 04:23:18 +09:00
|
|
|
d.push('Z');
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-25 04:23:18 +09:00
|
|
|
current.path.setAttributeNS(null, 'd', d.join(' '));
|
2014-07-25 21:29:10 +09:00
|
|
|
current.path.setAttributeNS(null, 'fill', 'none');
|
|
|
|
|
2016-10-13 04:22:35 +09:00
|
|
|
this._ensureTransformGroup().appendChild(current.path);
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
// Saving a reference in current.element so that it can be addressed
|
|
|
|
// in 'fill' and 'stroke'
|
|
|
|
current.element = current.path;
|
|
|
|
current.setCurrentPoint(x, y);
|
|
|
|
},
|
|
|
|
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
endPath: function SVGGraphics_endPath() {
|
|
|
|
if (!this.pendingClip) {
|
|
|
|
return;
|
|
|
|
}
|
2014-07-04 00:59:04 +09:00
|
|
|
var current = this.current;
|
|
|
|
// Add current path to clipping path
|
2016-10-18 06:09:24 +09:00
|
|
|
var clipId = 'clippath' + clipCount;
|
2014-07-04 00:59:04 +09:00
|
|
|
clipCount++;
|
2017-07-24 07:09:18 +09:00
|
|
|
var clipPath = this.svgFactory.createElement('svg:clipPath');
|
2016-10-18 06:09:24 +09:00
|
|
|
clipPath.setAttributeNS(null, 'id', clipId);
|
|
|
|
clipPath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
2018-08-29 06:42:07 +09:00
|
|
|
// A deep clone is needed when text is used as a clipping path.
|
|
|
|
const clipElement = current.element.cloneNode(true);
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
if (this.pendingClip === 'evenodd') {
|
2014-07-04 00:59:04 +09:00
|
|
|
clipElement.setAttributeNS(null, 'clip-rule', 'evenodd');
|
|
|
|
} else {
|
|
|
|
clipElement.setAttributeNS(null, 'clip-rule', 'nonzero');
|
|
|
|
}
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
this.pendingClip = null;
|
2016-10-18 06:09:24 +09:00
|
|
|
clipPath.appendChild(clipElement);
|
|
|
|
this.defs.appendChild(clipPath);
|
|
|
|
|
|
|
|
if (current.activeClipUrl) {
|
|
|
|
// The previous clipping group content can go out of order -- resetting
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
// cached clipGroups.
|
2016-10-18 06:09:24 +09:00
|
|
|
current.clipGroup = null;
|
|
|
|
this.extraStack.forEach(function (prev) {
|
|
|
|
prev.clipGroup = null;
|
|
|
|
});
|
2018-04-18 01:20:29 +09:00
|
|
|
// Intersect with the previous clipping path.
|
|
|
|
clipPath.setAttributeNS(null, 'clip-path', current.activeClipUrl);
|
2016-10-18 06:09:24 +09:00
|
|
|
}
|
|
|
|
current.activeClipUrl = 'url(#' + clipId + ')';
|
|
|
|
|
|
|
|
this.tgrp = null;
|
2014-07-04 00:59:04 +09:00
|
|
|
},
|
|
|
|
|
Move svg:clipPath generation from clip to endPath
In the PDF from issue 8527, the clip operator (W) shows up before a path
is defined. The current SVG backend however expects a path to exist
before generating a `<svg:clipPath>` element.
In the example, the path was defined after the clip, followed by a
endPath operator (n).
So this commit fixes the bug by moving the path generation logic from
clip to endPath.
Our canvas backend appears to use similar logic:
`CanvasGraphics_endPath` calls `consumePath`, which in turn draws the
clip and resets the `pendingClip` state. The canvas backend calls
`consumePath` from multiple other places, so we probably need to check
whether doing so is also necessary for the SVG backend.
I scanned our corpus of PDF files in test/pdfs, and found that in every
instance (except for one), the "W" PDF operator (clip) is immediately
followed by "n" (endPath). The new test from this commit (clippath.pdf)
starts with "W", followed by a path definition and then "n".
# Commands used to find some of the clipping commands:
grep -ra '^W$' -C7 | less -S
grep -ra '^W ' -C7 | less -S
grep -ra ' W$' -C7 | less -S
test/pdfs/issue6413.pdf is the only file where "W" (a tline 55) is not
followed by "n". In fact, the "W" is the last operation of a series of
XObject painting operations, and removing it does not have any effect
on the rendered PDF (confirmed by looking at the output of PDF.js's
canvas backend, and ImageMagick's convert command).
2017-06-19 19:40:48 +09:00
|
|
|
clip: function SVGGraphics_clip(type) {
|
|
|
|
this.pendingClip = type;
|
|
|
|
},
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
closePath: function SVGGraphics_closePath() {
|
|
|
|
var current = this.current;
|
2017-11-15 01:35:39 +09:00
|
|
|
if (current.path) {
|
|
|
|
var d = current.path.getAttributeNS(null, 'd');
|
|
|
|
d += 'Z';
|
|
|
|
current.path.setAttributeNS(null, 'd', d);
|
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
setLeading: function SVGGraphics_setLeading(leading) {
|
|
|
|
this.current.leading = -leading;
|
|
|
|
},
|
|
|
|
|
|
|
|
setTextRise: function SVGGraphics_setTextRise(textRise) {
|
|
|
|
this.current.textRise = textRise;
|
|
|
|
},
|
|
|
|
|
2018-08-29 06:42:07 +09:00
|
|
|
setTextRenderingMode(textRenderingMode) {
|
|
|
|
this.current.textRenderingMode = textRenderingMode;
|
|
|
|
},
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
setHScale: function SVGGraphics_setHScale(scale) {
|
|
|
|
this.current.textHScale = scale / 100;
|
|
|
|
},
|
|
|
|
|
|
|
|
setGState: function SVGGraphics_setGState(states) {
|
|
|
|
for (var i = 0, ii = states.length; i < ii; i++) {
|
|
|
|
var state = states[i];
|
|
|
|
var key = state[0];
|
|
|
|
var value = state[1];
|
|
|
|
|
|
|
|
switch (key) {
|
|
|
|
case 'LW':
|
|
|
|
this.setLineWidth(value);
|
|
|
|
break;
|
|
|
|
case 'LC':
|
|
|
|
this.setLineCap(value);
|
|
|
|
break;
|
|
|
|
case 'LJ':
|
|
|
|
this.setLineJoin(value);
|
|
|
|
break;
|
|
|
|
case 'ML':
|
|
|
|
this.setMiterLimit(value);
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
this.setDash(value[0], value[1]);
|
|
|
|
break;
|
|
|
|
case 'Font':
|
2014-07-05 17:48:11 +09:00
|
|
|
this.setFont(value);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
2017-06-23 07:24:47 +09:00
|
|
|
case 'CA':
|
|
|
|
this.setStrokeAlpha(value);
|
|
|
|
break;
|
2017-06-23 07:19:20 +09:00
|
|
|
case 'ca':
|
|
|
|
this.setFillAlpha(value);
|
|
|
|
break;
|
2016-10-13 04:22:35 +09:00
|
|
|
default:
|
|
|
|
warn('Unimplemented graphic state ' + key);
|
2014-05-20 08:53:40 +09:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
fill: function SVGGraphics_fill() {
|
|
|
|
var current = this.current;
|
2017-11-15 01:35:39 +09:00
|
|
|
if (current.element) {
|
|
|
|
current.element.setAttributeNS(null, 'fill', current.fillColor);
|
|
|
|
current.element.setAttributeNS(null, 'fill-opacity', current.fillAlpha);
|
2018-04-18 01:20:29 +09:00
|
|
|
this.endPath();
|
2017-11-15 01:35:39 +09:00
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
stroke: function SVGGraphics_stroke() {
|
|
|
|
var current = this.current;
|
2017-06-26 05:28:46 +09:00
|
|
|
|
2017-11-15 01:35:39 +09:00
|
|
|
if (current.element) {
|
2018-08-29 06:42:07 +09:00
|
|
|
this._setStrokeAttributes(current.element);
|
2017-11-15 01:35:39 +09:00
|
|
|
|
|
|
|
current.element.setAttributeNS(null, 'fill', 'none');
|
2018-04-18 01:20:29 +09:00
|
|
|
|
|
|
|
this.endPath();
|
2017-11-15 01:35:39 +09:00
|
|
|
}
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
2018-08-29 06:42:07 +09:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_setStrokeAttributes(element) {
|
|
|
|
const current = this.current;
|
|
|
|
element.setAttributeNS(null, 'stroke', current.strokeColor);
|
|
|
|
element.setAttributeNS(null, 'stroke-opacity', current.strokeAlpha);
|
|
|
|
element.setAttributeNS(null, 'stroke-miterlimit',
|
|
|
|
pf(current.miterLimit));
|
|
|
|
element.setAttributeNS(null, 'stroke-linecap', current.lineCap);
|
|
|
|
element.setAttributeNS(null, 'stroke-linejoin', current.lineJoin);
|
|
|
|
element.setAttributeNS(null, 'stroke-width',
|
|
|
|
pf(current.lineWidth) + 'px');
|
|
|
|
element.setAttributeNS(null, 'stroke-dasharray',
|
|
|
|
current.dashArray.map(pf).join(' '));
|
|
|
|
element.setAttributeNS(null, 'stroke-dashoffset',
|
|
|
|
pf(current.dashPhase) + 'px');
|
|
|
|
},
|
|
|
|
|
2014-05-20 08:53:40 +09:00
|
|
|
eoFill: function SVGGraphics_eoFill() {
|
2017-11-15 01:35:39 +09:00
|
|
|
if (this.current.element) {
|
|
|
|
this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
|
|
|
|
}
|
2017-06-23 07:19:20 +09:00
|
|
|
this.fill();
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
fillStroke: function SVGGraphics_fillStroke() {
|
2014-07-04 01:03:31 +09:00
|
|
|
// Order is important since stroke wants fill to be none.
|
|
|
|
// First stroke, then if fill needed, it will be overwritten.
|
2014-05-20 08:53:40 +09:00
|
|
|
this.stroke();
|
2014-07-04 01:03:31 +09:00
|
|
|
this.fill();
|
|
|
|
},
|
|
|
|
|
|
|
|
eoFillStroke: function SVGGraphics_eoFillStroke() {
|
2017-11-15 01:35:39 +09:00
|
|
|
if (this.current.element) {
|
|
|
|
this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
|
|
|
|
}
|
2014-07-04 01:03:31 +09:00
|
|
|
this.fillStroke();
|
2014-05-20 08:53:40 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
closeStroke: function SVGGraphics_closeStroke() {
|
|
|
|
this.closePath();
|
|
|
|
this.stroke();
|
|
|
|
},
|
|
|
|
|
|
|
|
closeFillStroke: function SVGGraphics_closeFillStroke() {
|
|
|
|
this.closePath();
|
|
|
|
this.fillStroke();
|
|
|
|
},
|
2014-06-25 04:23:18 +09:00
|
|
|
|
2018-01-10 02:42:12 +09:00
|
|
|
closeEOFillStroke() {
|
|
|
|
this.closePath();
|
|
|
|
this.eoFillStroke();
|
|
|
|
},
|
|
|
|
|
2014-06-25 05:16:50 +09:00
|
|
|
paintSolidColorImageMask:
|
2014-08-10 21:40:49 +09:00
|
|
|
function SVGGraphics_paintSolidColorImageMask() {
|
|
|
|
var current = this.current;
|
2017-07-24 07:09:18 +09:00
|
|
|
var rect = this.svgFactory.createElement('svg:rect');
|
2014-08-12 01:18:32 +09:00
|
|
|
rect.setAttributeNS(null, 'x', '0');
|
|
|
|
rect.setAttributeNS(null, 'y', '0');
|
|
|
|
rect.setAttributeNS(null, 'width', '1px');
|
|
|
|
rect.setAttributeNS(null, 'height', '1px');
|
2014-08-10 21:40:49 +09:00
|
|
|
rect.setAttributeNS(null, 'fill', current.fillColor);
|
2016-10-13 04:22:35 +09:00
|
|
|
|
|
|
|
this._ensureTransformGroup().appendChild(rect);
|
2014-06-25 05:16:50 +09:00
|
|
|
},
|
2014-06-25 05:24:00 +09:00
|
|
|
|
2014-08-08 01:30:48 +09:00
|
|
|
paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
|
|
|
|
var imgObj = this.objs.get(objId);
|
2017-07-24 07:09:18 +09:00
|
|
|
var imgEl = this.svgFactory.createElement('svg:image');
|
2014-08-15 05:11:27 +09:00
|
|
|
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
|
2017-05-08 12:32:44 +09:00
|
|
|
imgEl.setAttributeNS(null, 'width', pf(w));
|
|
|
|
imgEl.setAttributeNS(null, 'height', pf(h));
|
2014-08-12 01:18:32 +09:00
|
|
|
imgEl.setAttributeNS(null, 'x', '0');
|
|
|
|
imgEl.setAttributeNS(null, 'y', pf(-h));
|
|
|
|
imgEl.setAttributeNS(null, 'transform',
|
|
|
|
'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')');
|
2014-08-08 01:30:48 +09:00
|
|
|
|
2016-10-13 04:22:35 +09:00
|
|
|
this._ensureTransformGroup().appendChild(imgEl);
|
2014-08-08 01:30:48 +09:00
|
|
|
},
|
|
|
|
|
|
|
|
paintImageXObject: function SVGGraphics_paintImageXObject(objId) {
|
|
|
|
var imgData = this.objs.get(objId);
|
|
|
|
if (!imgData) {
|
|
|
|
warn('Dependent image isn\'t ready yet');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.paintInlineImageXObject(imgData);
|
|
|
|
},
|
|
|
|
|
|
|
|
paintInlineImageXObject:
|
2014-08-10 21:40:49 +09:00
|
|
|
function SVGGraphics_paintInlineImageXObject(imgData, mask) {
|
2014-08-08 01:30:48 +09:00
|
|
|
var width = imgData.width;
|
|
|
|
var height = imgData.height;
|
|
|
|
|
2017-11-29 04:24:27 +09:00
|
|
|
var imgSrc = convertImgDataToPng(imgData, this.forceDataSchema, !!mask);
|
2017-07-24 07:09:18 +09:00
|
|
|
var cliprect = this.svgFactory.createElement('svg:rect');
|
2014-08-12 01:18:32 +09:00
|
|
|
cliprect.setAttributeNS(null, 'x', '0');
|
|
|
|
cliprect.setAttributeNS(null, 'y', '0');
|
|
|
|
cliprect.setAttributeNS(null, 'width', pf(width));
|
|
|
|
cliprect.setAttributeNS(null, 'height', pf(height));
|
2016-10-13 04:22:35 +09:00
|
|
|
this.current.element = cliprect;
|
2014-08-08 01:30:48 +09:00
|
|
|
this.clip('nonzero');
|
2017-07-24 07:09:18 +09:00
|
|
|
var imgEl = this.svgFactory.createElement('svg:image');
|
2014-08-15 05:11:27 +09:00
|
|
|
imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
|
2014-08-12 01:18:32 +09:00
|
|
|
imgEl.setAttributeNS(null, 'x', '0');
|
|
|
|
imgEl.setAttributeNS(null, 'y', pf(-height));
|
|
|
|
imgEl.setAttributeNS(null, 'width', pf(width) + 'px');
|
|
|
|
imgEl.setAttributeNS(null, 'height', pf(height) + 'px');
|
|
|
|
imgEl.setAttributeNS(null, 'transform',
|
|
|
|
'scale(' + pf(1 / width) + ' ' +
|
|
|
|
pf(-1 / height) + ')');
|
2014-08-08 01:30:48 +09:00
|
|
|
if (mask) {
|
|
|
|
mask.appendChild(imgEl);
|
|
|
|
} else {
|
2016-10-13 04:22:35 +09:00
|
|
|
this._ensureTransformGroup().appendChild(imgEl);
|
2014-08-08 01:30:48 +09:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
paintImageMaskXObject:
|
2014-08-10 21:40:49 +09:00
|
|
|
function SVGGraphics_paintImageMaskXObject(imgData) {
|
2014-08-08 01:30:48 +09:00
|
|
|
var current = this.current;
|
|
|
|
var width = imgData.width;
|
|
|
|
var height = imgData.height;
|
|
|
|
var fillColor = current.fillColor;
|
|
|
|
|
|
|
|
current.maskId = 'mask' + maskCount++;
|
2017-07-24 07:09:18 +09:00
|
|
|
var mask = this.svgFactory.createElement('svg:mask');
|
2014-08-08 01:30:48 +09:00
|
|
|
mask.setAttributeNS(null, 'id', current.maskId);
|
|
|
|
|
2017-07-24 07:09:18 +09:00
|
|
|
var rect = this.svgFactory.createElement('svg:rect');
|
2014-08-12 01:18:32 +09:00
|
|
|
rect.setAttributeNS(null, 'x', '0');
|
|
|
|
rect.setAttributeNS(null, 'y', '0');
|
|
|
|
rect.setAttributeNS(null, 'width', pf(width));
|
|
|
|
rect.setAttributeNS(null, 'height', pf(height));
|
2014-08-08 01:30:48 +09:00
|
|
|
rect.setAttributeNS(null, 'fill', fillColor);
|
2016-11-01 23:04:21 +09:00
|
|
|
rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId + ')');
|
2014-08-08 01:30:48 +09:00
|
|
|
this.defs.appendChild(mask);
|
2016-10-13 04:22:35 +09:00
|
|
|
|
|
|
|
this._ensureTransformGroup().appendChild(rect);
|
2014-08-08 01:30:48 +09:00
|
|
|
|
|
|
|
this.paintInlineImageXObject(imgData, mask);
|
2014-06-25 05:24:00 +09:00
|
|
|
},
|
2014-08-15 05:54:38 +09:00
|
|
|
|
|
|
|
paintFormXObjectBegin:
|
|
|
|
function SVGGraphics_paintFormXObjectBegin(matrix, bbox) {
|
2017-09-02 03:27:13 +09:00
|
|
|
if (Array.isArray(matrix) && matrix.length === 6) {
|
2014-08-15 05:54:38 +09:00
|
|
|
this.transform(matrix[0], matrix[1], matrix[2],
|
|
|
|
matrix[3], matrix[4], matrix[5]);
|
|
|
|
}
|
|
|
|
|
2018-10-16 22:23:14 +09:00
|
|
|
if (bbox) {
|
2014-08-15 05:54:38 +09:00
|
|
|
var width = bbox[2] - bbox[0];
|
|
|
|
var height = bbox[3] - bbox[1];
|
|
|
|
|
2017-07-24 07:09:18 +09:00
|
|
|
var cliprect = this.svgFactory.createElement('svg:rect');
|
2014-08-15 05:54:38 +09:00
|
|
|
cliprect.setAttributeNS(null, 'x', bbox[0]);
|
|
|
|
cliprect.setAttributeNS(null, 'y', bbox[1]);
|
|
|
|
cliprect.setAttributeNS(null, 'width', pf(width));
|
|
|
|
cliprect.setAttributeNS(null, 'height', pf(height));
|
|
|
|
this.current.element = cliprect;
|
|
|
|
this.clip('nonzero');
|
|
|
|
this.endPath();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
paintFormXObjectEnd:
|
2016-10-13 04:22:35 +09:00
|
|
|
function SVGGraphics_paintFormXObjectEnd() {},
|
|
|
|
|
2016-10-16 04:05:57 +09:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
2017-07-24 07:09:18 +09:00
|
|
|
_initialize(viewport) {
|
|
|
|
let svg = this.svgFactory.create(viewport.width, viewport.height);
|
2016-10-16 04:05:57 +09:00
|
|
|
|
|
|
|
// Create the definitions element.
|
2017-07-24 07:09:18 +09:00
|
|
|
let definitions = this.svgFactory.createElement('svg:defs');
|
2016-10-16 04:05:57 +09:00
|
|
|
svg.appendChild(definitions);
|
|
|
|
this.defs = definitions;
|
|
|
|
|
|
|
|
// Create the root group element, which acts a container for all other
|
|
|
|
// groups and applies the viewport transform.
|
2017-07-24 07:09:18 +09:00
|
|
|
let rootGroup = this.svgFactory.createElement('svg:g');
|
2016-10-16 04:05:57 +09:00
|
|
|
rootGroup.setAttributeNS(null, 'transform', pm(viewport.transform));
|
|
|
|
svg.appendChild(rootGroup);
|
|
|
|
|
|
|
|
// For the construction of the SVG image we are only interested in the
|
|
|
|
// root group, so we expose it as the entry point of the SVG image for
|
|
|
|
// the other code in this class.
|
|
|
|
this.svg = rootGroup;
|
|
|
|
|
|
|
|
return svg;
|
|
|
|
},
|
|
|
|
|
2016-10-18 06:09:24 +09:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_ensureClipGroup: function SVGGraphics_ensureClipGroup() {
|
|
|
|
if (!this.current.clipGroup) {
|
2017-07-24 07:09:18 +09:00
|
|
|
var clipGroup = this.svgFactory.createElement('svg:g');
|
2016-10-18 06:09:24 +09:00
|
|
|
clipGroup.setAttributeNS(null, 'clip-path',
|
|
|
|
this.current.activeClipUrl);
|
|
|
|
this.svg.appendChild(clipGroup);
|
|
|
|
this.current.clipGroup = clipGroup;
|
|
|
|
}
|
|
|
|
return this.current.clipGroup;
|
|
|
|
},
|
|
|
|
|
2016-10-13 04:22:35 +09:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
_ensureTransformGroup: function SVGGraphics_ensureTransformGroup() {
|
|
|
|
if (!this.tgrp) {
|
2017-07-24 07:09:18 +09:00
|
|
|
this.tgrp = this.svgFactory.createElement('svg:g');
|
2016-10-13 04:22:35 +09:00
|
|
|
this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
|
2016-10-18 06:09:24 +09:00
|
|
|
if (this.current.activeClipUrl) {
|
|
|
|
this._ensureClipGroup().appendChild(this.tgrp);
|
2016-10-13 04:22:35 +09:00
|
|
|
} else {
|
|
|
|
this.svg.appendChild(this.tgrp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.tgrp;
|
Fix inconsistent spacing and trailing commas in objects in remaining `src/` files, so we can enable the `comma-dangle` and `object-curly-spacing` ESLint rules later on
http://eslint.org/docs/rules/comma-dangle
http://eslint.org/docs/rules/object-curly-spacing
Given that we currently have quite inconsistent object formatting, fixing this in *one* big patch probably wouldn't be feasible (since I cannot imagine anyone wanting to review that); hence I've opted to try and do this piecewise instead.
Please note: This patch was created automatically, using the ESLint `--fix` command line option. In a couple of places this caused lines to become too long, and I've fixed those manually; please refer to the interdiff below for the only hand-edits in this patch.
```diff
diff --git a/src/display/canvas.js b/src/display/canvas.js
index 5739f6f2..4216b2d2 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -2071,7 +2071,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var map = [];
for (var i = 0, ii = positions.length; i < ii; i += 2) {
map.push({ transform: [scaleX, 0, 0, scaleY, positions[i],
- positions[i + 1]], x: 0, y: 0, w: width, h: height, });
+ positions[i + 1]], x: 0, y: 0, w: width, h: height, });
}
this.paintInlineImageXObjectGroup(imgData, map);
},
diff --git a/src/display/svg.js b/src/display/svg.js
index 9eb05dfa..2aa21482 100644
--- a/src/display/svg.js
+++ b/src/display/svg.js
@@ -458,7 +458,11 @@ SVGGraphics = (function SVGGraphicsClosure() {
for (var x = 0; x < fnArrayLen; x++) {
var fnId = fnArray[x];
- opList.push({ 'fnId': fnId, 'fn': REVOPS[fnId], 'args': argsArray[x], });
+ opList.push({
+ 'fnId': fnId,
+ 'fn': REVOPS[fnId],
+ 'args': argsArray[x],
+ });
}
return opListToTree(opList);
},
```
2017-06-02 18:26:37 +09:00
|
|
|
},
|
2014-05-20 08:53:40 +09:00
|
|
|
};
|
|
|
|
return SVGGraphics;
|
|
|
|
})();
|
2014-08-14 03:59:28 +09:00
|
|
|
|
2016-10-15 00:57:53 +09:00
|
|
|
}
|
2017-04-02 21:25:33 +09:00
|
|
|
|
|
|
|
export {
|
|
|
|
SVGGraphics,
|
|
|
|
};
|