@emasoft/svg-matrix 1.0.27 → 1.0.29

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.
Files changed (46) hide show
  1. package/README.md +325 -0
  2. package/bin/svg-matrix.js +994 -378
  3. package/bin/svglinter.cjs +4172 -433
  4. package/bin/svgm.js +744 -184
  5. package/package.json +16 -4
  6. package/src/animation-references.js +71 -52
  7. package/src/arc-length.js +160 -96
  8. package/src/bezier-analysis.js +257 -117
  9. package/src/bezier-intersections.js +411 -148
  10. package/src/browser-verify.js +240 -100
  11. package/src/clip-path-resolver.js +350 -142
  12. package/src/convert-path-data.js +279 -134
  13. package/src/css-specificity.js +78 -70
  14. package/src/flatten-pipeline.js +751 -263
  15. package/src/geometry-to-path.js +511 -182
  16. package/src/index.js +191 -46
  17. package/src/inkscape-support.js +404 -0
  18. package/src/marker-resolver.js +278 -164
  19. package/src/mask-resolver.js +209 -98
  20. package/src/matrix.js +147 -67
  21. package/src/mesh-gradient.js +187 -96
  22. package/src/off-canvas-detection.js +201 -104
  23. package/src/path-analysis.js +187 -107
  24. package/src/path-data-plugins.js +628 -167
  25. package/src/path-simplification.js +0 -1
  26. package/src/pattern-resolver.js +125 -88
  27. package/src/polygon-clip.js +111 -66
  28. package/src/svg-boolean-ops.js +194 -118
  29. package/src/svg-collections.js +48 -19
  30. package/src/svg-flatten.js +282 -164
  31. package/src/svg-parser.js +427 -200
  32. package/src/svg-rendering-context.js +147 -104
  33. package/src/svg-toolbox.js +16411 -3298
  34. package/src/svg2-polyfills.js +114 -245
  35. package/src/transform-decomposition.js +46 -41
  36. package/src/transform-optimization.js +89 -68
  37. package/src/transforms2d.js +49 -16
  38. package/src/transforms3d.js +58 -22
  39. package/src/use-symbol-resolver.js +150 -110
  40. package/src/vector.js +67 -15
  41. package/src/vendor/README.md +110 -0
  42. package/src/vendor/inkscape-hatch-polyfill.js +401 -0
  43. package/src/vendor/inkscape-hatch-polyfill.min.js +8 -0
  44. package/src/vendor/inkscape-mesh-polyfill.js +843 -0
  45. package/src/vendor/inkscape-mesh-polyfill.min.js +8 -0
  46. package/src/verification.js +288 -124
@@ -27,82 +27,84 @@
27
27
  * @module svg-rendering-context
28
28
  */
29
29
 
30
- import Decimal from 'decimal.js';
31
- import { FillRule, pointInPolygonWithRule, offsetPolygon, strokeToFilledPolygon } from './svg-boolean-ops.js';
32
- import * as PolygonClip from './polygon-clip.js';
30
+ import Decimal from "decimal.js";
31
+ import {
32
+ FillRule,
33
+ pointInPolygonWithRule,
34
+ offsetPolygon as _offsetPolygon,
35
+ strokeToFilledPolygon,
36
+ } from "./svg-boolean-ops.js";
37
+ import * as _PolygonClip from "./polygon-clip.js";
33
38
 
34
39
  Decimal.set({ precision: 80 });
35
40
 
36
- const D = x => (x instanceof Decimal ? x : new Decimal(x));
41
+ const D = (x) => (x instanceof Decimal ? x : new Decimal(x));
37
42
 
38
43
  /**
39
44
  * Default SVG property values per SVG 1.1/2.0 specification
40
45
  */
41
46
  export const SVG_DEFAULTS = {
42
47
  // Fill properties
43
- fill: 'black',
44
- 'fill-rule': 'nonzero',
45
- 'fill-opacity': 1,
48
+ fill: "black",
49
+ "fill-rule": "nonzero",
50
+ "fill-opacity": 1,
46
51
 
47
52
  // Stroke properties
48
- stroke: 'none',
49
- 'stroke-width': 1,
50
- 'stroke-linecap': 'butt', // butt | round | square
51
- 'stroke-linejoin': 'miter', // miter | round | bevel
52
- 'stroke-miterlimit': 4,
53
- 'stroke-dasharray': 'none',
54
- 'stroke-dashoffset': 0,
55
- 'stroke-opacity': 1,
53
+ stroke: "none",
54
+ "stroke-width": 1,
55
+ "stroke-linecap": "butt", // butt | round | square
56
+ "stroke-linejoin": "miter", // miter | round | bevel
57
+ "stroke-miterlimit": 4,
58
+ "stroke-dasharray": "none",
59
+ "stroke-dashoffset": 0,
60
+ "stroke-opacity": 1,
56
61
 
57
62
  // Markers
58
- 'marker-start': 'none',
59
- 'marker-mid': 'none',
60
- 'marker-end': 'none',
63
+ "marker-start": "none",
64
+ "marker-mid": "none",
65
+ "marker-end": "none",
61
66
 
62
67
  // Paint order (SVG 2)
63
- 'paint-order': 'normal', // normal = fill stroke markers
68
+ "paint-order": "normal", // normal = fill stroke markers
64
69
 
65
70
  // Clipping
66
- 'clip-path': 'none',
67
- 'clip-rule': 'nonzero',
71
+ "clip-path": "none",
72
+ "clip-rule": "nonzero",
68
73
 
69
74
  // Masking
70
- 'mask': 'none',
71
- 'mask-type': 'luminance', // luminance | alpha
75
+ mask: "none",
76
+ "mask-type": "luminance", // luminance | alpha
72
77
 
73
78
  // Opacity
74
- 'opacity': 1,
79
+ opacity: 1,
75
80
 
76
81
  // Transform
77
- 'transform': 'none',
78
- 'vector-effect': 'none', // none | non-scaling-stroke
82
+ transform: "none",
83
+ "vector-effect": "none", // none | non-scaling-stroke
79
84
 
80
85
  // Filter
81
- 'filter': 'none'
86
+ filter: "none",
82
87
  };
83
88
 
84
89
  /**
85
90
  * Properties that affect the geometric extent of an element
86
91
  */
87
92
  export const GEOMETRY_AFFECTING_PROPERTIES = [
88
- 'stroke-width',
89
- 'stroke-linecap',
90
- 'stroke-linejoin',
91
- 'stroke-miterlimit',
92
- 'marker-start',
93
- 'marker-mid',
94
- 'marker-end',
95
- 'filter',
96
- 'transform'
93
+ "stroke-width",
94
+ "stroke-linecap",
95
+ "stroke-linejoin",
96
+ "stroke-miterlimit",
97
+ "marker-start",
98
+ "marker-mid",
99
+ "marker-end",
100
+ "filter",
101
+ "transform",
97
102
  ];
98
103
 
99
104
  /**
100
105
  * Properties that affect what's considered "inside" a shape
101
106
  */
102
- export const FILL_AFFECTING_PROPERTIES = [
103
- 'fill-rule',
104
- 'clip-rule'
105
- ];
107
+ export const FILL_AFFECTING_PROPERTIES = ["fill-rule", "clip-rule"];
106
108
 
107
109
  /**
108
110
  * SVG Rendering Context class
@@ -125,27 +127,29 @@ export class SVGRenderingContext {
125
127
  this.properties = this._extractProperties(element, inherited);
126
128
 
127
129
  // Parse stroke-dasharray into array
128
- this.dashArray = this._parseDashArray(this.properties['stroke-dasharray']);
129
- this.dashOffset = D(this.properties['stroke-dashoffset'] || 0);
130
+ this.dashArray = this._parseDashArray(this.properties["stroke-dasharray"]);
131
+ this.dashOffset = D(this.properties["stroke-dashoffset"] || 0);
130
132
 
131
133
  // Parse marker references
132
134
  this.markers = {
133
- start: this._parseMarkerRef(this.properties['marker-start']),
134
- mid: this._parseMarkerRef(this.properties['marker-mid']),
135
- end: this._parseMarkerRef(this.properties['marker-end'])
135
+ start: this._parseMarkerRef(this.properties["marker-start"]),
136
+ mid: this._parseMarkerRef(this.properties["marker-mid"]),
137
+ end: this._parseMarkerRef(this.properties["marker-end"]),
136
138
  };
137
139
 
138
140
  // Determine if element has visible fill
139
- this.hasFill = this.properties.fill !== 'none' &&
140
- this.properties['fill-opacity'] > 0;
141
+ this.hasFill =
142
+ this.properties.fill !== "none" && this.properties["fill-opacity"] > 0;
141
143
 
142
144
  // Determine if element has visible stroke
143
- this.hasStroke = this.properties.stroke !== 'none' &&
144
- D(this.properties['stroke-width']).gt(0) &&
145
- this.properties['stroke-opacity'] > 0;
145
+ this.hasStroke =
146
+ this.properties.stroke !== "none" &&
147
+ D(this.properties["stroke-width"]).gt(0) &&
148
+ this.properties["stroke-opacity"] > 0;
146
149
 
147
150
  // Determine if element has markers
148
- this.hasMarkers = this.markers.start || this.markers.mid || this.markers.end;
151
+ this.hasMarkers =
152
+ this.markers.start || this.markers.mid || this.markers.end;
149
153
  }
150
154
 
151
155
  /**
@@ -172,10 +176,16 @@ export class SVGRenderingContext {
172
176
  }
173
177
 
174
178
  // Convert numeric properties
175
- const numericProps = ['stroke-width', 'stroke-miterlimit', 'stroke-dashoffset',
176
- 'opacity', 'fill-opacity', 'stroke-opacity'];
179
+ const numericProps = [
180
+ "stroke-width",
181
+ "stroke-miterlimit",
182
+ "stroke-dashoffset",
183
+ "opacity",
184
+ "fill-opacity",
185
+ "stroke-opacity",
186
+ ];
177
187
  for (const prop of numericProps) {
178
- if (typeof props[prop] === 'string') {
188
+ if (typeof props[prop] === "string") {
179
189
  const parsed = parseFloat(props[prop]);
180
190
  if (!isNaN(parsed)) {
181
191
  props[prop] = parsed;
@@ -194,9 +204,9 @@ export class SVGRenderingContext {
194
204
  const props = {};
195
205
  if (!style) return props;
196
206
 
197
- const declarations = style.split(';');
207
+ const declarations = style.split(";");
198
208
  for (const decl of declarations) {
199
- const [prop, value] = decl.split(':').map(s => s.trim());
209
+ const [prop, value] = decl.split(":").map((s) => s.trim());
200
210
  if (prop && value) {
201
211
  props[prop] = value;
202
212
  }
@@ -209,10 +219,13 @@ export class SVGRenderingContext {
209
219
  * @private
210
220
  */
211
221
  _parseDashArray(dasharray) {
212
- if (!dasharray || dasharray === 'none') return null;
222
+ if (!dasharray || dasharray === "none") return null;
213
223
 
214
- const parts = dasharray.toString().split(/[\s,]+/).filter(s => s);
215
- const values = parts.map(s => D(parseFloat(s)));
224
+ const parts = dasharray
225
+ .toString()
226
+ .split(/[\s,]+/)
227
+ .filter((s) => s);
228
+ const values = parts.map((s) => D(parseFloat(s)));
216
229
 
217
230
  // Per SVG spec, if odd number of values, duplicate the array
218
231
  if (values.length % 2 === 1) {
@@ -226,7 +239,7 @@ export class SVGRenderingContext {
226
239
  * @private
227
240
  */
228
241
  _parseMarkerRef(value) {
229
- if (!value || value === 'none') return null;
242
+ if (!value || value === "none") return null;
230
243
  const match = value.match(/url\(#?([^)]+)\)/);
231
244
  return match ? match[1] : null;
232
245
  }
@@ -236,7 +249,7 @@ export class SVGRenderingContext {
236
249
  * @returns {string} 'nonzero' or 'evenodd'
237
250
  */
238
251
  get fillRule() {
239
- return this.properties['fill-rule'] || 'nonzero';
252
+ return this.properties["fill-rule"] || "nonzero";
240
253
  }
241
254
 
242
255
  /**
@@ -244,7 +257,7 @@ export class SVGRenderingContext {
244
257
  * @returns {string} 'nonzero' or 'evenodd'
245
258
  */
246
259
  get clipRule() {
247
- return this.properties['clip-rule'] || 'nonzero';
260
+ return this.properties["clip-rule"] || "nonzero";
248
261
  }
249
262
 
250
263
  /**
@@ -252,7 +265,7 @@ export class SVGRenderingContext {
252
265
  * @returns {Decimal}
253
266
  */
254
267
  get strokeWidth() {
255
- return D(this.properties['stroke-width'] || 0);
268
+ return D(this.properties["stroke-width"] || 0);
256
269
  }
257
270
 
258
271
  /**
@@ -260,7 +273,7 @@ export class SVGRenderingContext {
260
273
  * @returns {string} 'butt', 'round', or 'square'
261
274
  */
262
275
  get strokeLinecap() {
263
- return this.properties['stroke-linecap'] || 'butt';
276
+ return this.properties["stroke-linecap"] || "butt";
264
277
  }
265
278
 
266
279
  /**
@@ -268,7 +281,7 @@ export class SVGRenderingContext {
268
281
  * @returns {string} 'miter', 'round', or 'bevel'
269
282
  */
270
283
  get strokeLinejoin() {
271
- return this.properties['stroke-linejoin'] || 'miter';
284
+ return this.properties["stroke-linejoin"] || "miter";
272
285
  }
273
286
 
274
287
  /**
@@ -276,7 +289,7 @@ export class SVGRenderingContext {
276
289
  * @returns {Decimal}
277
290
  */
278
291
  get strokeMiterlimit() {
279
- return D(this.properties['stroke-miterlimit'] || 4);
292
+ return D(this.properties["stroke-miterlimit"] || 4);
280
293
  }
281
294
 
282
295
  /**
@@ -297,12 +310,12 @@ export class SVGRenderingContext {
297
310
  let extent = halfWidth;
298
311
 
299
312
  // Miter joins can extend further
300
- if (this.strokeLinejoin === 'miter') {
313
+ if (this.strokeLinejoin === "miter") {
301
314
  extent = halfWidth.times(this.strokeMiterlimit);
302
315
  }
303
316
 
304
317
  // Square linecaps extend by half stroke width beyond endpoints
305
- if (this.strokeLinecap === 'square') {
318
+ if (this.strokeLinecap === "square") {
306
319
  const capExtent = halfWidth;
307
320
  if (capExtent.gt(extent)) {
308
321
  extent = capExtent;
@@ -327,7 +340,7 @@ export class SVGRenderingContext {
327
340
  x: bbox.x.minus(extent),
328
341
  y: bbox.y.minus(extent),
329
342
  width: bbox.width.plus(extent.times(2)),
330
- height: bbox.height.plus(extent.times(2))
343
+ height: bbox.height.plus(extent.times(2)),
331
344
  };
332
345
  }
333
346
 
@@ -348,8 +361,8 @@ export class SVGRenderingContext {
348
361
 
349
362
  if (markerSizes) {
350
363
  const sizes = [markerSizes.start, markerSizes.mid, markerSizes.end]
351
- .filter(s => s)
352
- .map(s => D(s));
364
+ .filter((s) => s)
365
+ .map((s) => D(s));
353
366
  if (sizes.length > 0) {
354
367
  maxMarkerSize = Decimal.max(...sizes);
355
368
  }
@@ -366,7 +379,7 @@ export class SVGRenderingContext {
366
379
  x: bbox.x.minus(extent),
367
380
  y: bbox.y.minus(extent),
368
381
  width: bbox.width.plus(extent.times(2)),
369
- height: bbox.height.plus(extent.times(2))
382
+ height: bbox.height.plus(extent.times(2)),
370
383
  };
371
384
  }
372
385
 
@@ -381,12 +394,12 @@ export class SVGRenderingContext {
381
394
  */
382
395
  expandBBoxForFilter(bbox, filterDef = null) {
383
396
  const filterRef = this.properties.filter;
384
- if (!filterRef || filterRef === 'none') return bbox;
397
+ if (!filterRef || filterRef === "none") return bbox;
385
398
 
386
399
  // Default filter region is 10% larger on each side (per SVG spec)
387
400
  // filterUnits="objectBoundingBox" x="-10%" y="-10%" width="120%" height="120%"
388
- let extentX = bbox.width.times('0.1');
389
- let extentY = bbox.height.times('0.1');
401
+ let extentX = bbox.width.times("0.1");
402
+ let extentY = bbox.height.times("0.1");
390
403
 
391
404
  // If filter definition provided with explicit bounds, use those
392
405
  if (filterDef) {
@@ -398,7 +411,7 @@ export class SVGRenderingContext {
398
411
  x: bbox.x.minus(extentX),
399
412
  y: bbox.y.minus(extentY),
400
413
  width: bbox.width.plus(extentX.times(2)),
401
- height: bbox.height.plus(extentY.times(2))
414
+ height: bbox.height.plus(extentY.times(2)),
402
415
  };
403
416
  }
404
417
 
@@ -438,7 +451,7 @@ export class SVGRenderingContext {
438
451
  areas.push({
439
452
  polygon: polygon,
440
453
  fillRule: this.fillRule,
441
- type: 'fill'
454
+ type: "fill",
442
455
  });
443
456
  }
444
457
 
@@ -448,14 +461,14 @@ export class SVGRenderingContext {
448
461
  width: this.strokeWidth.toNumber(),
449
462
  linecap: this.strokeLinecap,
450
463
  linejoin: this.strokeLinejoin,
451
- miterlimit: this.strokeMiterlimit.toNumber()
464
+ miterlimit: this.strokeMiterlimit.toNumber(),
452
465
  });
453
466
 
454
467
  if (strokePolygon && strokePolygon.length > 0) {
455
468
  areas.push({
456
469
  polygon: strokePolygon,
457
- fillRule: 'nonzero', // Stroke is always nonzero
458
- type: 'stroke'
470
+ fillRule: "nonzero", // Stroke is always nonzero
471
+ type: "stroke",
459
472
  });
460
473
  }
461
474
  }
@@ -473,7 +486,8 @@ export class SVGRenderingContext {
473
486
  isPointInRenderedArea(point, polygon) {
474
487
  // Check fill area
475
488
  if (this.hasFill) {
476
- const fillRule = this.fillRule === 'evenodd' ? FillRule.EVENODD : FillRule.NONZERO;
489
+ const fillRule =
490
+ this.fillRule === "evenodd" ? FillRule.EVENODD : FillRule.NONZERO;
477
491
  const inFill = pointInPolygonWithRule(point, polygon, fillRule);
478
492
  if (inFill >= 0) return true;
479
493
  }
@@ -484,11 +498,15 @@ export class SVGRenderingContext {
484
498
  width: this.strokeWidth.toNumber(),
485
499
  linecap: this.strokeLinecap,
486
500
  linejoin: this.strokeLinejoin,
487
- miterlimit: this.strokeMiterlimit.toNumber()
501
+ miterlimit: this.strokeMiterlimit.toNumber(),
488
502
  });
489
503
 
490
504
  if (strokePolygon && strokePolygon.length > 0) {
491
- const inStroke = pointInPolygonWithRule(point, strokePolygon, FillRule.NONZERO);
505
+ const inStroke = pointInPolygonWithRule(
506
+ point,
507
+ strokePolygon,
508
+ FillRule.NONZERO,
509
+ );
492
510
  if (inStroke >= 0) return true;
493
511
  }
494
512
  }
@@ -507,45 +525,51 @@ export class SVGRenderingContext {
507
525
  canMergeWith(other) {
508
526
  // Fill rules must match
509
527
  if (this.fillRule !== other.fillRule) {
510
- return { canMerge: false, reason: 'Different fill-rule' };
528
+ return { canMerge: false, reason: "Different fill-rule" };
511
529
  }
512
530
 
513
531
  // Stroke properties must match if either has stroke
514
532
  if (this.hasStroke || other.hasStroke) {
515
533
  if (this.hasStroke !== other.hasStroke) {
516
- return { canMerge: false, reason: 'Different stroke presence' };
534
+ return { canMerge: false, reason: "Different stroke presence" };
517
535
  }
518
536
 
519
537
  if (!this.strokeWidth.eq(other.strokeWidth)) {
520
- return { canMerge: false, reason: 'Different stroke-width' };
538
+ return { canMerge: false, reason: "Different stroke-width" };
521
539
  }
522
540
 
523
541
  if (this.strokeLinecap !== other.strokeLinecap) {
524
- return { canMerge: false, reason: 'Different stroke-linecap' };
542
+ return { canMerge: false, reason: "Different stroke-linecap" };
525
543
  }
526
544
 
527
545
  if (this.strokeLinejoin !== other.strokeLinejoin) {
528
- return { canMerge: false, reason: 'Different stroke-linejoin' };
546
+ return { canMerge: false, reason: "Different stroke-linejoin" };
529
547
  }
530
548
  }
531
549
 
532
550
  // Neither can have markers (markers break continuity)
533
551
  if (this.hasMarkers || other.hasMarkers) {
534
- return { canMerge: false, reason: 'Has markers' };
552
+ return { canMerge: false, reason: "Has markers" };
535
553
  }
536
554
 
537
555
  // Neither can have clip-path or mask
538
- if (this.properties['clip-path'] !== 'none' || other.properties['clip-path'] !== 'none') {
539
- return { canMerge: false, reason: 'Has clip-path' };
556
+ if (
557
+ this.properties["clip-path"] !== "none" ||
558
+ other.properties["clip-path"] !== "none"
559
+ ) {
560
+ return { canMerge: false, reason: "Has clip-path" };
540
561
  }
541
562
 
542
- if (this.properties.mask !== 'none' || other.properties.mask !== 'none') {
543
- return { canMerge: false, reason: 'Has mask' };
563
+ if (this.properties.mask !== "none" || other.properties.mask !== "none") {
564
+ return { canMerge: false, reason: "Has mask" };
544
565
  }
545
566
 
546
567
  // Neither can have filter
547
- if (this.properties.filter !== 'none' || other.properties.filter !== 'none') {
548
- return { canMerge: false, reason: 'Has filter' };
568
+ if (
569
+ this.properties.filter !== "none" ||
570
+ other.properties.filter !== "none"
571
+ ) {
572
+ return { canMerge: false, reason: "Has filter" };
549
573
  }
550
574
 
551
575
  return { canMerge: true, reason: null };
@@ -565,8 +589,8 @@ export class SVGRenderingContext {
565
589
  strokeExtent: this.getStrokeExtent().toNumber(),
566
590
  linecap: this.strokeLinecap,
567
591
  linejoin: this.strokeLinejoin,
568
- clipPath: this.properties['clip-path'],
569
- filter: this.properties.filter
592
+ clipPath: this.properties["clip-path"],
593
+ filter: this.properties.filter,
570
594
  };
571
595
  }
572
596
  }
@@ -579,7 +603,11 @@ export class SVGRenderingContext {
579
603
  * @param {Map} defsMap - Definitions map
580
604
  * @returns {SVGRenderingContext}
581
605
  */
582
- export function createRenderingContext(element, inherited = {}, defsMap = null) {
606
+ export function createRenderingContext(
607
+ element,
608
+ inherited = {},
609
+ defsMap = null,
610
+ ) {
583
611
  return new SVGRenderingContext(element, inherited, defsMap);
584
612
  }
585
613
 
@@ -594,11 +622,26 @@ export function getInheritedProperties(element) {
594
622
 
595
623
  // Inheritable properties per SVG spec
596
624
  const inheritableProps = [
597
- 'fill', 'fill-rule', 'fill-opacity',
598
- 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin',
599
- 'stroke-miterlimit', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-opacity',
600
- 'marker-start', 'marker-mid', 'marker-end',
601
- 'clip-rule', 'opacity', 'font-family', 'font-size', 'font-style', 'font-weight'
625
+ "fill",
626
+ "fill-rule",
627
+ "fill-opacity",
628
+ "stroke",
629
+ "stroke-width",
630
+ "stroke-linecap",
631
+ "stroke-linejoin",
632
+ "stroke-miterlimit",
633
+ "stroke-dasharray",
634
+ "stroke-dashoffset",
635
+ "stroke-opacity",
636
+ "marker-start",
637
+ "marker-mid",
638
+ "marker-end",
639
+ "clip-rule",
640
+ "opacity",
641
+ "font-family",
642
+ "font-size",
643
+ "font-style",
644
+ "font-weight",
602
645
  ];
603
646
 
604
647
  let current = element.parentNode;
@@ -623,5 +666,5 @@ export default {
623
666
  GEOMETRY_AFFECTING_PROPERTIES,
624
667
  FILL_AFFECTING_PROPERTIES,
625
668
  createRenderingContext,
626
- getInheritedProperties
669
+ getInheritedProperties,
627
670
  };