html2canvas-pro 2.6.0 → 2.6.2

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * html2canvas-pro 2.6.0 <https://yorickshan.github.io/html2canvas-pro/>
2
+ * html2canvas-pro 2.6.2 <https://yorickshan.github.io/html2canvas-pro/>
3
3
  * Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
4
4
  * Released under MIT License
5
5
  */
@@ -7,7 +7,7 @@ Object.defineProperties(exports, {
7
7
  __esModule: { value: true },
8
8
  [Symbol.toStringTag]: { value: "Module" }
9
9
  });
10
- //#region src/config.ts
10
+ // src/config.ts
11
11
  /**
12
12
  * Html2Canvas Configuration
13
13
  *
@@ -50,8 +50,7 @@ var Html2CanvasConfig = class Html2CanvasConfig {
50
50
  });
51
51
  }
52
52
  };
53
- //#endregion
54
- //#region src/core/validator.ts
53
+ // src/core/validator.ts
55
54
  /**
56
55
  * Input Validator
57
56
  *
@@ -439,8 +438,7 @@ function createDefaultValidator(config = {}) {
439
438
  ...config
440
439
  });
441
440
  }
442
- //#endregion
443
- //#region src/core/performance-monitor.ts
441
+ // src/core/performance-monitor.ts
444
442
  /**
445
443
  * Performance Monitor
446
444
  *
@@ -449,7 +447,8 @@ function createDefaultValidator(config = {}) {
449
447
  *
450
448
  * Usage:
451
449
  * ```typescript
452
- * const monitor = new PerformanceMonitor(context);
450
+ * // Standalone (logs disabled) or with the render pipeline's context.
451
+ * const monitor = new PerformanceMonitor(null);
453
452
  *
454
453
  * monitor.start('clone');
455
454
  * await cloneDocument();
@@ -459,13 +458,13 @@ function createDefaultValidator(config = {}) {
459
458
  * ```
460
459
  */
461
460
  var PerformanceMonitor = class {
462
- context;
461
+ logger;
463
462
  activeMetrics = /* @__PURE__ */ new Map();
464
463
  completedMetrics = [];
465
464
  enabled;
466
465
  getTime;
467
- constructor(context, enabled = true) {
468
- this.context = context;
466
+ constructor(logger, enabled = true) {
467
+ this.logger = logger;
469
468
  this.enabled = enabled;
470
469
  this.getTime = typeof performance !== "undefined" && typeof performance.now === "function" ? () => performance.now() : () => Date.now();
471
470
  }
@@ -477,7 +476,7 @@ var PerformanceMonitor = class {
477
476
  */
478
477
  start(name, metadata) {
479
478
  if (!this.enabled) return;
480
- if (this.activeMetrics.has(name)) this.context?.logger.warn(`Performance metric '${name}' already started. Overwriting.`);
479
+ if (this.activeMetrics.has(name)) this.logger?.warn(`Performance metric '${name}' already started. Overwriting.`);
481
480
  this.activeMetrics.set(name, {
482
481
  name,
483
482
  startTime: this.getTime(),
@@ -494,14 +493,14 @@ var PerformanceMonitor = class {
494
493
  if (!this.enabled) return;
495
494
  const metric = this.activeMetrics.get(name);
496
495
  if (!metric) {
497
- this.context?.logger.warn(`Performance metric '${name}' not found. Was start() called?`);
496
+ this.logger?.warn(`Performance metric '${name}' not found. Was start() called?`);
498
497
  return;
499
498
  }
500
499
  metric.endTime = this.getTime();
501
500
  metric.duration = metric.endTime - metric.startTime;
502
501
  this.completedMetrics.push(metric);
503
502
  this.activeMetrics.delete(name);
504
- this.context?.logger.debug(`⏱️ ${name}: ${metric.duration.toFixed(2)}ms`, metric.metadata);
503
+ this.logger?.debug(`⏱️ ${name}: ${metric.duration.toFixed(2)}ms`, metric.metadata);
505
504
  return metric;
506
505
  }
507
506
  /**
@@ -581,11 +580,12 @@ var PerformanceMonitor = class {
581
580
  * Log performance summary to console
582
581
  */
583
582
  logSummary() {
584
- if (!this.enabled || this.completedMetrics.length === 0 || !this.context) return;
583
+ if (!this.enabled || this.completedMetrics.length === 0 || !this.logger) return;
584
+ const logger = this.logger;
585
585
  const summary = this.getSummary();
586
- this.context.logger.info(`\n📊 Performance Summary (Total: ${summary.totalDuration.toFixed(2)}ms):`);
586
+ logger.info(`\n📊 Performance Summary (Total: ${summary.totalDuration.toFixed(2)}ms):`);
587
587
  summary.breakdown.sort((a, b) => b.duration - a.duration).forEach((item) => {
588
- this.context.logger.info(` ${item.name.padEnd(20)} ${item.duration.toFixed(2).padStart(8)}ms ${item.percentage.padStart(6)}`);
588
+ logger.info(` ${item.name.padEnd(20)} ${item.duration.toFixed(2).padStart(8)}ms ${item.percentage.padStart(6)}`);
589
589
  });
590
590
  }
591
591
  /**
@@ -609,8 +609,7 @@ var PerformanceMonitor = class {
609
609
  return Array.from(this.activeMetrics.keys());
610
610
  }
611
611
  };
612
- //#endregion
613
- //#region src/css/layout/bounds.ts
612
+ // src/css/layout/bounds.ts
614
613
  var Bounds = class Bounds {
615
614
  left;
616
615
  top;
@@ -646,8 +645,7 @@ const parseDocumentSize = (document) => {
646
645
  if (!body || !documentElement) throw new Error(`Unable to get document size`);
647
646
  return new Bounds(0, 0, Math.max(Math.max(body.scrollWidth, documentElement.scrollWidth), Math.max(body.offsetWidth, documentElement.offsetWidth), Math.max(body.clientWidth, documentElement.clientWidth)), Math.max(Math.max(body.scrollHeight, documentElement.scrollHeight), Math.max(body.offsetHeight, documentElement.offsetHeight), Math.max(body.clientHeight, documentElement.clientHeight)));
648
647
  };
649
- //#endregion
650
- //#region src/core/util.ts
648
+ // src/core/util.ts
651
649
  /**
652
650
  * Indexed access where the shape/arity is guaranteed by construction (the CSS
653
651
  * grammar or a preceding length check). Throws on the impossible case instead
@@ -725,8 +723,7 @@ const stringToNumber = (codePoints) => {
725
723
  const exp = exponent.length ? parseInt(String.fromCodePoint(...exponent), 10) : 0;
726
724
  return sign * (int + frac * Math.pow(10, -fracd)) * Math.pow(10, expsign * exp);
727
725
  };
728
- //#endregion
729
- //#region src/css/syntax/token-singletons.ts
726
+ // src/css/syntax/token-singletons.ts
730
727
  const LEFT_PARENTHESIS_TOKEN = { type: 2 };
731
728
  const RIGHT_PARENTHESIS_TOKEN = { type: 3 };
732
729
  const COMMA_TOKEN = { type: 4 };
@@ -748,8 +745,7 @@ const LEFT_SQUARE_BRACKET_TOKEN = { type: 28 };
748
745
  const RIGHT_SQUARE_BRACKET_TOKEN = { type: 29 };
749
746
  const WHITESPACE_TOKEN = { type: 31 };
750
747
  const EOF_TOKEN = { type: 32 };
751
- //#endregion
752
- //#region src/css/syntax/tokenizer.ts
748
+ // src/css/syntax/tokenizer.ts
753
749
  var Tokenizer = class Tokenizer {
754
750
  static _pool = [];
755
751
  static MAX_POOL_SIZE = 40;
@@ -1205,8 +1201,7 @@ var Tokenizer = class Tokenizer {
1205
1201
  }
1206
1202
  }
1207
1203
  };
1208
- //#endregion
1209
- //#region src/css/syntax/parser.ts
1204
+ // src/css/syntax/parser.ts
1210
1205
  var Parser = class Parser {
1211
1206
  _tokens;
1212
1207
  constructor(tokens) {
@@ -1315,8 +1310,7 @@ const isEndingTokenFor = (token, type) => {
1315
1310
  if (type === 28 && token.type === 29) return true;
1316
1311
  return type === 2 && token.type === 3;
1317
1312
  };
1318
- //#endregion
1319
- //#region src/css/types/safe-eval.ts
1313
+ // src/css/types/safe-eval.ts
1320
1314
  /**
1321
1315
  * Safe arithmetic expression evaluator — replaces `new Function()`.
1322
1316
  *
@@ -1374,8 +1368,7 @@ const safeEvalArithmetic = (expr) => {
1374
1368
  }
1375
1369
  return stack.length === 1 ? stack[0] ?? NaN : NaN;
1376
1370
  };
1377
- //#endregion
1378
- //#region src/css/types/color-math.ts
1371
+ // src/css/types/color-math.ts
1379
1372
  /**
1380
1373
  * Color mathematics utilities
1381
1374
  * Extracted to break circular dependency between srgb.ts and color-utilities.ts
@@ -1396,8 +1389,7 @@ const multiplyMatrices = (A, B) => {
1396
1389
  A[6] * B[0] + A[7] * B[1] + A[8] * B[2]
1397
1390
  ];
1398
1391
  };
1399
- //#endregion
1400
- //#region src/css/types/color-spaces/srgb.ts
1392
+ // src/css/types/color-spaces/srgb.ts
1401
1393
  /**
1402
1394
  * SRGB related functions
1403
1395
  */
@@ -1506,11 +1498,9 @@ const srgbLinearFromXYZ = (args) => {
1506
1498
  args[3]
1507
1499
  ];
1508
1500
  };
1509
- //#endregion
1510
- //#region src/css/types/length.ts
1501
+ // src/css/types/length.ts
1511
1502
  const isLength = (token) => token.type === 17 || token.type === 15;
1512
- //#endregion
1513
- //#region src/css/types/length-percentage.ts
1503
+ // src/css/types/length-percentage.ts
1514
1504
  const isLengthPercentage = (token) => token.type === 16 || isLength(token) || isCalcWithPercentage(token);
1515
1505
  /**
1516
1506
  * Check if a token is a CalcWithPercentage deferred token.
@@ -1634,8 +1624,7 @@ const getAbsoluteValue = (token, parent) => {
1634
1624
  }
1635
1625
  return token.number;
1636
1626
  };
1637
- //#endregion
1638
- //#region src/css/types/angle.ts
1627
+ // src/css/types/angle.ts
1639
1628
  const DEG = "deg";
1640
1629
  const GRAD = "grad";
1641
1630
  const RAD = "rad";
@@ -1688,8 +1677,7 @@ const parseNamedSide = (tokens) => {
1688
1677
  return 0;
1689
1678
  };
1690
1679
  const deg = (deg) => Math.PI * deg / 180;
1691
- //#endregion
1692
- //#region src/css/types/color-utilities.ts
1680
+ // src/css/types/color-utilities.ts
1693
1681
  const isTransparent = (color) => (255 & color) === 0;
1694
1682
  const asString = (color) => {
1695
1683
  const alpha = 255 & color;
@@ -2144,8 +2132,7 @@ const convertXyz50 = (args) => {
2144
2132
  args[3]
2145
2133
  ]);
2146
2134
  };
2147
- //#endregion
2148
- //#region src/css/types/color-spaces/p3.ts
2135
+ // src/css/types/color-spaces/p3.ts
2149
2136
  /**
2150
2137
  * Display-P3 related functions
2151
2138
  */
@@ -2263,8 +2250,7 @@ const convertP3 = (args) => {
2263
2250
  args[3]
2264
2251
  ]);
2265
2252
  };
2266
- //#endregion
2267
- //#region src/css/types/color-spaces/a98.ts
2253
+ // src/css/types/color-spaces/a98.ts
2268
2254
  /**
2269
2255
  * A98-RGB related functions
2270
2256
  */
@@ -2370,8 +2356,7 @@ const convertA98rgb = (args) => {
2370
2356
  args[3]
2371
2357
  ]);
2372
2358
  };
2373
- //#endregion
2374
- //#region src/css/types/color-spaces/pro-photo.ts
2359
+ // src/css/types/color-spaces/pro-photo.ts
2375
2360
  /**
2376
2361
  * Pro Photo related functions
2377
2362
  */
@@ -2496,8 +2481,7 @@ const convertProPhoto = (args) => {
2496
2481
  args[3]
2497
2482
  ]);
2498
2483
  };
2499
- //#endregion
2500
- //#region src/css/types/color-spaces/rec2020.ts
2484
+ // src/css/types/color-spaces/rec2020.ts
2501
2485
  /**
2502
2486
  * REC2020 related functions
2503
2487
  */
@@ -2618,8 +2602,7 @@ const convertRec2020 = (args) => {
2618
2602
  args[3]
2619
2603
  ]);
2620
2604
  };
2621
- //#endregion
2622
- //#region src/css/types/functions/color-mix.ts
2605
+ // src/css/types/functions/color-mix.ts
2623
2606
  const HUE_DEG_INDEX = {
2624
2607
  lch: 2,
2625
2608
  oklch: 2,
@@ -3005,8 +2988,7 @@ const colorMix = (context, args) => {
3005
2988
  return 0;
3006
2989
  }
3007
2990
  };
3008
- //#endregion
3009
- //#region src/css/types/color.ts
2991
+ // src/css/types/color.ts
3010
2992
  const color$1 = {
3011
2993
  name: "color",
3012
2994
  parse: (context, value) => {
@@ -3410,8 +3392,7 @@ const COLORS = {
3410
3392
  YELLOW: 4294902015,
3411
3393
  YELLOWGREEN: 2597139199
3412
3394
  };
3413
- //#endregion
3414
- //#region src/dom/node-type-guards.ts
3395
+ // src/dom/node-type-guards.ts
3415
3396
  /**
3416
3397
  * DOM Node Type Guards
3417
3398
  *
@@ -3467,8 +3448,7 @@ const VOID_OR_REPLACED_TAGS = /* @__PURE__ */ new Set([
3467
3448
  * SVG elements also do not support pseudo-elements.
3468
3449
  */
3469
3450
  const canHavePseudoElements = (element) => !isSVGElementNode(element) && !VOID_OR_REPLACED_TAGS.has(element.tagName);
3470
- //#endregion
3471
- //#region src/css/property-descriptors/list-style-type.ts
3451
+ // src/css/property-descriptors/list-style-type.ts
3472
3452
  const listStyleType = {
3473
3453
  name: "list-style-type",
3474
3454
  initialValue: "none",
@@ -3533,11 +3513,9 @@ const listStyleType = {
3533
3513
  }
3534
3514
  }
3535
3515
  };
3536
- //#endregion
3537
- //#region src/core/bitwise.ts
3516
+ // src/core/bitwise.ts
3538
3517
  const contains = (bit, value) => (bit & value) !== 0;
3539
- //#endregion
3540
- //#region src/css/types/functions/counter.ts
3518
+ // src/css/types/functions/counter.ts
3541
3519
  var CounterState = class {
3542
3520
  counters = {};
3543
3521
  getCounterValue(name) {
@@ -3953,8 +3931,7 @@ const createCounterText = (value, type, appendSuffix) => {
3953
3931
  default: return createCounterStyleFromRange(value, 48, 57, true, defaultSuffix);
3954
3932
  }
3955
3933
  };
3956
- //#endregion
3957
- //#region src/css/property-descriptors/display.ts
3934
+ // src/css/property-descriptors/display.ts
3958
3935
  const display = {
3959
3936
  name: "display",
3960
3937
  initialValue: "inline-block",
@@ -4003,8 +3980,7 @@ const parseDisplayValue$1 = (display) => {
4003
3980
  }
4004
3981
  return 0;
4005
3982
  };
4006
- //#endregion
4007
- //#region src/css/property-descriptors/float.ts
3983
+ // src/css/property-descriptors/float.ts
4008
3984
  const float = {
4009
3985
  name: "float",
4010
3986
  initialValue: "none",
@@ -4020,8 +3996,7 @@ const float = {
4020
3996
  return 0;
4021
3997
  }
4022
3998
  };
4023
- //#endregion
4024
- //#region src/css/property-descriptors/overflow.ts
3999
+ // src/css/property-descriptors/overflow.ts
4025
4000
  const overflow = {
4026
4001
  name: "overflow",
4027
4002
  initialValue: "visible",
@@ -4039,8 +4014,7 @@ const overflow = {
4039
4014
  });
4040
4015
  }
4041
4016
  };
4042
- //#endregion
4043
- //#region src/css/property-descriptors/text-decoration-color.ts
4017
+ // src/css/property-descriptors/text-decoration-color.ts
4044
4018
  const textDecorationColor = {
4045
4019
  name: `text-decoration-color`,
4046
4020
  initialValue: "transparent",
@@ -4048,8 +4022,7 @@ const textDecorationColor = {
4048
4022
  type: 3,
4049
4023
  format: "color"
4050
4024
  };
4051
- //#endregion
4052
- //#region src/css/property-descriptors/text-decoration-line.ts
4025
+ // src/css/property-descriptors/text-decoration-line.ts
4053
4026
  const textDecorationLine = {
4054
4027
  name: "text-decoration-line",
4055
4028
  initialValue: "none",
@@ -4067,8 +4040,7 @@ const textDecorationLine = {
4067
4040
  }).filter((line) => line !== 0);
4068
4041
  }
4069
4042
  };
4070
- //#endregion
4071
- //#region src/css/property-descriptors/content.ts
4043
+ // src/css/property-descriptors/content.ts
4072
4044
  const content = {
4073
4045
  name: "content",
4074
4046
  initialValue: "none",
@@ -4081,8 +4053,7 @@ const content = {
4081
4053
  return tokens;
4082
4054
  }
4083
4055
  };
4084
- //#endregion
4085
- //#region src/css/property-descriptors/quotes.ts
4056
+ // src/css/property-descriptors/quotes.ts
4086
4057
  const quotes = {
4087
4058
  name: "quotes",
4088
4059
  initialValue: "none",
@@ -4112,8 +4083,7 @@ const getQuote = (quotes, depth, open) => {
4112
4083
  if (!quote) return "";
4113
4084
  return open ? quote.open : quote.close;
4114
4085
  };
4115
- //#endregion
4116
- //#region src/css/property-descriptors/counter-increment.ts
4086
+ // src/css/property-descriptors/counter-increment.ts
4117
4087
  /** Shared counter-ID parsing: returns next number or a fallback default. */
4118
4088
  const parseCounterValue = (tokens, defaultNumber) => {
4119
4089
  const entries = [];
@@ -4143,8 +4113,7 @@ const counterIncrement = {
4143
4113
  }));
4144
4114
  }
4145
4115
  };
4146
- //#endregion
4147
- //#region src/css/property-descriptors/counter-reset.ts
4116
+ // src/css/property-descriptors/counter-reset.ts
4148
4117
  const counterReset = {
4149
4118
  name: "counter-reset",
4150
4119
  initialValue: "none",
@@ -4158,8 +4127,7 @@ const counterReset = {
4158
4127
  }));
4159
4128
  }
4160
4129
  };
4161
- //#endregion
4162
- //#region src/css/property-descriptors/background-clip.ts
4130
+ // src/css/property-descriptors/background-clip.ts
4163
4131
  const backgroundClip = {
4164
4132
  name: "background-clip",
4165
4133
  initialValue: "border-box",
@@ -4176,8 +4144,7 @@ const backgroundClip = {
4176
4144
  });
4177
4145
  }
4178
4146
  };
4179
- //#endregion
4180
- //#region src/css/property-descriptors/background-color.ts
4147
+ // src/css/property-descriptors/background-color.ts
4181
4148
  const backgroundColor = {
4182
4149
  name: `background-color`,
4183
4150
  initialValue: "transparent",
@@ -4185,8 +4152,7 @@ const backgroundColor = {
4185
4152
  type: 3,
4186
4153
  format: "color"
4187
4154
  };
4188
- //#endregion
4189
- //#region src/css/types/functions/gradient.ts
4155
+ // src/css/types/functions/gradient.ts
4190
4156
  const parseColorStop = (context, args) => {
4191
4157
  const color = color$1.parse(context, at(args, 0));
4192
4158
  const stop = args[1];
@@ -4322,8 +4288,7 @@ const calculateRadius = (gradient, x, y, width, height) => {
4322
4288
  }
4323
4289
  return [rx, ry];
4324
4290
  };
4325
- //#endregion
4326
- //#region src/css/types/functions/linear-gradient.ts
4291
+ // src/css/types/functions/linear-gradient.ts
4327
4292
  const linearGradient = (context, tokens) => {
4328
4293
  let angle$2 = deg(180);
4329
4294
  const stops = [];
@@ -4347,8 +4312,7 @@ const linearGradient = (context, tokens) => {
4347
4312
  type: 1
4348
4313
  };
4349
4314
  };
4350
- //#endregion
4351
- //#region src/css/types/functions/-prefix-linear-gradient.ts
4315
+ // src/css/types/functions/-prefix-linear-gradient.ts
4352
4316
  const prefixLinearGradient = (context, tokens) => {
4353
4317
  let angle$1 = deg(180);
4354
4318
  const stops = [];
@@ -4377,8 +4341,7 @@ const prefixLinearGradient = (context, tokens) => {
4377
4341
  type: 1
4378
4342
  };
4379
4343
  };
4380
- //#endregion
4381
- //#region src/css/types/functions/-webkit-gradient.ts
4344
+ // src/css/types/functions/-webkit-gradient.ts
4382
4345
  const webkitGradient = (context, tokens) => {
4383
4346
  const angle = deg(180);
4384
4347
  const stops = [];
@@ -4440,8 +4403,7 @@ const webkitGradient = (context, tokens) => {
4440
4403
  type
4441
4404
  };
4442
4405
  };
4443
- //#endregion
4444
- //#region src/css/types/functions/radial-gradient.ts
4406
+ // src/css/types/functions/radial-gradient.ts
4445
4407
  const CLOSEST_SIDE = "closest-side";
4446
4408
  const FARTHEST_SIDE = "farthest-side";
4447
4409
  const CLOSEST_CORNER = "closest-corner";
@@ -4521,8 +4483,7 @@ const radialGradient = (context, tokens) => {
4521
4483
  type: 2
4522
4484
  };
4523
4485
  };
4524
- //#endregion
4525
- //#region src/css/types/functions/-prefix-radial-gradient.ts
4486
+ // src/css/types/functions/-prefix-radial-gradient.ts
4526
4487
  const prefixRadialGradient = (context, tokens) => {
4527
4488
  let shape = 1;
4528
4489
  let size = 3;
@@ -4593,16 +4554,14 @@ const prefixRadialGradient = (context, tokens) => {
4593
4554
  type: 2
4594
4555
  };
4595
4556
  };
4596
- //#endregion
4597
- //#region src/css/types/functions/repeating-linear-gradient.ts
4557
+ // src/css/types/functions/repeating-linear-gradient.ts
4598
4558
  const repeatingLinearGradient = (context, tokens) => {
4599
4559
  return {
4600
4560
  ...linearGradient(context, tokens),
4601
4561
  type: 3
4602
4562
  };
4603
4563
  };
4604
- //#endregion
4605
- //#region src/css/types/functions/repeating-radial-gradient.ts
4564
+ // src/css/types/functions/repeating-radial-gradient.ts
4606
4565
  /**
4607
4566
  * repeating-radial-gradient shares the radial-gradient grammar exactly; only
4608
4567
  * the image type differs, which switches the renderer to periodic stops.
@@ -4613,8 +4572,7 @@ const repeatingRadialGradient = (context, tokens) => {
4613
4572
  type: 4
4614
4573
  };
4615
4574
  };
4616
- //#endregion
4617
- //#region src/css/types/functions/conic-gradient.ts
4575
+ // src/css/types/functions/conic-gradient.ts
4618
4576
  /**
4619
4577
  * conic-gradient( [ from <angle> ]? [ at <position> ]?, <color-stop-list> )
4620
4578
  *
@@ -4684,8 +4642,7 @@ const repeatingConicGradient = (context, tokens) => {
4684
4642
  type: 6
4685
4643
  };
4686
4644
  };
4687
- //#endregion
4688
- //#region src/css/types/functions/image-set.ts
4645
+ // src/css/types/functions/image-set.ts
4689
4646
  const parseResolution = (token) => {
4690
4647
  if (!token) return 1;
4691
4648
  if (isDimensionToken(token)) {
@@ -4719,8 +4676,7 @@ const imageSet = (context, tokens) => {
4719
4676
  const chosen = at(satisfying.length > 0 ? satisfying : candidates.slice().sort((a, b) => b.resolution - a.resolution), 0);
4720
4677
  return image.parse(context, chosen.imageToken);
4721
4678
  };
4722
- //#endregion
4723
- //#region src/css/types/image.ts
4679
+ // src/css/types/image.ts
4724
4680
  const isLinearGradient = (background) => {
4725
4681
  return background.type === 1;
4726
4682
  };
@@ -4790,8 +4746,7 @@ const SUPPORTED_IMAGE_FUNCTIONS = {
4790
4746
  "image-set": imageSet,
4791
4747
  "-webkit-image-set": imageSet
4792
4748
  };
4793
- //#endregion
4794
- //#region src/css/property-descriptors/background-image.ts
4749
+ // src/css/property-descriptors/background-image.ts
4795
4750
  const backgroundImage = {
4796
4751
  name: "background-image",
4797
4752
  initialValue: "none",
@@ -4805,8 +4760,7 @@ const backgroundImage = {
4805
4760
  return tokens.filter((value) => nonFunctionArgSeparator(value) && isSupportedImage(value)).map((value) => image.parse(context, value));
4806
4761
  }
4807
4762
  };
4808
- //#endregion
4809
- //#region src/css/property-descriptors/background-origin.ts
4763
+ // src/css/property-descriptors/background-origin.ts
4810
4764
  const backgroundOrigin = {
4811
4765
  name: "background-origin",
4812
4766
  initialValue: "border-box",
@@ -4822,8 +4776,7 @@ const backgroundOrigin = {
4822
4776
  });
4823
4777
  }
4824
4778
  };
4825
- //#endregion
4826
- //#region src/css/property-descriptors/background-position.ts
4779
+ // src/css/property-descriptors/background-position.ts
4827
4780
  const backgroundPosition = {
4828
4781
  name: "background-position",
4829
4782
  initialValue: "0% 0%",
@@ -4835,8 +4788,7 @@ const backgroundPosition = {
4835
4788
  }).map(parseLengthPercentageTuple);
4836
4789
  }
4837
4790
  };
4838
- //#endregion
4839
- //#region src/css/property-descriptors/background-repeat.ts
4791
+ // src/css/property-descriptors/background-repeat.ts
4840
4792
  const backgroundRepeat = {
4841
4793
  name: "background-repeat",
4842
4794
  initialValue: "repeat",
@@ -4856,8 +4808,7 @@ const parseBackgroundRepeat = (value) => {
4856
4808
  default: return 0;
4857
4809
  }
4858
4810
  };
4859
- //#endregion
4860
- //#region src/css/property-descriptors/background-size.ts
4811
+ // src/css/property-descriptors/background-size.ts
4861
4812
  const backgroundSize = {
4862
4813
  name: "background-size",
4863
4814
  initialValue: "0",
@@ -4868,8 +4819,7 @@ const backgroundSize = {
4868
4819
  }
4869
4820
  };
4870
4821
  const isBackgroundSizeInfoToken = (value) => isIdentToken(value) || isLengthPercentage(value);
4871
- //#endregion
4872
- //#region src/css/property-descriptors/border-color.ts
4822
+ // src/css/property-descriptors/border-color.ts
4873
4823
  const borderColorForSide = (side) => ({
4874
4824
  name: `border-${side}-color`,
4875
4825
  initialValue: "transparent",
@@ -4881,8 +4831,7 @@ const borderTopColor = borderColorForSide("top");
4881
4831
  const borderRightColor = borderColorForSide("right");
4882
4832
  const borderBottomColor = borderColorForSide("bottom");
4883
4833
  const borderLeftColor = borderColorForSide("left");
4884
- //#endregion
4885
- //#region src/css/property-descriptors/border-radius.ts
4834
+ // src/css/property-descriptors/border-radius.ts
4886
4835
  const borderRadiusForSide = (side) => ({
4887
4836
  name: `border-${side}-radius`,
4888
4837
  initialValue: "0 0",
@@ -4894,8 +4843,7 @@ const borderTopLeftRadius = borderRadiusForSide("top-left");
4894
4843
  const borderTopRightRadius = borderRadiusForSide("top-right");
4895
4844
  const borderBottomRightRadius = borderRadiusForSide("bottom-right");
4896
4845
  const borderBottomLeftRadius = borderRadiusForSide("bottom-left");
4897
- //#endregion
4898
- //#region src/css/property-descriptors/border-style.ts
4846
+ // src/css/property-descriptors/border-style.ts
4899
4847
  const borderStyleForSide = (side) => ({
4900
4848
  name: `border-${side}-style`,
4901
4849
  initialValue: "solid",
@@ -4915,8 +4863,7 @@ const borderTopStyle = borderStyleForSide("top");
4915
4863
  const borderRightStyle = borderStyleForSide("right");
4916
4864
  const borderBottomStyle = borderStyleForSide("bottom");
4917
4865
  const borderLeftStyle = borderStyleForSide("left");
4918
- //#endregion
4919
- //#region src/css/property-descriptors/border-width.ts
4866
+ // src/css/property-descriptors/border-width.ts
4920
4867
  const borderWidthForSide = (side) => ({
4921
4868
  name: `border-${side}-width`,
4922
4869
  initialValue: "0",
@@ -4931,8 +4878,7 @@ const borderTopWidth = borderWidthForSide("top");
4931
4878
  const borderRightWidth = borderWidthForSide("right");
4932
4879
  const borderBottomWidth = borderWidthForSide("bottom");
4933
4880
  const borderLeftWidth = borderWidthForSide("left");
4934
- //#endregion
4935
- //#region src/css/property-descriptors/clip-path.ts
4881
+ // src/css/property-descriptors/clip-path.ts
4936
4882
  const NONE = { type: 0 };
4937
4883
  /**
4938
4884
  * Parse a shape-radius token: <length-percentage> | closest-side | farthest-side.
@@ -5153,8 +5099,7 @@ const clipPath = {
5153
5099
  return NONE;
5154
5100
  }
5155
5101
  };
5156
- //#endregion
5157
- //#region src/css/property-descriptors/color.ts
5102
+ // src/css/property-descriptors/color.ts
5158
5103
  const color = {
5159
5104
  name: `color`,
5160
5105
  initialValue: "transparent",
@@ -5162,8 +5107,7 @@ const color = {
5162
5107
  type: 3,
5163
5108
  format: "color"
5164
5109
  };
5165
- //#endregion
5166
- //#region src/css/property-descriptors/direction.ts
5110
+ // src/css/property-descriptors/direction.ts
5167
5111
  const direction = {
5168
5112
  name: "direction",
5169
5113
  initialValue: "ltr",
@@ -5176,8 +5120,7 @@ const direction = {
5176
5120
  }
5177
5121
  }
5178
5122
  };
5179
- //#endregion
5180
- //#region src/css/property-descriptors/font-family.ts
5123
+ // src/css/property-descriptors/font-family.ts
5181
5124
  const fontFamily = {
5182
5125
  name: `font-family`,
5183
5126
  initialValue: "",
@@ -5214,8 +5157,7 @@ const fontFamily = {
5214
5157
  return results.map((result, index) => quoted[index] || result.indexOf(" ") !== -1 ? `'${result.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\a ").replace(/\r/g, "\\d ").replace(/\f/g, "\\c ")}'` : result);
5215
5158
  }
5216
5159
  };
5217
- //#endregion
5218
- //#region src/css/property-descriptors/font-size.ts
5160
+ // src/css/property-descriptors/font-size.ts
5219
5161
  const fontSize = {
5220
5162
  name: `font-size`,
5221
5163
  initialValue: "0",
@@ -5223,8 +5165,7 @@ const fontSize = {
5223
5165
  type: 3,
5224
5166
  format: "length"
5225
5167
  };
5226
- //#endregion
5227
- //#region src/css/property-descriptors/letter-spacing.ts
5168
+ // src/css/property-descriptors/letter-spacing.ts
5228
5169
  const letterSpacing = {
5229
5170
  name: "letter-spacing",
5230
5171
  initialValue: "0",
@@ -5237,8 +5178,7 @@ const letterSpacing = {
5237
5178
  return 0;
5238
5179
  }
5239
5180
  };
5240
- //#endregion
5241
- //#region src/css/property-descriptors/line-break.ts
5181
+ // src/css/property-descriptors/line-break.ts
5242
5182
  const lineBreak = {
5243
5183
  name: "line-break",
5244
5184
  initialValue: "normal",
@@ -5251,8 +5191,7 @@ const lineBreak = {
5251
5191
  }
5252
5192
  }
5253
5193
  };
5254
- //#endregion
5255
- //#region src/css/property-descriptors/line-height.ts
5194
+ // src/css/property-descriptors/line-height.ts
5256
5195
  const lineHeight = {
5257
5196
  name: "line-height",
5258
5197
  initialValue: "normal",
@@ -5265,8 +5204,7 @@ const computeLineHeight = (token, fontSize) => {
5265
5204
  else if (isLengthPercentage(token)) return getAbsoluteValue(token, fontSize);
5266
5205
  return fontSize;
5267
5206
  };
5268
- //#endregion
5269
- //#region src/css/property-descriptors/list-style-image.ts
5207
+ // src/css/property-descriptors/list-style-image.ts
5270
5208
  const listStyleImage = {
5271
5209
  name: "list-style-image",
5272
5210
  initialValue: "none",
@@ -5279,8 +5217,7 @@ const listStyleImage = {
5279
5217
  return image.parse(context, token);
5280
5218
  }
5281
5219
  };
5282
- //#endregion
5283
- //#region src/css/property-descriptors/list-style-position.ts
5220
+ // src/css/property-descriptors/list-style-position.ts
5284
5221
  const listStylePosition = {
5285
5222
  name: "list-style-position",
5286
5223
  initialValue: "outside",
@@ -5293,8 +5230,7 @@ const listStylePosition = {
5293
5230
  }
5294
5231
  }
5295
5232
  };
5296
- //#endregion
5297
- //#region src/css/property-descriptors/margin.ts
5233
+ // src/css/property-descriptors/margin.ts
5298
5234
  const marginForSide = (side) => ({
5299
5235
  name: `margin-${side}`,
5300
5236
  initialValue: "0",
@@ -5305,8 +5241,7 @@ const marginTop = marginForSide("top");
5305
5241
  const marginRight = marginForSide("right");
5306
5242
  const marginBottom = marginForSide("bottom");
5307
5243
  const marginLeft = marginForSide("left");
5308
- //#endregion
5309
- //#region src/css/property-descriptors/overflow-wrap.ts
5244
+ // src/css/property-descriptors/overflow-wrap.ts
5310
5245
  const overflowWrap = {
5311
5246
  name: "overflow-wrap",
5312
5247
  initialValue: "normal",
@@ -5319,8 +5254,7 @@ const overflowWrap = {
5319
5254
  }
5320
5255
  }
5321
5256
  };
5322
- //#endregion
5323
- //#region src/css/property-descriptors/padding.ts
5257
+ // src/css/property-descriptors/padding.ts
5324
5258
  const paddingForSide = (side) => ({
5325
5259
  name: `padding-${side}`,
5326
5260
  initialValue: "0",
@@ -5332,8 +5266,7 @@ const paddingTop = paddingForSide("top");
5332
5266
  const paddingRight = paddingForSide("right");
5333
5267
  const paddingBottom = paddingForSide("bottom");
5334
5268
  const paddingLeft = paddingForSide("left");
5335
- //#endregion
5336
- //#region src/css/property-descriptors/text-align.ts
5269
+ // src/css/property-descriptors/text-align.ts
5337
5270
  const textAlign = {
5338
5271
  name: "text-align",
5339
5272
  initialValue: "left",
@@ -5348,8 +5281,7 @@ const textAlign = {
5348
5281
  }
5349
5282
  }
5350
5283
  };
5351
- //#endregion
5352
- //#region src/css/property-descriptors/position.ts
5284
+ // src/css/property-descriptors/position.ts
5353
5285
  const position = {
5354
5286
  name: "position",
5355
5287
  initialValue: "static",
@@ -5365,8 +5297,7 @@ const position = {
5365
5297
  return 0;
5366
5298
  }
5367
5299
  };
5368
- //#endregion
5369
- //#region src/css/property-descriptors/text-shadow.ts
5300
+ // src/css/property-descriptors/text-shadow.ts
5370
5301
  const textShadow = {
5371
5302
  name: "text-shadow",
5372
5303
  initialValue: "none",
@@ -5396,8 +5327,7 @@ const textShadow = {
5396
5327
  });
5397
5328
  }
5398
5329
  };
5399
- //#endregion
5400
- //#region src/css/property-descriptors/text-transform.ts
5330
+ // src/css/property-descriptors/text-transform.ts
5401
5331
  const textTransform = {
5402
5332
  name: "text-transform",
5403
5333
  initialValue: "none",
@@ -5412,8 +5342,7 @@ const textTransform = {
5412
5342
  return 0;
5413
5343
  }
5414
5344
  };
5415
- //#endregion
5416
- //#region src/css/property-descriptors/transform.ts
5345
+ // src/css/property-descriptors/transform.ts
5417
5346
  const transform$1 = {
5418
5347
  name: "transform",
5419
5348
  initialValue: "none",
@@ -5468,8 +5397,7 @@ const SUPPORTED_TRANSFORM_FUNCTIONS = {
5468
5397
  matrix3d,
5469
5398
  rotate: rotate$1
5470
5399
  };
5471
- //#endregion
5472
- //#region src/css/property-descriptors/transform-origin.ts
5400
+ // src/css/property-descriptors/transform-origin.ts
5473
5401
  const DEFAULT_VALUE = {
5474
5402
  type: 16,
5475
5403
  number: 50,
@@ -5487,8 +5415,7 @@ const transformOrigin = {
5487
5415
  return [at(origins, 0), at(origins, 1)];
5488
5416
  }
5489
5417
  };
5490
- //#endregion
5491
- //#region src/css/property-descriptors/rotate.ts
5418
+ // src/css/property-descriptors/rotate.ts
5492
5419
  const rotate = {
5493
5420
  name: "rotate",
5494
5421
  initialValue: "none",
@@ -5503,8 +5430,7 @@ const rotate = {
5503
5430
  return null;
5504
5431
  }
5505
5432
  };
5506
- //#endregion
5507
- //#region src/css/property-descriptors/visibility.ts
5433
+ // src/css/property-descriptors/visibility.ts
5508
5434
  const visibility = {
5509
5435
  name: "visibility",
5510
5436
  initialValue: "none",
@@ -5518,8 +5444,7 @@ const visibility = {
5518
5444
  }
5519
5445
  }
5520
5446
  };
5521
- //#endregion
5522
- //#region src/css/property-descriptors/word-break.ts
5447
+ // src/css/property-descriptors/word-break.ts
5523
5448
  const wordBreak = {
5524
5449
  name: "word-break",
5525
5450
  initialValue: "normal",
@@ -5533,8 +5458,7 @@ const wordBreak = {
5533
5458
  }
5534
5459
  }
5535
5460
  };
5536
- //#endregion
5537
- //#region src/css/property-descriptors/white-space.ts
5461
+ // src/css/property-descriptors/white-space.ts
5538
5462
  const whiteSpace = {
5539
5463
  name: "white-space",
5540
5464
  initialValue: "normal",
@@ -5550,8 +5474,7 @@ const whiteSpace = {
5550
5474
  }
5551
5475
  }
5552
5476
  };
5553
- //#endregion
5554
- //#region src/css/property-descriptors/writing-mode.ts
5477
+ // src/css/property-descriptors/writing-mode.ts
5555
5478
  const isVerticalWritingMode = (writingMode) => writingMode !== 0;
5556
5479
  const isSidewaysWritingMode = (writingMode) => writingMode === 3 || writingMode === 4;
5557
5480
  const writingMode = {
@@ -5569,8 +5492,7 @@ const writingMode = {
5569
5492
  }
5570
5493
  }
5571
5494
  };
5572
- //#endregion
5573
- //#region src/css/property-descriptors/z-index.ts
5495
+ // src/css/property-descriptors/z-index.ts
5574
5496
  const zIndex = {
5575
5497
  name: "z-index",
5576
5498
  initialValue: "auto",
@@ -5588,8 +5510,7 @@ const zIndex = {
5588
5510
  throw new Error(`Invalid z-index number parsed`);
5589
5511
  }
5590
5512
  };
5591
- //#endregion
5592
- //#region src/css/types/time.ts
5513
+ // src/css/types/time.ts
5593
5514
  const time = {
5594
5515
  name: "time",
5595
5516
  parse: (_context, value) => {
@@ -5600,8 +5521,7 @@ const time = {
5600
5521
  throw new Error(`Unsupported time type`);
5601
5522
  }
5602
5523
  };
5603
- //#endregion
5604
- //#region src/css/property-descriptors/opacity.ts
5524
+ // src/css/property-descriptors/opacity.ts
5605
5525
  const opacity = {
5606
5526
  name: "opacity",
5607
5527
  initialValue: "1",
@@ -5612,8 +5532,7 @@ const opacity = {
5612
5532
  return 1;
5613
5533
  }
5614
5534
  };
5615
- //#endregion
5616
- //#region src/css/property-descriptors/text-decoration-style.ts
5535
+ // src/css/property-descriptors/text-decoration-style.ts
5617
5536
  const textDecorationStyle = {
5618
5537
  name: "text-decoration-style",
5619
5538
  initialValue: "solid",
@@ -5629,8 +5548,7 @@ const textDecorationStyle = {
5629
5548
  }
5630
5549
  }
5631
5550
  };
5632
- //#endregion
5633
- //#region src/css/property-descriptors/text-decoration-thickness.ts
5551
+ // src/css/property-descriptors/text-decoration-thickness.ts
5634
5552
  const textDecorationThickness = {
5635
5553
  name: "text-decoration-thickness",
5636
5554
  initialValue: "auto",
@@ -5645,8 +5563,7 @@ const textDecorationThickness = {
5645
5563
  return "auto";
5646
5564
  }
5647
5565
  };
5648
- //#endregion
5649
- //#region src/css/property-descriptors/text-underline-offset.ts
5566
+ // src/css/property-descriptors/text-underline-offset.ts
5650
5567
  const textUnderlineOffset = {
5651
5568
  name: "text-underline-offset",
5652
5569
  initialValue: "auto",
@@ -5660,8 +5577,7 @@ const textUnderlineOffset = {
5660
5577
  return "auto";
5661
5578
  }
5662
5579
  };
5663
- //#endregion
5664
- //#region src/css/property-descriptors/font-weight.ts
5580
+ // src/css/property-descriptors/font-weight.ts
5665
5581
  const fontWeight = {
5666
5582
  name: "font-weight",
5667
5583
  initialValue: "normal",
@@ -5676,8 +5592,7 @@ const fontWeight = {
5676
5592
  return 400;
5677
5593
  }
5678
5594
  };
5679
- //#endregion
5680
- //#region src/css/property-descriptors/font-variant.ts
5595
+ // src/css/property-descriptors/font-variant.ts
5681
5596
  const fontVariant = {
5682
5597
  name: "font-variant",
5683
5598
  initialValue: "none",
@@ -5687,8 +5602,7 @@ const fontVariant = {
5687
5602
  return tokens.filter(isIdentToken).map((token) => token.value);
5688
5603
  }
5689
5604
  };
5690
- //#endregion
5691
- //#region src/css/property-descriptors/font-style.ts
5605
+ // src/css/property-descriptors/font-style.ts
5692
5606
  const fontStyle = {
5693
5607
  name: "font-style",
5694
5608
  initialValue: "normal",
@@ -5702,8 +5616,7 @@ const fontStyle = {
5702
5616
  }
5703
5617
  }
5704
5618
  };
5705
- //#endregion
5706
- //#region src/css/property-descriptors/duration.ts
5619
+ // src/css/property-descriptors/duration.ts
5707
5620
  const duration = {
5708
5621
  name: "duration",
5709
5622
  initialValue: "0s",
@@ -5713,8 +5626,7 @@ const duration = {
5713
5626
  return tokens.filter(isDimensionToken).map((token) => time.parse(context, token));
5714
5627
  }
5715
5628
  };
5716
- //#endregion
5717
- //#region src/css/property-descriptors/box-shadow.ts
5629
+ // src/css/property-descriptors/box-shadow.ts
5718
5630
  const boxShadow = {
5719
5631
  name: "box-shadow",
5720
5632
  initialValue: "none",
@@ -5748,8 +5660,7 @@ const boxShadow = {
5748
5660
  });
5749
5661
  }
5750
5662
  };
5751
- //#endregion
5752
- //#region src/css/property-descriptors/paint-order.ts
5663
+ // src/css/property-descriptors/paint-order.ts
5753
5664
  const paintOrder = {
5754
5665
  name: "paint-order",
5755
5666
  initialValue: "normal",
@@ -5779,8 +5690,7 @@ const paintOrder = {
5779
5690
  return layers;
5780
5691
  }
5781
5692
  };
5782
- //#endregion
5783
- //#region src/css/property-descriptors/webkit-text-stroke-color.ts
5693
+ // src/css/property-descriptors/webkit-text-stroke-color.ts
5784
5694
  const webkitTextStrokeColor = {
5785
5695
  name: `-webkit-text-stroke-color`,
5786
5696
  initialValue: "currentcolor",
@@ -5788,8 +5698,7 @@ const webkitTextStrokeColor = {
5788
5698
  type: 3,
5789
5699
  format: "color"
5790
5700
  };
5791
- //#endregion
5792
- //#region src/css/property-descriptors/webkit-text-stroke-width.ts
5701
+ // src/css/property-descriptors/webkit-text-stroke-width.ts
5793
5702
  const webkitTextStrokeWidth = {
5794
5703
  name: `-webkit-text-stroke-width`,
5795
5704
  initialValue: "0",
@@ -5800,8 +5709,7 @@ const webkitTextStrokeWidth = {
5800
5709
  return 0;
5801
5710
  }
5802
5711
  };
5803
- //#endregion
5804
- //#region src/css/property-descriptors/webkit-line-clamp.ts
5712
+ // src/css/property-descriptors/webkit-line-clamp.ts
5805
5713
  /**
5806
5714
  * -webkit-line-clamp property descriptor
5807
5715
  * Used with display: -webkit-box and -webkit-box-orient: vertical
@@ -5818,8 +5726,7 @@ const webkitLineClamp = {
5818
5726
  return 0;
5819
5727
  }
5820
5728
  };
5821
- //#endregion
5822
- //#region src/css/property-descriptors/object-fit.ts
5729
+ // src/css/property-descriptors/object-fit.ts
5823
5730
  const objectFit = {
5824
5731
  name: "object-fit",
5825
5732
  initialValue: "fill",
@@ -5840,8 +5747,7 @@ const parseDisplayValue = (display) => {
5840
5747
  }
5841
5748
  return 0;
5842
5749
  };
5843
- //#endregion
5844
- //#region src/css/property-descriptors/text-overflow.ts
5750
+ // src/css/property-descriptors/text-overflow.ts
5845
5751
  const textOverflow = {
5846
5752
  name: "text-overflow",
5847
5753
  initialValue: "clip",
@@ -5854,8 +5760,7 @@ const textOverflow = {
5854
5760
  }
5855
5761
  }
5856
5762
  };
5857
- //#endregion
5858
- //#region src/css/property-descriptors/image-rendering.ts
5763
+ // src/css/property-descriptors/image-rendering.ts
5859
5764
  const imageRendering = {
5860
5765
  name: "image-rendering",
5861
5766
  initialValue: "auto",
@@ -5874,8 +5779,7 @@ const imageRendering = {
5874
5779
  }
5875
5780
  }
5876
5781
  };
5877
- //#endregion
5878
- //#region src/css/property-descriptors/mix-blend-mode.ts
5782
+ // src/css/property-descriptors/mix-blend-mode.ts
5879
5783
  const MIX_BLEND_MODE$1 = {
5880
5784
  NORMAL: "normal",
5881
5785
  MULTIPLY: "multiply",
@@ -5904,8 +5808,7 @@ const mixBlendMode = {
5904
5808
  return VALID_VALUES$1.has(token) ? token : MIX_BLEND_MODE$1.NORMAL;
5905
5809
  }
5906
5810
  };
5907
- //#endregion
5908
- //#region src/css/property-descriptors/filter.ts
5811
+ // src/css/property-descriptors/filter.ts
5909
5812
  const filter = {
5910
5813
  name: "filter",
5911
5814
  initialValue: "none",
@@ -5975,8 +5878,7 @@ const renderFilterArgs = (values) => {
5975
5878
  }
5976
5879
  return parts.join("").trim();
5977
5880
  };
5978
- //#endregion
5979
- //#region src/css/property-descriptors/font-variant-ligatures.ts
5881
+ // src/css/property-descriptors/font-variant-ligatures.ts
5980
5882
  const fontVariantLigatures = {
5981
5883
  name: "font-variant-ligatures",
5982
5884
  initialValue: "normal",
@@ -5997,8 +5899,7 @@ const fontVariantLigatures = {
5997
5899
  }
5998
5900
  }
5999
5901
  };
6000
- //#endregion
6001
- //#region src/css/property-descriptors/zoom.ts
5902
+ // src/css/property-descriptors/zoom.ts
6002
5903
  const zoom = {
6003
5904
  name: "zoom",
6004
5905
  initialValue: "1",
@@ -6010,8 +5911,7 @@ const zoom = {
6010
5911
  return 1;
6011
5912
  }
6012
5913
  };
6013
- //#endregion
6014
- //#region src/css/property-descriptors/object-position.ts
5914
+ // src/css/property-descriptors/object-position.ts
6015
5915
  const objectPosition = {
6016
5916
  name: "object-position",
6017
5917
  initialValue: "50% 50%",
@@ -6073,8 +5973,7 @@ const backgroundBlendMode = {
6073
5973
  return modes.length > 0 ? modes : ["normal"];
6074
5974
  }
6075
5975
  };
6076
- //#endregion
6077
- //#region src/css/property-descriptors/border-image-source.ts
5976
+ // src/css/property-descriptors/border-image-source.ts
6078
5977
  const borderImageSource = {
6079
5978
  name: "border-image-source",
6080
5979
  initialValue: "none",
@@ -6088,8 +5987,7 @@ const borderImageSource = {
6088
5987
  return image.parse(context, at(filtered, 0));
6089
5988
  }
6090
5989
  };
6091
- //#endregion
6092
- //#region src/css/property-descriptors/border-image-slice.ts
5990
+ // src/css/property-descriptors/border-image-slice.ts
6093
5991
  const fillSides$1 = (sides) => {
6094
5992
  const result = [...sides];
6095
5993
  if (result.length === 1) {
@@ -6138,8 +6036,7 @@ const borderImageSlice = {
6138
6036
  };
6139
6037
  }
6140
6038
  };
6141
- //#endregion
6142
- //#region src/css/property-descriptors/border-image-repeat.ts
6039
+ // src/css/property-descriptors/border-image-repeat.ts
6143
6040
  const parseRepeatValue = (value) => {
6144
6041
  switch (value) {
6145
6042
  case "repeat": return 1;
@@ -6164,8 +6061,7 @@ const borderImageRepeat = {
6164
6061
  };
6165
6062
  }
6166
6063
  };
6167
- //#endregion
6168
- //#region src/css/property-descriptors/box-decoration-break.ts
6064
+ // src/css/property-descriptors/box-decoration-break.ts
6169
6065
  const boxDecorationBreak = {
6170
6066
  name: "box-decoration-break",
6171
6067
  initialValue: "slice",
@@ -6178,8 +6074,7 @@ const boxDecorationBreak = {
6178
6074
  }
6179
6075
  }
6180
6076
  };
6181
- //#endregion
6182
- //#region src/css/property-descriptors/accent-color.ts
6077
+ // src/css/property-descriptors/accent-color.ts
6183
6078
  const accentColor = {
6184
6079
  name: "accent-color",
6185
6080
  initialValue: "auto",
@@ -6190,8 +6085,7 @@ const accentColor = {
6190
6085
  return color$1.parse(context, token);
6191
6086
  }
6192
6087
  };
6193
- //#endregion
6194
- //#region src/css/property-descriptors/webkit-text-fill-color.ts
6088
+ // src/css/property-descriptors/webkit-text-fill-color.ts
6195
6089
  const webkitTextFillColor = {
6196
6090
  name: "-webkit-text-fill-color",
6197
6091
  initialValue: "currentcolor",
@@ -6202,8 +6096,7 @@ const webkitTextFillColor = {
6202
6096
  return color$1.parse(context, token);
6203
6097
  }
6204
6098
  };
6205
- //#endregion
6206
- //#region src/css/property-descriptors/isolation.ts
6099
+ // src/css/property-descriptors/isolation.ts
6207
6100
  const isolation = {
6208
6101
  name: "isolation",
6209
6102
  initialValue: "auto",
@@ -6213,8 +6106,52 @@ const isolation = {
6213
6106
  return value === "isolate" ? 1 : 0;
6214
6107
  }
6215
6108
  };
6216
- //#endregion
6217
- //#region src/css/property-descriptors/outline.ts
6109
+ // src/css/property-descriptors/will-change.ts
6110
+ const STACKING_HINTS = /* @__PURE__ */ new Set([
6111
+ "transform",
6112
+ "translate",
6113
+ "rotate",
6114
+ "scale",
6115
+ "opacity",
6116
+ "filter",
6117
+ "backdrop-filter",
6118
+ "mix-blend-mode",
6119
+ "isolation",
6120
+ "clip-path",
6121
+ "mask",
6122
+ "mask-image",
6123
+ "mask-border",
6124
+ "perspective",
6125
+ "contain",
6126
+ "offset-path",
6127
+ "offset-distance",
6128
+ "offset-rotate",
6129
+ "top",
6130
+ "left",
6131
+ "bottom",
6132
+ "right",
6133
+ "z-index"
6134
+ ]);
6135
+ const willChange = {
6136
+ name: "will-change",
6137
+ initialValue: "auto",
6138
+ prefix: false,
6139
+ type: 1,
6140
+ parse: (_context, tokens) => {
6141
+ return tokens.some((token) => isIdentToken(token) && STACKING_HINTS.has(token.value)) ? 1 : 0;
6142
+ }
6143
+ };
6144
+ // src/css/property-descriptors/contain.ts
6145
+ const contain = {
6146
+ name: "contain",
6147
+ initialValue: "none",
6148
+ prefix: false,
6149
+ type: 2,
6150
+ parse: (_context, value) => {
6151
+ return /\b(paint|strict|content)\b/.test(value) ? 1 : 0;
6152
+ }
6153
+ };
6154
+ // src/css/property-descriptors/outline.ts
6218
6155
  const outlineStyle = {
6219
6156
  name: "outline-style",
6220
6157
  initialValue: "none",
@@ -6257,8 +6194,7 @@ const outlineOffset = {
6257
6194
  return isDimensionToken(token) || isNumberToken(token) ? token.number : 0;
6258
6195
  }
6259
6196
  };
6260
- //#endregion
6261
- //#region src/css/property-descriptors/backdrop-filter.ts
6197
+ // src/css/property-descriptors/backdrop-filter.ts
6262
6198
  const backdropFilter = {
6263
6199
  name: "backdrop-filter",
6264
6200
  initialValue: "none",
@@ -6266,8 +6202,7 @@ const backdropFilter = {
6266
6202
  type: 1,
6267
6203
  parse: (context, tokens) => filter.parse(context, tokens)
6268
6204
  };
6269
- //#endregion
6270
- //#region src/css/property-descriptors/mask.ts
6205
+ // src/css/property-descriptors/mask.ts
6271
6206
  const maskImage = {
6272
6207
  name: "mask-image",
6273
6208
  initialValue: "none",
@@ -6297,8 +6232,7 @@ const maskSize = {
6297
6232
  type: 1,
6298
6233
  parse: backgroundSize.parse
6299
6234
  };
6300
- //#endregion
6301
- //#region src/css/property-descriptors/text-emphasis.ts
6235
+ // src/css/property-descriptors/text-emphasis.ts
6302
6236
  const SHAPES = [
6303
6237
  "dot",
6304
6238
  "circle",
@@ -6373,8 +6307,7 @@ const textEmphasisPosition = {
6373
6307
  };
6374
6308
  }
6375
6309
  };
6376
- //#endregion
6377
- //#region src/css/property-descriptors/border-image-width.ts
6310
+ // src/css/property-descriptors/border-image-width.ts
6378
6311
  const fillSides = (sides) => {
6379
6312
  const result = [...sides];
6380
6313
  if (result.length === 1) {
@@ -6471,8 +6404,7 @@ const borderImageOutset = {
6471
6404
  };
6472
6405
  }
6473
6406
  };
6474
- //#endregion
6475
- //#region src/css/property-descriptors/webkit-box-reflect.ts
6407
+ // src/css/property-descriptors/webkit-box-reflect.ts
6476
6408
  /**
6477
6409
  * -webkit-box-reflect: <direction> <offset>? <mask-image>?
6478
6410
  *
@@ -6516,8 +6448,7 @@ const webkitBoxReflect = {
6516
6448
  };
6517
6449
  }
6518
6450
  };
6519
- //#endregion
6520
- //#region src/css/property-descriptors/translate.ts
6451
+ // src/css/property-descriptors/translate.ts
6521
6452
  const translate = {
6522
6453
  name: "translate",
6523
6454
  initialValue: "none",
@@ -6530,8 +6461,7 @@ const translate = {
6530
6461
  return [at(values, 0), values.length > 1 ? at(values, 1) : ZERO_LENGTH];
6531
6462
  }
6532
6463
  };
6533
- //#endregion
6534
- //#region src/css/property-descriptors/scale.ts
6464
+ // src/css/property-descriptors/scale.ts
6535
6465
  const scale = {
6536
6466
  name: "scale",
6537
6467
  initialValue: "none",
@@ -6566,8 +6496,7 @@ const STYLESHEET_READY_TIMEOUT_MS = 1e4;
6566
6496
  * never fires, the mount is rejected instead of hanging forever.
6567
6497
  */
6568
6498
  const IFRAME_LOAD_WATCHDOG_MS = 6e4;
6569
- //#endregion
6570
- //#region src/css/parse.ts
6499
+ // src/css/parse.ts
6571
6500
  const STANDARD_PROPERTIES = [
6572
6501
  [
6573
6502
  "animationDuration",
@@ -7004,6 +6933,16 @@ const STANDARD_PROPERTIES = [
7004
6933
  isolation,
7005
6934
  "isolation"
7006
6935
  ],
6936
+ [
6937
+ "willChange",
6938
+ willChange,
6939
+ "will-change"
6940
+ ],
6941
+ [
6942
+ "contain",
6943
+ contain,
6944
+ "contain"
6945
+ ],
7007
6946
  [
7008
6947
  "outlineColor",
7009
6948
  outlineColor,
@@ -7135,8 +7074,7 @@ const parse = (context, descriptor, style) => {
7135
7074
  }
7136
7075
  return result;
7137
7076
  };
7138
- //#endregion
7139
- //#region src/css/grouped/border-styles.ts
7077
+ // src/css/grouped/border-styles.ts
7140
7078
  /**
7141
7079
  * Read-only grouped accessor for border-related CSS properties.
7142
7080
  *
@@ -7213,8 +7151,7 @@ var BorderStyles = class {
7213
7151
  return this.styles.boxShadow;
7214
7152
  }
7215
7153
  };
7216
- //#endregion
7217
- //#region src/css/grouped/background-styles.ts
7154
+ // src/css/grouped/background-styles.ts
7218
7155
  /**
7219
7156
  * Read-only grouped accessor for background-related CSS properties.
7220
7157
  *
@@ -7252,8 +7189,7 @@ var BackgroundStyles = class {
7252
7189
  return this.styles.backgroundBlendMode;
7253
7190
  }
7254
7191
  };
7255
- //#endregion
7256
- //#region src/css/grouped/font-styles.ts
7192
+ // src/css/grouped/font-styles.ts
7257
7193
  /**
7258
7194
  * Read-only grouped accessor for font/text-related CSS properties.
7259
7195
  *
@@ -7348,8 +7284,7 @@ var FontStyles = class {
7348
7284
  return this.styles.paintOrder;
7349
7285
  }
7350
7286
  };
7351
- //#endregion
7352
- //#region src/css/grouped/layout-styles.ts
7287
+ // src/css/grouped/layout-styles.ts
7353
7288
  /**
7354
7289
  * Read-only grouped accessor for layout/display/positioning CSS properties.
7355
7290
  *
@@ -7477,8 +7412,7 @@ var LayoutStyles = class {
7477
7412
  return this.styles.isInlineLevel();
7478
7413
  }
7479
7414
  };
7480
- //#endregion
7481
- //#region src/css/index.ts
7415
+ // src/css/index.ts
7482
7416
  var CSSParsedDeclaration = class {
7483
7417
  animationDuration;
7484
7418
  backgroundClip;
@@ -7572,6 +7506,8 @@ var CSSParsedDeclaration = class {
7572
7506
  accentColor;
7573
7507
  webkitTextFillColor;
7574
7508
  isolation;
7509
+ willChange;
7510
+ contain;
7575
7511
  outlineColor;
7576
7512
  outlineStyle;
7577
7513
  outlineWidth;
@@ -7670,8 +7606,7 @@ var CSSParsedCounterDeclaration = class {
7670
7606
  this.counterReset = parse(context, counterReset, declaration.counterReset);
7671
7607
  }
7672
7608
  };
7673
- //#endregion
7674
- //#region src/core/debugger.ts
7609
+ // src/core/debugger.ts
7675
7610
  const elementDebuggerAttribute = "data-html2canvas-debug";
7676
7611
  const getElementDebugType = (element) => {
7677
7612
  if (typeof element.getAttribute !== "function") return 0;
@@ -7687,8 +7622,7 @@ const isDebugging = (element, type) => {
7687
7622
  const elementType = getElementDebugType(element);
7688
7623
  return elementType === 1 || type === elementType;
7689
7624
  };
7690
- //#endregion
7691
- //#region src/dom/adopted-styles.ts
7625
+ // src/dom/adopted-styles.ts
7692
7626
  /**
7693
7627
  * Constructable stylesheet cloning (adoptedStyleSheets).
7694
7628
  *
@@ -7729,8 +7663,7 @@ const createAdoptedStylesElement = (styleDocument, sheets, nonce) => {
7729
7663
  if (nonce) style.nonce = nonce;
7730
7664
  return style;
7731
7665
  };
7732
- //#endregion
7733
- //#region src/dom/slot-cloner.ts
7666
+ // src/dom/slot-cloner.ts
7734
7667
  /** Exported for reuse in document-cloner.ts */
7735
7668
  const IGNORE_ATTRIBUTE = "data-html2canvas-ignore";
7736
7669
  /**
@@ -7867,8 +7800,7 @@ var SlotCloner = class {
7867
7800
  if (style) target.appendChild(style);
7868
7801
  }
7869
7802
  };
7870
- //#endregion
7871
- //#region src/dom/copy-css-styles.ts
7803
+ // src/dom/copy-css-styles.ts
7872
7804
  /**
7873
7805
  * Computed-style copying for cloned elements.
7874
7806
  *
@@ -7896,8 +7828,7 @@ const copyCSSStyles = (style, target) => {
7896
7828
  if (parts.length > 0) target.style.cssText = parts.join(";") + ";";
7897
7829
  return target;
7898
7830
  };
7899
- //#endregion
7900
- //#region src/dom/pseudo-content.ts
7831
+ // src/dom/pseudo-content.ts
7901
7832
  /**
7902
7833
  * Pseudo-element (::before / ::after) content resolution.
7903
7834
  *
@@ -7917,19 +7848,19 @@ const PSEUDO_HIDE_ELEMENT_STYLE = `{
7917
7848
  }`;
7918
7849
  /**
7919
7850
  * Inject the stylesheet that hides pseudo-element surrogate containers.
7920
- * Called on the cloned <body> so the surrogates themselves never render.
7851
+ * Added to the cloned <head> so the surrogates themselves never render.
7921
7852
  */
7922
- const createPseudoHideStyles = (body, cspNonce) => {
7923
- createStyles(body, `.${PSEUDO_HIDE_ELEMENT_CLASS_BEFORE}${PSEUDO_BEFORE}${PSEUDO_HIDE_ELEMENT_STYLE}
7853
+ const createPseudoHideStyles = (parent, cspNonce) => {
7854
+ createStyles(parent, `.${PSEUDO_HIDE_ELEMENT_CLASS_BEFORE}${PSEUDO_BEFORE}${PSEUDO_HIDE_ELEMENT_STYLE}
7924
7855
  .${PSEUDO_HIDE_ELEMENT_CLASS_AFTER}${PSEUDO_AFTER}${PSEUDO_HIDE_ELEMENT_STYLE}`, cspNonce);
7925
7856
  };
7926
- const createStyles = (body, styles, cspNonce) => {
7927
- const document = body.ownerDocument;
7857
+ const createStyles = (parent, styles, cspNonce) => {
7858
+ const document = parent.ownerDocument;
7928
7859
  if (document) {
7929
7860
  const style = document.createElement("style");
7930
7861
  style.textContent = styles;
7931
7862
  if (cspNonce) style.nonce = cspNonce;
7932
- body.appendChild(style);
7863
+ parent.appendChild(style);
7933
7864
  }
7934
7865
  };
7935
7866
  /**
@@ -8003,8 +7934,7 @@ var PseudoContentResolver = class {
8003
7934
  return anonymousReplacedElement;
8004
7935
  }
8005
7936
  };
8006
- //#endregion
8007
- //#region src/core/abort-helper.ts
7937
+ // src/core/abort-helper.ts
8008
7938
  /**
8009
7939
  * AbortSignal helper utilities.
8010
7940
  */
@@ -8019,8 +7949,7 @@ var PseudoContentResolver = class {
8019
7949
  const throwIfAborted = (signal) => {
8020
7950
  if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
8021
7951
  };
8022
- //#endregion
8023
- //#region src/dom/iframe-mount.ts
7952
+ // src/dom/iframe-mount.ts
8024
7953
  const trustedTypePolicies = /* @__PURE__ */ new WeakMap();
8025
7954
  /**
8026
7955
  * Resolve the Trusted Types policy used for writing the clone document.
@@ -8049,9 +7978,20 @@ const createIFrameContainer = (ownerDocument, bounds, customContainer) => {
8049
7978
  cloneIframeContainer.style.position = "fixed";
8050
7979
  cloneIframeContainer.style.left = "-10000px";
8051
7980
  cloneIframeContainer.style.top = "0px";
8052
- cloneIframeContainer.style.border = "0";
8053
7981
  cloneIframeContainer.width = bounds.width.toString();
8054
7982
  cloneIframeContainer.height = bounds.height.toString();
7983
+ const contentBox = [
7984
+ ["width", `${bounds.width}px`],
7985
+ ["height", `${bounds.height}px`],
7986
+ ["min-width", "0px"],
7987
+ ["max-width", "none"],
7988
+ ["min-height", "0px"],
7989
+ ["max-height", "none"],
7990
+ ["box-sizing", "content-box"],
7991
+ ["padding", "0px"],
7992
+ ["border", "0"]
7993
+ ];
7994
+ for (const [property, value] of contentBox) cloneIframeContainer.style.setProperty(property, value, "important");
8055
7995
  cloneIframeContainer.scrolling = "no";
8056
7996
  cloneIframeContainer.setAttribute(IGNORE_ATTRIBUTE, "true");
8057
7997
  (customContainer || ownerDocument.body).appendChild(cloneIframeContainer);
@@ -8184,6 +8124,11 @@ const stylesheetsReady = (documentClone, logger, signal, timeoutMs = STYLESHEET_
8184
8124
  pending.push(new Promise((resolve) => {
8185
8125
  let elapsed = 0;
8186
8126
  const timer = setInterval(() => {
8127
+ if (signal?.aborted) {
8128
+ clearInterval(timer);
8129
+ resolve();
8130
+ return;
8131
+ }
8187
8132
  elapsed += 50;
8188
8133
  const currentSheet = style.sheet;
8189
8134
  if (currentSheet && isSheetFullyApplied(currentSheet) || elapsed >= timeoutMs) {
@@ -8354,8 +8299,7 @@ const mountCloneInIFrame = (context, ownerDocument, windowSize, mount) => {
8354
8299
  throw error;
8355
8300
  });
8356
8301
  };
8357
- //#endregion
8358
- //#region src/dom/document-cloner.ts
8302
+ // src/dom/document-cloner.ts
8359
8303
  /**
8360
8304
  * Find the parent ShadowRoot of an element, if any
8361
8305
  * @param element - The element to check
@@ -8400,6 +8344,7 @@ var DocumentCloner = class {
8400
8344
  }
8401
8345
  this.documentElement = this.cloneNode(element.ownerDocument.documentElement, false);
8402
8346
  this.appendDocumentAdoptedStyles(element.ownerDocument);
8347
+ this.appendPseudoHideStyles();
8403
8348
  }
8404
8349
  /**
8405
8350
  * Re-materialise the source document's constructable stylesheets
@@ -8419,6 +8364,16 @@ var DocumentCloner = class {
8419
8364
  const style = createAdoptedStylesElement(this.documentElement.ownerDocument ?? ownerDocument, sheets, this.options.cspNonce);
8420
8365
  if (style) head.appendChild(style);
8421
8366
  }
8367
+ /**
8368
+ * Add the rules that hide the source ::before / ::after (the clone draws
8369
+ * them as surrogate elements) to the clone's <head>. Inside <body> the
8370
+ * <style> would be one of its children, and `body > :first-child`,
8371
+ * `:nth-child()` and sibling selectors would match the wrong elements.
8372
+ */
8373
+ appendPseudoHideStyles() {
8374
+ const head = this.documentElement.getElementsByTagName("head").item(0);
8375
+ createPseudoHideStyles(head ?? this.documentElement, this.options.cspNonce);
8376
+ }
8422
8377
  toIFrame(ownerDocument, windowSize) {
8423
8378
  return mountCloneInIFrame(this.context, ownerDocument, windowSize, {
8424
8379
  documentElement: this.documentElement,
@@ -8554,7 +8509,6 @@ var DocumentCloner = class {
8554
8509
  const style = window.getComputedStyle(node);
8555
8510
  const checkPseudoElements = canHavePseudoElements(node);
8556
8511
  if (this.referenceElement === node && isHTMLElementNode(clone)) this.clonedReferenceElement = clone;
8557
- if (isBodyElement(clone)) createPseudoHideStyles(clone, this.options.cspNonce);
8558
8512
  const counters = this.counters.parse(new CSSParsedCounterDeclaration(this.context, style));
8559
8513
  if (checkPseudoElements) {
8560
8514
  const styleBefore = window.getComputedStyle(node, ":before");
@@ -8588,8 +8542,7 @@ var DocumentCloner = class {
8588
8542
  return false;
8589
8543
  }
8590
8544
  };
8591
- //#endregion
8592
- //#region src/dom/dom-normalizer.ts
8545
+ // src/dom/dom-normalizer.ts
8593
8546
  /**
8594
8547
  * Normalize element styles for accurate rendering
8595
8548
  * This includes disabling animations and neutralizing transforms.
@@ -8677,8 +8630,115 @@ var DOMNormalizer = class {
8677
8630
  if (originalStyles.scale !== void 0) element.style.scale = originalStyles.scale;
8678
8631
  }
8679
8632
  };
8680
- //#endregion
8681
- //#region src/dom/element-container.ts
8633
+ // src/dom/filter-reference.ts
8634
+ const SVG_NS$1 = "http://www.w3.org/2000/svg";
8635
+ const XLINK_NS = "http://www.w3.org/1999/xlink";
8636
+ const REGION_DEFAULTS = {
8637
+ x: "-10%",
8638
+ y: "-10%",
8639
+ width: "120%",
8640
+ height: "120%"
8641
+ };
8642
+ const PRESENTATION_PROPERTIES = [
8643
+ "color-interpolation-filters",
8644
+ "flood-color",
8645
+ "flood-opacity",
8646
+ "lighting-color"
8647
+ ];
8648
+ const REFERENCE_RE = /^(["']?)(#[^"'\s()]+)\1$/;
8649
+ const URL_RE = /url\(\s*([^)]*?)\s*\)/g;
8650
+ /** The `#id` of a same-document url() body (`"#id"`, `'#id'` or `#id`), or null. */
8651
+ const parseFilterReference = (body) => {
8652
+ const match = REFERENCE_RE.exec(body.trim());
8653
+ return match ? match[2] : null;
8654
+ };
8655
+ /**
8656
+ * Resolve every same-document url() reference of a computed filter value.
8657
+ * References that cannot be expressed in the serialized SVG are left out, so
8658
+ * the compositor rejects the chain and the subtree keeps the legacy renderer.
8659
+ */
8660
+ function resolveFilterReferences(element, filter, box) {
8661
+ if (!filter || filter.indexOf("url(") === -1) return void 0;
8662
+ const references = /* @__PURE__ */ new Map();
8663
+ const seen = /* @__PURE__ */ new Set();
8664
+ for (const match of filter.matchAll(URL_RE)) {
8665
+ const ref = parseFilterReference(match[1]);
8666
+ if (!ref || seen.has(ref)) continue;
8667
+ seen.add(ref);
8668
+ const reference = resolveFilterReference(element.ownerDocument, ref, box);
8669
+ if (reference) references.set(ref, reference);
8670
+ }
8671
+ return references;
8672
+ }
8673
+ function resolveFilterReference(document, ref, box) {
8674
+ const source = document.getElementById(ref.slice(1));
8675
+ if (!source || source.namespaceURI !== SVG_NS$1 || source.localName !== "filter") return null;
8676
+ if (!isSelfContained(source)) return null;
8677
+ const region = filterRegion(source, box);
8678
+ if (!region) return null;
8679
+ const copy = source.cloneNode(true);
8680
+ inlinePresentation(source, copy);
8681
+ copy.removeAttribute("id");
8682
+ copy.setAttribute("filterUnits", "userSpaceOnUse");
8683
+ Object.keys(region).forEach((name) => copy.setAttribute(name, String(region[name])));
8684
+ const outset = Math.max(0, -region.x, -region.y, region.x + region.width - box.width, region.y + region.height - box.height);
8685
+ return {
8686
+ element: copy,
8687
+ region,
8688
+ outset: Math.ceil(outset)
8689
+ };
8690
+ }
8691
+ const hasHref = (node) => node.hasAttribute("href") || node.hasAttributeNS(XLINK_NS, "href");
8692
+ function isSelfContained(source) {
8693
+ if (source.getAttribute("primitiveUnits") === "objectBoundingBox" || hasHref(source)) return false;
8694
+ for (const primitive of Array.from(source.querySelectorAll("*"))) {
8695
+ if (primitive.localName === "feImage" || hasHref(primitive)) return false;
8696
+ for (const name of [
8697
+ "x",
8698
+ "y",
8699
+ "width",
8700
+ "height"
8701
+ ]) if ((primitive.getAttribute(name) ?? "").indexOf("%") !== -1) return false;
8702
+ }
8703
+ return true;
8704
+ }
8705
+ function filterRegion(source, box) {
8706
+ const boundingBox = source.getAttribute("filterUnits") !== "userSpaceOnUse";
8707
+ const read = (name, size) => {
8708
+ const raw = (source.getAttribute(name) ?? (boundingBox ? REGION_DEFAULTS[name] : "")).trim();
8709
+ if (raw === "") return null;
8710
+ const percentage = raw.endsWith("%");
8711
+ const value = Number(percentage ? raw.slice(0, -1) : raw.replace(/px$/, ""));
8712
+ if (!Number.isFinite(value)) return null;
8713
+ if (boundingBox) return (percentage ? value / 100 : value) * size;
8714
+ return percentage ? null : value;
8715
+ };
8716
+ const x = read("x", box.width);
8717
+ const y = read("y", box.height);
8718
+ const width = read("width", box.width);
8719
+ const height = read("height", box.height);
8720
+ if (x === null || y === null || width === null || height === null || width <= 0 || height <= 0) return null;
8721
+ return {
8722
+ x,
8723
+ y,
8724
+ width,
8725
+ height
8726
+ };
8727
+ }
8728
+ function inlinePresentation(source, copy) {
8729
+ const view = source.ownerDocument.defaultView;
8730
+ if (!view) return;
8731
+ const sources = [source, ...Array.from(source.querySelectorAll("*"))];
8732
+ const copies = [copy, ...Array.from(copy.querySelectorAll("*"))];
8733
+ sources.forEach((node, index) => {
8734
+ const style = view.getComputedStyle(node);
8735
+ for (const property of PRESENTATION_PROPERTIES) {
8736
+ const value = style.getPropertyValue(property);
8737
+ if (value) copies[index]?.setAttribute(property, value);
8738
+ }
8739
+ });
8740
+ }
8741
+ // src/dom/element-container.ts
8682
8742
  var ElementContainer = class {
8683
8743
  context;
8684
8744
  styles;
@@ -8691,6 +8751,11 @@ var ElementContainer = class {
8691
8751
  * bounds to leave a matching gap (issue #227).
8692
8752
  */
8693
8753
  legendBounds;
8754
+ /**
8755
+ * Same-document `filter: url(#id)` references, resolved while the cloned
8756
+ * DOM is available. The surface compositor renders them in an SVG pass.
8757
+ */
8758
+ filterReferences;
8694
8759
  createsStackingContext = false;
8695
8760
  createsRealStackingContext = false;
8696
8761
  isListOwner = false;
@@ -8715,6 +8780,7 @@ var ElementContainer = class {
8715
8780
  this.bounds = new Bounds(this.bounds.left, borderBoxTop, this.bounds.width, this.bounds.height - (borderBoxTop - this.bounds.top));
8716
8781
  }
8717
8782
  }
8783
+ this.filterReferences = resolveFilterReferences(element, this.styles.filter, this.bounds);
8718
8784
  if (isDebugging(element, 4)) this.debugRender = true;
8719
8785
  }
8720
8786
  /**
@@ -8737,8 +8803,7 @@ var ElementContainer = class {
8737
8803
  for (const child of this.elements) child.restoreTree();
8738
8804
  }
8739
8805
  };
8740
- //#endregion
8741
- //#region src/core/features.ts
8806
+ // src/core/features.ts
8742
8807
  /**
8743
8808
  * Runtime feature detection.
8744
8809
  *
@@ -8824,8 +8889,7 @@ const FEATURES = {
8824
8889
  return value;
8825
8890
  }
8826
8891
  };
8827
- //#endregion
8828
- //#region src/css/layout/text.ts
8892
+ // src/css/layout/text.ts
8829
8893
  var TextBounds = class {
8830
8894
  text;
8831
8895
  bounds;
@@ -8900,8 +8964,7 @@ const breakText = (value, styles) => {
8900
8964
  if (isVerticalWritingMode(styles.writingMode)) return segmentGraphemes(value);
8901
8965
  return styles.letterSpacing !== 0 ? segmentGraphemes(value) : segmentWords(value);
8902
8966
  };
8903
- //#endregion
8904
- //#region src/dom/text-container.ts
8967
+ // src/dom/text-container.ts
8905
8968
  var TextContainer = class {
8906
8969
  text;
8907
8970
  textBounds;
@@ -8924,8 +8987,7 @@ const capitalize = (m, p1, p2) => {
8924
8987
  if (m.length > 0) return p1 + p2.toUpperCase();
8925
8988
  return m;
8926
8989
  };
8927
- //#endregion
8928
- //#region src/dom/replaced-elements/image-element-container.ts
8990
+ // src/dom/replaced-elements/image-element-container.ts
8929
8991
  var ImageElementContainer = class extends ElementContainer {
8930
8992
  src;
8931
8993
  intrinsicWidth;
@@ -8938,8 +9000,7 @@ var ImageElementContainer = class extends ElementContainer {
8938
9000
  this.context.cache.addImage(this.src);
8939
9001
  }
8940
9002
  };
8941
- //#endregion
8942
- //#region src/dom/replaced-elements/canvas-element-container.ts
9003
+ // src/dom/replaced-elements/canvas-element-container.ts
8943
9004
  var CanvasElementContainer = class extends ElementContainer {
8944
9005
  canvas;
8945
9006
  intrinsicWidth;
@@ -8951,8 +9012,7 @@ var CanvasElementContainer = class extends ElementContainer {
8951
9012
  this.intrinsicHeight = canvas.height;
8952
9013
  }
8953
9014
  };
8954
- //#endregion
8955
- //#region src/dom/replaced-elements/svg-element-container.ts
9015
+ // src/dom/replaced-elements/svg-element-container.ts
8956
9016
  const BOX_OFFSET_PROPERTIES = [
8957
9017
  "position",
8958
9018
  "inset",
@@ -9002,8 +9062,7 @@ var SVGElementContainer = class extends ElementContainer {
9002
9062
  this.context.cache.addImage(this.svg);
9003
9063
  }
9004
9064
  };
9005
- //#endregion
9006
- //#region src/dom/elements/li-element-container.ts
9065
+ // src/dom/elements/li-element-container.ts
9007
9066
  var LIElementContainer = class extends ElementContainer {
9008
9067
  value;
9009
9068
  constructor(context, element, options = {}) {
@@ -9011,8 +9070,7 @@ var LIElementContainer = class extends ElementContainer {
9011
9070
  this.value = element.value;
9012
9071
  }
9013
9072
  };
9014
- //#endregion
9015
- //#region src/dom/elements/ol-element-container.ts
9073
+ // src/dom/elements/ol-element-container.ts
9016
9074
  var OLElementContainer = class extends ElementContainer {
9017
9075
  start;
9018
9076
  reversed;
@@ -9022,8 +9080,7 @@ var OLElementContainer = class extends ElementContainer {
9022
9080
  this.reversed = typeof element.reversed === "boolean" && element.reversed === true;
9023
9081
  }
9024
9082
  };
9025
- //#endregion
9026
- //#region src/dom/replaced-elements/input-element-container.ts
9083
+ // src/dom/replaced-elements/input-element-container.ts
9027
9084
  const CHECKBOX_BORDER_RADIUS = [{
9028
9085
  type: 15,
9029
9086
  flags: 0,
@@ -9078,8 +9135,7 @@ var InputElementContainer = class extends ElementContainer {
9078
9135
  }
9079
9136
  }
9080
9137
  };
9081
- //#endregion
9082
- //#region src/dom/elements/select-element-container.ts
9138
+ // src/dom/elements/select-element-container.ts
9083
9139
  var SelectElementContainer = class extends ElementContainer {
9084
9140
  value;
9085
9141
  constructor(context, element, options = {}) {
@@ -9088,8 +9144,7 @@ var SelectElementContainer = class extends ElementContainer {
9088
9144
  this.value = option ? option.text || "" : "";
9089
9145
  }
9090
9146
  };
9091
- //#endregion
9092
- //#region src/dom/elements/textarea-element-container.ts
9147
+ // src/dom/elements/textarea-element-container.ts
9093
9148
  var TextareaElementContainer = class extends ElementContainer {
9094
9149
  value;
9095
9150
  constructor(context, element, options = {}) {
@@ -9097,8 +9152,7 @@ var TextareaElementContainer = class extends ElementContainer {
9097
9152
  this.value = element.value;
9098
9153
  }
9099
9154
  };
9100
- //#endregion
9101
- //#region src/dom/replaced-elements/iframe-element-container.ts
9155
+ // src/dom/replaced-elements/iframe-element-container.ts
9102
9156
  var IFrameElementContainer = class extends ElementContainer {
9103
9157
  src;
9104
9158
  width;
@@ -9129,8 +9183,7 @@ var IFrameElementContainer = class extends ElementContainer {
9129
9183
  }
9130
9184
  }
9131
9185
  };
9132
- //#endregion
9133
- //#region src/dom/node-parser.ts
9186
+ // src/dom/node-parser.ts
9134
9187
  const LIST_OWNERS = [
9135
9188
  "OL",
9136
9189
  "UL",
@@ -9196,15 +9249,14 @@ const parseTree = (context, element, options = {}) => {
9196
9249
  return container;
9197
9250
  };
9198
9251
  const createsRealStackingContext = (node, container, root) => {
9199
- return container.styles.isPositionedWithZIndex() || container.styles.opacity < 1 || Boolean(container.styles.filter) || Boolean(container.styles.backdropFilter) || container.styles.maskImage.length > 0 || Boolean(container.styles.webkitBoxReflect) || container.styles.isolation === 1 || container.styles.isTransformed() || isBodyElement(node) && root.styles.isTransparent();
9252
+ return container.styles.isPositionedWithZIndex() || container.styles.opacity < 1 || Boolean(container.styles.filter) || Boolean(container.styles.backdropFilter) || container.styles.maskImage.length > 0 || Boolean(container.styles.webkitBoxReflect) || container.styles.isolation === 1 || container.styles.willChange === 1 || container.styles.contain === 1 || container.styles.isTransformed() || isBodyElement(node) && root.styles.isTransparent();
9200
9253
  };
9201
9254
  const createsStackingContext = (styles) => {
9202
9255
  if (styles.isPositioned() || styles.isFloating()) return true;
9203
9256
  if (styles.mixBlendMode !== MIX_BLEND_MODE$1.NORMAL) return true;
9204
9257
  return contains(styles.display, 268435456) || contains(styles.display, 33554432) || contains(styles.display, 536870912) || contains(styles.display, 134217728);
9205
9258
  };
9206
- //#endregion
9207
- //#region src/render/path.ts
9259
+ // src/render/path.ts
9208
9260
  const equalPath = (a, b) => {
9209
9261
  if (a.length === b.length) return a.some((v, i) => v === b[i]);
9210
9262
  return false;
@@ -9220,8 +9272,7 @@ const transformPath = (path, deltaX, deltaY, deltaW, deltaH) => {
9220
9272
  return point;
9221
9273
  });
9222
9274
  };
9223
- //#endregion
9224
- //#region src/render/vector.ts
9275
+ // src/render/vector.ts
9225
9276
  var Vector = class Vector {
9226
9277
  type;
9227
9278
  x;
@@ -9235,8 +9286,7 @@ var Vector = class Vector {
9235
9286
  return new Vector(this.x + deltaX, this.y + deltaY);
9236
9287
  }
9237
9288
  };
9238
- //#endregion
9239
- //#region src/render/bezier-curve.ts
9289
+ // src/render/bezier-curve.ts
9240
9290
  const lerp = (a, b, t) => {
9241
9291
  return new Vector(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t);
9242
9292
  };
@@ -9270,8 +9320,7 @@ var BezierCurve = class BezierCurve {
9270
9320
  }
9271
9321
  };
9272
9322
  const isBezierCurve = (path) => path.type === 1;
9273
- //#endregion
9274
- //#region src/render/bound-curves.ts
9323
+ // src/render/bound-curves.ts
9275
9324
  var BoundCurves = class {
9276
9325
  topLeftBorderDoubleOuterBox;
9277
9326
  topRightBorderDoubleOuterBox;
@@ -9395,8 +9444,7 @@ const calculatePaddingBoxPath = (curves) => {
9395
9444
  curves.bottomLeftPaddingBox
9396
9445
  ];
9397
9446
  };
9398
- //#endregion
9399
- //#region src/render/effects.ts
9447
+ // src/render/effects.ts
9400
9448
  var TransformEffect = class {
9401
9449
  offsetX;
9402
9450
  offsetY;
@@ -9603,8 +9651,7 @@ const isOpacityEffect = (effect) => effect.type === 2;
9603
9651
  const isClipPathEffect = (effect) => effect.type === 3;
9604
9652
  const isBlendEffect = (effect) => effect.type === 4;
9605
9653
  const isFilterEffect = (effect) => effect.type === 5;
9606
- //#endregion
9607
- //#region src/render/stacking-context.ts
9654
+ // src/render/stacking-context.ts
9608
9655
  var StackingContext = class {
9609
9656
  element;
9610
9657
  negativeZIndex;
@@ -9927,8 +9974,7 @@ const parseStackingContexts = (container) => {
9927
9974
  processListItems(paintContainer.container, listItems);
9928
9975
  return root;
9929
9976
  };
9930
- //#endregion
9931
- //#region src/render/canvas/gradient-rasterizer.ts
9977
+ // src/render/canvas/gradient-rasterizer.ts
9932
9978
  const clampStop = (stop) => Math.min(1, Math.max(0, stop));
9933
9979
  /**
9934
9980
  * Stack the one-cycle stop list periodically across [0, 1]. Returns null for
@@ -10007,8 +10053,7 @@ const rasterizeRadialGradient = (ownerDocument, rx, ry, stops, repeating = false
10007
10053
  ry
10008
10054
  };
10009
10055
  };
10010
- //#endregion
10011
- //#region src/render/box-sizing.ts
10056
+ // src/render/box-sizing.ts
10012
10057
  const paddingBox = (element) => {
10013
10058
  const bounds = element.bounds;
10014
10059
  const styles = element.styles;
@@ -10023,8 +10068,7 @@ const contentBox = (element) => {
10023
10068
  const paddingBottom = getAbsoluteValue(styles.paddingBottom, bounds.width);
10024
10069
  return bounds.add(paddingLeft + styles.borderLeftWidth, paddingTop + styles.borderTopWidth, -(styles.borderRightWidth + styles.borderLeftWidth + paddingLeft + paddingRight), -(styles.borderTopWidth + styles.borderBottomWidth + paddingTop + paddingBottom));
10025
10070
  };
10026
- //#endregion
10027
- //#region src/render/background.ts
10071
+ // src/render/background.ts
10028
10072
  const calculateBackgroundPositioningArea = (backgroundOrigin, element) => {
10029
10073
  if (backgroundOrigin === 0) return element.bounds;
10030
10074
  if (backgroundOrigin === 2) return contentBox(element);
@@ -10125,8 +10169,7 @@ const calculateBackgroundRepeatPath = (repeat, [x, y], [width, height], backgrou
10125
10169
  ];
10126
10170
  }
10127
10171
  };
10128
- //#endregion
10129
- //#region src/render/canvas/filter-surface.ts
10172
+ // src/render/canvas/filter-surface.ts
10130
10173
  var FilterSurfaceError = class extends Error {};
10131
10174
  const releaseSurface = (canvas) => {
10132
10175
  canvas.width = canvas.height = 0;
@@ -10230,6 +10273,13 @@ const parseFilterFunction = (name, body) => {
10230
10273
  value: Number.parseFloat(numeric) * (percentage ? 1 / 100 : 1)
10231
10274
  };
10232
10275
  }
10276
+ if (name === "url") {
10277
+ const ref = parseFilterReference(body);
10278
+ return ref ? {
10279
+ kind: "url",
10280
+ ref
10281
+ } : null;
10282
+ }
10233
10283
  return null;
10234
10284
  };
10235
10285
  /** Split on whitespace outside parentheses so rgba(...) colours stay one token. */
@@ -10285,22 +10335,25 @@ const nativeFilterString = (filter, scale) => filter.functions.map((fn) => {
10285
10335
  case "blur": return `blur(${fn.value * scale}px)`;
10286
10336
  case "drop-shadow": return `drop-shadow(${fn.x * scale}px ${fn.y * scale}px ${fn.blur * scale}px ${fn.color})`;
10287
10337
  case "unitless": return fn.name === "hue-rotate" ? `hue-rotate(${fn.value}deg)` : `${fn.name}(${fn.value})`;
10338
+ case "url": return `url("${fn.ref}")`;
10288
10339
  }
10289
10340
  }).join(" ");
10290
10341
  /**
10291
10342
  * Outset (in CSS pixels) a surface must grow so blur/shadow spillover is not
10292
10343
  * cropped. Unitless functions never spread beyond the bounds. Consecutive
10293
- * blurs compound, so their radii sum.
10344
+ * blurs compound, so their radii sum. A url() reference can paint up to its
10345
+ * filter region, which may extend beyond the border box.
10294
10346
  */
10295
- function filterOutset(filter) {
10347
+ function filterOutset(filter, references) {
10296
10348
  let blurSum = 0;
10297
10349
  let maxShadowOffset = 0;
10350
+ let referenceOutset = 0;
10298
10351
  for (const fn of filter.functions) if (fn.kind === "blur") blurSum += fn.value;
10299
10352
  else if (fn.kind === "drop-shadow") {
10300
10353
  blurSum += fn.blur;
10301
10354
  maxShadowOffset = Math.max(maxShadowOffset, Math.abs(fn.x), Math.abs(fn.y));
10302
- }
10303
- return Math.ceil(3 * blurSum + maxShadowOffset);
10355
+ } else if (fn.kind === "url") referenceOutset += references?.get(fn.ref)?.outset ?? 0;
10356
+ return Math.ceil(3 * blurSum + maxShadowOffset + referenceOutset);
10304
10357
  }
10305
10358
  function canvasLike(source) {
10306
10359
  const canvas = (source.ownerDocument ?? document).createElement("canvas");
@@ -10396,8 +10449,9 @@ const isSvgExpressible = (filter) => {
10396
10449
  if (blurs > 0 && shadows > 0) return filter.functions.findIndex((fn) => fn.kind === "blur") < filter.functions.findIndex((fn) => fn.kind === "drop-shadow");
10397
10450
  return true;
10398
10451
  };
10399
- async function renderFilterSurface(source, filter, opacity, scale, signal) {
10452
+ async function renderFilterSurface(source, filter, opacity, scale, signal, references) {
10400
10453
  throwIfAborted(signal);
10454
+ if (filter.functions.some((fn) => fn.kind === "url")) return renderReferencedFilterSurface(source, filter, opacity, scale, signal, references);
10401
10455
  if (filter.functions.length > 0 && supportsNativeFilters(source.ownerDocument ?? document)) {
10402
10456
  const output = tryNativeFilterSurface(source, filter, opacity, scale, signal);
10403
10457
  if (output) return output;
@@ -10405,6 +10459,136 @@ async function renderFilterSurface(source, filter, opacity, scale, signal) {
10405
10459
  if (!isSvgExpressible(filter)) throw new FilterSurfaceError("Filter chain requires native canvas filters");
10406
10460
  return renderSvgFilterSurface(source, filter, opacity, scale, signal);
10407
10461
  }
10462
+ /**
10463
+ * Split a chain at its url() references: each reference is one SVG pass, and
10464
+ * the standard functions between them run through the usual backends. Every
10465
+ * step filters the previous step's complete output at alpha 1, then CSS
10466
+ * opacity is applied once, as for any other chain.
10467
+ */
10468
+ async function renderReferencedFilterSurface(source, filter, opacity, scale, signal, context) {
10469
+ const steps = [];
10470
+ for (const fn of filter.functions) {
10471
+ if (fn.kind === "url") {
10472
+ const reference = context?.references?.get(fn.ref);
10473
+ if (!reference) throw new FilterSurfaceError(`Filter reference ${fn.ref} cannot be resolved`);
10474
+ steps.push(reference);
10475
+ continue;
10476
+ }
10477
+ const last = steps[steps.length - 1];
10478
+ if (Array.isArray(last)) last.push(fn);
10479
+ else steps.push([fn]);
10480
+ }
10481
+ const origin = context?.origin ?? {
10482
+ x: 0,
10483
+ y: 0
10484
+ };
10485
+ const last = steps[steps.length - 1];
10486
+ const opacityApplied = Array.isArray(last);
10487
+ let current = source;
10488
+ try {
10489
+ for (const step of steps) {
10490
+ const next = Array.isArray(step) ? await renderFilterSurface(current, { functions: step }, step === last ? opacity : 1, scale, signal) : await renderReferenceSurface(current, step, origin, scale, signal);
10491
+ if (current !== source) releaseSurface(current);
10492
+ current = next;
10493
+ }
10494
+ if (opacityApplied || opacity === 1) {
10495
+ const output = current;
10496
+ current = source;
10497
+ return output;
10498
+ }
10499
+ return drawWithOpacity(current, opacity);
10500
+ } finally {
10501
+ if (current !== source) releaseSurface(current);
10502
+ }
10503
+ }
10504
+ function drawWithOpacity(source, opacity) {
10505
+ const output = canvasLike(source);
10506
+ const context = output.getContext("2d");
10507
+ if (!context) {
10508
+ releaseSurface(output);
10509
+ throw new FilterSurfaceError("Filter surface canvas is unavailable");
10510
+ }
10511
+ context.globalAlpha = opacity;
10512
+ try {
10513
+ context.drawImage(source, 0, 0);
10514
+ return output;
10515
+ } catch {
10516
+ releaseSurface(output);
10517
+ throw new FilterSurfaceError("Filter surface image cannot be drawn");
10518
+ }
10519
+ }
10520
+ const SVG_NS = "http://www.w3.org/2000/svg";
10521
+ function createSvgElement(owner, tag, attributes = {}) {
10522
+ const node = owner.createElementNS(SVG_NS, tag);
10523
+ Object.entries(attributes).forEach(([key, value]) => node.setAttribute(key, String(value)));
10524
+ return node;
10525
+ }
10526
+ function serializeSurface(source) {
10527
+ try {
10528
+ const url = source.toDataURL("image/png");
10529
+ if (url === "data:,") throw new Error("Canvas size is unsupported");
10530
+ return url;
10531
+ } catch {
10532
+ throw new FilterSurfaceError("Filter surface pixels cannot be serialized");
10533
+ }
10534
+ }
10535
+ /** Decode a filtered SVG image and draw it onto a surface-sized canvas. */
10536
+ async function drawSvgSurface(svg, source, opacity, signal) {
10537
+ const imageWindow = (source.ownerDocument ?? document).defaultView;
10538
+ const image = imageWindow?.Image ? new imageWindow.Image() : new Image();
10539
+ let output;
10540
+ try {
10541
+ image.src = `data:image/svg+xml,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;
10542
+ await decodeSurface(image, signal);
10543
+ throwIfAborted(signal);
10544
+ output = canvasLike(source);
10545
+ const context = output.getContext("2d");
10546
+ if (!context) throw new FilterSurfaceError("Filter surface canvas is unavailable");
10547
+ context.globalAlpha = opacity;
10548
+ context.drawImage(image, 0, 0);
10549
+ return output;
10550
+ } catch (error) {
10551
+ if (output) releaseSurface(output);
10552
+ if (signal?.aborted) throwIfAborted(signal);
10553
+ throw error instanceof FilterSurfaceError ? error : new FilterSurfaceError("Filter surface image cannot be drawn");
10554
+ } finally {
10555
+ image.removeAttribute("src");
10556
+ }
10557
+ }
10558
+ /**
10559
+ * Apply a referenced SVG filter to the complete surface. The viewBox is in CSS
10560
+ * pixels, so the filter's user units scale with the capture, and the image is
10561
+ * placed so user space starts at the element's border box, as it does for the
10562
+ * live element. Canvas filters cannot express either: their lengths are in
10563
+ * device pixels and their bounding box is the whole canvas.
10564
+ */
10565
+ async function renderReferenceSurface(source, reference, origin, scale, signal) {
10566
+ throwIfAborted(signal);
10567
+ const owner = source.ownerDocument ?? document;
10568
+ const width = source.width / scale;
10569
+ const height = source.height / scale;
10570
+ const svg = createSvgElement(owner, "svg", {
10571
+ width: source.width,
10572
+ height: source.height,
10573
+ viewBox: `0 0 ${width} ${height}`
10574
+ });
10575
+ const defs = createSvgElement(owner, "defs");
10576
+ const filterElement = owner.importNode(reference.element, true);
10577
+ filterElement.setAttribute("id", "composited-reference");
10578
+ defs.appendChild(filterElement);
10579
+ svg.appendChild(defs);
10580
+ const group = createSvgElement(owner, "g", { transform: `translate(${origin.x} ${origin.y})` });
10581
+ group.appendChild(createSvgElement(owner, "image", {
10582
+ x: -origin.x,
10583
+ y: -origin.y,
10584
+ width,
10585
+ height,
10586
+ href: serializeSurface(source),
10587
+ filter: "url(#composited-reference)"
10588
+ }));
10589
+ svg.appendChild(group);
10590
+ return drawSvgSurface(svg, source, 1, signal);
10591
+ }
10408
10592
  async function renderSvgFilterSurface(source, filter, opacity, scale, signal) {
10409
10593
  throwIfAborted(signal);
10410
10594
  const blur = filter.functions.find((fn) => fn.kind === "blur");
@@ -10416,29 +10600,9 @@ async function renderSvgFilterSurface(source, filter, opacity, scale, signal) {
10416
10600
  blur: shadow.blur,
10417
10601
  color: shadow.color
10418
10602
  } : void 0;
10419
- if (!blurValue && !shadowValue) {
10420
- const output = canvasLike(source);
10421
- const context = output.getContext("2d");
10422
- if (!context) {
10423
- releaseSurface(output);
10424
- throw new FilterSurfaceError("Filter surface canvas is unavailable");
10425
- }
10426
- context.globalAlpha = opacity;
10427
- try {
10428
- context.drawImage(source, 0, 0);
10429
- return output;
10430
- } catch {
10431
- releaseSurface(output);
10432
- throw new FilterSurfaceError("Filter surface image cannot be drawn");
10433
- }
10434
- }
10435
- const namespace = "http://www.w3.org/2000/svg";
10603
+ if (!blurValue && !shadowValue) return drawWithOpacity(source, opacity);
10436
10604
  const svgDocument = source.ownerDocument ?? document;
10437
- const element = (tag, attributes = {}) => {
10438
- const node = svgDocument.createElementNS(namespace, tag);
10439
- Object.entries(attributes).forEach(([key, value]) => node.setAttribute(key, String(value)));
10440
- return node;
10441
- };
10605
+ const element = (tag, attributes = {}) => createSvgElement(svgDocument, tag, attributes);
10442
10606
  const svg = element("svg", {
10443
10607
  width: source.width,
10444
10608
  height: source.height,
@@ -10480,39 +10644,13 @@ async function renderSvgFilterSurface(source, filter, opacity, scale, signal) {
10480
10644
  }
10481
10645
  defs.appendChild(filterElement);
10482
10646
  svg.appendChild(defs);
10483
- let sourceUrl;
10484
- try {
10485
- sourceUrl = source.toDataURL("image/png");
10486
- if (sourceUrl === "data:,") throw new Error("Canvas size is unsupported");
10487
- } catch {
10488
- throw new FilterSurfaceError("Filter surface pixels cannot be serialized");
10489
- }
10490
10647
  svg.appendChild(element("image", {
10491
10648
  width: source.width,
10492
10649
  height: source.height,
10493
- href: sourceUrl,
10650
+ href: serializeSurface(source),
10494
10651
  filter: "url(#composited-filter)"
10495
10652
  }));
10496
- const imageWindow = svgDocument.defaultView;
10497
- const image = imageWindow?.Image ? new imageWindow.Image() : new Image();
10498
- let output;
10499
- try {
10500
- image.src = `data:image/svg+xml,${encodeURIComponent(new XMLSerializer().serializeToString(svg))}`;
10501
- await decodeSurface(image, signal);
10502
- throwIfAborted(signal);
10503
- output = canvasLike(source);
10504
- const context = output.getContext("2d");
10505
- if (!context) throw new FilterSurfaceError("Filter surface canvas is unavailable");
10506
- context.globalAlpha = opacity;
10507
- context.drawImage(image, 0, 0);
10508
- return output;
10509
- } catch (error) {
10510
- if (output) releaseSurface(output);
10511
- if (signal?.aborted) throwIfAborted(signal);
10512
- throw error instanceof FilterSurfaceError ? error : new FilterSurfaceError("Filter surface image cannot be drawn");
10513
- } finally {
10514
- image.removeAttribute("src");
10515
- }
10653
+ return drawSvgSurface(svg, source, opacity, signal);
10516
10654
  }
10517
10655
  function reserveSurface(budget, width, height) {
10518
10656
  const pixels = width * height * 4;
@@ -10536,7 +10674,7 @@ function surfaceBounds(container) {
10536
10674
  }
10537
10675
  for (const child of container.elements) if (child.styles.isVisible()) bounds = union(bounds, surfaceBounds(child));
10538
10676
  const filter = parseFilterChain(styles.filter);
10539
- return expand(bounds, filter ? filterOutset(filter) : 0);
10677
+ return expand(bounds, filter ? filterOutset(filter, container.filterReferences) : 0);
10540
10678
  }
10541
10679
  function cropSurface(bounds, viewport, margin, scale) {
10542
10680
  const area = expand(viewport, margin);
@@ -10546,8 +10684,91 @@ function cropSurface(bounds, viewport, margin, scale) {
10546
10684
  const bottom = Math.ceil(Math.min(bounds.top + bounds.height, area.top + area.height) * scale) / scale;
10547
10685
  return new Bounds(left, top, Math.max(0, right - left), Math.max(0, bottom - top));
10548
10686
  }
10549
- //#endregion
10550
- //#region src/render/canvas/text/text-decoration-renderer.ts
10687
+ // src/render/matrix.ts
10688
+ /**
10689
+ * 2D affine matrix utilities for the composited-surface render path.
10690
+ *
10691
+ * Matrices use the canvas `transform(a, b, c, d, e, f)` column-vector
10692
+ * convention:
10693
+ *
10694
+ * | a c e | | x' | | a·x + c·y + e |
10695
+ * | b d f | × | y' | = | b·x + d·y + f |
10696
+ * | 0 0 1 | | 1 | | 1 |
10697
+ *
10698
+ * `TransformEffect` carries the same tuple order, so effects and bounds can
10699
+ * share these helpers. Composition follows the canvas post-multiply rule:
10700
+ * `multiplyMatrix(ancestor, own)` equals `ancestor` followed by `own`.
10701
+ */
10702
+ const IDENTITY_MATRIX = [
10703
+ 1,
10704
+ 0,
10705
+ 0,
10706
+ 1,
10707
+ 0,
10708
+ 0
10709
+ ];
10710
+ const isIdentityMatrix = (m) => m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
10711
+ /**
10712
+ * Compose two transforms: the result applies `a` first, then `b`
10713
+ * (canvas post-multiply, matching successive `ctx.transform` calls).
10714
+ */
10715
+ const multiplyMatrix = (a, b) => [
10716
+ a[0] * b[0] + a[2] * b[1],
10717
+ a[1] * b[0] + a[3] * b[1],
10718
+ a[0] * b[2] + a[2] * b[3],
10719
+ a[1] * b[2] + a[3] * b[3],
10720
+ a[0] * b[4] + a[2] * b[5] + a[4],
10721
+ a[1] * b[4] + a[3] * b[5] + a[5]
10722
+ ];
10723
+ /** Apply a matrix to a point, returning the mapped [x, y]. */
10724
+ const applyMatrixToPoint = (m, x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
10725
+ /**
10726
+ * Map a layout-space Bounds through the matrix and return the axis-aligned
10727
+ * bounding box of the four transformed corners. Non-uniform scales and
10728
+ * rotations grow the box; this is intentionally conservative.
10729
+ */
10730
+ const transformBoundsToAabb = (m, bounds) => {
10731
+ const corners = [
10732
+ applyMatrixToPoint(m, bounds.left, bounds.top),
10733
+ applyMatrixToPoint(m, bounds.left + bounds.width, bounds.top),
10734
+ applyMatrixToPoint(m, bounds.left, bounds.top + bounds.height),
10735
+ applyMatrixToPoint(m, bounds.left + bounds.width, bounds.top + bounds.height)
10736
+ ];
10737
+ const left = Math.min(...corners.map((p) => p[0]));
10738
+ const right = Math.max(...corners.map((p) => p[0]));
10739
+ const top = Math.min(...corners.map((p) => p[1]));
10740
+ const bottom = Math.max(...corners.map((p) => p[1]));
10741
+ return new Bounds(left, top, right - left, bottom - top);
10742
+ };
10743
+ /**
10744
+ * Invert an affine matrix. Returns null for singular matrices
10745
+ * (zero-scale transforms have no meaningful inverse).
10746
+ */
10747
+ const invertMatrix = (m) => {
10748
+ const det = m[0] * m[3] - m[1] * m[2];
10749
+ if (!Number.isFinite(det) || det === 0) return null;
10750
+ const invDet = 1 / det;
10751
+ return [
10752
+ m[3] * invDet,
10753
+ -m[1] * invDet,
10754
+ -m[2] * invDet,
10755
+ m[0] * invDet,
10756
+ (m[2] * m[5] - m[3] * m[4]) * invDet,
10757
+ (m[1] * m[4] - m[0] * m[5]) * invDet
10758
+ ];
10759
+ };
10760
+ /**
10761
+ * Map a visual-space viewport back into the layout space of `m`'s inputs.
10762
+ * Used where a crop window (visual coordinates) must select content measured
10763
+ * in layout coordinates: the conservative answer is the AABB of the inverse
10764
+ * viewport corners.
10765
+ */
10766
+ const inverseTransformBoundsToAabb = (m, bounds) => {
10767
+ const inverse = invertMatrix(m);
10768
+ if (!inverse) return null;
10769
+ return transformBoundsToAabb(inverse, bounds);
10770
+ };
10771
+ // src/render/canvas/text/text-decoration-renderer.ts
10551
10772
  var TextDecorationRenderer = class {
10552
10773
  ctx;
10553
10774
  constructor(ctx) {
@@ -10635,8 +10856,7 @@ var TextDecorationRenderer = class {
10635
10856
  this.ctx.restore();
10636
10857
  }
10637
10858
  };
10638
- //#endregion
10639
- //#region src/render/canvas/font-utils.ts
10859
+ // src/render/canvas/font-utils.ts
10640
10860
  /**
10641
10861
  * Font measurement utility
10642
10862
  *
@@ -10671,8 +10891,7 @@ const measureFontMetrics = (ctx, fallback) => {
10671
10891
  const measureBaseline = (ctx, fallback) => {
10672
10892
  return measureFontMetrics(ctx, fallback).baseline;
10673
10893
  };
10674
- //#endregion
10675
- //#region src/render/canvas/text-renderer.ts
10894
+ // src/render/canvas/text-renderer.ts
10676
10895
  const TEXT_OVERFLOW_EPSILON = 1;
10677
10896
  /**
10678
10897
  * Detect CJK (Chinese, Japanese, Korean) characters in a string.
@@ -11098,8 +11317,7 @@ var TextRenderer = class {
11098
11317
  }
11099
11318
  }
11100
11319
  };
11101
- //#endregion
11102
- //#region src/render/canvas/canvas-path.ts
11320
+ // src/render/canvas/canvas-path.ts
11103
11321
  const formatCanvasPath = (ctx, paths) => {
11104
11322
  paths.forEach((point, index) => {
11105
11323
  const start = isBezierCurve(point) ? point.start : point;
@@ -11113,8 +11331,7 @@ const createCanvasPath = (ctx, paths) => {
11113
11331
  formatCanvasPath(ctx, paths);
11114
11332
  ctx.closePath();
11115
11333
  };
11116
- //#endregion
11117
- //#region src/core/lru-map.ts
11334
+ // src/core/lru-map.ts
11118
11335
  /**
11119
11336
  * Generic LRU (Least-Recently-Used) wrapper over a native `Map`.
11120
11337
  *
@@ -11172,8 +11389,7 @@ var LRUMap = class {
11172
11389
  this._map.clear();
11173
11390
  }
11174
11391
  };
11175
- //#endregion
11176
- //#region src/render/canvas/background-renderer.ts
11392
+ // src/render/canvas/background-renderer.ts
11177
11393
  /**
11178
11394
  * Background Renderer
11179
11395
  *
@@ -11536,8 +11752,7 @@ var BackgroundRenderer = class {
11536
11752
  createCanvasPath(this.ctx, paths);
11537
11753
  }
11538
11754
  };
11539
- //#endregion
11540
- //#region src/render/border.ts
11755
+ // src/render/border.ts
11541
11756
  const parsePathForBorder = (curves, borderSide) => {
11542
11757
  switch (borderSide) {
11543
11758
  case 0: return createPathFromCurves(curves.topLeftBorderBox, curves.topLeftPaddingBox, curves.topRightBorderBox, curves.topRightPaddingBox);
@@ -11590,8 +11805,7 @@ const createPathFromCurves = (outer1, inner1, outer2, inner2) => {
11590
11805
  else path.push(inner1);
11591
11806
  return path;
11592
11807
  };
11593
- //#endregion
11594
- //#region src/render/canvas/border-renderer.ts
11808
+ // src/render/canvas/border-renderer.ts
11595
11809
  /**
11596
11810
  * Border Renderer
11597
11811
  *
@@ -11725,8 +11939,7 @@ var BorderRenderer = class {
11725
11939
  this.ctx.restore();
11726
11940
  }
11727
11941
  };
11728
- //#endregion
11729
- //#region src/render/canvas/border-image-renderer.ts
11942
+ // src/render/canvas/border-image-renderer.ts
11730
11943
  /**
11731
11944
  * Resolve border-image-width to per-side pixel widths. `auto` uses the
11732
11945
  * corresponding border width, numbers multiply it, lengths are absolute and
@@ -11934,8 +12147,7 @@ var BorderImageRenderer = class {
11934
12147
  this.ctx.restore();
11935
12148
  }
11936
12149
  };
11937
- //#endregion
11938
- //#region src/render/canvas/effects-renderer.ts
12150
+ // src/render/canvas/effects-renderer.ts
11939
12151
  /**
11940
12152
  * Effects Renderer
11941
12153
  *
@@ -12083,8 +12295,7 @@ var EffectsRenderer = class {
12083
12295
  return this.activeEffects.length > 0;
12084
12296
  }
12085
12297
  };
12086
- //#endregion
12087
- //#region src/render/canvas/mask-renderer.ts
12298
+ // src/render/canvas/mask-renderer.ts
12088
12299
  /**
12089
12300
  * Mask Renderer
12090
12301
  *
@@ -12231,8 +12442,7 @@ const paintMaskLayers = async (ctx, layers, styles, area, matchImage) => {
12231
12442
  } else paintGradientLayer(ctx, layer, area);
12232
12443
  }
12233
12444
  };
12234
- //#endregion
12235
- //#region src/render/object-fit.ts
12445
+ // src/render/object-fit.ts
12236
12446
  const calculateObjectFitRendering = (intrinsicWidth, intrinsicHeight, box, objectFit, objectPosition) => {
12237
12447
  let sx = 0;
12238
12448
  let sy = 0;
@@ -12318,8 +12528,7 @@ const calculateObjectFitRendering = (intrinsicWidth, intrinsicHeight, box, objec
12318
12528
  dh
12319
12529
  };
12320
12530
  };
12321
- //#endregion
12322
- //#region src/render/canvas/content-renderer.ts
12531
+ // src/render/canvas/content-renderer.ts
12323
12532
  /**
12324
12533
  * Render replaced elements: Image, Canvas, SVG, IFrame.
12325
12534
  */
@@ -12540,8 +12749,7 @@ const canvasTextAlign = (textAlign) => {
12540
12749
  default: return "left";
12541
12750
  }
12542
12751
  };
12543
- //#endregion
12544
- //#region src/render/canvas/box-shadow-geometry.ts
12752
+ // src/render/canvas/box-shadow-geometry.ts
12545
12753
  const shadowRadius = (radius, spread) => {
12546
12754
  const delta = spread > radius ? spread * (1 + Math.pow(radius / spread - 1, 3)) : spread;
12547
12755
  return Math.max(0, radius + delta);
@@ -12585,8 +12793,7 @@ const spreadShadowPath = (paths, spread) => {
12585
12793
  return new BezierCurve(resize(point.start), resize(point.startControl), resize(point.endControl), resize(point.end));
12586
12794
  });
12587
12795
  };
12588
- //#endregion
12589
- //#region src/render/canvas/box-shadow-transform.ts
12796
+ // src/render/canvas/box-shadow-transform.ts
12590
12797
  const shadowSpace = (matrix, width, height) => {
12591
12798
  const { a, b, c, d, e, f } = matrix;
12592
12799
  if (![
@@ -12629,8 +12836,7 @@ const shadowSpace = (matrix, width, height) => {
12629
12836
  uniform: Math.abs(xx - yy) <= tolerance && Math.abs(xy) <= tolerance
12630
12837
  };
12631
12838
  };
12632
- //#endregion
12633
- //#region src/render/canvas/box-shadow-painter.ts
12839
+ // src/render/canvas/box-shadow-painter.ts
12634
12840
  const complement = (ctx, rect, hole) => {
12635
12841
  ctx.beginPath();
12636
12842
  ctx.rect(rect.left, rect.top, rect.width, rect.height);
@@ -12758,8 +12964,7 @@ const paintBoxShadow = async (ctx, paint, shadow, options, budget) => {
12758
12964
  ctx.restore();
12759
12965
  }
12760
12966
  };
12761
- //#endregion
12762
- //#region src/render/canvas/text-clip-renderer.ts
12967
+ // src/render/canvas/text-clip-renderer.ts
12763
12968
  var TextClipRenderer = class {
12764
12969
  ctx;
12765
12970
  context;
@@ -12919,8 +13124,7 @@ var TextClipRenderer = class {
12919
13124
  return canvases.length ? canvases : null;
12920
13125
  }
12921
13126
  };
12922
- //#endregion
12923
- //#region src/render/canvas/canvas-renderer.ts
13127
+ // src/render/canvas/canvas-renderer.ts
12924
13128
  var CanvasRenderer = class CanvasRenderer {
12925
13129
  surfaceRoot;
12926
13130
  surfaceBudget;
@@ -12998,7 +13202,9 @@ var CanvasRenderer = class CanvasRenderer {
12998
13202
  const hasMask = styles.maskImage.length > 0;
12999
13203
  const reflect = styles.webkitBoxReflect;
13000
13204
  const hasBlend = styles.mixBlendMode !== MIX_BLEND_MODE$1.NORMAL;
13001
- if (stack.element !== this.surfaceRoot && !this.legacySubtree && (hasMask || reflect || hasBlend || filter !== null && (hasFilter || styles.opacity < 1)) && this.canComposite(stack.element)) {
13205
+ const reflectTransformed = reflect && !isIdentityMatrix(this.ancestorTransform(stack.element));
13206
+ if (reflectTransformed) this.context.logger.warn("-webkit-box-reflect under an ancestor transform is not supported; the reflection is skipped for this subtree");
13207
+ if (stack.element !== this.surfaceRoot && !this.legacySubtree && !reflectTransformed && (hasMask || reflect || hasBlend || filter !== null && (hasFilter || styles.opacity < 1)) && this.canComposite(stack.element)) {
13002
13208
  if (!await this.renderCompositedStack(stack, filter, hasMask, reflect, hasBlend)) {
13003
13209
  this.legacySubtree = true;
13004
13210
  try {
@@ -13015,7 +13221,7 @@ var CanvasRenderer = class CanvasRenderer {
13015
13221
  canComposite(paint) {
13016
13222
  const supported = (container) => {
13017
13223
  const styles = container.styles;
13018
- return !styles.isTransformed() && styles.zoom === 1 && styles.clipPath.type === 0 && !contains(styles.display, 2048) && parseFilterChain(styles.filter) !== null;
13224
+ return styles.clipPath.type === 0 && !contains(styles.display, 2048) && parseFilterChain(styles.filter) !== null;
13019
13225
  };
13020
13226
  const subtree = (container) => supported(container) && container.elements.every(subtree);
13021
13227
  let ancestor = paint.parent;
@@ -13025,24 +13231,82 @@ var CanvasRenderer = class CanvasRenderer {
13025
13231
  }
13026
13232
  return subtree(paint.container);
13027
13233
  }
13234
+ /**
13235
+ * Root-to-element transform accumulated from the ancestor chain's
13236
+ * TransformEffects (including zoom), stopping at the surface root. The
13237
+ * element's own TransformEffect is intentionally excluded: inside the
13238
+ * offscreen surface it is still applied by the normal effects pass, and
13239
+ * at composition time it is filtered from the recomposed effect list.
13240
+ */
13241
+ ancestorTransform(paint) {
13242
+ const chain = [];
13243
+ let node = paint;
13244
+ while (node && node !== this.surfaceRoot) {
13245
+ for (const effect of node.effects) if (isTransformEffect(effect)) chain.push(effect);
13246
+ node = node.parent;
13247
+ }
13248
+ if (chain.length === 0) return IDENTITY_MATRIX;
13249
+ let matrix = IDENTITY_MATRIX;
13250
+ for (let i = chain.length - 1; i >= 0; i--) {
13251
+ const effect = at(chain, i);
13252
+ const anchored = multiplyMatrix(multiplyMatrix([
13253
+ 1,
13254
+ 0,
13255
+ 0,
13256
+ 1,
13257
+ effect.offsetX,
13258
+ effect.offsetY
13259
+ ], effect.matrix), [
13260
+ 1,
13261
+ 0,
13262
+ 0,
13263
+ 1,
13264
+ -effect.offsetX,
13265
+ -effect.offsetY
13266
+ ]);
13267
+ matrix = multiplyMatrix(matrix, anchored);
13268
+ }
13269
+ return matrix;
13270
+ }
13028
13271
  async renderCompositedStack(stack, filter, hasMask, reflect, hasBlend = false) {
13029
13272
  const signal = this.options.signal;
13030
13273
  if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
13031
- const bounds = cropSurface(surfaceBounds(stack.element.container), new Bounds(this.options.x, this.options.y, this.options.width, this.options.height), filter ? filterOutset(filter) : 0, this.options.scale);
13274
+ const container = stack.element.container;
13275
+ const ancestorMatrix = this.ancestorTransform(stack.element);
13276
+ const ownTransforms = stack.element.effects.filter(isTransformEffect);
13277
+ let chainMatrix = ancestorMatrix;
13278
+ for (const effect of ownTransforms) chainMatrix = multiplyMatrix(chainMatrix, multiplyMatrix(multiplyMatrix([
13279
+ 1,
13280
+ 0,
13281
+ 0,
13282
+ 1,
13283
+ effect.offsetX,
13284
+ effect.offsetY
13285
+ ], effect.matrix), [
13286
+ 1,
13287
+ 0,
13288
+ 0,
13289
+ 1,
13290
+ -effect.offsetX,
13291
+ -effect.offsetY
13292
+ ]));
13293
+ const layoutBounds = surfaceBounds(container);
13294
+ const bounds = cropSurface(isIdentityMatrix(chainMatrix) ? layoutBounds : transformBoundsToAabb(chainMatrix, layoutBounds), new Bounds(this.options.x, this.options.y, this.options.width, this.options.height), filter ? filterOutset(filter, container.filterReferences) : 0, this.options.scale);
13032
13295
  if (!bounds.width || !bounds.height) return true;
13033
13296
  const reserved = reserveSurface(this.surfaceBudget, Math.ceil(bounds.width * this.options.scale), Math.ceil(bounds.height * this.options.scale));
13034
13297
  if (!reserved) {
13035
- this.context.logger.info("Filter surface budget exceeded; using the existing renderer");
13298
+ this.context.logger.warn("Filter surface budget exceeded; mask/filter/blend effects are dropped for this subtree");
13036
13299
  return false;
13037
13300
  }
13301
+ const surfaceWindow = isIdentityMatrix(ancestorMatrix) || !hasMask ? bounds : inverseTransformBoundsToAabb(ancestorMatrix, bounds) ?? bounds;
13038
13302
  const options = {
13039
13303
  ...this.options,
13040
13304
  canvas: void 0,
13041
13305
  backgroundColor: null,
13042
- x: bounds.left,
13043
- y: bounds.top,
13044
- width: bounds.width,
13045
- height: bounds.height
13306
+ x: surfaceWindow.left,
13307
+ y: surfaceWindow.top,
13308
+ width: surfaceWindow.width,
13309
+ height: surfaceWindow.height
13046
13310
  };
13047
13311
  let source;
13048
13312
  let filtered;
@@ -13050,12 +13314,18 @@ var CanvasRenderer = class CanvasRenderer {
13050
13314
  source = new CanvasRenderer(this.context, options, stack.element, this.surfaceBudget);
13051
13315
  await source.renderStackContent(stack);
13052
13316
  source.effectsRenderer.applyEffects([]);
13053
- if (filter) filtered = await renderFilterSurface(source.canvas, filter, stack.element.container.styles.opacity, options.scale, signal);
13317
+ if (filter) filtered = await renderFilterSurface(source.canvas, filter, container.styles.opacity, options.scale, signal, {
13318
+ references: container.filterReferences,
13319
+ origin: {
13320
+ x: container.bounds.left - surfaceWindow.left,
13321
+ y: container.bounds.top - surfaceWindow.top
13322
+ }
13323
+ });
13054
13324
  const composited = filtered ?? source.canvas;
13055
- if (hasMask) await this.applyMask(composited, stack.element.container.styles, bounds);
13325
+ if (hasMask) await this.applyMask(composited, stack.element.container.styles, surfaceWindow, container.bounds, ownTransforms);
13056
13326
  if (signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
13057
13327
  const own = stack.element.effects;
13058
- const effects = stack.element.getEffects(4, this.surfaceRoot).filter((effect) => !own.includes(effect) || !isFilterEffect(effect) && !isOpacityEffect(effect) && !isBlendEffect(effect) && !isClipEffect(effect));
13328
+ const effects = stack.element.getEffects(4, this.surfaceRoot).filter((effect) => !own.includes(effect) || !isFilterEffect(effect) && !isOpacityEffect(effect) && !isBlendEffect(effect) && !isClipEffect(effect) && !isTransformEffect(effect));
13059
13329
  this.effectsRenderer.applyEffects(effects);
13060
13330
  if (hasBlend) {
13061
13331
  this.ctx.save();
@@ -13079,8 +13349,15 @@ var CanvasRenderer = class CanvasRenderer {
13079
13349
  * Composite an alpha mask onto a finished element surface: all mask
13080
13350
  * layers are painted additively into a mask surface, then kept pixels are
13081
13351
  * selected with destination-in.
13352
+ *
13353
+ * Coordinate spaces: the source surface paints in LAYOUT space (the
13354
+ * ancestor TransformEffects stay active on the main canvas and transform
13355
+ * the draw-back), so the mask must be painted in layout space too —
13356
+ * anchored to the element's border box (containerBounds) — riding ONLY
13357
+ * the element's own transform effects, which apply inside the surface
13358
+ * rather than at draw-back.
13082
13359
  */
13083
- async applyMask(surface, styles, bounds) {
13360
+ async applyMask(surface, styles, surfaceWindow, containerBounds, ownTransforms) {
13084
13361
  const ctx = surface.getContext("2d");
13085
13362
  if (!ctx) return;
13086
13363
  const maskCanvas = this.context.resourceDocument.createElement("canvas");
@@ -13092,14 +13369,21 @@ var CanvasRenderer = class CanvasRenderer {
13092
13369
  return;
13093
13370
  }
13094
13371
  maskCtx.scale(this.options.scale, this.options.scale);
13095
- maskCtx.translate(-bounds.left, -bounds.top);
13372
+ maskCtx.translate(-surfaceWindow.left, -surfaceWindow.top);
13373
+ for (let i = ownTransforms.length - 1; i >= 0; i--) {
13374
+ const effect = at(ownTransforms, i);
13375
+ maskCtx.translate(effect.offsetX, effect.offsetY);
13376
+ maskCtx.transform(...effect.matrix);
13377
+ maskCtx.translate(-effect.offsetX, -effect.offsetY);
13378
+ }
13379
+ const layoutArea = {
13380
+ left: containerBounds.left,
13381
+ top: containerBounds.top,
13382
+ width: containerBounds.width,
13383
+ height: containerBounds.height
13384
+ };
13096
13385
  try {
13097
- await paintMaskLayers(maskCtx, styles.maskImage, styles, {
13098
- left: bounds.left,
13099
- top: bounds.top,
13100
- width: bounds.width,
13101
- height: bounds.height
13102
- }, async (url) => await this.context.cache.match(url));
13386
+ await paintMaskLayers(maskCtx, styles.maskImage, styles, layoutArea, async (url) => await this.context.cache.match(url));
13103
13387
  } catch (error) {
13104
13388
  this.context.logger.error(`Error rendering mask-image: ${error instanceof Error ? error.message : error}`);
13105
13389
  releaseSurface(maskCanvas);
@@ -13243,7 +13527,7 @@ var CanvasRenderer = class CanvasRenderer {
13243
13527
  y: this.options.y,
13244
13528
  width: this.options.width,
13245
13529
  height: this.options.height
13246
- }, (ctx, opts) => new CanvasRenderer(ctx, opts), container, curves, styles, (c, cv, img) => this.renderReplacedElement(c, cv, img));
13530
+ }, (ctx, opts) => new CanvasRenderer(ctx, opts, void 0, this.surfaceBudget), container, curves, styles, (c, cv, img) => this.renderReplacedElement(c, cv, img));
13247
13531
  renderFormElements(this.ctx, this.textRenderer, this.path.bind(this), container, styles);
13248
13532
  await renderListMarker(this.ctx, this.context, this.textRenderer, paint, container, styles);
13249
13533
  }
@@ -13639,8 +13923,7 @@ const calculateBackgroundCurvedPaintingArea = (clip, curves) => {
13639
13923
  const hasTextBackgroundClip = (styles) => {
13640
13924
  return styles.backgroundClip.some((clip) => clip === 3);
13641
13925
  };
13642
- //#endregion
13643
- //#region src/render/canvas/foreignobject-renderer.ts
13926
+ // src/render/canvas/foreignobject-renderer.ts
13644
13927
  var ForeignObjectRenderer = class {
13645
13928
  canvas;
13646
13929
  ctx;
@@ -13705,8 +13988,7 @@ const stripRootOffsets = (element) => {
13705
13988
  for (const [property, value] of previous) style[property] = value;
13706
13989
  };
13707
13990
  };
13708
- //#endregion
13709
- //#region src/core/logger.ts
13991
+ // src/core/logger.ts
13710
13992
  var Logger = class {
13711
13993
  id;
13712
13994
  enabled;
@@ -13743,8 +14025,7 @@ var Logger = class {
13743
14025
  }
13744
14026
  }
13745
14027
  };
13746
- //#endregion
13747
- //#region src/core/cache-storage.ts
14028
+ // src/core/cache-storage.ts
13748
14029
  var Cache = class {
13749
14030
  context;
13750
14031
  _options;
@@ -13989,8 +14270,7 @@ const isInlineImage = (src) => INLINE_IMG.test(src);
13989
14270
  const isInlineBase64Image = (src) => INLINE_BASE64.test(src);
13990
14271
  const isBlobImage = (src) => src.substring(0, 4) === "blob";
13991
14272
  const isSVG = (src) => src.slice(-3).toLowerCase() === "svg" || INLINE_SVG.test(src);
13992
- //#endregion
13993
- //#region src/core/origin-checker.ts
14273
+ // src/core/origin-checker.ts
13994
14274
  /**
13995
14275
  * Origin Checker
13996
14276
  *
@@ -14042,8 +14322,7 @@ var OriginChecker = class {
14042
14322
  return this.origin;
14043
14323
  }
14044
14324
  };
14045
- //#endregion
14046
- //#region src/core/context.ts
14325
+ // src/core/context.ts
14047
14326
  var Context = class Context {
14048
14327
  static instanceCount = 1;
14049
14328
  instanceName = `#${Context.instanceCount++}`;
@@ -14090,8 +14369,7 @@ var Context = class Context {
14090
14369
  this._windowBounds = this._windowBounds.add(left, top, 0, 0);
14091
14370
  }
14092
14371
  };
14093
- //#endregion
14094
- //#region src/core/config-assembler.ts
14372
+ // src/core/config-assembler.ts
14095
14373
  /**
14096
14374
  * Coerce known numeric options from string (or other) values to actual numbers.
14097
14375
  * Mutates the opts object in place — this is intentionally a normalisation
@@ -14168,8 +14446,7 @@ const assembleRenderOptions = (opts, backgroundColor, left, top, width, height,
14168
14446
  imageSmoothing: opts.imageSmoothing,
14169
14447
  imageSmoothingQuality: opts.imageSmoothingQuality
14170
14448
  });
14171
- //#endregion
14172
- //#region src/core/background-parser.ts
14449
+ // src/core/background-parser.ts
14173
14450
  /**
14174
14451
  * Resolve the background colour for the rendered canvas, following CSS
14175
14452
  * background propagation rules:
@@ -14190,8 +14467,7 @@ const parseBackgroundColor = (context, element, backgroundColorOverride) => {
14190
14467
  const defaultBackgroundColor = typeof backgroundColorOverride === "string" ? parseColor(context, backgroundColorOverride) : backgroundColorOverride === null ? 0 : 4294967295;
14191
14468
  return element === ownerDocument.documentElement ? isTransparent(documentBackgroundColor) ? isTransparent(bodyBackgroundColor) ? defaultBackgroundColor : bodyBackgroundColor : documentBackgroundColor : defaultBackgroundColor;
14192
14469
  };
14193
- //#endregion
14194
- //#region src/core/render-element.ts
14470
+ // src/core/render-element.ts
14195
14471
  const emitProgress = (onProgress, context, phase, progress) => {
14196
14472
  if (!onProgress) return;
14197
14473
  try {
@@ -14220,7 +14496,7 @@ const renderElement = async (element, opts, config) => {
14220
14496
  const windowBounds = new Bounds(windowOptions.scrollX, windowOptions.scrollY, windowOptions.windowWidth, windowOptions.windowHeight);
14221
14497
  const context = new Context(contextOptions, windowBounds, config);
14222
14498
  const performanceMonitoring = opts.enablePerformanceMonitoring ?? opts.logging ?? false;
14223
- const perfMonitor = new PerformanceMonitor(context, performanceMonitoring);
14499
+ const perfMonitor = new PerformanceMonitor(context.logger, performanceMonitoring);
14224
14500
  perfMonitor.start("total", {
14225
14501
  width: windowOptions.windowWidth,
14226
14502
  height: windowOptions.windowHeight
@@ -14289,8 +14565,7 @@ const renderElement = async (element, opts, config) => {
14289
14565
  emitProgress(opts.onProgress, context, "render", 100);
14290
14566
  return canvas;
14291
14567
  };
14292
- //#endregion
14293
- //#region src/index.ts
14568
+ // src/index.ts
14294
14569
  /**
14295
14570
  * Renders an HTML element to a `<canvas>` element.
14296
14571
  *
@@ -14326,7 +14601,6 @@ const html2canvas = (element, options = {}, config) => {
14326
14601
  });
14327
14602
  return renderElement(element, options, finalConfig);
14328
14603
  };
14329
- //#endregion
14330
14604
  exports.Html2CanvasConfig = Html2CanvasConfig;
14331
14605
  exports.PerformanceMonitor = PerformanceMonitor;
14332
14606
  exports.Validator = Validator;