pptx-react-viewer 1.22.1 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/{Model3DScene-NLUSXHD6.mjs → Model3DScene-4XNBDASE.mjs} +2 -2
- package/dist/Model3DScene-4XNBDASE.mjs.br +0 -0
- package/dist/Model3DScene-4XNBDASE.mjs.gz +0 -0
- package/dist/{Model3DScene-3YB3JAJS.js → Model3DScene-AQS7KDM4.js} +3 -3
- package/dist/Model3DScene-AQS7KDM4.js.br +0 -0
- package/dist/Model3DScene-AQS7KDM4.js.gz +0 -0
- package/dist/{PowerPointViewer-WGVR_u4z.d.ts → PowerPointViewer-DFTatVS4.d.ts} +2 -2
- package/dist/{PowerPointViewer-WGVR_u4z.d.ts.map → PowerPointViewer-DFTatVS4.d.ts.map} +1 -1
- package/dist/{SurfaceChart3DScene-PUQ5DCO5.js → SurfaceChart3DScene-HA2SD6BY.js} +3 -3
- package/dist/SurfaceChart3DScene-HA2SD6BY.js.br +0 -0
- package/dist/SurfaceChart3DScene-HA2SD6BY.js.gz +0 -0
- package/dist/{SurfaceChart3DScene-YBMJQGH3.mjs → SurfaceChart3DScene-K7ZDXDBL.mjs} +2 -2
- package/dist/SurfaceChart3DScene-K7ZDXDBL.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-K7ZDXDBL.mjs.gz +0 -0
- package/dist/{chunk-VSNXVKJI.js → chunk-2DXNTVFV.js} +159 -62
- package/dist/chunk-2DXNTVFV.js.br +0 -0
- package/dist/chunk-2DXNTVFV.js.gz +0 -0
- package/dist/{chunk-B7JRQB5F.mjs → chunk-36NC56XG.mjs} +311 -292
- package/dist/chunk-36NC56XG.mjs.br +0 -0
- package/dist/chunk-36NC56XG.mjs.gz +0 -0
- package/dist/{chunk-3ZGCM6RC.mjs → chunk-AFWMAFWR.mjs} +1076 -289
- package/dist/chunk-AFWMAFWR.mjs.br +0 -0
- package/dist/chunk-AFWMAFWR.mjs.gz +0 -0
- package/dist/{chunk-QVQTDWB7.js → chunk-H5RREYCO.js} +463 -454
- package/dist/chunk-H5RREYCO.js.br +0 -0
- package/dist/chunk-H5RREYCO.js.gz +0 -0
- package/dist/{chunk-5SBQZEKD.mjs → chunk-I42XL2WU.mjs} +130 -34
- package/dist/chunk-I42XL2WU.mjs.br +0 -0
- package/dist/chunk-I42XL2WU.mjs.gz +0 -0
- package/dist/{chunk-DZUI64SO.mjs → chunk-LFEVG3ED.mjs} +13 -4
- package/dist/chunk-LFEVG3ED.mjs.br +0 -0
- package/dist/chunk-LFEVG3ED.mjs.gz +0 -0
- package/dist/{chunk-YPZV4KJT.js → chunk-LS2AIX2H.js} +1087 -1068
- package/dist/chunk-LS2AIX2H.js.br +0 -0
- package/dist/chunk-LS2AIX2H.js.gz +0 -0
- package/dist/{chunk-AD3EAEY6.js → chunk-MS6S6YYR.js} +1076 -289
- package/dist/chunk-MS6S6YYR.js.br +0 -0
- package/dist/chunk-MS6S6YYR.js.gz +0 -0
- package/dist/{dist-3YRZ26TL.mjs → dist-5KQQ6GP2.mjs} +1 -1
- package/dist/dist-5KQQ6GP2.mjs.br +0 -0
- package/dist/dist-5KQQ6GP2.mjs.gz +0 -0
- package/dist/{dist-M2P6HBG4.js → dist-CVSSAFDL.js} +560 -560
- package/dist/dist-CVSSAFDL.js.br +0 -0
- package/dist/dist-CVSSAFDL.js.gz +0 -0
- package/dist/hooks-unstable.d.ts +5107 -5242
- package/dist/hooks-unstable.d.ts.map +1 -1
- package/dist/hooks-unstable.js +76 -76
- package/dist/hooks-unstable.js.br +0 -0
- package/dist/hooks-unstable.js.gz +0 -0
- package/dist/hooks-unstable.mjs +3 -3
- package/dist/hooks-unstable.mjs.br +0 -0
- package/dist/hooks-unstable.mjs.gz +0 -0
- package/dist/i18n.d.ts +3 -0
- package/dist/{index-SUL_8gq8.d.ts → index-CGKutKk1.d.ts} +4 -1
- package/dist/index-CGKutKk1.d.ts.map +1 -0
- package/dist/{index-ntF3kHHU.d.ts → index-COgh2UTL.d.ts} +2 -2
- package/dist/{index-ntF3kHHU.d.ts.map → index-COgh2UTL.d.ts.map} +1 -1
- package/dist/index.d.ts +3328 -3386
- package/dist/index.js +30 -30
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.mjs +4 -4
- package/dist/index.mjs.br +0 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/pptx-viewer.css +1 -1
- package/dist/pptx-viewer.css.br +0 -0
- package/dist/pptx-viewer.css.gz +0 -0
- package/dist/{types-Cdh0XYcS.d.ts → types-Da1M5VBY.d.ts} +2 -2
- package/dist/{types-Cdh0XYcS.d.ts.map → types-Da1M5VBY.d.ts.map} +1 -1
- package/dist/viewer/index.d.ts +5118 -5224
- package/dist/viewer/index.js +20 -20
- package/dist/viewer/index.js.br +0 -0
- package/dist/viewer/index.js.gz +0 -0
- package/dist/viewer/index.mjs +4 -4
- package/dist/viewer/index.mjs.br +0 -0
- package/dist/viewer/index.mjs.gz +0 -0
- package/package.json +1 -1
- package/dist/Model3DScene-3YB3JAJS.js.br +0 -0
- package/dist/Model3DScene-3YB3JAJS.js.gz +0 -0
- package/dist/Model3DScene-NLUSXHD6.mjs.br +0 -0
- package/dist/Model3DScene-NLUSXHD6.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-PUQ5DCO5.js.br +0 -0
- package/dist/SurfaceChart3DScene-PUQ5DCO5.js.gz +0 -0
- package/dist/SurfaceChart3DScene-YBMJQGH3.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-YBMJQGH3.mjs.gz +0 -0
- package/dist/chunk-3ZGCM6RC.mjs.br +0 -0
- package/dist/chunk-3ZGCM6RC.mjs.gz +0 -0
- package/dist/chunk-5SBQZEKD.mjs.br +0 -0
- package/dist/chunk-5SBQZEKD.mjs.gz +0 -0
- package/dist/chunk-AD3EAEY6.js.br +0 -0
- package/dist/chunk-AD3EAEY6.js.gz +0 -0
- package/dist/chunk-B7JRQB5F.mjs.br +0 -0
- package/dist/chunk-B7JRQB5F.mjs.gz +0 -0
- package/dist/chunk-DZUI64SO.mjs.br +0 -0
- package/dist/chunk-DZUI64SO.mjs.gz +0 -0
- package/dist/chunk-QVQTDWB7.js.br +0 -0
- package/dist/chunk-QVQTDWB7.js.gz +0 -0
- package/dist/chunk-VSNXVKJI.js.br +0 -0
- package/dist/chunk-VSNXVKJI.js.gz +0 -0
- package/dist/chunk-YPZV4KJT.js.br +0 -0
- package/dist/chunk-YPZV4KJT.js.gz +0 -0
- package/dist/dist-3YRZ26TL.mjs.br +0 -0
- package/dist/dist-3YRZ26TL.mjs.gz +0 -0
- package/dist/dist-M2P6HBG4.js.br +0 -0
- package/dist/dist-M2P6HBG4.js.gz +0 -0
- package/dist/index-SUL_8gq8.d.ts.map +0 -1
|
@@ -9,7 +9,24 @@ var JSZip6__default = /*#__PURE__*/_interopDefault(JSZip6);
|
|
|
9
9
|
|
|
10
10
|
// ../core/dist/index.mjs
|
|
11
11
|
|
|
12
|
-
// ../../node_modules/.bun/mtx-decompressor@1.
|
|
12
|
+
// ../../node_modules/.bun/mtx-decompressor@1.6.0/node_modules/mtx-decompressor/dist/index.mjs
|
|
13
|
+
var WARNING_CODES = /* @__PURE__ */ new Set([
|
|
14
|
+
"WARN_BAD_VERSION"
|
|
15
|
+
/* WarnBadVersion */
|
|
16
|
+
]);
|
|
17
|
+
var EotError = class _EotError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(code, message) {
|
|
20
|
+
super(message);
|
|
21
|
+
this.name = "EotError";
|
|
22
|
+
this.code = code;
|
|
23
|
+
Object.setPrototypeOf(this, _EotError.prototype);
|
|
24
|
+
}
|
|
25
|
+
/** True when this represents a recoverable warning rather than a fatal error. */
|
|
26
|
+
get isWarning() {
|
|
27
|
+
return WARNING_CODES.has(this.code);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
13
30
|
var Stream = class _Stream {
|
|
14
31
|
buf;
|
|
15
32
|
size;
|
|
@@ -49,7 +66,26 @@ var Stream = class _Stream {
|
|
|
49
66
|
this.buf = newBuf;
|
|
50
67
|
this.reserved = n;
|
|
51
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Reject byte-level access while the stream sits mid-byte (`bitPos != 0`).
|
|
71
|
+
*
|
|
72
|
+
* libeot returns `EOT_OFF_BYTE_BOUNDARY` for any byte read/write/seek issued
|
|
73
|
+
* before a partial byte has been consumed. The bit-level reader
|
|
74
|
+
* ({@link readNBits}) is the sole legitimate mid-byte accessor and bypasses
|
|
75
|
+
* this guard by touching `buf`/`pos` directly. On valid input the only
|
|
76
|
+
* `readNBits` caller consumes whole bytes per point, so the stream is always
|
|
77
|
+
* byte-aligned when a byte accessor runs and this guard never fires.
|
|
78
|
+
*/
|
|
79
|
+
ensureByteAligned() {
|
|
80
|
+
if (this.bitPos !== 0) {
|
|
81
|
+
throw new EotError(
|
|
82
|
+
"OFF_BYTE_BOUNDARY",
|
|
83
|
+
`Stream: byte-level access at a non-byte boundary (bitPos=${this.bitPos}, pos=${this.pos})`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
52
87
|
ensureWrite(n) {
|
|
88
|
+
this.ensureByteAligned();
|
|
53
89
|
const needed = this.pos + n;
|
|
54
90
|
if (needed > this.reserved) {
|
|
55
91
|
this.reserve(Math.max(needed, this.reserved * 2 || 256));
|
|
@@ -59,6 +95,7 @@ var Stream = class _Stream {
|
|
|
59
95
|
}
|
|
60
96
|
}
|
|
61
97
|
ensureRead(n) {
|
|
98
|
+
this.ensureByteAligned();
|
|
62
99
|
if (this.pos + n > this.size) {
|
|
63
100
|
throw new Error(
|
|
64
101
|
`Stream: not enough data (need ${n} bytes at pos ${this.pos}, size ${this.size})`
|
|
@@ -66,14 +103,18 @@ var Stream = class _Stream {
|
|
|
66
103
|
}
|
|
67
104
|
}
|
|
68
105
|
// --- Seek ---
|
|
106
|
+
// A seek requires the stream to be byte-aligned and never clears `bitPos`
|
|
107
|
+
// itself (mirroring libeot, which refuses to seek mid-byte rather than
|
|
108
|
+
// silently re-aligning). The alignment guard leaves `bitPos` at 0.
|
|
69
109
|
seekAbsolute(pos2) {
|
|
110
|
+
this.ensureByteAligned();
|
|
70
111
|
if (pos2 > this.size) {
|
|
71
112
|
throw new Error(`Stream: seek past end (${pos2} > ${this.size})`);
|
|
72
113
|
}
|
|
73
114
|
this.pos = pos2;
|
|
74
|
-
this.bitPos = 0;
|
|
75
115
|
}
|
|
76
116
|
seekRelative(offset) {
|
|
117
|
+
this.ensureByteAligned();
|
|
77
118
|
const newPos = this.pos + offset;
|
|
78
119
|
if (newPos < 0) {
|
|
79
120
|
throw new Error("Stream: negative seek");
|
|
@@ -82,17 +123,23 @@ var Stream = class _Stream {
|
|
|
82
123
|
throw new Error("Stream: seek past end");
|
|
83
124
|
}
|
|
84
125
|
this.pos = newPos;
|
|
85
|
-
this.bitPos = 0;
|
|
86
126
|
}
|
|
127
|
+
// Seek into already-reserved-but-unwritten space, extending `size` up to the
|
|
128
|
+
// seek target. libeot returns `EOT_SEEK_PAST_EOS` when the target exceeds the
|
|
129
|
+
// reserved capacity; we mirror that rather than growing the buffer, so an
|
|
130
|
+
// over-reach surfaces as a failure instead of a silent realloc.
|
|
87
131
|
seekAbsoluteThroughReserve(pos2) {
|
|
132
|
+
this.ensureByteAligned();
|
|
88
133
|
if (pos2 > this.reserved) {
|
|
89
|
-
|
|
134
|
+
throw new EotError(
|
|
135
|
+
"SEEK_PAST_EOS",
|
|
136
|
+
`Stream: seek to ${pos2} past reserved end (${this.reserved})`
|
|
137
|
+
);
|
|
90
138
|
}
|
|
91
139
|
if (pos2 > this.size) {
|
|
92
140
|
this.size = pos2;
|
|
93
141
|
}
|
|
94
142
|
this.pos = pos2;
|
|
95
|
-
this.bitPos = 0;
|
|
96
143
|
}
|
|
97
144
|
seekRelativeThroughReserve(offset) {
|
|
98
145
|
this.seekAbsoluteThroughReserve(this.pos + offset);
|
|
@@ -146,6 +193,9 @@ var Stream = class _Stream {
|
|
|
146
193
|
this.buf[this.pos++] = v & 255;
|
|
147
194
|
}
|
|
148
195
|
writeU24(v) {
|
|
196
|
+
if (v < 0 || v > 16777215) {
|
|
197
|
+
throw new Error(`Stream: writeU24 value out of range: ${v}`);
|
|
198
|
+
}
|
|
149
199
|
this.ensureWrite(3);
|
|
150
200
|
this.buf[this.pos++] = v >> 16 & 255;
|
|
151
201
|
this.buf[this.pos++] = v >> 8 & 255;
|
|
@@ -169,6 +219,9 @@ var Stream = class _Stream {
|
|
|
169
219
|
if (n === 0) {
|
|
170
220
|
return 0;
|
|
171
221
|
}
|
|
222
|
+
if (n > 32) {
|
|
223
|
+
throw new Error(`Stream: readNBits width out of range: ${n} (max 32)`);
|
|
224
|
+
}
|
|
172
225
|
let value = 0;
|
|
173
226
|
let bitsRemaining = n;
|
|
174
227
|
while (bitsRemaining > 0) {
|
|
@@ -187,18 +240,36 @@ var Stream = class _Stream {
|
|
|
187
240
|
}
|
|
188
241
|
bitsRemaining -= bitsToRead;
|
|
189
242
|
}
|
|
190
|
-
return value;
|
|
243
|
+
return value >>> 0;
|
|
191
244
|
}
|
|
192
245
|
// --- Copy ---
|
|
193
|
-
/**
|
|
246
|
+
/**
|
|
247
|
+
* Copy `length` bytes from this stream to `dest`.
|
|
248
|
+
*
|
|
249
|
+
* Both streams must be byte-aligned. The destination must already have the
|
|
250
|
+
* capacity reserved: libeot returns `EOT_OUT_OF_RESERVED_SPACE` when a copy
|
|
251
|
+
* would overrun the reserved buffer, so we throw rather than auto-growing —
|
|
252
|
+
* an under-reservation is a bug we want surfaced, not silently patched.
|
|
253
|
+
*/
|
|
194
254
|
copyTo(dest, length) {
|
|
255
|
+
this.ensureByteAligned();
|
|
256
|
+
dest.ensureByteAligned();
|
|
195
257
|
if (this.pos + length > this.size) {
|
|
196
258
|
throw new Error("Stream: not enough data for copy");
|
|
197
259
|
}
|
|
198
|
-
dest.
|
|
260
|
+
const needed = dest.pos + length;
|
|
261
|
+
if (needed > dest.reserved) {
|
|
262
|
+
throw new EotError(
|
|
263
|
+
"OUT_OF_RESERVED_SPACE",
|
|
264
|
+
`Stream: copy of ${length} bytes exceeds reserved capacity (need ${needed}, reserved ${dest.reserved})`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
199
267
|
dest.buf.set(this.buf.subarray(this.pos, this.pos + length), dest.pos);
|
|
200
268
|
this.pos += length;
|
|
201
269
|
dest.pos += length;
|
|
270
|
+
if (dest.pos > dest.size) {
|
|
271
|
+
dest.size = dest.pos;
|
|
272
|
+
}
|
|
202
273
|
}
|
|
203
274
|
/** Read rest of data as 4-byte-aligned U32 values. Returns 0 on incomplete read. */
|
|
204
275
|
readRestAsU32() {
|
|
@@ -219,19 +290,27 @@ var Stream = class _Stream {
|
|
|
219
290
|
}
|
|
220
291
|
return this.readU32();
|
|
221
292
|
}
|
|
222
|
-
/**
|
|
293
|
+
/**
|
|
294
|
+
* Compute the SFNT-style checksum of bytes in `[beginPos, endPos)` as a sum
|
|
295
|
+
* of big-endian U32 words, zero-padding a final partial word. Bounds strictly
|
|
296
|
+
* on `endPos` (not the stream's `size`), so an unaligned range never folds in
|
|
297
|
+
* bytes past `endPos`. Leaves the stream position unchanged.
|
|
298
|
+
*/
|
|
223
299
|
checksumU32(beginPos, endPos) {
|
|
300
|
+
if (beginPos > endPos) {
|
|
301
|
+
throw new Error(`Stream: checksumU32 beginPos ${beginPos} > endPos ${endPos}`);
|
|
302
|
+
}
|
|
303
|
+
if (endPos > this.size) {
|
|
304
|
+
throw new Error(`Stream: checksumU32 endPos ${endPos} exceeds size ${this.size}`);
|
|
305
|
+
}
|
|
224
306
|
let sum = 0;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (chunk === null) {
|
|
230
|
-
break;
|
|
307
|
+
for (let p = beginPos; p < endPos; p += 4) {
|
|
308
|
+
let word = 0;
|
|
309
|
+
for (let i = 0; i < 4; i++) {
|
|
310
|
+
word = word << 8 | (p + i < endPos ? this.buf[p + i] : 0);
|
|
231
311
|
}
|
|
232
|
-
sum = sum +
|
|
312
|
+
sum = sum + (word >>> 0) >>> 0;
|
|
233
313
|
}
|
|
234
|
-
this.pos = savedPos;
|
|
235
314
|
return sum;
|
|
236
315
|
}
|
|
237
316
|
/** Get a copy of the written data. */
|
|
@@ -431,10 +510,9 @@ function read255Short(s) {
|
|
|
431
510
|
}
|
|
432
511
|
function unpackCVT(table, sIn) {
|
|
433
512
|
sIn.seekAbsolute(table.offset);
|
|
434
|
-
const
|
|
435
|
-
const numEntries = tableLength >>> 1;
|
|
513
|
+
const numEntries = sIn.readU16();
|
|
436
514
|
const out = new Stream(null, 0);
|
|
437
|
-
out.reserve(
|
|
515
|
+
out.reserve(numEntries * 2);
|
|
438
516
|
let lastValue = 0;
|
|
439
517
|
for (let i = 0; i < numEntries; i++) {
|
|
440
518
|
const code = sIn.readU8();
|
|
@@ -506,7 +584,13 @@ function decodePushInstructions(sIn, sOut, pushCount) {
|
|
|
506
584
|
}
|
|
507
585
|
while (remaining > 0) {
|
|
508
586
|
const code = sIn.peekU8();
|
|
509
|
-
if (code === 251
|
|
587
|
+
if (code === 251) {
|
|
588
|
+
if (remaining < 3 || data.length < 2) {
|
|
589
|
+
throw new EotError(
|
|
590
|
+
"CORRUPT_HOPCODE_DATA",
|
|
591
|
+
`corrupt hop3 (0xFB) push data: remaining=${remaining}, decoded=${data.length}`
|
|
592
|
+
);
|
|
593
|
+
}
|
|
510
594
|
sIn.readU8();
|
|
511
595
|
const prev = data[data.length - 2];
|
|
512
596
|
put(prev);
|
|
@@ -514,7 +598,13 @@ function decodePushInstructions(sIn, sOut, pushCount) {
|
|
|
514
598
|
put(val);
|
|
515
599
|
put(prev);
|
|
516
600
|
remaining -= 3;
|
|
517
|
-
} else if (code === 252
|
|
601
|
+
} else if (code === 252) {
|
|
602
|
+
if (remaining < 5 || data.length < 2) {
|
|
603
|
+
throw new EotError(
|
|
604
|
+
"CORRUPT_HOPCODE_DATA",
|
|
605
|
+
`corrupt hop4 (0xFC) push data: remaining=${remaining}, decoded=${data.length}`
|
|
606
|
+
);
|
|
607
|
+
}
|
|
518
608
|
sIn.readU8();
|
|
519
609
|
const prev = data[data.length - 2];
|
|
520
610
|
put(prev);
|
|
@@ -608,8 +698,8 @@ function decodeSimpleGlyph(numContours, streams, out, calcBBox, minX, minY, maxX
|
|
|
608
698
|
}
|
|
609
699
|
xDeltas[i] = dx;
|
|
610
700
|
yDeltas[i] = dy;
|
|
611
|
-
cumulativeX +=
|
|
612
|
-
cumulativeY +=
|
|
701
|
+
cumulativeX += xDeltas[i];
|
|
702
|
+
cumulativeY += yDeltas[i];
|
|
613
703
|
if (calcBBox) {
|
|
614
704
|
if (cumulativeX < minX) {
|
|
615
705
|
minX = cumulativeX;
|
|
@@ -813,8 +903,9 @@ function parseMaxp(table) {
|
|
|
813
903
|
maxComponentElements
|
|
814
904
|
};
|
|
815
905
|
}
|
|
816
|
-
function parseCTF(streams) {
|
|
906
|
+
function parseCTF(streams, options) {
|
|
817
907
|
const s0 = streams[0];
|
|
908
|
+
const droppedTables = [];
|
|
818
909
|
s0.readU32();
|
|
819
910
|
const numTables = s0.readU16();
|
|
820
911
|
s0.readU16();
|
|
@@ -825,10 +916,13 @@ function parseCTF(streams) {
|
|
|
825
916
|
let locaIdx = -1;
|
|
826
917
|
let maxpIdx = -1;
|
|
827
918
|
let headIdx = -1;
|
|
919
|
+
let hmtxIdx = -1;
|
|
828
920
|
for (let i = 0; i < numTables; i++) {
|
|
829
921
|
const tag = s0.readChar() + s0.readChar() + s0.readChar() + s0.readChar();
|
|
830
922
|
if (tag === "hdmx" || tag === "VDMX") {
|
|
831
923
|
s0.seekRelative(12);
|
|
924
|
+
droppedTables.push(tag);
|
|
925
|
+
options?.onWarn?.(`Ignoring ${tag} table \u2014 MTX does not preserve it`);
|
|
832
926
|
continue;
|
|
833
927
|
}
|
|
834
928
|
s0.seekRelative(4);
|
|
@@ -851,6 +945,8 @@ function parseCTF(streams) {
|
|
|
851
945
|
maxpIdx = idx;
|
|
852
946
|
} else if (tag === "head") {
|
|
853
947
|
headIdx = idx;
|
|
948
|
+
} else if (tag === "hmtx") {
|
|
949
|
+
hmtxIdx = idx;
|
|
854
950
|
} else ;
|
|
855
951
|
}
|
|
856
952
|
for (let i = 0; i < tables.length; i++) {
|
|
@@ -869,26 +965,29 @@ function parseCTF(streams) {
|
|
|
869
965
|
}
|
|
870
966
|
table.buf = buf;
|
|
871
967
|
if (table.tag === "head") {
|
|
968
|
+
if (table.bufSize < 12) {
|
|
969
|
+
throw new EotError(
|
|
970
|
+
"MALFORMED_HEAD_TABLE",
|
|
971
|
+
`head table too small: ${table.bufSize} bytes (need at least 12)`
|
|
972
|
+
);
|
|
973
|
+
}
|
|
872
974
|
table.buf[8] = 0;
|
|
873
975
|
table.buf[9] = 0;
|
|
874
976
|
table.buf[10] = 0;
|
|
875
977
|
table.buf[11] = 0;
|
|
876
978
|
}
|
|
877
979
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
headData = parseHead(tables[headIdx]);
|
|
980
|
+
if (maxpIdx < 0) {
|
|
981
|
+
throw new EotError("NO_MAXP_TABLE", "CTF font is missing a maxp table");
|
|
881
982
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
maxPoints: 0,
|
|
885
|
-
maxContours: 0,
|
|
886
|
-
maxSizeOfInstructions: 0,
|
|
887
|
-
maxComponentElements: 0
|
|
888
|
-
};
|
|
889
|
-
if (maxpIdx >= 0) {
|
|
890
|
-
maxpData = parseMaxp(tables[maxpIdx]);
|
|
983
|
+
if (headIdx < 0) {
|
|
984
|
+
throw new EotError("NO_HEAD_TABLE", "CTF font is missing a head table");
|
|
891
985
|
}
|
|
986
|
+
if (hmtxIdx < 0) {
|
|
987
|
+
throw new EotError("NO_HMTX_TABLE", "CTF font is missing an hmtx table");
|
|
988
|
+
}
|
|
989
|
+
const headData = parseHead(tables[headIdx]);
|
|
990
|
+
const maxpData = parseMaxp(tables[maxpIdx]);
|
|
892
991
|
if (glyfIdx >= 0) {
|
|
893
992
|
if (locaIdx < 0) {
|
|
894
993
|
const locaTable = {
|
|
@@ -903,11 +1002,11 @@ function parseCTF(streams) {
|
|
|
903
1002
|
}
|
|
904
1003
|
populateGlyfAndLoca(tables[glyfIdx], tables[locaIdx], headData, maxpData, streams);
|
|
905
1004
|
}
|
|
906
|
-
return { tables };
|
|
1005
|
+
return droppedTables.length > 0 ? { tables, droppedTables } : { tables };
|
|
907
1006
|
}
|
|
908
1007
|
function bitsUsed(x) {
|
|
909
1008
|
if (x <= 0) {
|
|
910
|
-
return
|
|
1009
|
+
return 1;
|
|
911
1010
|
}
|
|
912
1011
|
return 32 - Math.clz32(x);
|
|
913
1012
|
}
|
|
@@ -1099,12 +1198,15 @@ var BitIO = class {
|
|
|
1099
1198
|
/**
|
|
1100
1199
|
* @param data Source byte buffer.
|
|
1101
1200
|
* @param offset Starting byte offset into `data`.
|
|
1102
|
-
* @param size
|
|
1201
|
+
* @param size Absolute end index into `data` (exclusive) — reading stops
|
|
1202
|
+
* once `index` reaches it. Defaults to `data.length`. Clamped
|
|
1203
|
+
* to `data.length` so an over-large value cannot read past the
|
|
1204
|
+
* end of the buffer and silently yield zero bits.
|
|
1103
1205
|
*/
|
|
1104
1206
|
constructor(data, offset = 0, size) {
|
|
1105
1207
|
this.data = data;
|
|
1106
1208
|
this.index = offset;
|
|
1107
|
-
this.size = size ?? data.length;
|
|
1209
|
+
this.size = Math.min(size ?? data.length, data.length);
|
|
1108
1210
|
}
|
|
1109
1211
|
/**
|
|
1110
1212
|
* Read a single bit from the stream.
|
|
@@ -1117,13 +1219,14 @@ var BitIO = class {
|
|
|
1117
1219
|
* shifted out of the original byte value).
|
|
1118
1220
|
*/
|
|
1119
1221
|
inputBit() {
|
|
1120
|
-
if (this.bitCount
|
|
1222
|
+
if (this.bitCount === 0) {
|
|
1121
1223
|
if (this.index >= this.size) {
|
|
1122
1224
|
throw new Error("BitIO: end of data");
|
|
1123
1225
|
}
|
|
1124
1226
|
this.bitBuffer = this.data[this.index++];
|
|
1125
|
-
this.bitCount =
|
|
1227
|
+
this.bitCount = 8;
|
|
1126
1228
|
}
|
|
1229
|
+
this.bitCount--;
|
|
1127
1230
|
this.bitBuffer <<= 1;
|
|
1128
1231
|
return (this.bitBuffer & 256) !== 0;
|
|
1129
1232
|
}
|
|
@@ -1141,7 +1244,7 @@ var BitIO = class {
|
|
|
1141
1244
|
value |= 1;
|
|
1142
1245
|
}
|
|
1143
1246
|
}
|
|
1144
|
-
return value;
|
|
1247
|
+
return value >>> 0;
|
|
1145
1248
|
}
|
|
1146
1249
|
};
|
|
1147
1250
|
var LEN_WIDTH = 3;
|
|
@@ -1151,8 +1254,8 @@ var MAX_2BYTE_DIST = 512;
|
|
|
1151
1254
|
var PRELOAD_SIZE = 2 * 32 * 96 + 4 * 256;
|
|
1152
1255
|
var LEN_MIN = 2;
|
|
1153
1256
|
var DIST_MIN = 1;
|
|
1154
|
-
var MAX_OUT_LEN =
|
|
1155
|
-
var MAX_OUT =
|
|
1257
|
+
var MAX_OUT_LEN = (1 << 24) - 1;
|
|
1258
|
+
var MAX_OUT = 64 * 1024 * 1024;
|
|
1156
1259
|
var RLE_INITIAL = 0;
|
|
1157
1260
|
var RLE_NORMAL = 1;
|
|
1158
1261
|
var RLE_SEEN_ESCAPE = 2;
|
|
@@ -1324,7 +1427,8 @@ function lzcompDecompress(data, size, version) {
|
|
|
1324
1427
|
}
|
|
1325
1428
|
}
|
|
1326
1429
|
};
|
|
1327
|
-
|
|
1430
|
+
let pos2 = 0;
|
|
1431
|
+
for (; pos2 < outLen; ) {
|
|
1328
1432
|
const symbol = symEcoder.readSymbol();
|
|
1329
1433
|
let value;
|
|
1330
1434
|
if (symbol < 256) {
|
|
@@ -1355,6 +1459,12 @@ function lzcompDecompress(data, size, version) {
|
|
|
1355
1459
|
pos2++;
|
|
1356
1460
|
emitByte(value);
|
|
1357
1461
|
}
|
|
1462
|
+
if (pos2 !== outLen) {
|
|
1463
|
+
throw new EotError(
|
|
1464
|
+
"MTX_ERROR",
|
|
1465
|
+
`LZCOMP decode overran output: pos=${pos2}, expected=${outLen}`
|
|
1466
|
+
);
|
|
1467
|
+
}
|
|
1358
1468
|
return outBuf.subarray(0, outIdx);
|
|
1359
1469
|
}
|
|
1360
1470
|
function lgFloor(n) {
|
|
@@ -1458,14 +1568,18 @@ function dumpContainer(ctr) {
|
|
|
1458
1568
|
beginningChecksum = beginningChecksum + word >>> 0;
|
|
1459
1569
|
}
|
|
1460
1570
|
totalChecksum = totalChecksum + beginningChecksum >>> 0;
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
buf[adjOffset + 2] = finalChecksum >>> 8 & 255;
|
|
1467
|
-
buf[adjOffset + 3] = finalChecksum & 255;
|
|
1571
|
+
if (!headTable) {
|
|
1572
|
+
throw new EotError(
|
|
1573
|
+
"NO_HEAD_TABLE",
|
|
1574
|
+
"cannot assemble SFNT: container is missing a head table"
|
|
1575
|
+
);
|
|
1468
1576
|
}
|
|
1577
|
+
const finalChecksum = 2981146554 - totalChecksum >>> 0;
|
|
1578
|
+
const adjOffset = headTable.offset + 8;
|
|
1579
|
+
buf[adjOffset] = finalChecksum >>> 24 & 255;
|
|
1580
|
+
buf[adjOffset + 1] = finalChecksum >>> 16 & 255;
|
|
1581
|
+
buf[adjOffset + 2] = finalChecksum >>> 8 & 255;
|
|
1582
|
+
buf[adjOffset + 3] = finalChecksum & 255;
|
|
1469
1583
|
out.pos = afterTables;
|
|
1470
1584
|
return out.buf.subarray(0, out.pos);
|
|
1471
1585
|
}
|
|
@@ -1511,14 +1625,64 @@ function decompressMtx(fontData, options) {
|
|
|
1511
1625
|
}
|
|
1512
1626
|
const { streams } = unpackMtx(data, data.length);
|
|
1513
1627
|
const streamObjects = streams.map((buf) => new Stream(buf, buf.length));
|
|
1514
|
-
const container = parseCTF(streamObjects);
|
|
1628
|
+
const container = parseCTF(streamObjects, { onWarn: options?.onWarn });
|
|
1515
1629
|
return dumpContainer(container);
|
|
1516
1630
|
}
|
|
1517
1631
|
function decompressEotFont(fontData, compressed, encrypted) {
|
|
1518
1632
|
return decompressMtx(fontData, { encrypted});
|
|
1519
1633
|
}
|
|
1520
1634
|
|
|
1521
|
-
// ../../node_modules/.bun/emf-converter@1.
|
|
1635
|
+
// ../../node_modules/.bun/emf-converter@1.6.0/node_modules/emf-converter/dist/index.mjs
|
|
1636
|
+
function colorRefToHex(r, g, b) {
|
|
1637
|
+
const toHex3 = (v) => v.toString(16).padStart(2, "0");
|
|
1638
|
+
return `#${toHex3(r & 255)}${toHex3(g & 255)}${toHex3(b & 255)}`;
|
|
1639
|
+
}
|
|
1640
|
+
function readColorRef(view, offset) {
|
|
1641
|
+
const r = view.getUint8(offset);
|
|
1642
|
+
const g = view.getUint8(offset + 1);
|
|
1643
|
+
const b = view.getUint8(offset + 2);
|
|
1644
|
+
return colorRefToHex(r, g, b);
|
|
1645
|
+
}
|
|
1646
|
+
function argbToRgba(argb) {
|
|
1647
|
+
const a = (argb >>> 24 & 255) / 255;
|
|
1648
|
+
const r = argb >>> 16 & 255;
|
|
1649
|
+
const g = argb >>> 8 & 255;
|
|
1650
|
+
const b = argb & 255;
|
|
1651
|
+
return `rgba(${r},${g},${b},${a.toFixed(3)})`;
|
|
1652
|
+
}
|
|
1653
|
+
function lerpArgbToRgba(argbA, argbB, t) {
|
|
1654
|
+
const tc = Math.min(1, Math.max(0, t));
|
|
1655
|
+
const mix = (a2, b2) => Math.round(a2 + (b2 - a2) * tc);
|
|
1656
|
+
const aA = argbA >>> 24 & 255;
|
|
1657
|
+
const aB = argbB >>> 24 & 255;
|
|
1658
|
+
const r = mix(argbA >>> 16 & 255, argbB >>> 16 & 255);
|
|
1659
|
+
const g = mix(argbA >>> 8 & 255, argbB >>> 8 & 255);
|
|
1660
|
+
const b = mix(argbA & 255, argbB & 255);
|
|
1661
|
+
const a = mix(aA, aB) / 255;
|
|
1662
|
+
return `rgba(${r},${g},${b},${a.toFixed(3)})`;
|
|
1663
|
+
}
|
|
1664
|
+
function invertCssColor(color2) {
|
|
1665
|
+
const hex10 = /^#([0-9a-f]{6})$/i.exec(color2);
|
|
1666
|
+
if (hex10) {
|
|
1667
|
+
const v = parseInt(hex10[1], 16);
|
|
1668
|
+
const inv = 16777215 ^ v;
|
|
1669
|
+
return `#${inv.toString(16).padStart(6, "0")}`;
|
|
1670
|
+
}
|
|
1671
|
+
const shortHex = /^#([0-9a-f]{3})$/i.exec(color2);
|
|
1672
|
+
if (shortHex) {
|
|
1673
|
+
const [r, g, b] = shortHex[1].split("").map((c) => parseInt(c + c, 16));
|
|
1674
|
+
const toHex3 = (v) => (255 - v).toString(16).padStart(2, "0");
|
|
1675
|
+
return `#${toHex3(r)}${toHex3(g)}${toHex3(b)}`;
|
|
1676
|
+
}
|
|
1677
|
+
const rgba = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(color2);
|
|
1678
|
+
if (rgba) {
|
|
1679
|
+
const r = 255 - Math.min(255, parseInt(rgba[1], 10));
|
|
1680
|
+
const g = 255 - Math.min(255, parseInt(rgba[2], 10));
|
|
1681
|
+
const b = 255 - Math.min(255, parseInt(rgba[3], 10));
|
|
1682
|
+
return rgba[4] !== void 0 ? `rgba(${r},${g},${b},${rgba[4]})` : `rgb(${r},${g},${b})`;
|
|
1683
|
+
}
|
|
1684
|
+
return color2;
|
|
1685
|
+
}
|
|
1522
1686
|
var EMR_HEADER = 1;
|
|
1523
1687
|
var EMR_POLYBEZIER = 2;
|
|
1524
1688
|
var EMR_POLYGON = 3;
|
|
@@ -1539,10 +1703,21 @@ var EMR_SETBKMODE = 18;
|
|
|
1539
1703
|
var EMR_SETPOLYFILLMODE = 19;
|
|
1540
1704
|
var EMR_SETROP2 = 20;
|
|
1541
1705
|
var EMR_SETSTRETCHBLTMODE = 21;
|
|
1706
|
+
var R2_BLACK = 1;
|
|
1707
|
+
var R2_NOTMERGEPEN = 2;
|
|
1708
|
+
var R2_MASKNOTPEN = 3;
|
|
1709
|
+
var R2_NOTCOPYPEN = 4;
|
|
1710
|
+
var R2_MASKPENNOT = 5;
|
|
1542
1711
|
var R2_NOT = 6;
|
|
1543
1712
|
var R2_XORPEN = 7;
|
|
1713
|
+
var R2_NOTMASKPEN = 8;
|
|
1544
1714
|
var R2_MASKPEN = 9;
|
|
1715
|
+
var R2_NOTXORPEN = 10;
|
|
1716
|
+
var R2_NOP = 11;
|
|
1717
|
+
var R2_MERGENOTPEN = 12;
|
|
1718
|
+
var R2_MERGEPENNOT = 14;
|
|
1545
1719
|
var R2_MERGEPEN = 15;
|
|
1720
|
+
var R2_WHITE = 16;
|
|
1546
1721
|
var MAX_CANVAS_DIMENSION = 8192;
|
|
1547
1722
|
var MAX_RECORDS_DEFAULT = 2e5;
|
|
1548
1723
|
var MAX_RECORDS_EMFPLUS_DEFAULT = 5e5;
|
|
@@ -1773,28 +1948,61 @@ function createTempCanvas(width, height) {
|
|
|
1773
1948
|
}
|
|
1774
1949
|
return null;
|
|
1775
1950
|
}
|
|
1776
|
-
function
|
|
1951
|
+
function rop2Paint(rop2) {
|
|
1777
1952
|
switch (rop2) {
|
|
1953
|
+
case R2_BLACK:
|
|
1954
|
+
return { gco: "source-over", colorTransform: "black", exact: true };
|
|
1955
|
+
case R2_WHITE:
|
|
1956
|
+
return { gco: "source-over", colorTransform: "white", exact: true };
|
|
1957
|
+
case R2_NOP:
|
|
1958
|
+
return { gco: "source-over", colorTransform: "skip", exact: true };
|
|
1959
|
+
case R2_NOTCOPYPEN:
|
|
1960
|
+
return { gco: "source-over", colorTransform: "invert", exact: true };
|
|
1961
|
+
case R2_NOT:
|
|
1962
|
+
return { gco: "difference", colorTransform: "white", exact: true };
|
|
1778
1963
|
case R2_XORPEN:
|
|
1779
|
-
|
|
1964
|
+
case R2_MASKPENNOT:
|
|
1965
|
+
return { gco: "difference", colorTransform: "none", exact: false };
|
|
1966
|
+
case R2_NOTXORPEN:
|
|
1967
|
+
return { gco: "difference", colorTransform: "invert", exact: false };
|
|
1780
1968
|
case R2_MASKPEN:
|
|
1781
|
-
return "
|
|
1969
|
+
return { gco: "darken", colorTransform: "none", exact: false };
|
|
1970
|
+
case R2_MASKNOTPEN:
|
|
1971
|
+
case R2_NOTMERGEPEN:
|
|
1972
|
+
return { gco: "darken", colorTransform: "invert", exact: false };
|
|
1782
1973
|
case R2_MERGEPEN:
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1974
|
+
case R2_MERGEPENNOT:
|
|
1975
|
+
return { gco: "lighten", colorTransform: "none", exact: false };
|
|
1976
|
+
case R2_MERGENOTPEN:
|
|
1977
|
+
case R2_NOTMASKPEN:
|
|
1978
|
+
return { gco: "lighten", colorTransform: "invert", exact: false };
|
|
1786
1979
|
default:
|
|
1787
|
-
return "source-over";
|
|
1980
|
+
return { gco: "source-over", colorTransform: "none", exact: true };
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
function rop2TransformColor(color2, transform) {
|
|
1984
|
+
switch (transform) {
|
|
1985
|
+
case "invert":
|
|
1986
|
+
return invertCssColor(color2);
|
|
1987
|
+
case "black":
|
|
1988
|
+
return "#000000";
|
|
1989
|
+
case "white":
|
|
1990
|
+
return "#ffffff";
|
|
1991
|
+
case "skip":
|
|
1992
|
+
return "rgba(0,0,0,0)";
|
|
1993
|
+
default:
|
|
1994
|
+
return color2;
|
|
1788
1995
|
}
|
|
1789
1996
|
}
|
|
1790
1997
|
function applyPen(ctx, state) {
|
|
1791
|
-
|
|
1998
|
+
const paint = rop2Paint(state.rop2);
|
|
1999
|
+
ctx.globalCompositeOperation = paint.gco;
|
|
1792
2000
|
if (state.penStyle === 5) {
|
|
1793
2001
|
ctx.strokeStyle = "rgba(0,0,0,0)";
|
|
1794
2002
|
ctx.lineWidth = 0;
|
|
1795
2003
|
return;
|
|
1796
2004
|
}
|
|
1797
|
-
ctx.strokeStyle = state.penColor;
|
|
2005
|
+
ctx.strokeStyle = rop2TransformColor(state.penColor, paint.colorTransform);
|
|
1798
2006
|
ctx.lineWidth = Math.max(state.penWidth, 1);
|
|
1799
2007
|
switch (state.penStyle) {
|
|
1800
2008
|
case 1:
|
|
@@ -1815,12 +2023,13 @@ function applyPen(ctx, state) {
|
|
|
1815
2023
|
}
|
|
1816
2024
|
}
|
|
1817
2025
|
function applyBrush(ctx, state) {
|
|
1818
|
-
|
|
2026
|
+
const paint = rop2Paint(state.rop2);
|
|
2027
|
+
ctx.globalCompositeOperation = paint.gco;
|
|
1819
2028
|
if (state.brushStyle === 1) {
|
|
1820
2029
|
ctx.fillStyle = "rgba(0,0,0,0)";
|
|
1821
2030
|
return;
|
|
1822
2031
|
}
|
|
1823
|
-
ctx.fillStyle = state.brushColor;
|
|
2032
|
+
ctx.fillStyle = rop2TransformColor(state.brushColor, paint.colorTransform);
|
|
1824
2033
|
}
|
|
1825
2034
|
function cssFontWeight(weight) {
|
|
1826
2035
|
if (!weight || weight === 400) {
|
|
@@ -2051,46 +2260,35 @@ function parseWmfHeader(view) {
|
|
|
2051
2260
|
unitsPerInch
|
|
2052
2261
|
};
|
|
2053
2262
|
}
|
|
2054
|
-
function colorRefToHex(r, g, b) {
|
|
2055
|
-
const toHex3 = (v) => v.toString(16).padStart(2, "0");
|
|
2056
|
-
return `#${toHex3(r & 255)}${toHex3(g & 255)}${toHex3(b & 255)}`;
|
|
2057
|
-
}
|
|
2058
|
-
function readColorRef(view, offset) {
|
|
2059
|
-
const r = view.getUint8(offset);
|
|
2060
|
-
const g = view.getUint8(offset + 1);
|
|
2061
|
-
const b = view.getUint8(offset + 2);
|
|
2062
|
-
return colorRefToHex(r, g, b);
|
|
2063
|
-
}
|
|
2064
|
-
function argbToRgba(argb) {
|
|
2065
|
-
const a = (argb >>> 24 & 255) / 255;
|
|
2066
|
-
const r = argb >>> 16 & 255;
|
|
2067
|
-
const g = argb >>> 8 & 255;
|
|
2068
|
-
const b = argb & 255;
|
|
2069
|
-
return `rgba(${r},${g},${b},${a.toFixed(3)})`;
|
|
2070
|
-
}
|
|
2071
2263
|
function gmx(r, x) {
|
|
2264
|
+
const wt = r.state.worldTransform;
|
|
2265
|
+
const px2 = wt[0] * x + wt[4];
|
|
2072
2266
|
if (r.useMappingMode) {
|
|
2073
|
-
return (
|
|
2267
|
+
return (px2 - r.windowOrg.x) / (r.windowExt.cx || 1) * (r.viewportExt.cx || 1) + r.viewportOrg.x;
|
|
2074
2268
|
}
|
|
2075
|
-
return (
|
|
2269
|
+
return (px2 - r.bounds.left) * r.sx;
|
|
2076
2270
|
}
|
|
2077
2271
|
function gmy(r, y) {
|
|
2272
|
+
const wt = r.state.worldTransform;
|
|
2273
|
+
const py = wt[3] * y + wt[5];
|
|
2078
2274
|
if (r.useMappingMode) {
|
|
2079
|
-
return (
|
|
2275
|
+
return (py - r.windowOrg.y) / (r.windowExt.cy || 1) * (r.viewportExt.cy || 1) + r.viewportOrg.y;
|
|
2080
2276
|
}
|
|
2081
|
-
return (
|
|
2277
|
+
return (py - r.bounds.top) * r.sy;
|
|
2082
2278
|
}
|
|
2083
2279
|
function gmw(r, w) {
|
|
2280
|
+
const pw = r.state.worldTransform[0] * w;
|
|
2084
2281
|
if (r.useMappingMode) {
|
|
2085
|
-
return
|
|
2282
|
+
return pw / (r.windowExt.cx || 1) * (r.viewportExt.cx || 1);
|
|
2086
2283
|
}
|
|
2087
|
-
return
|
|
2284
|
+
return pw * r.sx;
|
|
2088
2285
|
}
|
|
2089
2286
|
function gmh(r, h) {
|
|
2287
|
+
const ph = r.state.worldTransform[3] * h;
|
|
2090
2288
|
if (r.useMappingMode) {
|
|
2091
|
-
return
|
|
2289
|
+
return ph / (r.windowExt.cy || 1) * (r.viewportExt.cy || 1);
|
|
2092
2290
|
}
|
|
2093
|
-
return
|
|
2291
|
+
return ph * r.sy;
|
|
2094
2292
|
}
|
|
2095
2293
|
function activateGdiMappingMode(r) {
|
|
2096
2294
|
r.useMappingMode = true;
|
|
@@ -2291,6 +2489,216 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
|
|
|
2291
2489
|
return false;
|
|
2292
2490
|
}
|
|
2293
2491
|
}
|
|
2492
|
+
var CLIP_HUGE = 1 << 24;
|
|
2493
|
+
function rectClipShape(x, y, w, h) {
|
|
2494
|
+
return { cmds: [{ op: "rect", x, y, w, h }], fillRule: "nonzero", simple: true };
|
|
2495
|
+
}
|
|
2496
|
+
function rectsClipShape(rects) {
|
|
2497
|
+
return {
|
|
2498
|
+
cmds: rects.map((r) => ({ op: "rect", x: r.x, y: r.y, w: r.w, h: r.h })),
|
|
2499
|
+
fillRule: "nonzero",
|
|
2500
|
+
simple: true
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
function emptyClipShape() {
|
|
2504
|
+
return { cmds: [{ op: "rect", x: 0, y: 0, w: 0, h: 0 }], fillRule: "nonzero", simple: true };
|
|
2505
|
+
}
|
|
2506
|
+
function translateClipShape(shape, dx, dy) {
|
|
2507
|
+
return {
|
|
2508
|
+
...shape,
|
|
2509
|
+
cmds: shape.cmds.map((c) => {
|
|
2510
|
+
switch (c.op) {
|
|
2511
|
+
case "rect":
|
|
2512
|
+
return { ...c, x: c.x + dx, y: c.y + dy };
|
|
2513
|
+
case "moveTo":
|
|
2514
|
+
case "lineTo":
|
|
2515
|
+
return { ...c, x: c.x + dx, y: c.y + dy };
|
|
2516
|
+
case "bezierCurveTo":
|
|
2517
|
+
return {
|
|
2518
|
+
...c,
|
|
2519
|
+
cp1x: c.cp1x + dx,
|
|
2520
|
+
cp1y: c.cp1y + dy,
|
|
2521
|
+
cp2x: c.cp2x + dx,
|
|
2522
|
+
cp2y: c.cp2y + dy,
|
|
2523
|
+
x: c.x + dx,
|
|
2524
|
+
y: c.y + dy
|
|
2525
|
+
};
|
|
2526
|
+
case "closePath":
|
|
2527
|
+
return c;
|
|
2528
|
+
}
|
|
2529
|
+
})
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
function translateClipRegion(region, dx, dy) {
|
|
2533
|
+
if (!region) {
|
|
2534
|
+
return null;
|
|
2535
|
+
}
|
|
2536
|
+
return region.map((s) => translateClipShape(s, dx, dy));
|
|
2537
|
+
}
|
|
2538
|
+
function isComposable(shape) {
|
|
2539
|
+
return shape.simple && shape.fillRule === "nonzero";
|
|
2540
|
+
}
|
|
2541
|
+
function invertClipShape(shape) {
|
|
2542
|
+
return {
|
|
2543
|
+
cmds: [
|
|
2544
|
+
{ op: "rect", x: -CLIP_HUGE, y: -CLIP_HUGE, w: 2 * CLIP_HUGE, h: 2 * CLIP_HUGE },
|
|
2545
|
+
...shape.cmds
|
|
2546
|
+
],
|
|
2547
|
+
fillRule: "evenodd",
|
|
2548
|
+
simple: false
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
function combineClip(current, shape, op) {
|
|
2552
|
+
switch (op) {
|
|
2553
|
+
case "replace":
|
|
2554
|
+
return { region: [shape], exact: true };
|
|
2555
|
+
case "intersect":
|
|
2556
|
+
return { region: current ? [...current, shape] : [shape], exact: true };
|
|
2557
|
+
case "exclude": {
|
|
2558
|
+
if (!isComposable(shape)) {
|
|
2559
|
+
return { region: current ? [...current, shape] : [shape], exact: false };
|
|
2560
|
+
}
|
|
2561
|
+
const inv = invertClipShape(shape);
|
|
2562
|
+
return { region: current ? [...current, inv] : [inv], exact: true };
|
|
2563
|
+
}
|
|
2564
|
+
case "union": {
|
|
2565
|
+
if (!current) {
|
|
2566
|
+
return { region: null, exact: true };
|
|
2567
|
+
}
|
|
2568
|
+
if (current.length === 1 && isComposable(current[0]) && isComposable(shape)) {
|
|
2569
|
+
return {
|
|
2570
|
+
region: [
|
|
2571
|
+
{ cmds: [...current[0].cmds, ...shape.cmds], fillRule: "nonzero", simple: false }
|
|
2572
|
+
],
|
|
2573
|
+
exact: false
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
return { region: current, exact: false };
|
|
2577
|
+
}
|
|
2578
|
+
case "xor": {
|
|
2579
|
+
if (!current) {
|
|
2580
|
+
if (isComposable(shape)) {
|
|
2581
|
+
return { region: [invertClipShape(shape)], exact: true };
|
|
2582
|
+
}
|
|
2583
|
+
return { region: [shape], exact: false };
|
|
2584
|
+
}
|
|
2585
|
+
if (current.length === 1 && isComposable(current[0]) && isComposable(shape)) {
|
|
2586
|
+
return {
|
|
2587
|
+
region: [
|
|
2588
|
+
{ cmds: [...current[0].cmds, ...shape.cmds], fillRule: "evenodd", simple: false }
|
|
2589
|
+
],
|
|
2590
|
+
exact: true
|
|
2591
|
+
};
|
|
2592
|
+
}
|
|
2593
|
+
if (isComposable(shape)) {
|
|
2594
|
+
return { region: [...current, invertClipShape(shape)], exact: false };
|
|
2595
|
+
}
|
|
2596
|
+
return { region: [...current, shape], exact: false };
|
|
2597
|
+
}
|
|
2598
|
+
case "complement": {
|
|
2599
|
+
if (!current) {
|
|
2600
|
+
return { region: [emptyClipShape()], exact: true };
|
|
2601
|
+
}
|
|
2602
|
+
if (current.length === 1 && isComposable(current[0])) {
|
|
2603
|
+
return { region: [shape, invertClipShape(current[0])], exact: true };
|
|
2604
|
+
}
|
|
2605
|
+
return { region: [shape], exact: false };
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
function combineClipRegions(current, incoming, op) {
|
|
2610
|
+
if (op === "replace") {
|
|
2611
|
+
return { region: incoming, exact: true };
|
|
2612
|
+
}
|
|
2613
|
+
if (incoming && incoming.length === 1) {
|
|
2614
|
+
return combineClip(current, incoming[0], op);
|
|
2615
|
+
}
|
|
2616
|
+
if (!incoming) {
|
|
2617
|
+
switch (op) {
|
|
2618
|
+
case "intersect":
|
|
2619
|
+
return { region: current, exact: true };
|
|
2620
|
+
case "union":
|
|
2621
|
+
return { region: null, exact: true };
|
|
2622
|
+
case "exclude":
|
|
2623
|
+
return { region: [emptyClipShape()], exact: true };
|
|
2624
|
+
case "xor":
|
|
2625
|
+
case "complement": {
|
|
2626
|
+
if (!current) {
|
|
2627
|
+
return { region: [emptyClipShape()], exact: true };
|
|
2628
|
+
}
|
|
2629
|
+
if (current.length === 1) {
|
|
2630
|
+
return combineClip(null, current[0], "exclude");
|
|
2631
|
+
}
|
|
2632
|
+
return { region: current, exact: false };
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
switch (op) {
|
|
2637
|
+
case "intersect":
|
|
2638
|
+
return { region: current ? [...current, ...incoming] : incoming, exact: true };
|
|
2639
|
+
case "union":
|
|
2640
|
+
return { region: current, exact: false };
|
|
2641
|
+
case "xor":
|
|
2642
|
+
return { region: current ?? incoming, exact: false };
|
|
2643
|
+
case "exclude":
|
|
2644
|
+
return { region: current, exact: false };
|
|
2645
|
+
case "complement": {
|
|
2646
|
+
if (!current) {
|
|
2647
|
+
return { region: [emptyClipShape()], exact: true };
|
|
2648
|
+
}
|
|
2649
|
+
if (current.length === 1) {
|
|
2650
|
+
return combineClip(incoming, current[0], "exclude");
|
|
2651
|
+
}
|
|
2652
|
+
return { region: incoming, exact: false };
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
function replayClipCmds(ctx, cmds) {
|
|
2657
|
+
for (const c of cmds) {
|
|
2658
|
+
switch (c.op) {
|
|
2659
|
+
case "rect":
|
|
2660
|
+
ctx.rect(c.x, c.y, c.w, c.h);
|
|
2661
|
+
break;
|
|
2662
|
+
case "moveTo":
|
|
2663
|
+
ctx.moveTo(c.x, c.y);
|
|
2664
|
+
break;
|
|
2665
|
+
case "lineTo":
|
|
2666
|
+
ctx.lineTo(c.x, c.y);
|
|
2667
|
+
break;
|
|
2668
|
+
case "bezierCurveTo":
|
|
2669
|
+
ctx.bezierCurveTo(c.cp1x, c.cp1y, c.cp2x, c.cp2y, c.x, c.y);
|
|
2670
|
+
break;
|
|
2671
|
+
case "closePath":
|
|
2672
|
+
ctx.closePath();
|
|
2673
|
+
break;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
function applyClipShapes(ctx, shapes) {
|
|
2678
|
+
for (const s of shapes) {
|
|
2679
|
+
ctx.beginPath();
|
|
2680
|
+
replayClipCmds(ctx, s.cmds);
|
|
2681
|
+
try {
|
|
2682
|
+
ctx.clip(s.fillRule);
|
|
2683
|
+
} catch {
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
function reapplyClipRegion(holder, region, identityTransform = false) {
|
|
2688
|
+
const { ctx } = holder;
|
|
2689
|
+
while (holder.clipSaveDepth > 0) {
|
|
2690
|
+
ctx.restore();
|
|
2691
|
+
holder.clipSaveDepth--;
|
|
2692
|
+
}
|
|
2693
|
+
if (region) {
|
|
2694
|
+
ctx.save();
|
|
2695
|
+
holder.clipSaveDepth = 1;
|
|
2696
|
+
if (identityTransform) {
|
|
2697
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
2698
|
+
}
|
|
2699
|
+
applyClipShapes(ctx, region);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2294
2702
|
function decodeRleBitmap(view, bitsOffset, bitsSize, width, height, _topDown, isRle4, colorTable, out, setPixel) {
|
|
2295
2703
|
let x = 0;
|
|
2296
2704
|
let y = height - 1;
|
|
@@ -2711,86 +3119,134 @@ function handleStretchDibits(rCtx, offset, dataOff, recSize) {
|
|
|
2711
3119
|
}
|
|
2712
3120
|
return true;
|
|
2713
3121
|
}
|
|
3122
|
+
function gdiCombineClip(rCtx, shape, op) {
|
|
3123
|
+
const { ctx } = rCtx;
|
|
3124
|
+
if (rCtx.clipUntracked && op !== "replace") {
|
|
3125
|
+
switch (op) {
|
|
3126
|
+
case "intersect":
|
|
3127
|
+
case "complement": {
|
|
3128
|
+
ctx.save();
|
|
3129
|
+
rCtx.clipSaveDepth++;
|
|
3130
|
+
applyClipShapes(ctx, [shape]);
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
case "exclude":
|
|
3134
|
+
case "xor": {
|
|
3135
|
+
const inv = combineClip(null, shape, "exclude");
|
|
3136
|
+
ctx.save();
|
|
3137
|
+
rCtx.clipSaveDepth++;
|
|
3138
|
+
applyClipShapes(ctx, inv.region ?? [shape]);
|
|
3139
|
+
return;
|
|
3140
|
+
}
|
|
3141
|
+
case "union":
|
|
3142
|
+
return;
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
const res = combineClip(op === "replace" ? null : rCtx.clipRegion ?? null, shape, op);
|
|
3146
|
+
if (!res.exact) ;
|
|
3147
|
+
rCtx.clipRegion = res.region;
|
|
3148
|
+
rCtx.clipUntracked = false;
|
|
3149
|
+
reapplyClipRegion(rCtx, res.region);
|
|
3150
|
+
}
|
|
3151
|
+
function readClipRectShape(rCtx, dataOff) {
|
|
3152
|
+
const { view } = rCtx;
|
|
3153
|
+
const left = view.getInt32(dataOff, true);
|
|
3154
|
+
const top = view.getInt32(dataOff + 4, true);
|
|
3155
|
+
const right = view.getInt32(dataOff + 8, true);
|
|
3156
|
+
const bottom = view.getInt32(dataOff + 12, true);
|
|
3157
|
+
return rectClipShape(
|
|
3158
|
+
gmx(rCtx, left),
|
|
3159
|
+
gmy(rCtx, top),
|
|
3160
|
+
gmw(rCtx, right - left),
|
|
3161
|
+
gmh(rCtx, bottom - top)
|
|
3162
|
+
);
|
|
3163
|
+
}
|
|
2714
3164
|
function handleIntersectClipRect(rCtx, dataOff, recSize) {
|
|
2715
|
-
const { ctx, view } = rCtx;
|
|
2716
3165
|
if (recSize >= 24) {
|
|
2717
|
-
|
|
2718
|
-
const top = view.getInt32(dataOff + 4, true);
|
|
2719
|
-
const right = view.getInt32(dataOff + 8, true);
|
|
2720
|
-
const bottom = view.getInt32(dataOff + 12, true);
|
|
2721
|
-
ctx.save();
|
|
2722
|
-
rCtx.clipSaveDepth++;
|
|
2723
|
-
ctx.beginPath();
|
|
2724
|
-
ctx.rect(gmx(rCtx, left), gmy(rCtx, top), gmw(rCtx, right - left), gmh(rCtx, bottom - top));
|
|
2725
|
-
try {
|
|
2726
|
-
ctx.clip();
|
|
2727
|
-
} catch {
|
|
2728
|
-
}
|
|
3166
|
+
gdiCombineClip(rCtx, readClipRectShape(rCtx, dataOff), "intersect");
|
|
2729
3167
|
}
|
|
2730
3168
|
return true;
|
|
2731
3169
|
}
|
|
3170
|
+
function handleExcludeClipRect(rCtx, dataOff, recSize) {
|
|
3171
|
+
if (recSize >= 24) {
|
|
3172
|
+
gdiCombineClip(rCtx, readClipRectShape(rCtx, dataOff), "exclude");
|
|
3173
|
+
}
|
|
3174
|
+
return true;
|
|
3175
|
+
}
|
|
3176
|
+
var RGN_MODE_OPS = {
|
|
3177
|
+
1: "intersect",
|
|
3178
|
+
// RGN_AND
|
|
3179
|
+
2: "union",
|
|
3180
|
+
// RGN_OR
|
|
3181
|
+
3: "xor",
|
|
3182
|
+
// RGN_XOR
|
|
3183
|
+
4: "exclude",
|
|
3184
|
+
// RGN_DIFF
|
|
3185
|
+
5: "replace"
|
|
3186
|
+
// RGN_COPY
|
|
3187
|
+
};
|
|
2732
3188
|
function handleExtSelectClipRgn(rCtx, dataOff, recSize) {
|
|
2733
|
-
const {
|
|
3189
|
+
const { view } = rCtx;
|
|
2734
3190
|
if (recSize < 16) {
|
|
2735
3191
|
return true;
|
|
2736
3192
|
}
|
|
2737
3193
|
const cbRgnData = view.getUint32(dataOff, true);
|
|
2738
3194
|
const iMode = view.getUint32(dataOff + 4, true);
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
if (cbRgnData < 32) {
|
|
2749
|
-
return true;
|
|
2750
|
-
}
|
|
2751
|
-
const nCount = view.getUint32(rgnStart + 8, true);
|
|
2752
|
-
if (nCount === 0) {
|
|
2753
|
-
return true;
|
|
2754
|
-
}
|
|
2755
|
-
while (rCtx.clipSaveDepth > 0) {
|
|
2756
|
-
ctx.restore();
|
|
2757
|
-
rCtx.clipSaveDepth--;
|
|
2758
|
-
}
|
|
2759
|
-
ctx.save();
|
|
2760
|
-
rCtx.clipSaveDepth++;
|
|
2761
|
-
ctx.beginPath();
|
|
2762
|
-
const rectsStart = rgnStart + 32;
|
|
2763
|
-
for (let i = 0; i < nCount; i++) {
|
|
2764
|
-
const rOff = rectsStart + i * 16;
|
|
2765
|
-
if (rOff + 16 > dataOff + 8 + cbRgnData) {
|
|
2766
|
-
break;
|
|
2767
|
-
}
|
|
2768
|
-
const left = view.getInt32(rOff, true);
|
|
2769
|
-
const top = view.getInt32(rOff + 4, true);
|
|
2770
|
-
const right = view.getInt32(rOff + 8, true);
|
|
2771
|
-
const bottom = view.getInt32(rOff + 12, true);
|
|
2772
|
-
ctx.rect(gmx(rCtx, left), gmy(rCtx, top), gmw(rCtx, right - left), gmh(rCtx, bottom - top));
|
|
3195
|
+
const op = RGN_MODE_OPS[iMode];
|
|
3196
|
+
if (!op) {
|
|
3197
|
+
return true;
|
|
3198
|
+
}
|
|
3199
|
+
if (cbRgnData === 0) {
|
|
3200
|
+
if (op === "replace") {
|
|
3201
|
+
rCtx.clipRegion = null;
|
|
3202
|
+
rCtx.clipUntracked = false;
|
|
3203
|
+
reapplyClipRegion(rCtx, null);
|
|
2773
3204
|
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
3205
|
+
return true;
|
|
3206
|
+
}
|
|
3207
|
+
const rgnStart = dataOff + 8;
|
|
3208
|
+
if (cbRgnData < 32) {
|
|
3209
|
+
return true;
|
|
3210
|
+
}
|
|
3211
|
+
const nCount = view.getUint32(rgnStart + 8, true);
|
|
3212
|
+
if (nCount === 0) {
|
|
3213
|
+
return true;
|
|
3214
|
+
}
|
|
3215
|
+
const rects = [];
|
|
3216
|
+
const rectsStart = rgnStart + 32;
|
|
3217
|
+
for (let i = 0; i < nCount; i++) {
|
|
3218
|
+
const rOff = rectsStart + i * 16;
|
|
3219
|
+
if (rOff + 16 > dataOff + 8 + cbRgnData) {
|
|
3220
|
+
break;
|
|
2777
3221
|
}
|
|
3222
|
+
const left = view.getInt32(rOff, true);
|
|
3223
|
+
const top = view.getInt32(rOff + 4, true);
|
|
3224
|
+
const right = view.getInt32(rOff + 8, true);
|
|
3225
|
+
const bottom = view.getInt32(rOff + 12, true);
|
|
3226
|
+
rects.push({
|
|
3227
|
+
x: gmx(rCtx, left),
|
|
3228
|
+
y: gmy(rCtx, top),
|
|
3229
|
+
w: gmw(rCtx, right - left),
|
|
3230
|
+
h: gmh(rCtx, bottom - top)
|
|
3231
|
+
});
|
|
2778
3232
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
function handleExcludeClipRect(rCtx, dataOff, recSize) {
|
|
2782
|
-
if (recSize >= 24) {
|
|
2783
|
-
rCtx.view.getInt32(dataOff, true);
|
|
2784
|
-
rCtx.view.getInt32(dataOff + 4, true);
|
|
2785
|
-
rCtx.view.getInt32(dataOff + 8, true);
|
|
2786
|
-
rCtx.view.getInt32(dataOff + 12, true);
|
|
3233
|
+
if (rects.length === 0) {
|
|
3234
|
+
return true;
|
|
2787
3235
|
}
|
|
3236
|
+
gdiCombineClip(rCtx, rectsClipShape(rects), op);
|
|
2788
3237
|
return true;
|
|
2789
3238
|
}
|
|
2790
3239
|
function handleOffsetClipRgn(rCtx, dataOff, recSize) {
|
|
2791
3240
|
if (recSize >= 16) {
|
|
2792
|
-
rCtx.view.getInt32(dataOff, true);
|
|
2793
|
-
rCtx.view.getInt32(dataOff + 4, true);
|
|
3241
|
+
const dx = rCtx.view.getInt32(dataOff, true);
|
|
3242
|
+
const dy = rCtx.view.getInt32(dataOff + 4, true);
|
|
3243
|
+
if (rCtx.clipUntracked) {
|
|
3244
|
+
return true;
|
|
3245
|
+
}
|
|
3246
|
+
if (rCtx.clipRegion) {
|
|
3247
|
+
rCtx.clipRegion = translateClipRegion(rCtx.clipRegion, gmw(rCtx, dx), gmh(rCtx, dy));
|
|
3248
|
+
reapplyClipRegion(rCtx, rCtx.clipRegion);
|
|
3249
|
+
}
|
|
2794
3250
|
}
|
|
2795
3251
|
return true;
|
|
2796
3252
|
}
|
|
@@ -3107,14 +3563,12 @@ function handleEmfGdiPolyPathRecord(rCtx, recType, offset, dataOff, recSize) {
|
|
|
3107
3563
|
ctx.restore();
|
|
3108
3564
|
rCtx.clipSaveDepth--;
|
|
3109
3565
|
}
|
|
3110
|
-
ctx.save();
|
|
3111
|
-
rCtx.clipSaveDepth++;
|
|
3112
|
-
ctx.clip();
|
|
3113
|
-
} else {
|
|
3114
|
-
ctx.save();
|
|
3115
|
-
rCtx.clipSaveDepth++;
|
|
3116
|
-
ctx.clip();
|
|
3117
3566
|
}
|
|
3567
|
+
ctx.save();
|
|
3568
|
+
rCtx.clipSaveDepth++;
|
|
3569
|
+
ctx.clip(state.polyFillMode === 2 ? "nonzero" : "evenodd");
|
|
3570
|
+
rCtx.clipRegion = null;
|
|
3571
|
+
rCtx.clipUntracked = true;
|
|
3118
3572
|
} catch {
|
|
3119
3573
|
}
|
|
3120
3574
|
return true;
|
|
@@ -3404,7 +3858,9 @@ function createEmfPlusState() {
|
|
|
3404
3858
|
objectTable: /* @__PURE__ */ new Map(),
|
|
3405
3859
|
worldTransform: [1, 0, 0, 1, 0, 0],
|
|
3406
3860
|
saveStack: [],
|
|
3407
|
-
saveIdMap: /* @__PURE__ */ new Map()
|
|
3861
|
+
saveIdMap: /* @__PURE__ */ new Map(),
|
|
3862
|
+
clipRegion: null,
|
|
3863
|
+
clipSaveDepth: 0
|
|
3408
3864
|
};
|
|
3409
3865
|
}
|
|
3410
3866
|
function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
@@ -3422,8 +3878,19 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
3422
3878
|
ctx.restore();
|
|
3423
3879
|
rCtx.clipSaveDepth--;
|
|
3424
3880
|
}
|
|
3881
|
+
rCtx.clipStack ?? (rCtx.clipStack = []);
|
|
3882
|
+
rCtx.clipStack.push({
|
|
3883
|
+
region: rCtx.clipRegion ?? null,
|
|
3884
|
+
untracked: rCtx.clipUntracked ?? false
|
|
3885
|
+
});
|
|
3425
3886
|
rCtx.stateStack.push(cloneState(state));
|
|
3426
3887
|
ctx.save();
|
|
3888
|
+
if (rCtx.clipUntracked) {
|
|
3889
|
+
rCtx.clipUntracked = false;
|
|
3890
|
+
rCtx.clipRegion = null;
|
|
3891
|
+
} else if (rCtx.clipRegion) {
|
|
3892
|
+
reapplyClipRegion(rCtx, rCtx.clipRegion);
|
|
3893
|
+
}
|
|
3427
3894
|
return true;
|
|
3428
3895
|
}
|
|
3429
3896
|
case EMR_RESTOREDC: {
|
|
@@ -3434,16 +3901,23 @@ function handleEmfGdiStateRecord(rCtx, recType, _offset, dataOff, recSize) {
|
|
|
3434
3901
|
}
|
|
3435
3902
|
let rel = view.getInt32(dataOff, true);
|
|
3436
3903
|
if (rel < 0) {
|
|
3437
|
-
rel = rCtx.stateStack.length + rel;
|
|
3904
|
+
rel = rCtx.stateStack.length + rel + 1;
|
|
3438
3905
|
}
|
|
3439
3906
|
while (rCtx.stateStack.length > rel && rCtx.stateStack.length > 0) {
|
|
3440
3907
|
rCtx.stateStack.pop();
|
|
3908
|
+
rCtx.clipStack?.pop();
|
|
3441
3909
|
ctx.restore();
|
|
3442
3910
|
}
|
|
3443
3911
|
const restored = rCtx.stateStack.pop();
|
|
3444
3912
|
if (restored) {
|
|
3913
|
+
const clipSnapshot = rCtx.clipStack?.pop();
|
|
3445
3914
|
Object.assign(state, restored);
|
|
3446
3915
|
ctx.restore();
|
|
3916
|
+
rCtx.clipRegion = clipSnapshot?.region ?? null;
|
|
3917
|
+
rCtx.clipUntracked = false;
|
|
3918
|
+
if (rCtx.clipRegion) {
|
|
3919
|
+
reapplyClipRegion(rCtx, rCtx.clipRegion);
|
|
3920
|
+
}
|
|
3447
3921
|
}
|
|
3448
3922
|
}
|
|
3449
3923
|
return true;
|
|
@@ -3558,6 +4032,47 @@ function parseEmfPlusPath(data, off, maxLen) {
|
|
|
3558
4032
|
const types = new Uint8Array(data.buffer, data.byteOffset + alignedPOff, pointCount);
|
|
3559
4033
|
return { kind: "plus-path", points: points3, types: new Uint8Array(types) };
|
|
3560
4034
|
}
|
|
4035
|
+
function emfPlusPathToClipCmds(path, m) {
|
|
4036
|
+
const tx = (x, y) => m[0] * x + m[2] * y + m[4];
|
|
4037
|
+
const ty = (x, y) => m[1] * x + m[3] * y + m[5];
|
|
4038
|
+
const cmds = [];
|
|
4039
|
+
const pts = path.points;
|
|
4040
|
+
const types = path.types;
|
|
4041
|
+
let i = 0;
|
|
4042
|
+
while (i < pts.length) {
|
|
4043
|
+
const t = types[i] & 15;
|
|
4044
|
+
const close = (types[i] & 128) !== 0;
|
|
4045
|
+
if (t === 0) {
|
|
4046
|
+
cmds.push({ op: "moveTo", x: tx(pts[i].x, pts[i].y), y: ty(pts[i].x, pts[i].y) });
|
|
4047
|
+
i++;
|
|
4048
|
+
} else if (t === 3) {
|
|
4049
|
+
if (i + 2 < pts.length) {
|
|
4050
|
+
cmds.push({
|
|
4051
|
+
op: "bezierCurveTo",
|
|
4052
|
+
cp1x: tx(pts[i].x, pts[i].y),
|
|
4053
|
+
cp1y: ty(pts[i].x, pts[i].y),
|
|
4054
|
+
cp2x: tx(pts[i + 1].x, pts[i + 1].y),
|
|
4055
|
+
cp2y: ty(pts[i + 1].x, pts[i + 1].y),
|
|
4056
|
+
x: tx(pts[i + 2].x, pts[i + 2].y),
|
|
4057
|
+
y: ty(pts[i + 2].x, pts[i + 2].y)
|
|
4058
|
+
});
|
|
4059
|
+
if ((types[i + 2] & 128) !== 0) {
|
|
4060
|
+
cmds.push({ op: "closePath" });
|
|
4061
|
+
}
|
|
4062
|
+
i += 3;
|
|
4063
|
+
continue;
|
|
4064
|
+
}
|
|
4065
|
+
break;
|
|
4066
|
+
} else {
|
|
4067
|
+
cmds.push({ op: "lineTo", x: tx(pts[i].x, pts[i].y), y: ty(pts[i].x, pts[i].y) });
|
|
4068
|
+
i++;
|
|
4069
|
+
}
|
|
4070
|
+
if (close) {
|
|
4071
|
+
cmds.push({ op: "closePath" });
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
return cmds;
|
|
4075
|
+
}
|
|
3561
4076
|
function replayEmfPlusPath(ctx, path) {
|
|
3562
4077
|
ctx.beginPath();
|
|
3563
4078
|
const pts = path.points;
|
|
@@ -3609,12 +4124,44 @@ function multiplyMatrix(m1, m2) {
|
|
|
3609
4124
|
m1[4] * m2[1] + m1[5] * m2[3] + m2[5]
|
|
3610
4125
|
];
|
|
3611
4126
|
}
|
|
3612
|
-
function
|
|
4127
|
+
function createBrushGradient(rCtx, grad) {
|
|
4128
|
+
const ctx = rCtx.ctx;
|
|
4129
|
+
try {
|
|
4130
|
+
let g = null;
|
|
4131
|
+
if (grad.type === "linear" && typeof ctx.createLinearGradient === "function") {
|
|
4132
|
+
if (grad.x1 === grad.x2 && grad.y1 === grad.y2) {
|
|
4133
|
+
return null;
|
|
4134
|
+
}
|
|
4135
|
+
g = ctx.createLinearGradient(grad.x1, grad.y1, grad.x2, grad.y2);
|
|
4136
|
+
} else if (grad.type === "radial" && typeof ctx.createRadialGradient === "function") {
|
|
4137
|
+
if (!(grad.r > 0)) {
|
|
4138
|
+
return null;
|
|
4139
|
+
}
|
|
4140
|
+
g = ctx.createRadialGradient(grad.cx, grad.cy, 0, grad.cx, grad.cy, grad.r);
|
|
4141
|
+
}
|
|
4142
|
+
if (!g) {
|
|
4143
|
+
return null;
|
|
4144
|
+
}
|
|
4145
|
+
for (const stop of grad.stops) {
|
|
4146
|
+
g.addColorStop(stop.offset, stop.color);
|
|
4147
|
+
}
|
|
4148
|
+
return g;
|
|
4149
|
+
} catch {
|
|
4150
|
+
return null;
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
function resolveBrushPaint(rCtx, flags, brushIdOrColor) {
|
|
3613
4154
|
if (flags & 32768) {
|
|
3614
4155
|
return argbToRgba(brushIdOrColor);
|
|
3615
4156
|
}
|
|
3616
4157
|
const obj = rCtx.objectTable.get(brushIdOrColor & 255);
|
|
3617
4158
|
if (obj && obj.kind === "plus-brush") {
|
|
4159
|
+
if (obj.gradient) {
|
|
4160
|
+
const g = createBrushGradient(rCtx, obj.gradient);
|
|
4161
|
+
if (g) {
|
|
4162
|
+
return g;
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
3618
4165
|
return obj.color;
|
|
3619
4166
|
}
|
|
3620
4167
|
return "rgba(0,0,0,1)";
|
|
@@ -3678,88 +4225,83 @@ function popState(rCtx, stackId) {
|
|
|
3678
4225
|
rCtx.saveIdMap = newMap;
|
|
3679
4226
|
}
|
|
3680
4227
|
}
|
|
3681
|
-
function
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
}
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
}
|
|
3720
|
-
var MAX_REGION_TRACE_DEPTH = 64;
|
|
3721
|
-
function traceRegionNodePath(ctx, node, depth = 0) {
|
|
3722
|
-
if (depth > MAX_REGION_TRACE_DEPTH) {
|
|
3723
|
-
ctx.rect(0, 0, 0, 0);
|
|
3724
|
-
return;
|
|
4228
|
+
function plusDeviceMatrix(rCtx) {
|
|
4229
|
+
const wt = rCtx.worldTransform;
|
|
4230
|
+
const s = getPageUnitMultiplier(rCtx.pageUnit, rCtx.pageScale) * rCtx.dpiScale;
|
|
4231
|
+
return [wt[0] * s, wt[1] * s, wt[2] * s, wt[3] * s, wt[4] * s, wt[5] * s];
|
|
4232
|
+
}
|
|
4233
|
+
function transformedRectShape(x, y, w, h, m) {
|
|
4234
|
+
const tx = (px2, py) => m[0] * px2 + m[2] * py + m[4];
|
|
4235
|
+
const ty = (px2, py) => m[1] * px2 + m[3] * py + m[5];
|
|
4236
|
+
const cmds = [
|
|
4237
|
+
{ op: "moveTo", x: tx(x, y), y: ty(x, y) },
|
|
4238
|
+
{ op: "lineTo", x: tx(x + w, y), y: ty(x + w, y) },
|
|
4239
|
+
{ op: "lineTo", x: tx(x + w, y + h), y: ty(x + w, y + h) },
|
|
4240
|
+
{ op: "lineTo", x: tx(x, y + h), y: ty(x, y + h) },
|
|
4241
|
+
{ op: "closePath" }
|
|
4242
|
+
];
|
|
4243
|
+
return { cmds, fillRule: "nonzero", simple: true };
|
|
4244
|
+
}
|
|
4245
|
+
function pathClipShape(path, m) {
|
|
4246
|
+
return { cmds: emfPlusPathToClipCmds(path.path, m), fillRule: "nonzero", simple: true };
|
|
4247
|
+
}
|
|
4248
|
+
var REGION_NODE_OPS = {
|
|
4249
|
+
0: "intersect",
|
|
4250
|
+
// legacy/lenient: treat 0 as And
|
|
4251
|
+
1: "intersect",
|
|
4252
|
+
// RegionNodeDataTypeAnd
|
|
4253
|
+
2: "union",
|
|
4254
|
+
// RegionNodeDataTypeOr
|
|
4255
|
+
3: "xor",
|
|
4256
|
+
// RegionNodeDataTypeXor
|
|
4257
|
+
4: "exclude",
|
|
4258
|
+
// RegionNodeDataTypeExclude
|
|
4259
|
+
5: "complement"
|
|
4260
|
+
// RegionNodeDataTypeComplement
|
|
4261
|
+
};
|
|
4262
|
+
var MAX_REGION_FLATTEN_DEPTH = 64;
|
|
4263
|
+
function flattenRegionNode(node, m, depth = 0) {
|
|
4264
|
+
if (depth > MAX_REGION_FLATTEN_DEPTH) {
|
|
4265
|
+
return { region: [emptyClipShape()], exact: false };
|
|
3725
4266
|
}
|
|
3726
4267
|
switch (node.type) {
|
|
3727
4268
|
case "rect":
|
|
3728
|
-
|
|
3729
|
-
break;
|
|
4269
|
+
return { region: [transformedRectShape(node.x, node.y, node.width, node.height, m)], exact: true };
|
|
3730
4270
|
case "path":
|
|
3731
|
-
|
|
3732
|
-
break;
|
|
4271
|
+
return { region: [pathClipShape(node, m)], exact: true };
|
|
3733
4272
|
case "infinite":
|
|
3734
|
-
|
|
3735
|
-
break;
|
|
4273
|
+
return { region: null, exact: true };
|
|
3736
4274
|
case "empty":
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
4275
|
+
return { region: [emptyClipShape()], exact: true };
|
|
4276
|
+
case "combine": {
|
|
4277
|
+
const left = flattenRegionNode(node.left, m, depth + 1);
|
|
4278
|
+
const right = flattenRegionNode(node.right, m, depth + 1);
|
|
4279
|
+
const op = REGION_NODE_OPS[node.combineMode] ?? "intersect";
|
|
4280
|
+
const combined = combineClipRegions(left.region, right.region, op);
|
|
4281
|
+
return { region: combined.region, exact: combined.exact && left.exact && right.exact };
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
var PLUS_COMBINE_OPS = {
|
|
4286
|
+
0: "replace",
|
|
4287
|
+
1: "intersect",
|
|
4288
|
+
2: "union",
|
|
4289
|
+
3: "xor",
|
|
4290
|
+
4: "exclude",
|
|
4291
|
+
5: "complement"
|
|
4292
|
+
};
|
|
4293
|
+
function reapplyPlusClip(rCtx) {
|
|
4294
|
+
reapplyClipRegion(rCtx, rCtx.clipRegion ?? null, true);
|
|
3755
4295
|
}
|
|
3756
|
-
function
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
4296
|
+
function applyPlusClipRegion(rCtx, incoming, combineMode, opName) {
|
|
4297
|
+
const op = PLUS_COMBINE_OPS[combineMode];
|
|
4298
|
+
const res = combineClipRegions(rCtx.clipRegion ?? null, incoming, op ?? "intersect");
|
|
4299
|
+
if (!res.exact) ;
|
|
4300
|
+
rCtx.clipRegion = res.region;
|
|
4301
|
+
reapplyPlusClip(rCtx);
|
|
4302
|
+
}
|
|
4303
|
+
function applyPlusClipShape(rCtx, shape, combineMode, opName) {
|
|
4304
|
+
applyPlusClipRegion(rCtx, [shape], combineMode);
|
|
3763
4305
|
}
|
|
3764
4306
|
function handleEmfPlusStateRecord(rCtx, recType, recFlags, dataOff, recDataSize) {
|
|
3765
4307
|
const { view } = rCtx;
|
|
@@ -3861,30 +4403,24 @@ function handleEmfPlusStateRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
3861
4403
|
const cy = view.getFloat32(dataOff + 4, true);
|
|
3862
4404
|
const cw = view.getFloat32(dataOff + 8, true);
|
|
3863
4405
|
const ch = view.getFloat32(dataOff + 12, true);
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
rCtx.ctx.beginPath();
|
|
3867
|
-
rCtx.ctx.rect(cx, cy, cw, ch);
|
|
3868
|
-
try {
|
|
3869
|
-
rCtx.ctx.clip();
|
|
3870
|
-
} catch {
|
|
3871
|
-
}
|
|
3872
|
-
});
|
|
4406
|
+
const shape = transformedRectShape(cx, cy, cw, ch, plusDeviceMatrix(rCtx));
|
|
4407
|
+
applyPlusClipShape(rCtx, shape, combineMode);
|
|
3873
4408
|
}
|
|
3874
4409
|
return true;
|
|
3875
4410
|
}
|
|
3876
4411
|
case EMFPLUS_RESETCLIP: {
|
|
3877
|
-
|
|
3878
|
-
|
|
4412
|
+
rCtx.clipRegion = null;
|
|
4413
|
+
reapplyPlusClip(rCtx);
|
|
3879
4414
|
return true;
|
|
3880
4415
|
}
|
|
3881
4416
|
case EMFPLUS_SETCLIPREGION: {
|
|
3882
4417
|
const regionId = recFlags & 255;
|
|
4418
|
+
const combineMode = recFlags >> 8 & 15;
|
|
3883
4419
|
const regionObj = rCtx.objectTable.get(regionId);
|
|
3884
4420
|
if (regionObj && regionObj.kind === "plus-region" && regionObj.nodes.length > 0) {
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
4421
|
+
const flattened = flattenRegionNode(regionObj.nodes[0], plusDeviceMatrix(rCtx));
|
|
4422
|
+
if (!flattened.exact) ;
|
|
4423
|
+
applyPlusClipRegion(rCtx, flattened.region, combineMode);
|
|
3888
4424
|
}
|
|
3889
4425
|
return true;
|
|
3890
4426
|
}
|
|
@@ -3893,22 +4429,26 @@ function handleEmfPlusStateRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
3893
4429
|
const combineMode = recFlags >> 8 & 15;
|
|
3894
4430
|
const pathObj = rCtx.objectTable.get(pathId);
|
|
3895
4431
|
if (pathObj && pathObj.kind === "plus-path") {
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
} catch {
|
|
3903
|
-
}
|
|
3904
|
-
});
|
|
4432
|
+
const shape = {
|
|
4433
|
+
cmds: emfPlusPathToClipCmds(pathObj, plusDeviceMatrix(rCtx)),
|
|
4434
|
+
fillRule: "nonzero",
|
|
4435
|
+
simple: true
|
|
4436
|
+
};
|
|
4437
|
+
applyPlusClipShape(rCtx, shape, combineMode);
|
|
3905
4438
|
}
|
|
3906
4439
|
return true;
|
|
3907
4440
|
}
|
|
3908
4441
|
case EMFPLUS_OFFSETCLIP: {
|
|
3909
4442
|
if (recDataSize >= 8) {
|
|
3910
|
-
view.getFloat32(dataOff, true);
|
|
3911
|
-
view.getFloat32(dataOff + 4, true);
|
|
4443
|
+
const dx = view.getFloat32(dataOff, true);
|
|
4444
|
+
const dy = view.getFloat32(dataOff + 4, true);
|
|
4445
|
+
if (rCtx.clipRegion) {
|
|
4446
|
+
const m = plusDeviceMatrix(rCtx);
|
|
4447
|
+
const ddx = m[0] * dx + m[2] * dy;
|
|
4448
|
+
const ddy = m[1] * dx + m[3] * dy;
|
|
4449
|
+
rCtx.clipRegion = translateClipRegion(rCtx.clipRegion, ddx, ddy);
|
|
4450
|
+
reapplyPlusClip(rCtx);
|
|
4451
|
+
}
|
|
3912
4452
|
}
|
|
3913
4453
|
return true;
|
|
3914
4454
|
}
|
|
@@ -3979,7 +4519,7 @@ function handleEmfPlusDrawRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
3979
4519
|
const count = view.getUint32(dataOff + 4, true);
|
|
3980
4520
|
const compressed = (recFlags & 16384) !== 0;
|
|
3981
4521
|
const rectSize = compressed ? 8 : 16;
|
|
3982
|
-
ctx.fillStyle =
|
|
4522
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
3983
4523
|
applyPlusWorldTransform(rCtx);
|
|
3984
4524
|
let rOff = dataOff + 8;
|
|
3985
4525
|
for (let i = 0; i < count && rOff + rectSize <= dataOff + recDataSize; i++) {
|
|
@@ -4029,7 +4569,7 @@ function handleEmfPlusDrawRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
4029
4569
|
w = view.getFloat32(dataOff + 12, true);
|
|
4030
4570
|
h = view.getFloat32(dataOff + 16, true);
|
|
4031
4571
|
}
|
|
4032
|
-
ctx.fillStyle =
|
|
4572
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4033
4573
|
applyPlusWorldTransform(rCtx);
|
|
4034
4574
|
ctx.beginPath();
|
|
4035
4575
|
ctx.ellipse(x + w / 2, y + h / 2, Math.abs(w) / 2, Math.abs(h) / 2, 0, 0, Math.PI * 2);
|
|
@@ -4075,7 +4615,7 @@ function handleEmfPlusDrawRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
4075
4615
|
let aOff = dataOff;
|
|
4076
4616
|
if (isFill) {
|
|
4077
4617
|
const brushVal = view.getUint32(aOff, true);
|
|
4078
|
-
ctx.fillStyle =
|
|
4618
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4079
4619
|
aOff += 4;
|
|
4080
4620
|
}
|
|
4081
4621
|
const startAngle = view.getFloat32(aOff, true) * Math.PI / 180;
|
|
@@ -4156,7 +4696,7 @@ function handleEmfPlusDrawRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
4156
4696
|
const count = view.getUint32(dataOff + 4, true);
|
|
4157
4697
|
const compressed = (recFlags & 16384) !== 0;
|
|
4158
4698
|
const ptSize = compressed ? 4 : 8;
|
|
4159
|
-
ctx.fillStyle =
|
|
4699
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4160
4700
|
applyPlusWorldTransform(rCtx);
|
|
4161
4701
|
ctx.beginPath();
|
|
4162
4702
|
let pOff = dataOff + 8;
|
|
@@ -4178,6 +4718,259 @@ function handleEmfPlusDrawRecord(rCtx, recType, recFlags, dataOff, recDataSize)
|
|
|
4178
4718
|
return false;
|
|
4179
4719
|
}
|
|
4180
4720
|
}
|
|
4721
|
+
var BRUSH_DATA_PATH = 1;
|
|
4722
|
+
var BRUSH_DATA_TRANSFORM = 2;
|
|
4723
|
+
var BRUSH_DATA_PRESET_COLORS = 4;
|
|
4724
|
+
var BRUSH_DATA_BLEND_FACTORS_H = 8;
|
|
4725
|
+
var MAX_GRADIENT_ELEMENTS = 4096;
|
|
4726
|
+
function looksLikeGraphicsVersion(v) {
|
|
4727
|
+
return v >>> 12 === 900097;
|
|
4728
|
+
}
|
|
4729
|
+
function readTransform(view, off) {
|
|
4730
|
+
return [
|
|
4731
|
+
view.getFloat32(off, true),
|
|
4732
|
+
view.getFloat32(off + 4, true),
|
|
4733
|
+
view.getFloat32(off + 8, true),
|
|
4734
|
+
view.getFloat32(off + 12, true),
|
|
4735
|
+
view.getFloat32(off + 16, true),
|
|
4736
|
+
view.getFloat32(off + 20, true)
|
|
4737
|
+
];
|
|
4738
|
+
}
|
|
4739
|
+
function applyMatrix(m, x, y) {
|
|
4740
|
+
return { x: m[0] * x + m[2] * y + m[4], y: m[1] * x + m[3] * y + m[5] };
|
|
4741
|
+
}
|
|
4742
|
+
function clamp01(v) {
|
|
4743
|
+
return Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : 0;
|
|
4744
|
+
}
|
|
4745
|
+
function normaliseStops(stops) {
|
|
4746
|
+
return stops.map((s) => ({ offset: clamp01(s.offset), color: s.color })).sort((a, b) => a.offset - b.offset);
|
|
4747
|
+
}
|
|
4748
|
+
function readPresetColors(view, off, end) {
|
|
4749
|
+
if (off + 4 > end) {
|
|
4750
|
+
return null;
|
|
4751
|
+
}
|
|
4752
|
+
const count = view.getUint32(off, true);
|
|
4753
|
+
if (count === 0 || count > MAX_GRADIENT_ELEMENTS) {
|
|
4754
|
+
return null;
|
|
4755
|
+
}
|
|
4756
|
+
const posOff = off + 4;
|
|
4757
|
+
const colOff = posOff + count * 4;
|
|
4758
|
+
const next = colOff + count * 4;
|
|
4759
|
+
if (next > end) {
|
|
4760
|
+
return null;
|
|
4761
|
+
}
|
|
4762
|
+
const stops = [];
|
|
4763
|
+
for (let i = 0; i < count; i++) {
|
|
4764
|
+
stops.push({
|
|
4765
|
+
offset: view.getFloat32(posOff + i * 4, true),
|
|
4766
|
+
color: argbToRgba(view.getUint32(colOff + i * 4, true))
|
|
4767
|
+
});
|
|
4768
|
+
}
|
|
4769
|
+
return { stops, next };
|
|
4770
|
+
}
|
|
4771
|
+
function readBlendFactors(view, off, end) {
|
|
4772
|
+
if (off + 4 > end) {
|
|
4773
|
+
return null;
|
|
4774
|
+
}
|
|
4775
|
+
const count = view.getUint32(off, true);
|
|
4776
|
+
if (count === 0 || count > MAX_GRADIENT_ELEMENTS) {
|
|
4777
|
+
return null;
|
|
4778
|
+
}
|
|
4779
|
+
const posOff = off + 4;
|
|
4780
|
+
const facOff = posOff + count * 4;
|
|
4781
|
+
const next = facOff + count * 4;
|
|
4782
|
+
if (next > end) {
|
|
4783
|
+
return null;
|
|
4784
|
+
}
|
|
4785
|
+
const entries = [];
|
|
4786
|
+
for (let i = 0; i < count; i++) {
|
|
4787
|
+
entries.push({
|
|
4788
|
+
pos: view.getFloat32(posOff + i * 4, true),
|
|
4789
|
+
factor: view.getFloat32(facOff + i * 4, true)
|
|
4790
|
+
});
|
|
4791
|
+
}
|
|
4792
|
+
return { entries, next };
|
|
4793
|
+
}
|
|
4794
|
+
function parseLinearGradient(view, b, end) {
|
|
4795
|
+
if (b + 40 > end) {
|
|
4796
|
+
return null;
|
|
4797
|
+
}
|
|
4798
|
+
const flags = view.getUint32(b, true);
|
|
4799
|
+
const rx = view.getFloat32(b + 8, true);
|
|
4800
|
+
const ry = view.getFloat32(b + 12, true);
|
|
4801
|
+
const rw = view.getFloat32(b + 16, true);
|
|
4802
|
+
const rh = view.getFloat32(b + 20, true);
|
|
4803
|
+
const startArgb = view.getUint32(b + 24, true);
|
|
4804
|
+
const endArgb = view.getUint32(b + 28, true);
|
|
4805
|
+
let o = b + 40;
|
|
4806
|
+
let transform = null;
|
|
4807
|
+
if (flags & BRUSH_DATA_TRANSFORM && o + 24 <= end) {
|
|
4808
|
+
transform = readTransform(view, o);
|
|
4809
|
+
o += 24;
|
|
4810
|
+
}
|
|
4811
|
+
let stops = [
|
|
4812
|
+
{ offset: 0, color: argbToRgba(startArgb) },
|
|
4813
|
+
{ offset: 1, color: argbToRgba(endArgb) }
|
|
4814
|
+
];
|
|
4815
|
+
if (flags & BRUSH_DATA_PRESET_COLORS) {
|
|
4816
|
+
const preset = readPresetColors(view, o, end);
|
|
4817
|
+
if (preset) {
|
|
4818
|
+
stops = preset.stops;
|
|
4819
|
+
}
|
|
4820
|
+
} else if (flags & BRUSH_DATA_BLEND_FACTORS_H) {
|
|
4821
|
+
const blend = readBlendFactors(view, o, end);
|
|
4822
|
+
if (blend) {
|
|
4823
|
+
stops = blend.entries.map((e) => ({
|
|
4824
|
+
offset: e.pos,
|
|
4825
|
+
color: lerpArgbToRgba(startArgb, endArgb, e.factor)
|
|
4826
|
+
}));
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
let p1 = { x: rx, y: ry + rh / 2 };
|
|
4830
|
+
let p2 = { x: rx + rw, y: ry + rh / 2 };
|
|
4831
|
+
if (transform) {
|
|
4832
|
+
p1 = applyMatrix(transform, p1.x, p1.y);
|
|
4833
|
+
p2 = applyMatrix(transform, p2.x, p2.y);
|
|
4834
|
+
}
|
|
4835
|
+
emfLog(
|
|
4836
|
+
`parseEmfPlusBrushObject: linear gradient (${p1.x.toFixed(1)},${p1.y.toFixed(1)})\u2192(${p2.x.toFixed(1)},${p2.y.toFixed(1)}), ${stops.length} stop(s)`
|
|
4837
|
+
);
|
|
4838
|
+
return {
|
|
4839
|
+
kind: "plus-brush",
|
|
4840
|
+
color: argbToRgba(startArgb),
|
|
4841
|
+
gradient: {
|
|
4842
|
+
type: "linear",
|
|
4843
|
+
x1: p1.x,
|
|
4844
|
+
y1: p1.y,
|
|
4845
|
+
x2: p2.x,
|
|
4846
|
+
y2: p2.y,
|
|
4847
|
+
stops: normaliseStops(stops)
|
|
4848
|
+
}
|
|
4849
|
+
};
|
|
4850
|
+
}
|
|
4851
|
+
function parsePathGradient(view, b, end) {
|
|
4852
|
+
if (b + 24 > end) {
|
|
4853
|
+
return null;
|
|
4854
|
+
}
|
|
4855
|
+
const flags = view.getUint32(b, true);
|
|
4856
|
+
const centerArgb = view.getUint32(b + 8, true);
|
|
4857
|
+
let cx = view.getFloat32(b + 12, true);
|
|
4858
|
+
let cy = view.getFloat32(b + 16, true);
|
|
4859
|
+
const surroundCount = view.getUint32(b + 20, true);
|
|
4860
|
+
if (surroundCount > MAX_GRADIENT_ELEMENTS) {
|
|
4861
|
+
return { kind: "plus-brush", color: argbToRgba(centerArgb) };
|
|
4862
|
+
}
|
|
4863
|
+
const surround = [];
|
|
4864
|
+
let o = b + 24;
|
|
4865
|
+
for (let i = 0; i < surroundCount && o + 4 <= end; i++) {
|
|
4866
|
+
surround.push(view.getUint32(o, true));
|
|
4867
|
+
o += 4;
|
|
4868
|
+
}
|
|
4869
|
+
let boundaryPts = [];
|
|
4870
|
+
if (flags & BRUSH_DATA_PATH) {
|
|
4871
|
+
if (o + 4 <= end) {
|
|
4872
|
+
const pathSize = view.getInt32(o, true);
|
|
4873
|
+
o += 4;
|
|
4874
|
+
if (pathSize > 0 && o + pathSize <= end) {
|
|
4875
|
+
const path = parseEmfPlusPath(view, o, pathSize);
|
|
4876
|
+
if (path) {
|
|
4877
|
+
boundaryPts = path.points;
|
|
4878
|
+
}
|
|
4879
|
+
o += pathSize;
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
} else if (o + 4 <= end) {
|
|
4883
|
+
const ptCount = view.getUint32(o, true);
|
|
4884
|
+
o += 4;
|
|
4885
|
+
if (ptCount > 0 && ptCount <= MAX_GRADIENT_ELEMENTS && o + ptCount * 8 <= end) {
|
|
4886
|
+
for (let i = 0; i < ptCount; i++) {
|
|
4887
|
+
boundaryPts.push({
|
|
4888
|
+
x: view.getFloat32(o + i * 8, true),
|
|
4889
|
+
y: view.getFloat32(o + i * 8 + 4, true)
|
|
4890
|
+
});
|
|
4891
|
+
}
|
|
4892
|
+
o += ptCount * 8;
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
4895
|
+
let transform = null;
|
|
4896
|
+
if (flags & BRUSH_DATA_TRANSFORM && o + 24 <= end) {
|
|
4897
|
+
transform = readTransform(view, o);
|
|
4898
|
+
o += 24;
|
|
4899
|
+
}
|
|
4900
|
+
if (transform) {
|
|
4901
|
+
({ x: cx, y: cy } = applyMatrix(transform, cx, cy));
|
|
4902
|
+
boundaryPts = boundaryPts.map((p) => applyMatrix(transform, p.x, p.y));
|
|
4903
|
+
}
|
|
4904
|
+
const surroundArgb = surround.length > 0 ? surround[0] : centerArgb;
|
|
4905
|
+
let stops = [
|
|
4906
|
+
{ offset: 0, color: argbToRgba(centerArgb) },
|
|
4907
|
+
{ offset: 1, color: argbToRgba(surroundArgb) }
|
|
4908
|
+
];
|
|
4909
|
+
if (flags & BRUSH_DATA_PRESET_COLORS) {
|
|
4910
|
+
const preset = readPresetColors(view, o, end);
|
|
4911
|
+
if (preset) {
|
|
4912
|
+
stops = preset.stops.map((s) => ({ offset: 1 - s.offset, color: s.color }));
|
|
4913
|
+
}
|
|
4914
|
+
} else if (flags & BRUSH_DATA_BLEND_FACTORS_H) {
|
|
4915
|
+
const blend = readBlendFactors(view, o, end);
|
|
4916
|
+
if (blend) {
|
|
4917
|
+
stops = blend.entries.map((e) => ({
|
|
4918
|
+
offset: 1 - e.pos,
|
|
4919
|
+
color: lerpArgbToRgba(surroundArgb, centerArgb, e.factor)
|
|
4920
|
+
}));
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
let r = 0;
|
|
4924
|
+
for (const p of boundaryPts) {
|
|
4925
|
+
const d = Math.hypot(p.x - cx, p.y - cy);
|
|
4926
|
+
if (d > r) {
|
|
4927
|
+
r = d;
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
if (!(r > 0)) {
|
|
4931
|
+
return { kind: "plus-brush", color: argbToRgba(centerArgb) };
|
|
4932
|
+
}
|
|
4933
|
+
emfLog(
|
|
4934
|
+
`parseEmfPlusBrushObject: path gradient centre=(${cx.toFixed(1)},${cy.toFixed(1)}), r=${r.toFixed(1)}, ${stops.length} stop(s)`
|
|
4935
|
+
);
|
|
4936
|
+
return {
|
|
4937
|
+
kind: "plus-brush",
|
|
4938
|
+
color: argbToRgba(centerArgb),
|
|
4939
|
+
gradient: { type: "radial", cx, cy, r, stops: normaliseStops(stops) }
|
|
4940
|
+
};
|
|
4941
|
+
}
|
|
4942
|
+
function parseEmfPlusBrushObject(view, dataOff, recDataSize) {
|
|
4943
|
+
if (recDataSize < 8) {
|
|
4944
|
+
return null;
|
|
4945
|
+
}
|
|
4946
|
+
const end = dataOff + recDataSize;
|
|
4947
|
+
const hasVersion = looksLikeGraphicsVersion(view.getUint32(dataOff, true));
|
|
4948
|
+
const typeOff = dataOff + (hasVersion ? 4 : 0);
|
|
4949
|
+
if (typeOff + 8 > end) {
|
|
4950
|
+
return null;
|
|
4951
|
+
}
|
|
4952
|
+
const brushType = view.getUint32(typeOff, true);
|
|
4953
|
+
const b = typeOff + 4;
|
|
4954
|
+
switch (brushType) {
|
|
4955
|
+
case EMFPLUS_BRUSHTYPE_SOLID:
|
|
4956
|
+
return { kind: "plus-brush", color: argbToRgba(view.getUint32(b, true)) };
|
|
4957
|
+
case EMFPLUS_BRUSHTYPE_HATCHFILL:
|
|
4958
|
+
if (b + 8 <= end) {
|
|
4959
|
+
return { kind: "plus-brush", color: argbToRgba(view.getUint32(b + 4, true)) };
|
|
4960
|
+
}
|
|
4961
|
+
return { kind: "plus-brush", color: "rgba(0,0,0,1)" };
|
|
4962
|
+
case EMFPLUS_BRUSHTYPE_LINEARGRADIENT: {
|
|
4963
|
+
const brush = parseLinearGradient(view, b, end);
|
|
4964
|
+
return brush ?? { kind: "plus-brush", color: "rgba(0,0,0,1)" };
|
|
4965
|
+
}
|
|
4966
|
+
case EMFPLUS_BRUSHTYPE_PATHGRADIENT: {
|
|
4967
|
+
const brush = parsePathGradient(view, b, end);
|
|
4968
|
+
return brush ?? { kind: "plus-brush", color: "rgba(0,0,0,1)" };
|
|
4969
|
+
}
|
|
4970
|
+
default:
|
|
4971
|
+
return { kind: "plus-brush", color: "rgba(0,0,0,1)" };
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4181
4974
|
var PIXELFORMAT_24BPP_RGB = 137224;
|
|
4182
4975
|
var PIXELFORMAT_32BPP_RGB = 139273;
|
|
4183
4976
|
var PIXELFORMAT_32BPP_ARGB = 2498570;
|
|
@@ -4284,7 +5077,8 @@ function parseEmfPlusPenObject(view, dataOff, recDataSize) {
|
|
|
4284
5077
|
if (recDataSize < 20) {
|
|
4285
5078
|
return null;
|
|
4286
5079
|
}
|
|
4287
|
-
const
|
|
5080
|
+
const hasVersion = looksLikeGraphicsVersion(view.getUint32(dataOff, true));
|
|
5081
|
+
const penFlags = view.getUint32(dataOff + (hasVersion ? 8 : 4), true);
|
|
4288
5082
|
const penWidth = view.getFloat32(dataOff + 16, true);
|
|
4289
5083
|
let brushOff = dataOff + 20;
|
|
4290
5084
|
const flagSizes = [
|
|
@@ -4344,9 +5138,9 @@ function parseEmfPlusPenObject(view, dataOff, recDataSize) {
|
|
|
4344
5138
|
}
|
|
4345
5139
|
let penColor = "rgba(0,0,0,1)";
|
|
4346
5140
|
if (brushOff + 8 <= dataOff + recDataSize) {
|
|
4347
|
-
const
|
|
4348
|
-
if (
|
|
4349
|
-
penColor =
|
|
5141
|
+
const brush = parseEmfPlusBrushObject(view, brushOff, dataOff + recDataSize - brushOff);
|
|
5142
|
+
if (brush) {
|
|
5143
|
+
penColor = brush.color;
|
|
4350
5144
|
}
|
|
4351
5145
|
}
|
|
4352
5146
|
return { kind: "plus-pen", color: penColor, width: penWidth || 1, dashStyle };
|
|
@@ -4440,19 +5234,9 @@ function handleEmfPlusObjectRecord(rCtx, recFlags, dataOff, recDataSize) {
|
|
|
4440
5234
|
// Brush
|
|
4441
5235
|
// ---------------------------------------------------------------
|
|
4442
5236
|
case EMFPLUS_OBJECTTYPE_BRUSH: {
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
if (brushType === EMFPLUS_BRUSHTYPE_SOLID && recDataSize >= 8) {
|
|
4447
|
-
color2 = argbToRgba(view.getUint32(dataOff + 4, true));
|
|
4448
|
-
} else if (brushType === EMFPLUS_BRUSHTYPE_LINEARGRADIENT && recDataSize >= 48) {
|
|
4449
|
-
color2 = argbToRgba(view.getUint32(dataOff + 40, true));
|
|
4450
|
-
} else if (brushType === EMFPLUS_BRUSHTYPE_PATHGRADIENT && recDataSize >= 12) {
|
|
4451
|
-
color2 = argbToRgba(view.getUint32(dataOff + 8, true));
|
|
4452
|
-
} else if (brushType === EMFPLUS_BRUSHTYPE_HATCHFILL && recDataSize >= 12) {
|
|
4453
|
-
color2 = argbToRgba(view.getUint32(dataOff + 8, true));
|
|
4454
|
-
}
|
|
4455
|
-
objectTable.set(objectId, { kind: "plus-brush", color: color2 });
|
|
5237
|
+
const brush = parseEmfPlusBrushObject(view, dataOff, recDataSize);
|
|
5238
|
+
if (brush) {
|
|
5239
|
+
objectTable.set(objectId, brush);
|
|
4456
5240
|
}
|
|
4457
5241
|
break;
|
|
4458
5242
|
}
|
|
@@ -4548,7 +5332,7 @@ function parseRegionNode(view, off, endOff, depth = 0) {
|
|
|
4548
5332
|
}
|
|
4549
5333
|
const nodeType = view.getUint32(off, true);
|
|
4550
5334
|
let cursor = off + 4;
|
|
4551
|
-
if (nodeType <=
|
|
5335
|
+
if (nodeType <= 5) {
|
|
4552
5336
|
const leftResult = parseRegionNode(view, cursor, endOff, depth + 1);
|
|
4553
5337
|
if (!leftResult) {
|
|
4554
5338
|
return null;
|
|
@@ -4635,7 +5419,7 @@ function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataS
|
|
|
4635
5419
|
const pathId = recFlags & 255;
|
|
4636
5420
|
const pathObj = objectTable.get(pathId);
|
|
4637
5421
|
if (pathObj && pathObj.kind === "plus-path") {
|
|
4638
|
-
ctx.fillStyle =
|
|
5422
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4639
5423
|
applyPlusWorldTransform(rCtx);
|
|
4640
5424
|
replayEmfPlusPath(ctx, pathObj);
|
|
4641
5425
|
ctx.fill();
|
|
@@ -4680,7 +5464,7 @@ function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataS
|
|
|
4680
5464
|
const italic = font.flags & 2 ? "italic " : "";
|
|
4681
5465
|
const family = mapFontFamily(font.family, rCtx.fontFamilyMap);
|
|
4682
5466
|
ctx.font = `${italic}${bold}${font.emSize}px ${family}`;
|
|
4683
|
-
ctx.fillStyle =
|
|
5467
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4684
5468
|
ctx.textBaseline = "top";
|
|
4685
5469
|
const sf = objectTable.get(formatId);
|
|
4686
5470
|
if (sf && sf.kind === "plus-stringformat") {
|
|
@@ -4720,7 +5504,7 @@ function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataS
|
|
|
4720
5504
|
const italic = font.flags & 2 ? "italic " : "";
|
|
4721
5505
|
const family = mapFontFamily(font.family, rCtx.fontFamilyMap);
|
|
4722
5506
|
ctx.font = `${italic}${bold}${font.emSize}px ${family}`;
|
|
4723
|
-
ctx.fillStyle =
|
|
5507
|
+
ctx.fillStyle = resolveBrushPaint(rCtx, recFlags, brushVal);
|
|
4724
5508
|
ctx.textBaseline = "alphabetic";
|
|
4725
5509
|
ctx.textAlign = "left";
|
|
4726
5510
|
applyPlusWorldTransform(rCtx);
|
|
@@ -4895,7 +5679,8 @@ function replayEmfPlusRecords(view, offset, length, ctx, _canvasW, _canvasH, sta
|
|
|
4895
5679
|
saveIdMap: s.saveIdMap,
|
|
4896
5680
|
totalImageObjects: 0,
|
|
4897
5681
|
totalDrawImageCalls: 0,
|
|
4898
|
-
clipSaveDepth:
|
|
5682
|
+
clipSaveDepth: s.clipSaveDepth,
|
|
5683
|
+
clipRegion: s.clipRegion,
|
|
4899
5684
|
pageUnit: 2,
|
|
4900
5685
|
pageScale: 1,
|
|
4901
5686
|
continuationBuffer: null,
|
|
@@ -5030,6 +5815,8 @@ function replayEmfPlusRecords(view, offset, length, ctx, _canvasW, _canvasH, sta
|
|
|
5030
5815
|
if (state) {
|
|
5031
5816
|
state.worldTransform = rCtx.worldTransform;
|
|
5032
5817
|
state.saveIdMap = rCtx.saveIdMap;
|
|
5818
|
+
state.clipRegion = rCtx.clipRegion ?? null;
|
|
5819
|
+
state.clipSaveDepth = rCtx.clipSaveDepth;
|
|
5033
5820
|
}
|
|
5034
5821
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5035
5822
|
return rCtx.deferredImages;
|