@knowvah/dot-engine 2.6.10 → 2.6.12

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 (131) hide show
  1. package/dist/async/render-async.d.ts.map +1 -1
  2. package/dist/common/agerr.d.ts +37 -0
  3. package/dist/common/agerr.d.ts.map +1 -0
  4. package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
  5. package/dist/common/color.d.ts.map +1 -1
  6. package/dist/common/crand.d.ts +0 -20
  7. package/dist/common/crand.d.ts.map +1 -1
  8. package/dist/common/emit-once.d.ts +6 -0
  9. package/dist/common/emit-once.d.ts.map +1 -0
  10. package/dist/common/graph-init.d.ts.map +1 -1
  11. package/dist/common/html-entities.d.ts +13 -5
  12. package/dist/common/html-entities.d.ts.map +1 -1
  13. package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
  14. package/dist/common/htmltable-emit-fill.d.ts +9 -0
  15. package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
  16. package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
  17. package/dist/common/htmltable-lex-chardata.d.ts +9 -0
  18. package/dist/common/htmltable-lex-chardata.d.ts.map +1 -1
  19. package/dist/common/htmltable-lex-expat.d.ts +1 -6
  20. package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
  21. package/dist/common/htmltable.d.ts +1 -7
  22. package/dist/common/htmltable.d.ts.map +1 -1
  23. package/dist/common/poly-gencode.d.ts.map +1 -1
  24. package/dist/common/poly-init.d.ts.map +1 -1
  25. package/dist/common/postproc.d.ts.map +1 -1
  26. package/dist/common/random.d.ts.map +1 -1
  27. package/dist/common/render-state.d.ts +8 -0
  28. package/dist/common/render-state.d.ts.map +1 -0
  29. package/dist/common/splines-geom.d.ts +8 -0
  30. package/dist/common/splines-geom.d.ts.map +1 -1
  31. package/dist/common/splines-routespl.d.ts.map +1 -1
  32. package/dist/common/textmeasure-lookup.d.ts.map +1 -1
  33. package/dist/common/textmeasure.d.ts.map +1 -1
  34. package/dist/gvc/anchor.d.ts.map +1 -1
  35. package/dist/gvc/device-cluster.d.ts.map +1 -1
  36. package/dist/gvc/device-labels.d.ts +14 -0
  37. package/dist/gvc/device-labels.d.ts.map +1 -1
  38. package/dist/gvc/device.d.ts.map +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +821 -471
  41. package/dist/index.js.map +4 -4
  42. package/dist/layout/dot/cluster.d.ts.map +1 -1
  43. package/dist/layout/dot/conc.d.ts.map +1 -1
  44. package/dist/layout/dot/decomp.d.ts.map +1 -1
  45. package/dist/layout/dot/edge-route-clip.d.ts +18 -10
  46. package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
  47. package/dist/layout/dot/mincross-build.d.ts.map +1 -1
  48. package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
  49. package/dist/layout/dot/rank.d.ts.map +1 -1
  50. package/dist/layout/dot/splines.d.ts.map +1 -1
  51. package/dist/layout/fdp/index.d.ts.map +1 -1
  52. package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
  53. package/dist/layout/fdp/xlayout.d.ts.map +1 -1
  54. package/dist/layout/neato/edge-len.d.ts.map +1 -1
  55. package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
  56. package/dist/layout/neato/init.d.ts +4 -10
  57. package/dist/layout/neato/init.d.ts.map +1 -1
  58. package/dist/layout/neato/kk.d.ts.map +1 -1
  59. package/dist/layout/neato/multispline-router.d.ts.map +1 -1
  60. package/dist/layout/neato/multispline.d.ts.map +1 -1
  61. package/dist/layout/neato/poly.d.ts.map +1 -1
  62. package/dist/layout/neato/sgd.d.ts.map +1 -1
  63. package/dist/layout/neato/start.d.ts.map +1 -1
  64. package/dist/ortho/index.d.ts.map +1 -1
  65. package/dist/parser/index.d.ts.map +1 -1
  66. package/dist/render/color-resolve.d.ts +49 -1
  67. package/dist/render/color-resolve.d.ts.map +1 -1
  68. package/dist/render/public.d.ts.map +1 -1
  69. package/dist/render/svg-edge-split.d.ts +2 -0
  70. package/dist/render/svg-edge-split.d.ts.map +1 -1
  71. package/dist/render/xdot-public.d.ts.map +1 -1
  72. package/dist/render.js +569 -220
  73. package/dist/render.js.map +4 -4
  74. package/package.json +1 -1
  75. package/src/async/render-async.ts +6 -0
  76. package/src/common/agerr.ts +96 -0
  77. package/src/common/arrows-shapes-poly.ts +19 -5
  78. package/src/common/color.ts +38 -10
  79. package/src/common/crand.ts +8 -2
  80. package/src/common/emit-once.ts +27 -0
  81. package/src/common/graph-init.ts +2 -1
  82. package/src/common/html-entities.ts +77 -25
  83. package/src/common/htmltable-attr-warn.ts +3 -4
  84. package/src/common/htmltable-emit-fill.ts +48 -0
  85. package/src/common/htmltable-emit-rules.ts +2 -0
  86. package/src/common/htmltable-lex-chardata.ts +42 -8
  87. package/src/common/htmltable-lex-expat.ts +78 -23
  88. package/src/common/htmltable.ts +15 -16
  89. package/src/common/poly-gencode.ts +14 -2
  90. package/src/common/poly-init.ts +2 -1
  91. package/src/common/postproc.ts +4 -1
  92. package/src/common/random.ts +11 -1
  93. package/src/common/render-state.ts +36 -0
  94. package/src/common/splines-geom.ts +8 -4
  95. package/src/common/splines-routespl.ts +2 -1
  96. package/src/common/textmeasure-lookup.ts +10 -3
  97. package/src/common/textmeasure.ts +45 -2
  98. package/src/gvc/anchor.ts +1 -12
  99. package/src/gvc/device-cluster.ts +37 -9
  100. package/src/gvc/device-labels.ts +27 -0
  101. package/src/gvc/device.ts +18 -6
  102. package/src/index.ts +3 -0
  103. package/src/layout/dot/cluster.ts +2 -1
  104. package/src/layout/dot/conc.ts +6 -5
  105. package/src/layout/dot/decomp.ts +3 -0
  106. package/src/layout/dot/edge-route-clip.ts +27 -21
  107. package/src/layout/dot/mincross-build.ts +2 -0
  108. package/src/layout/dot/mincross-cross.ts +2 -0
  109. package/src/layout/dot/rank.ts +2 -0
  110. package/src/layout/dot/splines.ts +2 -1
  111. package/src/layout/fdp/index.ts +2 -1
  112. package/src/layout/fdp/tlayout-parms.ts +9 -2
  113. package/src/layout/fdp/xlayout.ts +10 -2
  114. package/src/layout/neato/cdt-surface.ts +6 -6
  115. package/src/layout/neato/edge-len.ts +2 -1
  116. package/src/layout/neato/fdp-adjust.ts +3 -2
  117. package/src/layout/neato/init.ts +11 -11
  118. package/src/layout/neato/kk.ts +2 -1
  119. package/src/layout/neato/multispline-router.ts +3 -3
  120. package/src/layout/neato/multispline.ts +3 -2
  121. package/src/layout/neato/poly.ts +3 -2
  122. package/src/layout/neato/sgd.ts +5 -2
  123. package/src/layout/neato/start.ts +14 -10
  124. package/src/ortho/index.ts +3 -1
  125. package/src/parser/dot.js +4 -1
  126. package/src/parser/dot.pegjs +5 -1
  127. package/src/parser/index.ts +4 -3
  128. package/src/render/color-resolve.ts +193 -4
  129. package/src/render/public.ts +2 -0
  130. package/src/render/svg-edge-split.ts +4 -2
  131. package/src/render/xdot-public.ts +2 -0
package/dist/index.js CHANGED
@@ -1,3 +1,54 @@
1
+ // src/common/render-state.ts
2
+ var resets = [];
3
+ function registerRenderState(reset2) {
4
+ resets.push(reset2);
5
+ }
6
+ function resetRenderState() {
7
+ for (const reset2 of resets) reset2();
8
+ }
9
+
10
+ // src/common/agerr.ts
11
+ var PREFIX_ERROR = "Error";
12
+ var PREFIX_WARNING = "Warning";
13
+ var PREFIX_SEP = ": ";
14
+ var DEL = 127;
15
+ var LAST_CNTRL = 31;
16
+ var WHITESPACE = /* @__PURE__ */ new Set([9, 10, 11, 12, 13]);
17
+ var OCTAL_WIDTH = 3;
18
+ var OCTAL_RADIX = 8;
19
+ var lastLevel = "warning";
20
+ registerRenderState(() => {
21
+ lastLevel = "warning";
22
+ });
23
+ function escapeControl(message) {
24
+ let out = "";
25
+ for (const ch of message) {
26
+ const c = ch.codePointAt(0);
27
+ if ((c <= LAST_CNTRL || c === DEL) && !WHITESPACE.has(c)) {
28
+ out += `\\${c.toString(OCTAL_RADIX).padStart(OCTAL_WIDTH, "0")}`;
29
+ } else out += ch;
30
+ }
31
+ return out;
32
+ }
33
+ function agerrLineOn(channel, line) {
34
+ if (channel === "warn") console.warn(escapeControl(line));
35
+ else console.error(escapeControl(line));
36
+ }
37
+ function agerr(level, msg, channel) {
38
+ if (level === "prev") {
39
+ agerrLineOn(channel ?? (lastLevel === "warning" ? "warn" : "error"), msg);
40
+ return;
41
+ }
42
+ lastLevel = level;
43
+ const prefix = level === "error" ? PREFIX_ERROR : PREFIX_WARNING;
44
+ agerrLineOn(channel ?? (level === "warning" ? "warn" : "error"), `${prefix}${PREFIX_SEP}${msg}`);
45
+ }
46
+ var agerrorf = (msg, channel) => agerr("error", msg, channel);
47
+ var agwarningf = (msg, channel) => agerr("warning", msg, channel);
48
+ function agerrFinished(line, channel) {
49
+ agerrLineOn(channel ?? (line.startsWith(PREFIX_WARNING) ? "warn" : "error"), line);
50
+ }
51
+
1
52
  // src/parser/dot.js
2
53
  var peg$SyntaxError = class extends SyntaxError {
3
54
  constructor(message, expected, found, location) {
@@ -248,7 +299,7 @@ function peg$parse(input, options) {
248
299
  return s;
249
300
  }
250
301
  function peg$f13(t, m, attrs) {
251
- if (m) console.error("Warning: attribute macros not implemented");
302
+ if (m) agwarningf("attribute macros not implemented", "error");
252
303
  return { type: "attr", target: t, attrs };
253
304
  }
254
305
  function peg$f14(a) {
@@ -4221,8 +4272,8 @@ var StmtProcessor = class _StmtProcessor {
4221
4272
  resolveEndpoint(item, root, scope, directed) {
4222
4273
  if ("type" in item && item.type === "subgraph") {
4223
4274
  this.processSubgraph(item, scope, root, directed);
4224
- const seen = /* @__PURE__ */ new Set();
4225
- const nodes = NameCollector.fromStmts(item.stmts).map((n) => this.registry.ensure(n, root, scope)).filter((nd) => seen.has(nd.id) ? false : (seen.add(nd.id), true));
4275
+ const seen2 = /* @__PURE__ */ new Set();
4276
+ const nodes = NameCollector.fromStmts(item.stmts).map((n) => this.registry.ensure(n, root, scope)).filter((nd) => seen2.has(nd.id) ? false : (seen2.add(nd.id), true));
4226
4277
  return nodes.sort((a, b) => a.id - b.id);
4227
4278
  }
4228
4279
  return [this.registry.ensure(item.id, root, scope)];
@@ -4466,22 +4517,22 @@ function countNewlines(s, from, to) {
4466
4517
  return n;
4467
4518
  }
4468
4519
  var HEADER_KEYWORDS = ["strict", "graph", "digraph"];
4469
- function isTruncatedHeaderKeyword(src, step, offset, seen) {
4470
- if (offset !== src.length || step.end !== offset || seen.length > 1) return false;
4471
- if (seen.length === 1 && seen[0].toLowerCase() !== "strict") return false;
4520
+ function isTruncatedHeaderKeyword(src, step, offset, seen2) {
4521
+ if (offset !== src.length || step.end !== offset || seen2.length > 1) return false;
4522
+ if (seen2.length === 1 && seen2[0].toLowerCase() !== "strict") return false;
4472
4523
  const word = step.text.toLowerCase();
4473
4524
  return HEADER_KEYWORDS.some((k) => k.length > word.length && k.startsWith(word));
4474
4525
  }
4475
- function reachesOffset(src, step, offset, seen) {
4526
+ function reachesOffset(src, step, offset, seen2) {
4476
4527
  if (step.end > offset) return true;
4477
- if (isTruncatedHeaderKeyword(src, step, offset, seen)) return true;
4528
+ if (isTruncatedHeaderKeyword(src, step, offset, seen2)) return true;
4478
4529
  if (step.text !== "-" && step.text !== ".") return false;
4479
4530
  return offset <= step.end + (step.text === "-" && src[step.end] === "." ? 1 : 0);
4480
4531
  }
4481
4532
  function scanAtError(src, offset) {
4482
4533
  let line = 1;
4483
4534
  let i = 0;
4484
- const seen = [];
4535
+ const seen2 = [];
4485
4536
  while (i < src.length) {
4486
4537
  const step = lexStep(src, i);
4487
4538
  if (step.kind === "open") {
@@ -4490,10 +4541,10 @@ function scanAtError(src, offset) {
4490
4541
  }
4491
4542
  if (step.kind === "skip" && step.line !== void 0) line = step.line;
4492
4543
  line += countNewlines(src, i, step.end);
4493
- if (step.kind === "token" && reachesOffset(src, step, offset, seen)) {
4544
+ if (step.kind === "token" && reachesOffset(src, step, offset, seen2)) {
4494
4545
  return { state: "INITIAL", text: step.text, line, buffer: "" };
4495
4546
  }
4496
- if (step.kind === "token") seen.push(step.text);
4547
+ if (step.kind === "token") seen2.push(step.text);
4497
4548
  i = step.end;
4498
4549
  }
4499
4550
  return { state: "INITIAL", text: "", line, buffer: "" };
@@ -4803,7 +4854,7 @@ function isPeggyError(err) {
4803
4854
  function warnNumberAmbiguities(src, upTo) {
4804
4855
  for (const a of scanNumberAmbiguities(src, Stripper.strip(src))) {
4805
4856
  if (a.offset > upTo) break;
4806
- console.error(numberAmbiguityMessage(a));
4857
+ agerrFinished(numberAmbiguityMessage(a), "error");
4807
4858
  }
4808
4859
  }
4809
4860
  function parse(src) {
@@ -4817,7 +4868,7 @@ function parse(src) {
4817
4868
  if (isPeggyError(err)) {
4818
4869
  const start = err.location.start;
4819
4870
  warnNumberAmbiguities(src, start.offset);
4820
- console.error(syntaxErrorMessage(src, start.offset));
4871
+ agerrFinished(syntaxErrorMessage(src, start.offset));
4821
4872
  const code = err.found === null ? "SYNTAX_UNEXPECTED_EOF" : "SYNTAX_ERROR";
4822
4873
  throw new ParseError(
4823
4874
  err instanceof Error ? err.message : String(err),
@@ -4842,7 +4893,7 @@ function parse(src) {
4842
4893
  const offset = err instanceof ParseError ? err.location.offset : void 0;
4843
4894
  if (offset !== void 0) {
4844
4895
  warnNumberAmbiguities(src, offset);
4845
- console.error(syntaxErrorMessage(src, offset));
4896
+ agerrFinished(syntaxErrorMessage(src, offset));
4846
4897
  }
4847
4898
  throw err;
4848
4899
  }
@@ -8542,6 +8593,9 @@ var COLOR_LIB = [
8542
8593
 
8543
8594
  // src/common/color.ts
8544
8595
  var colorScheme = "";
8596
+ registerRenderState(() => {
8597
+ colorScheme = "";
8598
+ });
8545
8599
  function setColorScheme(scheme) {
8546
8600
  colorScheme = scheme;
8547
8601
  }
@@ -8671,18 +8725,28 @@ function setBlackOpaque(color, targetType) {
8671
8725
  if (targetType === "rgba") setRgba(color, 0, 0, 0, 255);
8672
8726
  else if (targetType === "hsva") setHsvaDirect(color, 0, 0, 0, 1);
8673
8727
  }
8728
+ var SSCANF_SPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\v", "\f", "\r"]);
8729
+ function scanHexGroups(p, width2, max) {
8730
+ const out = [];
8731
+ if (p.charAt(0) !== "#") return out;
8732
+ let i = 1;
8733
+ while (out.length < max) {
8734
+ while (SSCANF_SPACE.has(p.charAt(i))) i++;
8735
+ let j = i;
8736
+ while (j < p.length && j - i < width2 && /[0-9a-fA-F]/.test(p.charAt(j))) j++;
8737
+ if (j === i) break;
8738
+ out.push(parseInt(p.slice(i, j), 16));
8739
+ i = j;
8740
+ }
8741
+ return out;
8742
+ }
8674
8743
  function parseHexColor(p) {
8675
- if (p.charAt(0) !== "#") return null;
8676
- const m8 = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(p);
8677
- if (m8) return { r: parseInt(m8[1], 16), g: parseInt(m8[2], 16), b: parseInt(m8[3], 16), a: parseInt(m8[4], 16) };
8678
- const m6 = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(p);
8679
- if (m6) return { r: parseInt(m6[1], 16), g: parseInt(m6[2], 16), b: parseInt(m6[3], 16), a: 255 };
8680
- const m3 = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/.exec(p);
8681
- if (!m3) return null;
8682
- const r = parseInt(m3[1], 16);
8683
- const g = parseInt(m3[2], 16);
8684
- const b = parseInt(m3[3], 16);
8685
- return { r: r | r << 4, g: g | g << 4, b: b | b << 4, a: 255 };
8744
+ const g = scanHexGroups(p, 2, 4);
8745
+ if (g.length >= 3) return { r: g[0], g: g[1], b: g[2], a: g[3] ?? 255 };
8746
+ const short = p.length === 4 ? scanHexGroups(p, 1, 3) : [];
8747
+ if (short.length !== 3) return null;
8748
+ const [r, gg, b] = short;
8749
+ return { r: r | r << 4, g: gg | gg << 4, b: b | b << 4, a: 255 };
8686
8750
  }
8687
8751
  function clamp01(x) {
8688
8752
  return Math.max(0, Math.min(1, x));
@@ -8728,6 +8792,263 @@ function colorxlate(str, color, targetType) {
8728
8792
  return 1 /* ColorUnknown */;
8729
8793
  }
8730
8794
 
8795
+ // src/common/multicolor.ts
8796
+ var EPS = 1e-5;
8797
+ function aeq0(x) {
8798
+ return x < EPS && x > -EPS;
8799
+ }
8800
+ function getSegLen(token) {
8801
+ const semi = token.indexOf(";");
8802
+ if (semi === -1) return { color: token, v: 0 };
8803
+ const color = token.slice(0, semi);
8804
+ const rest = token.slice(semi + 1);
8805
+ if (rest.length === 0) return { color, v: -1 };
8806
+ const parsed = parseFloat(rest);
8807
+ return !isNaN(parsed) && parsed >= 0 ? { color, v: parsed } : { color, v: -1 };
8808
+ }
8809
+ function appendSeg(token, left2, segs, warnedExceeded) {
8810
+ const { color, v } = getSegLen(token);
8811
+ if (v < 0) return null;
8812
+ let t = v;
8813
+ let rval = 0;
8814
+ const del = t - left2;
8815
+ if (del > 0) {
8816
+ if (!aeq0(del) && !warnedExceeded.v) {
8817
+ warnedExceeded.v = true;
8818
+ rval = 3;
8819
+ }
8820
+ t = left2;
8821
+ }
8822
+ left2 -= t;
8823
+ segs.push({ color: color.length > 0 ? color : null, t, hasFraction: t > 0 && v > 0 });
8824
+ return { left: left2, rval };
8825
+ }
8826
+ function distributeLeft(segs, left2) {
8827
+ if (left2 <= 0) return;
8828
+ const zeroCount = segs.filter((s) => s.t <= 0).length;
8829
+ if (zeroCount > 0) {
8830
+ const delta2 = left2 / zeroCount;
8831
+ for (const s of segs) {
8832
+ if (s.t <= 0) s.t = delta2;
8833
+ }
8834
+ } else if (segs.length > 0) {
8835
+ segs[segs.length - 1].t += left2;
8836
+ }
8837
+ }
8838
+ function trimTrailing(segs) {
8839
+ while (segs.length > 0 && (segs[segs.length - 1]?.t ?? 0) <= 0) {
8840
+ segs.pop();
8841
+ }
8842
+ }
8843
+ function parseSegs(colorlist) {
8844
+ const segs = [];
8845
+ let left2 = 1;
8846
+ let rval = 0;
8847
+ let badFloatCount = 0;
8848
+ const warnedExceeded = { v: false };
8849
+ for (const token of colorlist.split(":")) {
8850
+ const result = appendSeg(token, left2, segs, warnedExceeded);
8851
+ if (result === null) {
8852
+ const errCode = badFloatCount === 0 ? 2 : 1;
8853
+ badFloatCount++;
8854
+ return { segs: [], error: errCode };
8855
+ }
8856
+ if (result.rval === 3) rval = 3;
8857
+ left2 = result.left;
8858
+ if (aeq0(left2)) {
8859
+ left2 = 0;
8860
+ break;
8861
+ }
8862
+ }
8863
+ distributeLeft(segs, left2);
8864
+ trimTrailing(segs);
8865
+ return { segs, error: rval };
8866
+ }
8867
+
8868
+ // src/common/style-resolve.ts
8869
+ var DEFAULT_COLOR = "black";
8870
+ var DEFAULT_FILL = "lightgrey";
8871
+ var PENWIDTH_BOLD = 2;
8872
+ var TOKEN_FLAG = {
8873
+ filled: "filled",
8874
+ dashed: "dashed",
8875
+ dotted: "dotted",
8876
+ bold: "bold",
8877
+ invis: "invis",
8878
+ diagonals: "diagonals",
8879
+ rounded: "rounded",
8880
+ striped: "striped",
8881
+ wedged: "wedged",
8882
+ underline: "underline"
8883
+ };
8884
+ function zeroFlags() {
8885
+ return {
8886
+ filled: false,
8887
+ dashed: false,
8888
+ dotted: false,
8889
+ bold: false,
8890
+ invis: false,
8891
+ diagonals: false,
8892
+ rounded: false,
8893
+ radial: false,
8894
+ striped: false,
8895
+ wedged: false,
8896
+ underline: false,
8897
+ setLineWidth: null
8898
+ };
8899
+ }
8900
+ var FUNLIMIT = 64;
8901
+ function styleTokens(style2) {
8902
+ if (!style2) return [];
8903
+ const out = [];
8904
+ let fun = 0;
8905
+ for (const raw of style2.split(",")) {
8906
+ const token = raw.trim();
8907
+ if (token.length === 0) continue;
8908
+ if (fun === FUNLIMIT - 1) return [];
8909
+ fun++;
8910
+ out.push(token);
8911
+ }
8912
+ return out;
8913
+ }
8914
+ function parseSetLineWidth(token) {
8915
+ const m = /^setlinewidth\s*\(\s*([^)]*)\)\s*$/.exec(token);
8916
+ if (m === null) return null;
8917
+ const v = parseFloat(m[1]);
8918
+ return Number.isNaN(v) ? 0 : v;
8919
+ }
8920
+ function applyToken(flags, token) {
8921
+ if (token === "radial") {
8922
+ flags.radial = true;
8923
+ flags.filled = true;
8924
+ return;
8925
+ }
8926
+ const key = TOKEN_FLAG[token];
8927
+ if (key !== void 0) flags[key] = true;
8928
+ }
8929
+ function nonEmpty(s) {
8930
+ return s !== void 0 && s.length > 0;
8931
+ }
8932
+ function orElse(s, fallback) {
8933
+ return nonEmpty(s) ? s : fallback;
8934
+ }
8935
+ function firstSolidColor(raw) {
8936
+ const grad = parseGradientSpec(raw);
8937
+ return grad !== null ? grad[0] : raw;
8938
+ }
8939
+ function parseStyleFlags(style2) {
8940
+ const flags = zeroFlags();
8941
+ if (!style2) return flags;
8942
+ let fun = 0;
8943
+ for (const raw of style2.split(",")) {
8944
+ const token = raw.trim();
8945
+ if (token.length === 0) continue;
8946
+ if (fun === FUNLIMIT - 1) return zeroFlags();
8947
+ fun++;
8948
+ const lw = parseSetLineWidth(token);
8949
+ if (lw !== null) {
8950
+ flags.setLineWidth = lw;
8951
+ continue;
8952
+ }
8953
+ if (!token.includes("(")) applyToken(flags, token);
8954
+ }
8955
+ return flags;
8956
+ }
8957
+ function styleHasInvisibleAlias(style2) {
8958
+ if (!style2) return false;
8959
+ let fun = 0;
8960
+ for (const raw of style2.split(",")) {
8961
+ const token = raw.trim();
8962
+ if (token.length === 0) continue;
8963
+ if (fun === FUNLIMIT - 1) return false;
8964
+ fun++;
8965
+ if (token === "invisible") return true;
8966
+ }
8967
+ return false;
8968
+ }
8969
+ function resolvePenType(flags) {
8970
+ if (flags.invis) return 0 /* None */;
8971
+ if (flags.dashed) return 1 /* Dashed */;
8972
+ if (flags.dotted) return 2 /* Dotted */;
8973
+ return 3 /* Solid */;
8974
+ }
8975
+ function resolvePenWidth(flags, penwidthAttr) {
8976
+ if (penwidthAttr && penwidthAttr.length > 0) {
8977
+ const v = parseFloat(penwidthAttr);
8978
+ if (isFinite(v)) return v;
8979
+ }
8980
+ if (flags.setLineWidth !== null) return flags.setLineWidth;
8981
+ if (flags.bold) return PENWIDTH_BOLD;
8982
+ return 1;
8983
+ }
8984
+ function resolvePenColor(colorAttr) {
8985
+ if (!colorAttr || colorAttr.length === 0) return DEFAULT_COLOR;
8986
+ return firstSolidColor(colorAttr);
8987
+ }
8988
+ function clusterColorAttrs(attrs) {
8989
+ const base = nonEmpty(attrs.color) ? attrs.color : void 0;
8990
+ const pencolor = orElse(attrs.pencolor, base ?? "");
8991
+ const fillcolor = orElse(attrs.fillcolor, base ?? "");
8992
+ return {
8993
+ fillcolor: nonEmpty(fillcolor) ? fillcolor : void 0,
8994
+ pencolor: nonEmpty(pencolor) ? pencolor : void 0
8995
+ };
8996
+ }
8997
+ function applyBgcolor(attrs, filled, fillcolor) {
8998
+ if ((!filled || !fillcolor) && nonEmpty(attrs.bgcolor)) {
8999
+ return { filled: true, fillcolor: attrs.bgcolor };
9000
+ }
9001
+ return { filled, fillcolor };
9002
+ }
9003
+ function findStopColor(colorlist) {
9004
+ const { segs, error } = parseSegs(colorlist);
9005
+ if (error === 1 || error === 2) return null;
9006
+ if (segs.length < 2) return null;
9007
+ const seg0 = segs[0];
9008
+ const seg1 = segs[1];
9009
+ if (seg0.color === null) return null;
9010
+ const fillColor = seg0.color;
9011
+ const stopColor = seg1.color ?? DEFAULT_COLOR;
9012
+ const frac = seg0.hasFraction ? seg0.t : seg1.hasFraction ? 1 - seg1.t : 0;
9013
+ return { fillColor, stopColor, frac };
9014
+ }
9015
+ function parseAngle(gradientangle2) {
9016
+ if (!gradientangle2 || gradientangle2.length === 0) return 0;
9017
+ const v = parseInt(gradientangle2, 10);
9018
+ return isFinite(v) ? v : 0;
9019
+ }
9020
+ function buildResolvedFill(rawColor, flags, angle) {
9021
+ const stop = findStopColor(rawColor);
9022
+ if (stop === null) return { kind: "solid", color: rawColor };
9023
+ const kind = flags.radial ? "radial" : "linear";
9024
+ return { kind, fillColor: stop.fillColor, stopColor: stop.stopColor, frac: stop.frac, angle };
9025
+ }
9026
+ function resolveNodeFillEx(attrs) {
9027
+ const flags = parseStyleFlags(attrs.style);
9028
+ if (!flags.filled) return { kind: "none" };
9029
+ const raw = nonEmpty(attrs.fillcolor) ? attrs.fillcolor : nonEmpty(attrs.color) ? attrs.color : DEFAULT_FILL;
9030
+ return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
9031
+ }
9032
+ function resolveClusterFillEx(attrs) {
9033
+ const flags = parseStyleFlags(attrs.style);
9034
+ const colors = clusterColorAttrs(attrs);
9035
+ const bg = applyBgcolor(attrs, flags.filled, colors.fillcolor);
9036
+ if (!bg.filled) return { kind: "none" };
9037
+ const raw = bg.fillcolor ?? DEFAULT_FILL;
9038
+ return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
9039
+ }
9040
+
9041
+ // src/common/emit-once.ts
9042
+ var seen = /* @__PURE__ */ new Set();
9043
+ registerRenderState(() => {
9044
+ seen.clear();
9045
+ });
9046
+ function emitOnce(str) {
9047
+ if (seen.has(str)) return false;
9048
+ seen.add(str);
9049
+ return true;
9050
+ }
9051
+
8731
9052
  // src/render/color-resolve.ts
8732
9053
  var SVG_KNOWN_COLORS = [
8733
9054
  "aliceblue",
@@ -8880,12 +9201,33 @@ var SVG_KNOWN_COLORS = [
8880
9201
  "yellowgreen"
8881
9202
  ];
8882
9203
  var KNOWN_COLORS = new Set(SVG_KNOWN_COLORS);
8883
- function resolveRenderColor(raw) {
9204
+ var rendererColors = { hasKnownList: true };
9205
+ registerRenderState(() => {
9206
+ rendererColors.hasKnownList = true;
9207
+ });
9208
+ function setRendererKnownColors(hasList) {
9209
+ rendererColors.hasKnownList = hasList;
9210
+ }
9211
+ function firstColor(name) {
9212
+ const i = name.indexOf(":");
9213
+ return i < 0 ? name : name.slice(0, i);
9214
+ }
9215
+ function resolveRenderColor(raw, report = true) {
8884
9216
  if (raw === "" || raw === "none") return { type: "none" };
8885
- if (KNOWN_COLORS.has(raw.toLowerCase())) return { type: "string", s: raw };
9217
+ const known = KNOWN_COLORS.has(raw.toLowerCase());
9218
+ if (known && (rendererColors.hasKnownList || !report)) return { type: "string", s: raw };
8886
9219
  const color = { type: "rgba", r: 0, g: 0, b: 0, a: 0 };
8887
- colorxlate(raw, color, "rgba");
8888
- return color;
9220
+ const rc = colorxlate(raw, color, "rgba");
9221
+ if (report) reportColorxlate(raw, rc);
9222
+ return known ? { type: "string", s: raw } : color;
9223
+ }
9224
+ function reportColorxlate(name, rc) {
9225
+ if (rc === 0 /* ColorOk */) return;
9226
+ if (rc === 1 /* ColorUnknown */) {
9227
+ if (emitOnce(`color ${name}`)) agwarningf(`${name} is not a known color.`);
9228
+ } else {
9229
+ agerrorf("error in colorxlate()");
9230
+ }
8889
9231
  }
8890
9232
  function withColorScheme(scheme, fn) {
8891
9233
  const prev = getColorScheme();
@@ -8932,6 +9274,72 @@ function textFillAttrs(fontColor) {
8932
9274
  if (byte < 255) out += ' fill-opacity="' + (byte / 255).toFixed(6) + '"';
8933
9275
  return out;
8934
9276
  }
9277
+ var DEFAULT_COLOR2 = "black";
9278
+ var SEG_EPS = 1e-5;
9279
+ function reportColorNames(names) {
9280
+ for (const name of names) resolveRenderColor(firstColor(name));
9281
+ }
9282
+ function countChar(s, ch) {
9283
+ return s.split(ch).length - 1;
9284
+ }
9285
+ function multicolorNames(color, arrows) {
9286
+ const { segs, error } = parseSegs(color);
9287
+ if (error === 1 || error === 2) return null;
9288
+ const out = [];
9289
+ const front = segs[0]?.color ?? null;
9290
+ for (const bz of arrows) {
9291
+ let endcolor = null;
9292
+ for (const seg2 of segs) {
9293
+ if (seg2.color === null) break;
9294
+ if (Math.abs(seg2.t) < SEG_EPS) continue;
9295
+ out.push(seg2.color);
9296
+ endcolor = seg2.color;
9297
+ }
9298
+ if (bz.sflag && front !== null) out.push(front);
9299
+ if (bz.eflag && endcolor !== null) out.push(endcolor);
9300
+ }
9301
+ return out;
9302
+ }
9303
+ function taperedNames(color, fillcolor, hasFill) {
9304
+ const pen = color === "" ? DEFAULT_COLOR2 : color;
9305
+ return hasFill ? [pen, fillcolor === "" ? DEFAULT_COLOR2 : fillcolor] : [pen];
9306
+ }
9307
+ function edgeGraphicsColors(spec) {
9308
+ const numc = countChar(spec.color, ":");
9309
+ let color = spec.color;
9310
+ if (countChar(color, ";") > 0 && numc > 0) {
9311
+ const multi = multicolorNames(color, spec.arrows);
9312
+ if (multi !== null) return multi;
9313
+ color = DEFAULT_COLOR2;
9314
+ }
9315
+ const hasFill = spec.fillcolor !== "";
9316
+ const early = hasFill ? [spec.fillcolor] : [];
9317
+ if (spec.tapered) return [...early, ...taperedNames(color, spec.fillcolor, hasFill)];
9318
+ if (numc > 0) return [...early, ...color.split(":").filter((c) => c !== "")];
9319
+ const fill = hasFill ? spec.fillcolor : color;
9320
+ if (color !== "") return [...early, color, fill];
9321
+ return [...early, DEFAULT_COLOR2, fill !== "" ? fill : DEFAULT_COLOR2];
9322
+ }
9323
+ function reportEdgeColors(e) {
9324
+ const spl = e.info.spl;
9325
+ if (!spl) return;
9326
+ const color = e.attrs.get("color") ?? "";
9327
+ reportColorNames(edgeGraphicsColors({
9328
+ color,
9329
+ fillcolor: e.attrs.get("fillcolor") ?? "",
9330
+ tapered: styleTokens(e.attrs.get("style")).includes("tapered"),
9331
+ arrows: spl.list.map((bz) => ({ sflag: bz.sflag !== 0, eflag: bz.eflag !== 0 }))
9332
+ }));
9333
+ }
9334
+ function backgroundColors(bgcolor, truecolor) {
9335
+ let str = bgcolor !== void 0 && bgcolor !== "" ? bgcolor : "white";
9336
+ if (str === "transparent") {
9337
+ if (truecolor) return [];
9338
+ str = "white";
9339
+ }
9340
+ const stop = findStopColor(str);
9341
+ return stop === null ? [str, "transparent"] : [stop.fillColor, "transparent", stop.stopColor];
9342
+ }
8935
9343
 
8936
9344
  // src/common/poly-shapes-util.ts
8937
9345
  var RBCONST = 12;
@@ -9543,6 +9951,7 @@ function htmlFillPenWidth() {
9543
9951
  function resetHtmlFillPenWidth() {
9544
9952
  htmlFillPen = 1;
9545
9953
  }
9954
+ registerRenderState(resetHtmlFillPenWidth);
9546
9955
  function penTypeOf(style2) {
9547
9956
  const st = htmlStyle(style2);
9548
9957
  if (st.dashed) return 1 /* Dashed */;
@@ -9671,6 +10080,31 @@ function emitSidedPolylines(sides2, corners, renderer, job) {
9671
10080
  renderer.polyline(seq2.map((i) => corners[i]), job);
9672
10081
  }
9673
10082
  }
10083
+ var HTML_DEFAULT_COLOR = "black";
10084
+ function bgNames(bgcolor) {
10085
+ const spec = parseGradientSpec(bgcolor);
10086
+ return spec === null ? [bgcolor] : [spec[0], spec[1]];
10087
+ }
10088
+ function cellNames(cell2) {
10089
+ if (htmlStyle(cell2.style).invisible) return [];
10090
+ const out = cell2.bgcolor !== void 0 ? bgNames(cell2.bgcolor) : [];
10091
+ if (cell2.border > 0) out.push(cell2.color ?? HTML_DEFAULT_COLOR);
10092
+ if (cell2.nested !== void 0) out.push(...tableNames(cell2.nested));
10093
+ else for (const line of cell2.lines) if (line.fontColor !== null) out.push(line.fontColor);
10094
+ return out;
10095
+ }
10096
+ function tableNames(tbl) {
10097
+ if (htmlStyle(tbl.style).invisible) return [];
10098
+ const out = tbl.bgcolor !== void 0 ? bgNames(tbl.bgcolor) : [];
10099
+ const color = tbl.color ?? HTML_DEFAULT_COLOR;
10100
+ if (tbl.cells.some((c) => c.vruled === true || c.hruled === true)) out.push(color);
10101
+ if (tbl.border > 0) out.push(color);
10102
+ for (const cell2 of tbl.cells) out.push(...cellNames(cell2));
10103
+ return out;
10104
+ }
10105
+ function htmlLabelColors(label) {
10106
+ return [label.color ?? HTML_DEFAULT_COLOR, ...tableNames(label)];
10107
+ }
9674
10108
 
9675
10109
  // src/common/htmltable-emit-rules.ts
9676
10110
  function emitHtmlRules(ctx) {
@@ -9757,6 +10191,7 @@ function resetHtmlAnchorIds() {
9757
10191
  anchorEnv.objLabel = null;
9758
10192
  anchorEnv.imgscale = "false";
9759
10193
  }
10194
+ registerRenderState(resetHtmlAnchorIds);
9760
10195
  function initHtmlAnchor(data, box, renderer, job) {
9761
10196
  if (data.href === void 0 && data.title === void 0 && data.target === void 0) {
9762
10197
  return false;
@@ -10011,7 +10446,7 @@ var sides = (v) => {
10011
10446
  };
10012
10447
  var STYLE_WORDS = ["rounded", "radial", "solid", "invisible", "invis", "dotted", "dashed"];
10013
10448
  var STYLE_DELIM = " ,";
10014
- function styleTokens(v) {
10449
+ function styleTokens2(v) {
10015
10450
  const out = [];
10016
10451
  const span = (from, member) => {
10017
10452
  let i = from;
@@ -10030,7 +10465,7 @@ function styleTokens(v) {
10030
10465
  var style = (v) => {
10031
10466
  const legal = [];
10032
10467
  const text = [];
10033
- for (const tk of styleTokens(v)) {
10468
+ for (const tk of styleTokens2(v)) {
10034
10469
  if (STYLE_WORDS.includes(lower(tk))) legal.push(tk);
10035
10470
  else text.push(warning(`Illegal value ${tk} for STYLE - ignored
10036
10471
  `));
@@ -10149,10 +10584,7 @@ var StderrLines = class {
10149
10584
  this.pending = "";
10150
10585
  }
10151
10586
  };
10152
- var consoleLine = (line) => {
10153
- if (line.startsWith("Warning")) console.warn(line);
10154
- else console.error(line);
10155
- };
10587
+ var consoleLine = (line) => agerrFinished(line);
10156
10588
  var labelStderr = () => new StderrLines(consoleLine);
10157
10589
  var agerrLine = (out, msg) => {
10158
10590
  if (out === void 0) consoleLine(msg);
@@ -10439,28 +10871,46 @@ var HTML_ENTITIES = {
10439
10871
  "zwj": 8205,
10440
10872
  "zwnj": 8204
10441
10873
  };
10442
- var BASIC_ENTITIES = {
10443
- amp: 38,
10444
- lt: 60,
10445
- gt: 62,
10446
- quot: 34,
10447
- apos: 39
10448
- };
10449
- function numericEntityValue(body) {
10450
- const hex = body[1] === "x" || body[1] === "X";
10451
- const v = hex ? parseInt(body.slice(2), 16) : parseInt(body.slice(1), 10);
10452
- return Number.isFinite(v) && v > 0 && v <= 1114111 ? v : null;
10874
+ var ENTITY_NAME_LENGTH_MAX = 8;
10875
+ function numericEntity(s, at) {
10876
+ const hex = s[at + 1] === "x" || s[at + 1] === "X";
10877
+ const digit = hex ? /^[0-9A-Fa-f]$/ : /^[0-9]$/;
10878
+ let n = 0;
10879
+ let i = hex ? 2 : 1;
10880
+ for (; i < 8; i++) {
10881
+ const c = s[at + i] ?? "";
10882
+ if (!digit.test(c)) break;
10883
+ n = n * (hex ? 16 : 10) + parseInt(c, 16);
10884
+ }
10885
+ if (i < 8 && s[at + i] === ";") return { value: n, next: at + i + 1 };
10886
+ return { value: 0, next: at };
10887
+ }
10888
+ function namedEntity(s, at) {
10889
+ for (let i = 0; i < ENTITY_NAME_LENGTH_MAX; i++) {
10890
+ const c = s[at + i];
10891
+ if (c === void 0 || c === "\0") break;
10892
+ if (c === ";") {
10893
+ const key = s.slice(at, at + i);
10894
+ if (Object.hasOwn(HTML_ENTITIES, key)) return { value: HTML_ENTITIES[key], next: at + i + 1 };
10895
+ break;
10896
+ }
10897
+ }
10898
+ return { value: 0, next: at };
10453
10899
  }
10454
- function entityValue(body) {
10455
- if (body[0] === "#") return numericEntityValue(body);
10456
- return BASIC_ENTITIES[body] ?? HTML_ENTITIES[body] ?? null;
10900
+ function htmlEntity(s, at) {
10901
+ return s[at] === "#" ? numericEntity(s, at) : namedEntity(s, at);
10457
10902
  }
10458
10903
  function htmlEntityUTF8(s) {
10459
- if (s.indexOf("&") < 0) return s;
10460
- return s.replace(/&(#x[0-9a-fA-F]+|#[0-9]+|[A-Za-z]+);/g, (m, body) => {
10461
- const v = entityValue(body);
10462
- return v === null ? m : String.fromCodePoint(v);
10463
- });
10904
+ let amp = s.indexOf("&");
10905
+ if (amp < 0) return s;
10906
+ let out = "";
10907
+ let from = 0;
10908
+ for (; amp >= 0; amp = s.indexOf("&", from)) {
10909
+ const e = htmlEntity(s, amp + 1);
10910
+ out += s.slice(from, amp) + (e.value ? String.fromCodePoint(e.value) : "&");
10911
+ from = e.next;
10912
+ }
10913
+ return out + s.slice(from);
10464
10914
  }
10465
10915
 
10466
10916
  // src/common/htmltable-lex-attvalue.ts
@@ -10594,14 +11044,14 @@ function tagEdge(text, i) {
10594
11044
  if (i + 1 >= text.length) return PARTIAL;
10595
11045
  return text[i + 1] === ">" ? COMPLETE_END(i + 2) : void 0;
10596
11046
  }
10597
- function storeAttError(text, p, at, pair, seen) {
10598
- if (seen.has(pair.name)) return { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: at };
10599
- seen.add(pair.name);
11047
+ function storeAttError(text, p, at, pair, seen2) {
11048
+ if (seen2.has(pair.name)) return { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: at };
11049
+ seen2.add(pair.name);
10600
11050
  const err = attValueError(text.slice(pair.value.start, pair.value.end), pair.value.start);
10601
11051
  return err === void 0 ? void 0 : { message: err.message, offset: err.offset ?? p };
10602
11052
  }
10603
11053
  function scanAttributes(text, p, from) {
10604
- const seen = /* @__PURE__ */ new Set();
11054
+ const seen2 = /* @__PURE__ */ new Set();
10605
11055
  let attError;
10606
11056
  let i = skipSpace(text, from);
10607
11057
  for (; ; ) {
@@ -10610,7 +11060,7 @@ function scanAttributes(text, p, from) {
10610
11060
  if (edge !== void 0) return edge;
10611
11061
  const pair = scanPair(text, i);
10612
11062
  if ("kind" in pair) return pair;
10613
- attError ??= storeAttError(text, p, i, pair, seen);
11063
+ attError ??= storeAttError(text, p, i, pair, seen2);
10614
11064
  i = pair.next;
10615
11065
  }
10616
11066
  }
@@ -10678,9 +11128,11 @@ function scanCdata(text, p, base, dataOf, tokens) {
10678
11128
  }
10679
11129
  function scanText(text, p, base, tokens) {
10680
11130
  const e = text.indexOf("<", p);
10681
- const end = e < 0 ? text.length : e;
10682
- tokens.push({ kind: "text", start: base + p, end: base + end });
10683
- return end;
11131
+ const slice = text.slice(p, e < 0 ? text.length : e);
11132
+ const from = e < 0 ? heldRefStart(slice) : void 0;
11133
+ const end = from === void 0 ? p + slice.length : p + from;
11134
+ if (end > p) tokens.push({ kind: "text", start: base + p, end: base + end });
11135
+ return { at: end, held: from !== void 0 };
10684
11136
  }
10685
11137
  function scanContent(text, base, inCdata, dataOf) {
10686
11138
  const tokens = [];
@@ -10695,7 +11147,9 @@ function scanContent(text, base, inCdata, dataOf) {
10695
11147
  continue;
10696
11148
  }
10697
11149
  if (text[p] !== "<") {
10698
- p = scanText(text, p, base, tokens);
11150
+ const scanned = scanText(text, p, base, tokens);
11151
+ if (scanned.held) return { tokens, consumed: scanned.at, inCdata: false };
11152
+ p = scanned.at;
10699
11153
  continue;
10700
11154
  }
10701
11155
  const { scan, kind } = scanMarkup(text, p);
@@ -10795,24 +11249,44 @@ var ExpatFeed = class {
10795
11249
  }
10796
11250
  };
10797
11251
  var XML_PREDEFINED_ENTITIES = /* @__PURE__ */ new Set(["lt", "gt", "amp", "quot", "apos"]);
10798
- var ENTITY_NAME = /^[A-Za-z_:][\w.:-]*$/;
10799
- var CHAR_REF = /^&#(?:x[0-9A-Fa-f]+|[0-9]+);/;
10800
- function textRefError(text) {
10801
- for (let t = text.indexOf("&"); t >= 0; t = text.indexOf("&", t + 1)) {
10802
- if (text[t + 1] === "#") {
10803
- const ref = CHAR_REF.exec(text.slice(t))?.[0];
10804
- if (ref !== void 0 && charRefNumber(ref) < 0) return { message: XML_ERROR_BAD_CHAR_REF, offset: t };
10805
- continue;
11252
+ var SCANNED_ENTITY = /^&([^;&<]*);/;
11253
+ function contentRef(text, t) {
11254
+ const semi = text.indexOf(";", t);
11255
+ const ref = text.slice(t, semi < 0 ? text.length : semi + 1);
11256
+ const scan = scanAttValue(`"${ref}"`, 0);
11257
+ if ("close" in scan) return { end: t + scan.close - 1 };
11258
+ return { invalid: "invalid" in scan ? t + scan.invalid - 1 : text.length };
11259
+ }
11260
+ function firstRefProblem(text) {
11261
+ let t = text.indexOf("&");
11262
+ while (t >= 0) {
11263
+ if (text[t + 1] !== "#") {
11264
+ const name = SCANNED_ENTITY.exec(text.slice(t))?.[1];
11265
+ if (name !== void 0 && name.length >= 2 && Object.hasOwn(HTML_ENTITIES, name)) {
11266
+ t = text.indexOf("&", t + name.length + 2);
11267
+ continue;
11268
+ }
10806
11269
  }
10807
- const semi = text.indexOf(";", t + 1);
10808
- if (semi < 0) continue;
10809
- const key = text.slice(t + 1, semi);
10810
- if (ENTITY_NAME.test(key) && !Object.hasOwn(HTML_ENTITIES, key) && !XML_PREDEFINED_ENTITIES.has(key)) {
10811
- return { message: XML_ERROR_UNDEFINED_ENTITY, offset: t };
11270
+ const ref = contentRef(text, t);
11271
+ if ("invalid" in ref) return { message: XML_ERROR_INVALID_TOKEN, offset: ref.invalid, from: t };
11272
+ const key = text.slice(t + 1, ref.end - 1);
11273
+ if (text[t + 1] === "#") {
11274
+ if (charRefNumber(`&${key};`) < 0) return { message: XML_ERROR_BAD_CHAR_REF, offset: t, from: t };
11275
+ } else if (!XML_PREDEFINED_ENTITIES.has(key)) {
11276
+ return { message: XML_ERROR_UNDEFINED_ENTITY, offset: t, from: t };
10812
11277
  }
11278
+ t = text.indexOf("&", ref.end);
10813
11279
  }
10814
11280
  return void 0;
10815
11281
  }
11282
+ function textRefError(text) {
11283
+ const problem = firstRefProblem(text);
11284
+ return problem === void 0 ? void 0 : { message: problem.message, offset: problem.offset };
11285
+ }
11286
+ function heldRefStart(text) {
11287
+ const problem = firstRefProblem(text);
11288
+ return problem?.message === XML_ERROR_INVALID_TOKEN && problem.offset === text.length ? problem.from : void 0;
11289
+ }
10816
11290
  function parseTagChunk(chunk) {
10817
11291
  if (!chunk.endsWith(">")) return void 0;
10818
11292
  const body = chunk.slice(1, -1);
@@ -10854,8 +11328,26 @@ function releaseXb(st, first) {
10854
11328
  function cleanText(decoded) {
10855
11329
  return decoded.replace(/[\x00-\x1f]/g, "");
10856
11330
  }
11331
+ var XML_PREDEFINED = { lt: "<", gt: ">", amp: "&", quot: '"', apos: "'" };
11332
+ var SCAN_ENTITY_MIN = 2;
11333
+ var SCAN_ENTITY_MAX = 8;
11334
+ var TEXT_REF = /&(#x[0-9A-Fa-f]+|#[0-9]+|[^&;]+);/g;
11335
+ function textRefValue(ref, body) {
11336
+ if (body[0] === "#") {
11337
+ const v = charRefNumber(ref);
11338
+ return v < 0 ? ref : String.fromCodePoint(v);
11339
+ }
11340
+ const n = body.length;
11341
+ if (n >= SCAN_ENTITY_MIN && n <= SCAN_ENTITY_MAX && Object.hasOwn(HTML_ENTITIES, body)) {
11342
+ return String.fromCodePoint(HTML_ENTITIES[body]);
11343
+ }
11344
+ return Object.hasOwn(XML_PREDEFINED, body) ? XML_PREDEFINED[body] : ref;
11345
+ }
11346
+ function decodeTextRefs(raw) {
11347
+ return raw.indexOf("&") < 0 ? raw : raw.replace(TEXT_REF, textRefValue);
11348
+ }
10857
11349
  function textTokens(raw) {
10858
- return charDataTokens(htmlEntityUTF8(raw));
11350
+ return charDataTokens(decodeTextRefs(raw));
10859
11351
  }
10860
11352
  function charDataTokens(decoded) {
10861
11353
  const clean = cleanText(decoded);
@@ -11827,30 +12319,23 @@ var splitSizedLines = (texts, measurer, env) => {
11827
12319
  return lines;
11828
12320
  };
11829
12321
  var itemHasFlags = (i) => i.bold === true || i.italic === true || i.underline === true || i.strikethrough === true || i.overline === true || i.subscript === true || i.superscript === true;
11830
- var htmlTextIsSimple = (texts, env) => {
12322
+ var htmlTextIsSimple = (lines, env) => {
11831
12323
  let prevFs = -1;
11832
12324
  let prevFace = null;
11833
- let count = 0;
11834
- for (const txt of texts) {
11835
- for (const item of txt.items) {
11836
- if (item.br) {
11837
- count = 0;
11838
- continue;
11839
- }
11840
- if (item.text === void 0) continue;
11841
- if (++count > 1 || itemHasFlags(item)) return false;
11842
- const { fs, face } = itemFont(item, env);
11843
- if (prevFs < 0) prevFs = fs;
11844
- else if (fs !== prevFs) return false;
11845
- if (prevFace === null) prevFace = face;
11846
- else if (face !== prevFace) return false;
11847
- }
12325
+ for (const ln of lines) {
12326
+ const item = ln.items[0];
12327
+ if (ln.items.length > 1 || itemHasFlags(item)) return false;
12328
+ const { fs, face } = itemFont(item, env);
12329
+ if (prevFs < 0) prevFs = fs;
12330
+ else if (fs !== prevFs) return false;
12331
+ if (prevFace === null) prevFace = face;
12332
+ else if (face !== prevFace) return false;
11848
12333
  }
11849
12334
  return true;
11850
12335
  };
11851
12336
  var sizeTextContent = (texts, measurer, env = defaultSizeEnv()) => {
11852
12337
  const lines = splitSizedLines(texts, measurer, env);
11853
- const simple = htmlTextIsSimple(texts, env);
12338
+ const simple = htmlTextIsSimple(lines, env);
11854
12339
  let w = 0;
11855
12340
  let h = 0;
11856
12341
  for (const ln of lines) {
@@ -16922,6 +17407,7 @@ function normalizeFontName(name) {
16922
17407
  return result;
16923
17408
  }
16924
17409
  var warnedFontNames = /* @__PURE__ */ new Set();
17410
+ registerRenderState(() => warnedFontNames.clear());
16925
17411
  function getFamilyMetrics(fontName) {
16926
17412
  const key = normalizeFontName(fontName);
16927
17413
  for (const family of ALL_FONT_METRICS) {
@@ -16929,8 +17415,8 @@ function getFamilyMetrics(fontName) {
16929
17415
  }
16930
17416
  if (!warnedFontNames.has(fontName)) {
16931
17417
  warnedFontNames.add(fontName);
16932
- console.warn(
16933
- `Warning: no hard-coded metrics for '${fontName}'. Falling back to 'Times' metrics`
17418
+ agwarningf(
17419
+ `no hard-coded metrics for '${fontName}'. Falling back to 'Times' metrics`
16934
17420
  );
16935
17421
  }
16936
17422
  return TIMES_FALLBACK;
@@ -17089,10 +17575,37 @@ function getVariantWidths(family, bold, italic) {
17089
17575
  return family.regular;
17090
17576
  }
17091
17577
  var SPACE_CHAR_CODE = 32;
17578
+ var FIRST_NON_ASCII = 128;
17579
+ var warned = /* @__PURE__ */ new Set();
17580
+ var NON_ASCII_FLAG = "non-ascii";
17581
+ var ASCII_FLAG = "ascii";
17582
+ registerRenderState(() => warned.clear());
17583
+ function warnNonAscii(character) {
17584
+ if (warned.has(NON_ASCII_FLAG)) return;
17585
+ warned.add(NON_ASCII_FLAG);
17586
+ agwarningf(
17587
+ `Warning: no value for width of non-ASCII character ${character}. Falling back to width of space character`
17588
+ );
17589
+ }
17590
+ function warnAscii(character) {
17591
+ if (warned.has(ASCII_FLAG)) return;
17592
+ warned.add(ASCII_FLAG);
17593
+ agwarningf(
17594
+ `Warning: no value for width of ASCII character ${character}. Falling back to 0`
17595
+ );
17596
+ }
17092
17597
  function charWidthUnits(widths, charCode) {
17093
- const code = charCode >= 128 ? SPACE_CHAR_CODE : charCode;
17598
+ let code = charCode;
17599
+ if (code >= FIRST_NON_ASCII) {
17600
+ warnNonAscii(code);
17601
+ code = SPACE_CHAR_CODE;
17602
+ }
17094
17603
  const w = widths[code] ?? -1;
17095
- return w < 0 ? 0 : w;
17604
+ if (w < 0) {
17605
+ warnAscii(code);
17606
+ return 0;
17607
+ }
17608
+ return w;
17096
17609
  }
17097
17610
  var utf8Encoder = new TextEncoder();
17098
17611
  function utf8Bytes(text) {
@@ -17775,7 +18288,7 @@ function preprocessTooltip(s) {
17775
18288
  // src/common/make-label.ts
17776
18289
  var DEFAULT_FONTSIZE2 = 14;
17777
18290
  var DEFAULT_FONTNAME = "Times-Roman";
17778
- var DEFAULT_COLOR = "black";
18291
+ var DEFAULT_COLOR3 = "black";
17779
18292
  function getPenColor(obj) {
17780
18293
  if (obj === void 0) return void 0;
17781
18294
  const pc = obj.attrs.get("pencolor");
@@ -18397,252 +18910,6 @@ function assembleResult(p, dimen, grown, fixedshape) {
18397
18910
  };
18398
18911
  }
18399
18912
 
18400
- // src/common/multicolor.ts
18401
- var EPS = 1e-5;
18402
- function aeq0(x) {
18403
- return x < EPS && x > -EPS;
18404
- }
18405
- function getSegLen(token) {
18406
- const semi = token.indexOf(";");
18407
- if (semi === -1) return { color: token, v: 0 };
18408
- const color = token.slice(0, semi);
18409
- const rest = token.slice(semi + 1);
18410
- if (rest.length === 0) return { color, v: -1 };
18411
- const parsed = parseFloat(rest);
18412
- return !isNaN(parsed) && parsed >= 0 ? { color, v: parsed } : { color, v: -1 };
18413
- }
18414
- function appendSeg(token, left2, segs, warnedExceeded) {
18415
- const { color, v } = getSegLen(token);
18416
- if (v < 0) return null;
18417
- let t = v;
18418
- let rval = 0;
18419
- const del = t - left2;
18420
- if (del > 0) {
18421
- if (!aeq0(del) && !warnedExceeded.v) {
18422
- warnedExceeded.v = true;
18423
- rval = 3;
18424
- }
18425
- t = left2;
18426
- }
18427
- left2 -= t;
18428
- segs.push({ color: color.length > 0 ? color : null, t, hasFraction: t > 0 && v > 0 });
18429
- return { left: left2, rval };
18430
- }
18431
- function distributeLeft(segs, left2) {
18432
- if (left2 <= 0) return;
18433
- const zeroCount = segs.filter((s) => s.t <= 0).length;
18434
- if (zeroCount > 0) {
18435
- const delta2 = left2 / zeroCount;
18436
- for (const s of segs) {
18437
- if (s.t <= 0) s.t = delta2;
18438
- }
18439
- } else if (segs.length > 0) {
18440
- segs[segs.length - 1].t += left2;
18441
- }
18442
- }
18443
- function trimTrailing(segs) {
18444
- while (segs.length > 0 && (segs[segs.length - 1]?.t ?? 0) <= 0) {
18445
- segs.pop();
18446
- }
18447
- }
18448
- function parseSegs(colorlist) {
18449
- const segs = [];
18450
- let left2 = 1;
18451
- let rval = 0;
18452
- let badFloatCount = 0;
18453
- const warnedExceeded = { v: false };
18454
- for (const token of colorlist.split(":")) {
18455
- const result = appendSeg(token, left2, segs, warnedExceeded);
18456
- if (result === null) {
18457
- const errCode = badFloatCount === 0 ? 2 : 1;
18458
- badFloatCount++;
18459
- return { segs: [], error: errCode };
18460
- }
18461
- if (result.rval === 3) rval = 3;
18462
- left2 = result.left;
18463
- if (aeq0(left2)) {
18464
- left2 = 0;
18465
- break;
18466
- }
18467
- }
18468
- distributeLeft(segs, left2);
18469
- trimTrailing(segs);
18470
- return { segs, error: rval };
18471
- }
18472
-
18473
- // src/common/style-resolve.ts
18474
- var DEFAULT_COLOR2 = "black";
18475
- var DEFAULT_FILL = "lightgrey";
18476
- var PENWIDTH_BOLD = 2;
18477
- var TOKEN_FLAG = {
18478
- filled: "filled",
18479
- dashed: "dashed",
18480
- dotted: "dotted",
18481
- bold: "bold",
18482
- invis: "invis",
18483
- diagonals: "diagonals",
18484
- rounded: "rounded",
18485
- striped: "striped",
18486
- wedged: "wedged",
18487
- underline: "underline"
18488
- };
18489
- function zeroFlags() {
18490
- return {
18491
- filled: false,
18492
- dashed: false,
18493
- dotted: false,
18494
- bold: false,
18495
- invis: false,
18496
- diagonals: false,
18497
- rounded: false,
18498
- radial: false,
18499
- striped: false,
18500
- wedged: false,
18501
- underline: false,
18502
- setLineWidth: null
18503
- };
18504
- }
18505
- var FUNLIMIT = 64;
18506
- function styleTokens2(style2) {
18507
- if (!style2) return [];
18508
- const out = [];
18509
- let fun = 0;
18510
- for (const raw of style2.split(",")) {
18511
- const token = raw.trim();
18512
- if (token.length === 0) continue;
18513
- if (fun === FUNLIMIT - 1) return [];
18514
- fun++;
18515
- out.push(token);
18516
- }
18517
- return out;
18518
- }
18519
- function parseSetLineWidth(token) {
18520
- const m = /^setlinewidth\s*\(\s*([^)]*)\)\s*$/.exec(token);
18521
- if (m === null) return null;
18522
- const v = parseFloat(m[1]);
18523
- return Number.isNaN(v) ? 0 : v;
18524
- }
18525
- function applyToken(flags, token) {
18526
- if (token === "radial") {
18527
- flags.radial = true;
18528
- flags.filled = true;
18529
- return;
18530
- }
18531
- const key = TOKEN_FLAG[token];
18532
- if (key !== void 0) flags[key] = true;
18533
- }
18534
- function nonEmpty(s) {
18535
- return s !== void 0 && s.length > 0;
18536
- }
18537
- function orElse(s, fallback) {
18538
- return nonEmpty(s) ? s : fallback;
18539
- }
18540
- function firstSolidColor(raw) {
18541
- const grad = parseGradientSpec(raw);
18542
- return grad !== null ? grad[0] : raw;
18543
- }
18544
- function parseStyleFlags(style2) {
18545
- const flags = zeroFlags();
18546
- if (!style2) return flags;
18547
- let fun = 0;
18548
- for (const raw of style2.split(",")) {
18549
- const token = raw.trim();
18550
- if (token.length === 0) continue;
18551
- if (fun === FUNLIMIT - 1) return zeroFlags();
18552
- fun++;
18553
- const lw = parseSetLineWidth(token);
18554
- if (lw !== null) {
18555
- flags.setLineWidth = lw;
18556
- continue;
18557
- }
18558
- if (!token.includes("(")) applyToken(flags, token);
18559
- }
18560
- return flags;
18561
- }
18562
- function styleHasInvisibleAlias(style2) {
18563
- if (!style2) return false;
18564
- let fun = 0;
18565
- for (const raw of style2.split(",")) {
18566
- const token = raw.trim();
18567
- if (token.length === 0) continue;
18568
- if (fun === FUNLIMIT - 1) return false;
18569
- fun++;
18570
- if (token === "invisible") return true;
18571
- }
18572
- return false;
18573
- }
18574
- function resolvePenType(flags) {
18575
- if (flags.invis) return 0 /* None */;
18576
- if (flags.dashed) return 1 /* Dashed */;
18577
- if (flags.dotted) return 2 /* Dotted */;
18578
- return 3 /* Solid */;
18579
- }
18580
- function resolvePenWidth(flags, penwidthAttr) {
18581
- if (penwidthAttr && penwidthAttr.length > 0) {
18582
- const v = parseFloat(penwidthAttr);
18583
- if (isFinite(v)) return v;
18584
- }
18585
- if (flags.setLineWidth !== null) return flags.setLineWidth;
18586
- if (flags.bold) return PENWIDTH_BOLD;
18587
- return 1;
18588
- }
18589
- function resolvePenColor(colorAttr) {
18590
- if (!colorAttr || colorAttr.length === 0) return DEFAULT_COLOR2;
18591
- return firstSolidColor(colorAttr);
18592
- }
18593
- function clusterColorAttrs(attrs) {
18594
- const base = nonEmpty(attrs.color) ? attrs.color : void 0;
18595
- const pencolor = orElse(attrs.pencolor, base ?? "");
18596
- const fillcolor = orElse(attrs.fillcolor, base ?? "");
18597
- return {
18598
- fillcolor: nonEmpty(fillcolor) ? fillcolor : void 0,
18599
- pencolor: nonEmpty(pencolor) ? pencolor : void 0
18600
- };
18601
- }
18602
- function applyBgcolor(attrs, filled, fillcolor) {
18603
- if ((!filled || !fillcolor) && nonEmpty(attrs.bgcolor)) {
18604
- return { filled: true, fillcolor: attrs.bgcolor };
18605
- }
18606
- return { filled, fillcolor };
18607
- }
18608
- function findStopColor(colorlist) {
18609
- const { segs, error } = parseSegs(colorlist);
18610
- if (error === 1 || error === 2) return null;
18611
- if (segs.length < 2) return null;
18612
- const seg0 = segs[0];
18613
- const seg1 = segs[1];
18614
- if (seg0.color === null) return null;
18615
- const fillColor = seg0.color;
18616
- const stopColor = seg1.color ?? DEFAULT_COLOR2;
18617
- const frac = seg0.hasFraction ? seg0.t : seg1.hasFraction ? 1 - seg1.t : 0;
18618
- return { fillColor, stopColor, frac };
18619
- }
18620
- function parseAngle(gradientangle2) {
18621
- if (!gradientangle2 || gradientangle2.length === 0) return 0;
18622
- const v = parseInt(gradientangle2, 10);
18623
- return isFinite(v) ? v : 0;
18624
- }
18625
- function buildResolvedFill(rawColor, flags, angle) {
18626
- const stop = findStopColor(rawColor);
18627
- if (stop === null) return { kind: "solid", color: rawColor };
18628
- const kind = flags.radial ? "radial" : "linear";
18629
- return { kind, fillColor: stop.fillColor, stopColor: stop.stopColor, frac: stop.frac, angle };
18630
- }
18631
- function resolveNodeFillEx(attrs) {
18632
- const flags = parseStyleFlags(attrs.style);
18633
- if (!flags.filled) return { kind: "none" };
18634
- const raw = nonEmpty(attrs.fillcolor) ? attrs.fillcolor : nonEmpty(attrs.color) ? attrs.color : DEFAULT_FILL;
18635
- return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
18636
- }
18637
- function resolveClusterFillEx(attrs) {
18638
- const flags = parseStyleFlags(attrs.style);
18639
- const colors = clusterColorAttrs(attrs);
18640
- const bg = applyBgcolor(attrs, flags.filled, colors.fillcolor);
18641
- if (!bg.filled) return { kind: "none" };
18642
- const raw = bg.fillcolor ?? DEFAULT_FILL;
18643
- return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
18644
- }
18645
-
18646
18913
  // src/layout/dot/fastgr.ts
18647
18914
  var VIRTUAL = 1;
18648
18915
  var NORMAL = 0;
@@ -18859,10 +19126,10 @@ var SMALL2 = 1e-10;
18859
19126
  function ptToLine2(a, b, p) {
18860
19127
  const dx = b.x - a.x;
18861
19128
  const dy = b.y - a.y;
18862
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
19129
+ let a2 = fma(p.y - a.y, dx, -(dy * (p.x - a.x)));
18863
19130
  a2 *= a2;
18864
19131
  if (a2 < SMALL2) return 0;
18865
- return a2 / (dx * dx + dy * dy);
19132
+ return a2 / fma(dx, dx, dy * dy);
18866
19133
  }
18867
19134
  function checkControlPoints(cp) {
18868
19135
  const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
@@ -19319,10 +19586,14 @@ function cubicHalf(c, rightHalf) {
19319
19586
  function curveControlPoints(p, v, w, flag) {
19320
19587
  const AF0 = { x: p.x + v.x + w.x, y: p.y + v.y + w.y };
19321
19588
  const AF3 = { x: p.x - v.x + w.x, y: p.y - v.y + w.y };
19322
- const s = flag & ARR_MOD_INV ? 1 : -1;
19323
- const AF1 = { x: p.x + 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF0.y + s * w.y * (4 / 3) };
19324
- const AF2 = { x: p.x - 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF3.y + s * w.y * (4 / 3) };
19325
- return [AF0, AF1, AF2, AF3];
19589
+ const bulgeX = w.x * 4 / 3;
19590
+ const bulgeY = w.y * 4 / 3;
19591
+ const x1 = fma(v.x, 0.95, p.x) + w.x;
19592
+ const x2 = fma(v.x, -0.95, p.x) + w.x;
19593
+ if (flag & ARR_MOD_INV) {
19594
+ return [AF0, { x: x1 + bulgeX, y: AF0.y + bulgeY }, { x: x2 + bulgeX, y: AF3.y + bulgeY }, AF3];
19595
+ }
19596
+ return [AF0, { x: x1 - bulgeX, y: AF0.y - bulgeY }, { x: x2 - bulgeX, y: AF3.y - bulgeY }, AF3];
19326
19597
  }
19327
19598
  function genCurve(p0, u, _arrowsize, penwidth, flag, rankdir = 0) {
19328
19599
  if (rankdir !== 0) {
@@ -19625,13 +19896,14 @@ function bezierClipNode(sp, cx, cy, insideFn, leftInside) {
19625
19896
  y: p.y + cy
19626
19897
  }));
19627
19898
  }
19899
+ function distFused(p, q) {
19900
+ const dx = p.x - q.x;
19901
+ const dy = p.y - q.y;
19902
+ return Math.sqrt(fma(dx, dx, dy * dy));
19903
+ }
19628
19904
  function arrowEndClip(path4, arrowTip, elen) {
19629
- if (elen <= 0) return path4;
19630
19905
  const sp = [arrowTip, path4[2], path4[1], path4[0]];
19631
- const insideSphere = (lx, ly) => Math.hypot(lx, ly) <= elen;
19632
- const spRel = sp.map((p) => ({ x: p.x - arrowTip.x, y: p.y - arrowTip.y }));
19633
- const clippedRel = bezierClipLocal(spRel, insideSphere, true);
19634
- const clipped = clippedRel.map((p) => ({ x: p.x + arrowTip.x, y: p.y + arrowTip.y }));
19906
+ const clipped = elen > 0 ? bezierClipNode(sp, 0, 0, (x, y) => distFused({ x, y }, arrowTip) <= elen, true) : sp;
19635
19907
  return [clipped[3], clipped[2], clipped[1], clipped[0]];
19636
19908
  }
19637
19909
  function arrowClipLength(arrowName, arrowsize, penwidth) {
@@ -20752,7 +21024,7 @@ function readFontParams(sg) {
20752
21024
  return {
20753
21025
  fontsize: parseFloat(graphAttrInherited(sg, "fontsize") ?? "") || DEFAULT_FONTSIZE2,
20754
21026
  fontname: graphAttrInherited(sg, "fontname") ?? DEFAULT_FONTNAME,
20755
- fontcolor: graphAttrInherited(sg, "fontcolor") ?? DEFAULT_COLOR
21027
+ fontcolor: graphAttrInherited(sg, "fontcolor") ?? DEFAULT_COLOR3
20756
21028
  };
20757
21029
  }
20758
21030
  function applyLabelBorder(sg, dimen) {
@@ -20856,6 +21128,9 @@ function decompSearch(g, start, cmark) {
20856
21128
  }
20857
21129
  }
20858
21130
  var _dc = { cmark: 0 };
21131
+ registerRenderState(() => {
21132
+ _dc.cmark = 0;
21133
+ });
20859
21134
  function resolveNode(n, pass) {
20860
21135
  if (pass > 0) {
20861
21136
  const subg = n.info.clust;
@@ -22630,6 +22905,9 @@ function makeInterclustChain(from, to, orig) {
22630
22905
 
22631
22906
  // src/layout/dot/mincross-cross.ts
22632
22907
  var reMincross = false;
22908
+ registerRenderState(() => {
22909
+ reMincross = false;
22910
+ });
22633
22911
  function setReMincross(b) {
22634
22912
  reMincross = b;
22635
22913
  }
@@ -23080,6 +23358,9 @@ function allocateRanks(g) {
23080
23358
  g.info.rank = rt;
23081
23359
  }
23082
23360
  var fillSeq = 0;
23361
+ registerRenderState(() => {
23362
+ fillSeq = 0;
23363
+ });
23083
23364
  function makeFillNode(sg, rank3, seq2) {
23084
23365
  const n = agnode(sg, `__fill_${rank3}_${seq2}`, true);
23085
23366
  agsubnode(sg, n, true);
@@ -23437,7 +23718,7 @@ function pruneForeignClusterNodes(par, clust) {
23437
23718
  }
23438
23719
  function markClusterNode(clust, n, g) {
23439
23720
  if ((n.info.ranktype ?? 0) !== 0) {
23440
- console.error(`Warning: ${n.name} was already in a rankset, deleted from cluster ${g.name}`);
23721
+ agwarningf(`${n.name} was already in a rankset, deleted from cluster ${g.name}`, "error");
23441
23722
  agDeleteFromCluster(clust, n);
23442
23723
  return;
23443
23724
  }
@@ -23902,6 +24183,9 @@ var clType = LOCAL;
23902
24183
  function setClType(t) {
23903
24184
  clType = t;
23904
24185
  }
24186
+ registerRenderState(() => {
24187
+ clType = LOCAL;
24188
+ });
23905
24189
  function mapbool2(s) {
23906
24190
  if (!s || s === "") return false;
23907
24191
  const l = s.toLowerCase();
@@ -24669,7 +24953,7 @@ function readFontAttrs(n, g) {
24669
24953
  return {
24670
24954
  fontname: nodeAttr(n, g, "fontname") ?? DEFAULT_FONTNAME,
24671
24955
  fontsize: parseFloat(nodeAttr(n, g, "fontsize") ?? String(DEFAULT_FONTSIZE2)),
24672
- fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR
24956
+ fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR3
24673
24957
  };
24674
24958
  }
24675
24959
  function assignShapeInfo(n, polyDesc) {
@@ -24694,7 +24978,7 @@ function polyInit(n, g, measurer) {
24694
24978
  const shapefile = nodeAttr(n, g, "shapefile");
24695
24979
  n.info.shape = bindShape(shapeName2, shapefile);
24696
24980
  if (shapefile !== void 0 && shapefile !== "" && shapeName2 !== "epsf") {
24697
- console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
24981
+ agwarningf(`No or improper shapefile="${shapefile}" for node "${n.name}"`, "error");
24698
24982
  }
24699
24983
  if (n.info.shape.kind === 2 /* SH_RECORD */) {
24700
24984
  if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
@@ -25065,20 +25349,36 @@ function applyClusterObjState(sg, job) {
25065
25349
  if (job.obj === null) return false;
25066
25350
  const obj = job.obj;
25067
25351
  return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
25352
+ const filled = applyClusterFill(obj, fillRes);
25068
25353
  applyClusterPenState(obj, sg);
25069
- if (fillRes.kind === "none") {
25070
- obj.fill = 0 /* None */;
25071
- return false;
25072
- }
25073
- if (fillRes.kind === "solid") {
25074
- obj.fill = 1 /* Solid */;
25075
- obj.fillColor = resolveRenderColor(fillRes.color);
25076
- return true;
25077
- }
25078
- applyClusterGradient(obj, fillRes);
25079
- return true;
25354
+ reportColorNames(stripedClusterColors(sg));
25355
+ return filled;
25080
25356
  });
25081
25357
  }
25358
+ function stripedClusterColors(sg) {
25359
+ const flags = parseStyleFlags(clusterStyle(sg));
25360
+ if (!flags.striped || flags.rounded) return [];
25361
+ const color = clusterAttr(sg, "color") ?? "";
25362
+ let fill = clusterAttr(sg, "fillcolor") || color;
25363
+ const bg = clusterAttr(sg, "bgcolor") ?? "";
25364
+ if ((!flags.filled || fill === "") && bg !== "") fill = bg;
25365
+ const { segs, error } = parseSegs(fill === "" ? "lightgrey" : fill);
25366
+ if (error === 1 || error === 2) return [];
25367
+ return segs.flatMap((seg2) => seg2.color !== null && seg2.t > 0 ? [seg2.color] : []);
25368
+ }
25369
+ function applyClusterFill(obj, fillRes) {
25370
+ if (fillRes.kind === "none") {
25371
+ obj.fill = 0 /* None */;
25372
+ return false;
25373
+ }
25374
+ if (fillRes.kind === "solid") {
25375
+ obj.fill = 1 /* Solid */;
25376
+ obj.fillColor = resolveRenderColor(fillRes.color);
25377
+ return true;
25378
+ }
25379
+ applyClusterGradient(obj, fillRes);
25380
+ return true;
25381
+ }
25082
25382
 
25083
25383
  // src/render/svg-id.ts
25084
25384
  function svgClass(kind, classAttr) {
@@ -25166,6 +25466,7 @@ function renderPeripheries(poly, coord, filled, ctx) {
25166
25466
  }
25167
25467
  function renderLabel(label, coord, renderer, job) {
25168
25468
  if (label.u.kind !== "txt" || label.u.nspans < 1) return;
25469
+ reportColorNames([label.fontcolor]);
25169
25470
  label.pos = coord;
25170
25471
  label.set = true;
25171
25472
  const VALIGN_TOP2 = "t".charCodeAt(0);
@@ -25185,6 +25486,7 @@ function renderNodeLabel(n, coord, renderer, job) {
25185
25486
  label.pos = coord;
25186
25487
  label.set = true;
25187
25488
  const html = label.u.html;
25489
+ reportColorNames(htmlLabelColors(html));
25188
25490
  withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
25189
25491
  } else {
25190
25492
  renderLabel(label, coord, renderer, job);
@@ -25259,13 +25561,18 @@ function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
25259
25561
  obj.penColor = resolveRenderColor(resolvePenColor(colorAttr));
25260
25562
  obj.pen = resolvePenType(flags);
25261
25563
  obj.penWidth = resolvePenWidth(flags, penwidthAttr);
25262
- obj.rawStyle = styleTokens2(styleAttr);
25564
+ obj.rawStyle = styleTokens(styleAttr);
25263
25565
  }
25264
25566
  function applyNodeStyle(obj, n, job) {
25265
25567
  const styleAttr = nodeAttr(n, n.root, "style");
25266
25568
  const colorAttr = nodeAttr(n, n.root, "color");
25569
+ const penwidth = nodeAttr(n, n.root, "penwidth");
25570
+ if (n.info.shape?.kind === 2 /* SH_RECORD */) {
25571
+ applyPenState(obj, styleAttr, colorAttr, penwidth);
25572
+ return applyFillState(obj, n, job);
25573
+ }
25267
25574
  const filled = applyFillState(obj, n, job);
25268
- applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
25575
+ applyPenState(obj, styleAttr, colorAttr, penwidth);
25269
25576
  return filled;
25270
25577
  }
25271
25578
  function prepareDrawPoly(poly, filled, obj) {
@@ -25482,7 +25789,7 @@ function initFontEdgeAttr(e) {
25482
25789
  return {
25483
25790
  fontsize: lateDouble(e.attrs.get("fontsize"), DEFAULT_FONTSIZE2, MIN_FONTSIZE),
25484
25791
  fontname: e.attrs.get("fontname") || DEFAULT_FONTNAME,
25485
- fontcolor: e.attrs.get("fontcolor") || DEFAULT_COLOR
25792
+ fontcolor: e.attrs.get("fontcolor") || DEFAULT_COLOR3
25486
25793
  };
25487
25794
  }
25488
25795
  function initFontLabelEdgeAttr(e, fi) {
@@ -25608,7 +25915,7 @@ function findCharset(g) {
25608
25915
  }
25609
25916
  if (p === "big-5" || p === "big5") return CHAR_BIG5;
25610
25917
  if (p === "utf-8" || p === "utf8") return CHAR_UTF8;
25611
- console.error(`Warning: Unsupported charset "${raw}" - assuming utf-8`);
25918
+ agwarningf(`Unsupported charset "${raw}" - assuming utf-8`, "error");
25612
25919
  return CHAR_UTF8;
25613
25920
  }
25614
25921
  function maptoken(p, names, vals) {
@@ -27257,7 +27564,7 @@ function advanceTmpList(tmplist, offlist) {
27257
27564
  // src/render/svg-parallel-edge.ts
27258
27565
  var PENWIDTH_NORMAL2 = 1;
27259
27566
  var PENWIDTH_THRESHOLD2 = 5e-3;
27260
- var DEFAULT_COLOR3 = "black";
27567
+ var DEFAULT_COLOR4 = "black";
27261
27568
  function emitOffsetBezier(tmplist, job, color) {
27262
27569
  const obj = job.obj;
27263
27570
  const resolved = resolveRenderColor(color);
@@ -27299,11 +27606,11 @@ function emitParallelEdgePaths(e, job, colorList) {
27299
27606
  const spl = e.info.spl;
27300
27607
  const numc = (colorList.match(/:/g) ?? []).length;
27301
27608
  const segData = buildSegData(spl?.list ?? [], (2 + numc) / 2);
27302
- const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR3);
27609
+ const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR4);
27303
27610
  emitColorPasses(segData, colors, job);
27304
27611
  return {
27305
- headColor: colors[0] ?? DEFAULT_COLOR3,
27306
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR3
27612
+ headColor: colors[0] ?? DEFAULT_COLOR4,
27613
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR4
27307
27614
  };
27308
27615
  }
27309
27616
 
@@ -27815,7 +28122,6 @@ function beginAnchorIf(renderer, job) {
27815
28122
  }
27816
28123
  var DFLT_SAMPLE = 20;
27817
28124
  var MAP_HW = 2;
27818
- var MAP_SMALL = 1e-10;
27819
28125
  function mapTransform(p, ctx) {
27820
28126
  return {
27821
28127
  x: (p.x + ctx.pad.x - ctx.bb.ll.x) * ctx.scale + ctx.marginOff.x,
@@ -27932,16 +28238,8 @@ function computeLabelRectMap(lab, obj, ctx) {
27932
28238
  mapTransform({ x: lab.pos.x + dx, y: lab.pos.y + dy }, ctx)
27933
28239
  ];
27934
28240
  }
27935
- function ptToLine22(a, b, p) {
27936
- const dx = b.x - a.x;
27937
- const dy = b.y - a.y;
27938
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
27939
- a2 *= a2;
27940
- if (a2 < MAP_SMALL) return 0;
27941
- return a2 / (dx * dx + dy * dy);
27942
- }
27943
28241
  function checkControlPoints2(cp) {
27944
- return ptToLine22(cp[0], cp[3], cp[1]) < MAP_HW * MAP_HW && ptToLine22(cp[0], cp[3], cp[2]) < MAP_HW * MAP_HW;
28242
+ return ptToLine2(cp[0], cp[3], cp[1]) < MAP_HW * MAP_HW && ptToLine2(cp[0], cp[3], cp[2]) < MAP_HW * MAP_HW;
27945
28243
  }
27946
28244
  function bezierHalf(v) {
27947
28245
  const left2 = [];
@@ -28176,9 +28474,20 @@ function labelSpanX(lp, just) {
28176
28474
  if (just === "r") return lp.pos.x + lp.space.x / 2;
28177
28475
  return lp.pos.x;
28178
28476
  }
28477
+ function labelColorNames(lp) {
28478
+ if (lp.html) return lp.u.kind === "html" ? htmlLabelColors(lp.u.html) : [];
28479
+ return lp.u.kind === "txt" && lp.u.nspans >= 1 ? [lp.fontcolor] : [];
28480
+ }
28481
+ function reportEdgeLabelColors(e) {
28482
+ const labels = [e.info.label, e.info.xlabel, e.info.head_label, e.info.tail_label];
28483
+ for (const lp of labels) {
28484
+ if (lp?.set) reportColorNames(labelColorNames(lp));
28485
+ }
28486
+ }
28179
28487
  function renderOneLabel(lp, renderer, job, requireSet = true) {
28180
28488
  if (!lp) return;
28181
28489
  if (requireSet && !lp.set) return;
28490
+ reportColorNames(labelColorNames(lp));
28182
28491
  if (lp.html) {
28183
28492
  if (lp.u.kind === "html") {
28184
28493
  const html = lp.u.html;
@@ -28287,11 +28596,11 @@ function setEdgePen(e, job) {
28287
28596
  const flags = parseStyleFlags(e.attrs.get("style"));
28288
28597
  obj.penColor = withColorScheme(
28289
28598
  e.attrs.get("colorscheme"),
28290
- () => resolveRenderColor(resolvePenColor(e.attrs.get("color")))
28599
+ () => resolveRenderColor(resolvePenColor(e.attrs.get("color")), false)
28291
28600
  );
28292
28601
  obj.pen = resolvePenType(flags);
28293
28602
  obj.penWidth = resolvePenWidth(flags, e.attrs.get("penwidth"));
28294
- obj.rawStyle = styleTokens2(e.attrs.get("style"));
28603
+ obj.rawStyle = styleTokens(e.attrs.get("style"));
28295
28604
  }
28296
28605
  function renderEdge(e, renderer, job) {
28297
28606
  emitEdgeComments(e, renderer, job);
@@ -28306,6 +28615,8 @@ function renderEdge(e, renderer, job) {
28306
28615
  resolveEdgeAnchor(e, svgEdgeId(e, job), obj);
28307
28616
  withColorScheme(e.attrs.get("colorscheme"), () => {
28308
28617
  renderer.beginEdge(e, job);
28618
+ reportEdgeColors(e);
28619
+ reportEdgeLabelColors(e);
28309
28620
  renderer.endEdge(e, job);
28310
28621
  });
28311
28622
  } finally {
@@ -28389,8 +28700,11 @@ function renderPage(g, renderer, job, info) {
28389
28700
  resolveObjAnchor(g, labelTextOf2(g.info.label), svgGraphId(g, job), job.obj);
28390
28701
  }
28391
28702
  const anchored = beginAnchorIf(renderer, job);
28392
- renderer.pageBackground?.(g, job);
28393
- renderGraphLabel(g, renderer, job);
28703
+ withColorScheme(g.attrs.get("colorscheme"), () => {
28704
+ reportColorNames(backgroundColors(g.attrs.get("bgcolor"), renderer.type === "svg"));
28705
+ renderer.pageBackground?.(g, job);
28706
+ renderGraphLabel(g, renderer, job);
28707
+ });
28394
28708
  if (anchored) renderer.endAnchor?.(job);
28395
28709
  const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
28396
28710
  if (!clustersLast) renderClusters(g, renderer, job);
@@ -28422,6 +28736,7 @@ function render(ctx, g, format, inlineImages = false) {
28422
28736
  job.scale = { x: z * dpiScale, y: z * dpiScale };
28423
28737
  job.rotation = parseLandscape(g) ? 90 : 0;
28424
28738
  job.renderer = renderer;
28739
+ setRendererKnownColors(renderer.type === "svg");
28425
28740
  resetHtmlAnchorIds();
28426
28741
  for (const n of g.nodes.values()) polyInit(n, g, job.measurer);
28427
28742
  return renderGraph(g, job, renderer);
@@ -29693,20 +30008,20 @@ function fillRankVlist(g, r, root) {
29693
30008
  const rankArr = g.info.rank;
29694
30009
  const lead = g.info.rankleader[r];
29695
30010
  if (lead === void 0 || lead === null) {
29696
- console.error(`Error: rebuild_vlists: lead is null for rank ${r}`);
30011
+ agerrorf(`rebuild_vlists: lead is null for rank ${r}`);
29697
30012
  return -1;
29698
30013
  }
29699
30014
  const rootRank = root.info.rank[r];
29700
30015
  if (rootRank.v[lead.info.order ?? 0] !== lead) {
29701
- console.error(
29702
- `Error: rebuild_vlists: rank lead ${lead.name} not in order ${lead.info.order ?? 0} of rank ${r}`
30016
+ agerrorf(
30017
+ `rebuild_vlists: rank lead ${lead.name} not in order ${lead.info.order ?? 0} of rank ${r}`
29703
30018
  );
29704
30019
  return -1;
29705
30020
  }
29706
30021
  rankArr[r].v = rootRank.v;
29707
30022
  rankArr[r].vStart = lead.info.order ?? 0;
29708
30023
  const maxi = computeMaxi(g, r);
29709
- if (maxi === -1) console.error(`Warning: degenerate concentrated rank ${g.name},${r}`);
30024
+ if (maxi === -1) agwarningf(`degenerate concentrated rank ${g.name},${r}`, "error");
29710
30025
  rankArr[r].n = maxi + 1;
29711
30026
  return 0;
29712
30027
  }
@@ -29795,7 +30110,7 @@ function dotConcentrate(g) {
29795
30110
  const clust = g.info.clust ?? [];
29796
30111
  for (let c = 0; c < nCluster; c++) {
29797
30112
  if (rebuildVlists(clust[c]) !== 0) {
29798
- console.error("concentrate=true may not work correctly.");
30113
+ agerr("prev", "concentrate=true may not work correctly.");
29799
30114
  return -1;
29800
30115
  }
29801
30116
  }
@@ -32525,7 +32840,7 @@ function routeSplinesInternal(pp, polyline) {
32525
32840
  ];
32526
32841
  const pl = shortestPath(poly, eps);
32527
32842
  if (pl === null) {
32528
- console.warn("in routesplines, Pshortestpath failed");
32843
+ agerrLineOn("warn", "in routesplines, Pshortestpath failed");
32529
32844
  return null;
32530
32845
  }
32531
32846
  emitDump("S3_POLY", dumpNames, () => ({
@@ -34844,6 +35159,10 @@ function addXLabels(gp) {
34844
35159
  var IGNORED_EDGE = 6;
34845
35160
  var Rankdir = 0;
34846
35161
  var Offset = { x: 0, y: 0 };
35162
+ registerRenderState(() => {
35163
+ Rankdir = 0;
35164
+ Offset = { x: 0, y: 0 };
35165
+ });
34847
35166
  function mapPoint(p) {
34848
35167
  const r = ccwrotatepf(p, Rankdir * 90);
34849
35168
  return { x: r.x - Offset.x, y: r.y - Offset.y };
@@ -34931,7 +35250,7 @@ function translateDrawing(g) {
34931
35250
  if (e.tail !== v) continue;
34932
35251
  if (e.info.spl === void 0) {
34933
35252
  if (!(g.info.concentrate ?? false) && (e.info.edge_type ?? 0) !== IGNORED_EDGE) {
34934
- console.warn(`lost ${e.tail.name} ${e.head.name} edge`);
35253
+ agerrLineOn("warn", `lost ${e.tail.name} ${e.head.name} edge`);
34935
35254
  }
34936
35255
  continue;
34937
35256
  }
@@ -36044,7 +36363,11 @@ var A = BigInt("0x5deece66d");
36044
36363
  var C = BigInt("0xb");
36045
36364
  var MASK48 = (1n << 48n) - 1n;
36046
36365
  var TWO48 = 2 ** 48;
36047
- var state = 0x330en;
36366
+ var UNSEEDED_STATE = 0x1234abcd330en;
36367
+ var state = UNSEEDED_STATE;
36368
+ registerRenderState(() => {
36369
+ state = UNSEEDED_STATE;
36370
+ });
36048
36371
  function srand48(seed) {
36049
36372
  const s = BigInt(Math.trunc(seed)) & 0xffffffffn;
36050
36373
  state = (s << 16n | 0x330en) & MASK48;
@@ -38231,7 +38554,8 @@ function ensureDummyNodes(sg, gstart) {
38231
38554
  }
38232
38555
  function orthoEdges(g, useLbls, clipAndInstall2) {
38233
38556
  if (useLbls) {
38234
- console.warn(
38557
+ agerrLineOn(
38558
+ "warn",
38235
38559
  "Orthogonal edges do not currently handle edge labels. Try using xlabels.\n"
38236
38560
  );
38237
38561
  useLbls = false;
@@ -38591,12 +38915,12 @@ function origSeq(e) {
38591
38915
  return resolveOrigEdge(e).seq;
38592
38916
  }
38593
38917
  function dedupByOrig(group) {
38594
- const seen = /* @__PURE__ */ new Set();
38918
+ const seen2 = /* @__PURE__ */ new Set();
38595
38919
  const out = [];
38596
38920
  for (const e of group) {
38597
38921
  const o = resolveOrigEdge(e);
38598
- if (seen.has(o)) continue;
38599
- seen.add(o);
38922
+ if (seen2.has(o)) continue;
38923
+ seen2.add(o);
38600
38924
  out.push(o);
38601
38925
  }
38602
38926
  return out;
@@ -38913,7 +39237,7 @@ function orthoDispatch(g) {
38913
39237
  function curvedTop(g) {
38914
39238
  resetRW(g);
38915
39239
  if (((g.root.info.has_labels ?? 0) & EDGE_LABEL) !== 0) {
38916
- console.warn("edge labels with splines=curved not supported in dot - use xlabels\n");
39240
+ agerrLineOn("warn", "edge labels with splines=curved not supported in dot - use xlabels\n");
38917
39241
  }
38918
39242
  }
38919
39243
  function finalizeSplines(g, et, normalize) {
@@ -40561,7 +40885,7 @@ function lenattr(ep, g) {
40561
40885
  const val2 = /^\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(s);
40562
40886
  const len = val2 === null ? Number.NaN : parseFloat(val2[0]);
40563
40887
  if (Number.isNaN(len) || len < 0 || len === 0) {
40564
- console.warn(`bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
40888
+ agerrLineOn("warn", `bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
40565
40889
  return DEFAULT_EDGE_LEN;
40566
40890
  }
40567
40891
  return len;
@@ -40658,7 +40982,10 @@ var START_KEYWORDS = [
40658
40982
  ];
40659
40983
  var WARN_POS_IGNORED = "node positions are ignored unless start=random";
40660
40984
  var WARN_SELF_IGNORED = "start=0 not supported with mode=self - ignored";
40661
- var selfWarned = /* @__PURE__ */ new WeakSet();
40985
+ var selfOnce = { warned: false };
40986
+ registerRenderState(() => {
40987
+ selfOnce.warned = false;
40988
+ });
40662
40989
  var circuitWarned = /* @__PURE__ */ new WeakSet();
40663
40990
  function parseStart(p, dflt) {
40664
40991
  let init = dflt;
@@ -40689,7 +41016,7 @@ function initRegular(g, nG) {
40689
41016
  function checkStart(g, nG = g.nodes.size, dflt = INIT_RANDOM) {
40690
41017
  const { init, seed } = parseStart(g.root.attrs.get("start"), dflt);
40691
41018
  if (init !== INIT_RANDOM && [...g.nodes.values()].some((n) => n.attrs.has("pos"))) {
40692
- console.warn(WARN_POS_IGNORED);
41019
+ agerrLineOn("warn", WARN_POS_IGNORED);
40693
41020
  }
40694
41021
  if (init === INIT_REGULAR) initRegular(g, nG);
40695
41022
  srand48(seed);
@@ -40722,7 +41049,7 @@ function neatoMode(g) {
40722
41049
  if (str === void 0 || str === "") return MODE_MAJOR;
40723
41050
  const mode = modeByName().get(str);
40724
41051
  if (mode !== void 0) return mode;
40725
- console.warn(`Illegal value ${str} for attribute "mode" in graph ${g.root.name} - ignored`);
41052
+ agerrLineOn("warn", `Illegal value ${str} for attribute "mode" in graph ${g.root.name} - ignored`);
40726
41053
  return MODE_MAJOR;
40727
41054
  }
40728
41055
  function checkMode(g, mode) {
@@ -40736,9 +41063,9 @@ function checkStartAttr(g, mode) {
40736
41063
  const value = g.root.attrs.get("start");
40737
41064
  if (parseStart(value, INIT_RANDOM).init !== INIT_SELF) return;
40738
41065
  if (mode === MODE_MAJOR || mode === MODE_IPSEP) unsupported("start", value ?? "", "smart initialisation");
40739
- if ((mode === MODE_KK || mode === MODE_SGD) && !selfWarned.has(g.root)) {
40740
- selfWarned.add(g.root);
40741
- console.warn(WARN_SELF_IGNORED);
41066
+ if ((mode === MODE_KK || mode === MODE_SGD) && !selfOnce.warned) {
41067
+ selfOnce.warned = true;
41068
+ agerrLineOn("warn", WARN_SELF_IGNORED);
40742
41069
  }
40743
41070
  }
40744
41071
  function isConnected(g) {
@@ -40749,15 +41076,15 @@ function isConnected(g) {
40749
41076
  adj.get(e.tail)?.push(e.head);
40750
41077
  adj.get(e.head)?.push(e.tail);
40751
41078
  }
40752
- const seen = /* @__PURE__ */ new Set([nodes[0]]);
41079
+ const seen2 = /* @__PURE__ */ new Set([nodes[0]]);
40753
41080
  const stack = [nodes[0]];
40754
41081
  for (let n = stack.pop(); n !== void 0; n = stack.pop()) {
40755
- for (const m of adj.get(n) ?? []) if (!seen.has(m)) {
40756
- seen.add(m);
41082
+ for (const m of adj.get(n) ?? []) if (!seen2.has(m)) {
41083
+ seen2.add(m);
40757
41084
  stack.push(m);
40758
41085
  }
40759
41086
  }
40760
- return seen.size === nodes.length;
41087
+ return seen2.size === nodes.length;
40761
41088
  }
40762
41089
  function kkCircuitFallsBack(g) {
40763
41090
  const packed = getPack(g.root, -1, 0) >= 0 || (g.root.attrs.get("packmode") ?? "") !== "";
@@ -40766,7 +41093,8 @@ function kkCircuitFallsBack(g) {
40766
41093
  function warnCircuitDisconnected(g) {
40767
41094
  if (circuitWarned.has(g.root)) return;
40768
41095
  circuitWarned.add(g.root);
40769
- console.warn(
41096
+ agerrLineOn(
41097
+ "warn",
40770
41098
  `graph ${g.root.name} is disconnected. Hence, the circuit model
40771
41099
  is undefined. Reverting to the shortest path model.
40772
41100
  Alternatively, consider running neato using -Gpack=true or decomposing
@@ -40985,13 +41313,15 @@ function buildUnfixed(g, n) {
40985
41313
  }
40986
41314
  function resolveModel(model) {
40987
41315
  if (model === MODEL_CIRCUIT2) {
40988
- console.warn(
41316
+ agerrLineOn(
41317
+ "warn",
40989
41318
  "circuit model not yet supported in Gmode=sgd, reverting to shortpath model"
40990
41319
  );
40991
41320
  return MODEL_SHORTPATH;
40992
41321
  }
40993
41322
  if (model === MODEL_MDS) {
40994
- console.warn(
41323
+ agerrLineOn(
41324
+ "warn",
40995
41325
  "mds model not yet supported in Gmode=sgd, reverting to shortpath model"
40996
41326
  );
40997
41327
  return MODEL_SHORTPATH;
@@ -41376,7 +41706,7 @@ function moveNode(st, m) {
41376
41706
  function solveModel(g, st) {
41377
41707
  for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
41378
41708
  if (st.move === st.maxIter) {
41379
- console.warn(`Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
41709
+ agerrLineOn("warn", `Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
41380
41710
  }
41381
41711
  }
41382
41712
  function mdsEdges(g, nodes, lens) {
@@ -41835,6 +42165,7 @@ var MODE_MAJOR = 1;
41835
42165
  var MODE_HIER = 2;
41836
42166
  var MODE_IPSEP = 3;
41837
42167
  var MODE_SGD = 4;
42168
+ var SGD_ITERATIONS = 30;
41838
42169
  var MODEL_SHORTPATH2 = 0;
41839
42170
  var MODEL_CIRCUIT = 1;
41840
42171
  var MODEL_SUBSET = 2;
@@ -41874,6 +42205,11 @@ function assignNodeIds2(g) {
41874
42205
  }
41875
42206
  return nodeList;
41876
42207
  }
42208
+ function neatoMaxIter(maxiter, mode, n) {
42209
+ if (maxiter !== void 0) return parseInt(maxiter, 10) || 0;
42210
+ if (mode === MODE_MAJOR) return DFLT_ITERATIONS;
42211
+ return mode === MODE_SGD ? SGD_ITERATIONS : 100 * n;
42212
+ }
41877
42213
  function runMajorization(g, mode, model) {
41878
42214
  void model;
41879
42215
  const nodeList = assignNodeIds2(g);
@@ -41881,7 +42217,7 @@ function runMajorization(g, mode, model) {
41881
42217
  const haveLen = graphHasLen(g);
41882
42218
  const vtx = makeGraphDataC(g, nodeList, haveLen, mode === MODE_HIER || mode === MODE_IPSEP);
41883
42219
  checkStart(g);
41884
- const maxi = lateDouble(g.attrs.get("maxiter"), DFLT_ITERATIONS, 0);
42220
+ const maxi = neatoMaxIter(g.attrs.get("maxiter"), mode, n);
41885
42221
  const epsilon = lateDouble(g.attrs.get("epsilon"), 1e-4, 0);
41886
42222
  const weighted = haveLen && mode !== MODE_IPSEP;
41887
42223
  const Dij = weighted ? computeWeightedApspPacked2(vtx, n) : computeApspPacked2(vtx, n);
@@ -41911,18 +42247,18 @@ function makeGraphDataC(g, nodeList, haveLen, haveDir) {
41911
42247
  for (const np of nodeList) {
41912
42248
  const i = np.info.id;
41913
42249
  const entry = vtx[i];
41914
- const seen = /* @__PURE__ */ new Map();
42250
+ const seen2 = /* @__PURE__ */ new Map();
41915
42251
  for (const ep of [...np.outEdges(g), ...np.inEdges(g)]) {
41916
42252
  if (ep.head === ep.tail) continue;
41917
42253
  const vp = ep.tail === np ? ep.head : ep.tail;
41918
42254
  const vid = vp.info.id;
41919
42255
  const dist4 = haveLen ? lateDouble(ep.attrs.get("len"), 1, 0) : 1;
41920
- const idx = seen.get(vid);
42256
+ const idx = seen2.get(vid);
41921
42257
  if (idx !== void 0) {
41922
42258
  if (haveLen) entry.ewgts[idx] = Math.max(entry.ewgts[idx], dist4);
41923
42259
  continue;
41924
42260
  }
41925
- seen.set(vid, entry.nedges);
42261
+ seen2.set(vid, entry.nedges);
41926
42262
  entry.edges.push(vid);
41927
42263
  if (haveLen || haveDir) entry.ewgts.push(dist4);
41928
42264
  entry.nedges++;
@@ -42269,15 +42605,15 @@ function delaunayTri(xv, yv, n) {
42269
42605
  for (let i = 1; i < n; i++) edges2.push(vs[i - 1], vs[i]);
42270
42606
  return edges2;
42271
42607
  }
42272
- const seen = /* @__PURE__ */ new Set();
42608
+ const seen2 = /* @__PURE__ */ new Set();
42273
42609
  const pairs = [];
42274
42610
  for (const t of tris) {
42275
42611
  for (const [u, v] of [[t.a, t.b], [t.b, t.c], [t.c, t.a]]) {
42276
42612
  const i = Math.min(u, v);
42277
42613
  const j = Math.max(u, v);
42278
42614
  const key = i * 1048576 + j;
42279
- if (!seen.has(key)) {
42280
- seen.add(key);
42615
+ if (!seen2.has(key)) {
42616
+ seen2.add(key);
42281
42617
  pairs.push([i, j]);
42282
42618
  }
42283
42619
  }
@@ -42562,8 +42898,8 @@ var Cdt = class {
42562
42898
  const en = this.edgeOrNew(v3, v4);
42563
42899
  this.removeFace(f1);
42564
42900
  this.removeFace(f2);
42565
- const f3 = this.addFace([v4, v2, v3], [e5, e2, en]);
42566
- const f4 = this.addFace([v1, v4, v3], [e4, en, e3]);
42901
+ const f3 = this.addFace([v3, v4, v2], [en, e5, e2]);
42902
+ const f4 = this.addFace([v4, v3, v1], [en, e3, e4]);
42567
42903
  this.swapIfInCircle(f3, v4, v2, v3, e5, e2, en);
42568
42904
  this.swapIfInCircle(f4, v1, v4, v3, e4, en, e3);
42569
42905
  }
@@ -42865,10 +43201,7 @@ function sharedEdge(faces, p3, q3) {
42865
43201
  return { i: p1, j: p2 };
42866
43202
  }
42867
43203
  function addTriEdge(g, t, h, seg2) {
42868
- const dist4 = Math.hypot(
42869
- g.nodes[t].ctr.x - g.nodes[h].ctr.x,
42870
- g.nodes[t].ctr.y - g.nodes[h].ctr.y
42871
- );
43204
+ const dist4 = Math.sqrt(dist2(g.nodes[t].ctr, g.nodes[h].ctr));
42872
43205
  const idx = g.edges.length;
42873
43206
  g.edges.push({ t, h, seg: seg2, dist: dist4 });
42874
43207
  g.nodes[t].edges.push(idx);
@@ -43195,7 +43528,7 @@ var SEP = 15;
43195
43528
  function bisectorTarget(v, cosTheta, sinTheta) {
43196
43529
  return { x: fma(cosTheta, 100, v.x), y: fma(sinTheta, 100, v.y) };
43197
43530
  }
43198
- function distFused(p, q) {
43531
+ function distFused2(p, q) {
43199
43532
  const dx = p.x - q.x;
43200
43533
  const dy = p.y - q.y;
43201
43534
  return Math.sqrt(fma(dx, dx, dy * dy));
@@ -43220,7 +43553,7 @@ function mkCtrlPts(s, mult, prev, v, nxt, trip) {
43220
43553
  }
43221
43554
  const q = triPoint(trip, idx, v, w);
43222
43555
  if (q === null) return null;
43223
- const d = distFused(q, v);
43556
+ const d = distFused2(q, v);
43224
43557
  const sep = d >= mult * SEP ? SEP : d / mult;
43225
43558
  const ps = new Array(mult);
43226
43559
  if (idx < s) {
@@ -43349,8 +43682,8 @@ function chainOf(e) {
43349
43682
  return list;
43350
43683
  }
43351
43684
  function warnNoControlPoints(e) {
43352
- console.warn(
43353
- `Warning: Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`
43685
+ agwarningf(
43686
+ `Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`
43354
43687
  );
43355
43688
  return 1;
43356
43689
  }
@@ -46013,7 +46346,11 @@ function armPow(x, y) {
46013
46346
 
46014
46347
  // src/common/crand.ts
46015
46348
  var C_RAND_MAX = 2147483647;
46016
- var state2 = 1;
46349
+ var UNSEEDED_STATE2 = 1;
46350
+ var state2 = UNSEEDED_STATE2;
46351
+ registerRenderState(() => {
46352
+ state2 = UNSEEDED_STATE2;
46353
+ });
46017
46354
  function csrand(seed) {
46018
46355
  state2 = seed;
46019
46356
  }
@@ -47953,7 +48290,7 @@ function makeAddPoly(n, xmargin, ymargin) {
47953
48290
  case 3 /* SH_POINT */:
47954
48291
  return finishPoly(genRound(n, xmargin, ymargin), POLY_CIRCLE);
47955
48292
  default:
47956
- console.error(`Error: makeAddPoly: unknown shape type ${shapeName(n)}
48293
+ agerrorf(`makeAddPoly: unknown shape type ${shapeName(n)}
47957
48294
  `);
47958
48295
  return null;
47959
48296
  }
@@ -47986,7 +48323,7 @@ function baseShape(n) {
47986
48323
  case 3 /* SH_POINT */:
47987
48324
  return { verts: genRound(n, 0, 0), kind: POLY_CIRCLE };
47988
48325
  default:
47989
- console.error(`Error: makePoly: unknown shape type ${shapeName(n)}
48326
+ agerrorf(`makePoly: unknown shape type ${shapeName(n)}
47990
48327
  `);
47991
48328
  return null;
47992
48329
  }
@@ -49368,7 +49705,7 @@ function warnUnrecognizedOverlap(flag) {
49368
49705
  const s = flag.toLowerCase();
49369
49706
  if (s.startsWith("prism") || NAMED_MODES.has(s)) return;
49370
49707
  if (mapBoolDflt(flag, false) === mapBoolDflt(flag, true)) return;
49371
- console.warn(`Unrecognized overlap value "${flag}" - using false`);
49708
+ agerrLineOn("warn", `Unrecognized overlap value "${flag}" - using false`);
49372
49709
  }
49373
49710
  function getAdjustMode(flag) {
49374
49711
  warnUnrecognizedOverlap(flag);
@@ -49401,7 +49738,7 @@ function adjustLate(g, am) {
49401
49738
  case AM_VPSC:
49402
49739
  return vpscAdjust(g);
49403
49740
  default:
49404
- console.warn(`Unhandled adjust option ${am.print}`);
49741
+ agerrLineOn("warn", `Unhandled adjust option ${am.print}`);
49405
49742
  return 0;
49406
49743
  }
49407
49744
  }
@@ -49620,20 +49957,20 @@ function setSubtreeSize(g) {
49620
49957
  walkAncestorChain(n);
49621
49958
  }
49622
49959
  }
49623
- function applySpanToChild(g, n, next, ratio, seen) {
49960
+ function applySpanToChild(g, n, next, ratio, seen2) {
49624
49961
  const nd2 = rdata(next);
49625
- if (nd2.parent !== n || nd2.span !== 0 || seen.has(next)) return;
49626
- seen.add(next);
49962
+ if (nd2.parent !== n || nd2.span !== 0 || seen2.has(next)) return;
49963
+ seen2.add(next);
49627
49964
  nd2.span = ratio * nd2.subtreeSize;
49628
49965
  if (nd2.nChildren > 0) setChildSubtreeSpans(g, next);
49629
49966
  }
49630
49967
  function setChildSubtreeSpans(g, n) {
49631
49968
  const nd = rdata(n);
49632
49969
  const ratio = nd.span / nd.subtreeSize;
49633
- const seen = /* @__PURE__ */ new Set();
49970
+ const seen2 = /* @__PURE__ */ new Set();
49634
49971
  for (const ep of incidentEdges2(g, n)) {
49635
49972
  const next = neighborOf(ep, n);
49636
- if (next !== null) applySpanToChild(g, n, next, ratio, seen);
49973
+ if (next !== null) applySpanToChild(g, n, next, ratio, seen2);
49637
49974
  }
49638
49975
  }
49639
49976
  function setSubtreeSpans(sg, center) {
@@ -49902,7 +50239,7 @@ var fdpParms = {
49902
50239
  * equivalent). @see lib/fdpgen/fdp.h:fdpParms_s.Mlimit */
49903
50240
  Mlimit: Infinity
49904
50241
  };
49905
- var parms = {
50242
+ var PARMS_INIT = {
49906
50243
  useGrid: 0,
49907
50244
  useNew: 0,
49908
50245
  seed: 0,
@@ -49920,6 +50257,10 @@ var parms = {
49920
50257
  pass1: 0,
49921
50258
  loopcnt: 0
49922
50259
  };
50260
+ var parms = { ...PARMS_INIT };
50261
+ registerRenderState(() => {
50262
+ Object.assign(parms, PARMS_INIT);
50263
+ });
49923
50264
  function cool(t) {
49924
50265
  return parms.T0 * (parms.maxIters - t) / parms.maxIters;
49925
50266
  }
@@ -50564,14 +50905,19 @@ function fdpTLayout(g, xpms) {
50564
50905
  // src/layout/fdp/xlayout.ts
50565
50906
  var DFLT_OVERLAP = "9:prism";
50566
50907
  var PS2INCH3 = (x) => x / 72;
50567
- var xParams = {
50908
+ var XPARAMS_INIT = {
50568
50909
  numIters: 60,
50569
50910
  T0: 0,
50570
50911
  K: 0.3,
50571
50912
  C: 1.5,
50572
50913
  loopcnt: 0
50573
50914
  };
50915
+ var xParams = { ...XPARAMS_INIT };
50574
50916
  var xMarg = { x: 0, y: 0, doAdd: false };
50917
+ registerRenderState(() => {
50918
+ Object.assign(xParams, XPARAMS_INIT);
50919
+ xMarg = { x: 0, y: 0, doAdd: false };
50920
+ });
50575
50921
  function wd2(n) {
50576
50922
  return xMarg.doAdd ? n.info.width / 2 + xMarg.x : n.info.width * xMarg.x / 2;
50577
50923
  }
@@ -51433,7 +51779,7 @@ function fdpSplines(g) {
51433
51779
  );
51434
51780
  }
51435
51781
  if (g.info.n_cluster_edges) {
51436
- console.warn(CLUSTER_EDGE_WARNING);
51782
+ agerrLineOn("warn", CLUSTER_EDGE_WARNING);
51437
51783
  et = EDGETYPE_LINE;
51438
51784
  } else {
51439
51785
  splineEdges1(g, et);
@@ -52855,7 +53201,7 @@ function buildDerivedGraph(g) {
52855
53201
  }
52856
53202
  function buildDerivedEdges(g, dg) {
52857
53203
  const edges = [];
52858
- const seen = /* @__PURE__ */ new Set();
53204
+ const seen2 = /* @__PURE__ */ new Set();
52859
53205
  for (const n of nodesInSeq(g)) {
52860
53206
  for (const e of n.outEdges(g)) {
52861
53207
  if (e.tail === e.head) continue;
@@ -52863,8 +53209,8 @@ function buildDerivedEdges(g, dg) {
52863
53209
  const head = dg.nodes.get(e.head.name);
52864
53210
  if (!tail || !head) continue;
52865
53211
  const key = [tail.name, head.name].sort().join("\0");
52866
- if (seen.has(key)) continue;
52867
- seen.add(key);
53212
+ if (seen2.has(key)) continue;
53213
+ seen2.add(key);
52868
53214
  edges.push({ tail, head, order: 0, origEdge: e });
52869
53215
  }
52870
53216
  }
@@ -53708,12 +54054,12 @@ function svgEndCluster(job) {
53708
54054
  }
53709
54055
 
53710
54056
  // src/render/svg-edge-split.ts
53711
- var DEFAULT_COLOR4 = "black";
54057
+ var DEFAULT_COLOR5 = "black";
53712
54058
  var PENWIDTH_NORMAL4 = 1;
53713
54059
  var PENWIDTH_THRESHOLD4 = 5e-3;
53714
54060
  var EPS3 = 1e-5;
53715
54061
  function dist3(a, b) {
53716
- return Math.hypot(a.x - b.x, a.y - b.y);
54062
+ return Math.sqrt(dist2(a, b));
53717
54063
  }
53718
54064
  function approxLen(list, off) {
53719
54065
  return dist3(list[off], list[off + 1]) + dist3(list[off + 1], list[off + 2]) + dist3(list[off + 2], list[off + 3]);
@@ -53762,7 +54108,7 @@ function emitCurve(list, color, job) {
53762
54108
  }
53763
54109
  function stepSegment(list, s, st, out) {
53764
54110
  if (Math.abs(s.t) < EPS3) return;
53765
- const color = s.color ?? DEFAULT_COLOR4;
54111
+ const color = s.color ?? DEFAULT_COLOR5;
53766
54112
  st.left -= s.t;
53767
54113
  st.endColor = color;
53768
54114
  if (st.first) {
@@ -53781,7 +54127,7 @@ function stepSegment(list, s, st, out) {
53781
54127
  }
53782
54128
  }
53783
54129
  function splitSplineByColor(list, segs) {
53784
- const st = { left: 1, first: true, bzR: list, done: false, endColor: DEFAULT_COLOR4 };
54130
+ const st = { left: 1, first: true, bzR: list, done: false, endColor: DEFAULT_COLOR5 };
53785
54131
  const curves = [];
53786
54132
  for (const s of segs) {
53787
54133
  stepSegment(list, s, st, curves);
@@ -53796,16 +54142,16 @@ function drawSplitSpline(list, segs, job) {
53796
54142
  }
53797
54143
  function emitSplitEdgePaths(e, job, colorList) {
53798
54144
  const segs = parseSegs(colorList).segs;
53799
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR4;
54145
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR5;
53800
54146
  const spl = e.info.spl;
53801
- let endColor = firstColor;
53802
- if (spl === void 0) return { firstColor, endColor };
54147
+ let endColor = firstColor2;
54148
+ if (spl === void 0) return { firstColor: firstColor2, endColor };
53803
54149
  for (let si = 0; si < spl.size; si++) {
53804
54150
  const bz = spl.list[si];
53805
54151
  if (bz === void 0 || bz.size < 4) continue;
53806
54152
  endColor = drawSplitSpline(bz.list, segs, job);
53807
54153
  }
53808
- return { firstColor, endColor };
54154
+ return { firstColor: firstColor2, endColor };
53809
54155
  }
53810
54156
 
53811
54157
  // src/common/taper.ts
@@ -55250,7 +55596,7 @@ var DotWriterBase = class {
55250
55596
  };
55251
55597
 
55252
55598
  // src/render/dot/edge-draw.ts
55253
- var DEFAULT_COLOR5 = "black";
55599
+ var DEFAULT_COLOR6 = "black";
55254
55600
  var DEFAULT_LINE_STYLE = ["solid", "setlinewidth(1)"];
55255
55601
  function emitArrowOp(buf, op, pen) {
55256
55602
  switch (op.kind) {
@@ -55343,8 +55689,8 @@ var EdgeDrawBase = class extends DotWriterBase {
55343
55689
  */
55344
55690
  emitSplitSpline(bzList, colorAttr, edraw, job) {
55345
55691
  const segs = parseSegs(colorAttr).segs;
55346
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR5;
55347
- let endColor = firstColor;
55692
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR6;
55693
+ let endColor = firstColor2;
55348
55694
  for (const bz of bzList) {
55349
55695
  if (bz === void 0 || bz.size < 4) continue;
55350
55696
  const split = splitSplineByColor(bz.list.slice(0, bz.size), segs);
@@ -55353,7 +55699,7 @@ var EdgeDrawBase = class extends DotWriterBase {
55353
55699
  edraw.push(this.styleOp(job), xdotPenColor(resolveRenderColor(c.color)), xdotPoints("B", c.points));
55354
55700
  }
55355
55701
  }
55356
- return { firstColor, endColor };
55702
+ return { firstColor: firstColor2, endColor };
55357
55703
  }
55358
55704
  /**
55359
55705
  * Emit the parallel-multicolor edge spline: one offset Bézier per color,
@@ -55365,7 +55711,7 @@ var EdgeDrawBase = class extends DotWriterBase {
55365
55711
  const segData = bzList.map(
55366
55712
  (bz) => bz !== void 0 && bz.size >= 4 ? buildOffsetLists(bz.list, (2 + numc) / 2) : { offlist: [], tmplist: [] }
55367
55713
  );
55368
- const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR5);
55714
+ const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR6);
55369
55715
  for (const color of colors) {
55370
55716
  const pen = xdotPenColor(resolveRenderColor(color));
55371
55717
  for (const sd of segData) {
@@ -55375,8 +55721,8 @@ var EdgeDrawBase = class extends DotWriterBase {
55375
55721
  }
55376
55722
  }
55377
55723
  return {
55378
- headColor: colors[0] ?? DEFAULT_COLOR5,
55379
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR5
55724
+ headColor: colors[0] ?? DEFAULT_COLOR6,
55725
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR6
55380
55726
  };
55381
55727
  }
55382
55728
  /** Emit one arrow's primitive ops into `buf` (pen/fill from the edge color).
@@ -55893,8 +56239,8 @@ var SvgRenderer = class {
55893
56239
  const numc = (colorAttr.match(/:/g) ?? []).length;
55894
56240
  const numsemi = (colorAttr.match(/;/g) ?? []).length;
55895
56241
  if (numsemi > 0 && numc > 0) {
55896
- const { firstColor, endColor } = emitSplitEdgePaths(e, job, colorAttr);
55897
- emitMulticolorArrows(e, job, endColor, firstColor);
56242
+ const { firstColor: firstColor2, endColor } = emitSplitEdgePaths(e, job, colorAttr);
56243
+ emitMulticolorArrows(e, job, endColor, firstColor2);
55898
56244
  } else if (edgeIsTapered(e)) {
55899
56245
  svgTaperedEdge(e, job);
55900
56246
  } else if (numc > 0) {
@@ -57162,6 +57508,7 @@ function checkRenderArgs(g, format, opts) {
57162
57508
  }
57163
57509
  function render2(g, format, opts) {
57164
57510
  checkRenderArgs(g, format, opts);
57511
+ resetRenderState();
57165
57512
  const engine = opts?.engine ?? "dot";
57166
57513
  const inlineImages = opts?.inlineImages ?? false;
57167
57514
  const ctx = createDefaultContext();
@@ -57358,6 +57705,7 @@ async function renderAsync(g, format, opts) {
57358
57705
  const engine = opts?.engine ?? "dot";
57359
57706
  try {
57360
57707
  const { fontIssues, sizes, bytes } = await prefetchAll(g, opts);
57708
+ resetRenderState();
57361
57709
  const ctx = createDefaultContext();
57362
57710
  if (opts?.imageSizer !== void 0) {
57363
57711
  const sizer = (src) => sizes.get(src) ?? null;
@@ -57434,6 +57782,7 @@ function layoutAndRenderXdot(g, engine) {
57434
57782
  }
57435
57783
  function getDrawOps(g, opts) {
57436
57784
  checkDrawOpsArgs(g, opts);
57785
+ resetRenderState();
57437
57786
  const engine = opts?.engine ?? DEFAULT_DRAW_ENGINE;
57438
57787
  return collectGraphOps(parse(layoutAndRenderXdot(g, engine)));
57439
57788
  }
@@ -57592,6 +57941,7 @@ function classifyError(err) {
57592
57941
  }
57593
57942
  function renderSvg(dotSource, engine) {
57594
57943
  checkRenderArgs2(dotSource, engine);
57944
+ resetRenderState();
57595
57945
  const ctx = createDefaultContext();
57596
57946
  try {
57597
57947
  const g = parse(dotSource);