@knowvah/dot-engine 2.6.11 → 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 (125) 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/htmltable-attr-warn.d.ts.map +1 -1
  12. package/dist/common/htmltable-emit-fill.d.ts +9 -0
  13. package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
  14. package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
  15. package/dist/common/htmltable-lex-expat.d.ts +1 -6
  16. package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
  17. package/dist/common/htmltable.d.ts +1 -7
  18. package/dist/common/htmltable.d.ts.map +1 -1
  19. package/dist/common/poly-gencode.d.ts.map +1 -1
  20. package/dist/common/poly-init.d.ts.map +1 -1
  21. package/dist/common/postproc.d.ts.map +1 -1
  22. package/dist/common/random.d.ts.map +1 -1
  23. package/dist/common/render-state.d.ts +8 -0
  24. package/dist/common/render-state.d.ts.map +1 -0
  25. package/dist/common/splines-geom.d.ts +8 -0
  26. package/dist/common/splines-geom.d.ts.map +1 -1
  27. package/dist/common/splines-routespl.d.ts.map +1 -1
  28. package/dist/common/textmeasure-lookup.d.ts.map +1 -1
  29. package/dist/common/textmeasure.d.ts.map +1 -1
  30. package/dist/gvc/anchor.d.ts.map +1 -1
  31. package/dist/gvc/device-cluster.d.ts.map +1 -1
  32. package/dist/gvc/device-labels.d.ts +14 -0
  33. package/dist/gvc/device-labels.d.ts.map +1 -1
  34. package/dist/gvc/device.d.ts.map +1 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +765 -451
  37. package/dist/index.js.map +4 -4
  38. package/dist/layout/dot/cluster.d.ts.map +1 -1
  39. package/dist/layout/dot/conc.d.ts.map +1 -1
  40. package/dist/layout/dot/decomp.d.ts.map +1 -1
  41. package/dist/layout/dot/edge-route-clip.d.ts +18 -10
  42. package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
  43. package/dist/layout/dot/mincross-build.d.ts.map +1 -1
  44. package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
  45. package/dist/layout/dot/rank.d.ts.map +1 -1
  46. package/dist/layout/dot/splines.d.ts.map +1 -1
  47. package/dist/layout/fdp/index.d.ts.map +1 -1
  48. package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
  49. package/dist/layout/fdp/xlayout.d.ts.map +1 -1
  50. package/dist/layout/neato/edge-len.d.ts.map +1 -1
  51. package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
  52. package/dist/layout/neato/init.d.ts +4 -10
  53. package/dist/layout/neato/init.d.ts.map +1 -1
  54. package/dist/layout/neato/kk.d.ts.map +1 -1
  55. package/dist/layout/neato/multispline-router.d.ts.map +1 -1
  56. package/dist/layout/neato/multispline.d.ts.map +1 -1
  57. package/dist/layout/neato/poly.d.ts.map +1 -1
  58. package/dist/layout/neato/sgd.d.ts.map +1 -1
  59. package/dist/layout/neato/start.d.ts.map +1 -1
  60. package/dist/ortho/index.d.ts.map +1 -1
  61. package/dist/parser/index.d.ts.map +1 -1
  62. package/dist/render/color-resolve.d.ts +49 -1
  63. package/dist/render/color-resolve.d.ts.map +1 -1
  64. package/dist/render/public.d.ts.map +1 -1
  65. package/dist/render/svg-edge-split.d.ts +2 -0
  66. package/dist/render/svg-edge-split.d.ts.map +1 -1
  67. package/dist/render/xdot-public.d.ts.map +1 -1
  68. package/dist/render.js +513 -200
  69. package/dist/render.js.map +4 -4
  70. package/package.json +1 -1
  71. package/src/async/render-async.ts +6 -0
  72. package/src/common/agerr.ts +96 -0
  73. package/src/common/arrows-shapes-poly.ts +19 -5
  74. package/src/common/color.ts +38 -10
  75. package/src/common/crand.ts +8 -2
  76. package/src/common/emit-once.ts +27 -0
  77. package/src/common/graph-init.ts +2 -1
  78. package/src/common/htmltable-attr-warn.ts +3 -4
  79. package/src/common/htmltable-emit-fill.ts +48 -0
  80. package/src/common/htmltable-emit-rules.ts +2 -0
  81. package/src/common/htmltable-lex-expat.ts +78 -23
  82. package/src/common/htmltable.ts +15 -16
  83. package/src/common/poly-gencode.ts +14 -2
  84. package/src/common/poly-init.ts +2 -1
  85. package/src/common/postproc.ts +4 -1
  86. package/src/common/random.ts +11 -1
  87. package/src/common/render-state.ts +36 -0
  88. package/src/common/splines-geom.ts +8 -4
  89. package/src/common/splines-routespl.ts +2 -1
  90. package/src/common/textmeasure-lookup.ts +10 -3
  91. package/src/common/textmeasure.ts +45 -2
  92. package/src/gvc/anchor.ts +1 -12
  93. package/src/gvc/device-cluster.ts +37 -9
  94. package/src/gvc/device-labels.ts +27 -0
  95. package/src/gvc/device.ts +18 -6
  96. package/src/index.ts +3 -0
  97. package/src/layout/dot/cluster.ts +2 -1
  98. package/src/layout/dot/conc.ts +6 -5
  99. package/src/layout/dot/decomp.ts +3 -0
  100. package/src/layout/dot/edge-route-clip.ts +27 -21
  101. package/src/layout/dot/mincross-build.ts +2 -0
  102. package/src/layout/dot/mincross-cross.ts +2 -0
  103. package/src/layout/dot/rank.ts +2 -0
  104. package/src/layout/dot/splines.ts +2 -1
  105. package/src/layout/fdp/index.ts +2 -1
  106. package/src/layout/fdp/tlayout-parms.ts +9 -2
  107. package/src/layout/fdp/xlayout.ts +10 -2
  108. package/src/layout/neato/cdt-surface.ts +6 -6
  109. package/src/layout/neato/edge-len.ts +2 -1
  110. package/src/layout/neato/fdp-adjust.ts +3 -2
  111. package/src/layout/neato/init.ts +11 -11
  112. package/src/layout/neato/kk.ts +2 -1
  113. package/src/layout/neato/multispline-router.ts +3 -3
  114. package/src/layout/neato/multispline.ts +3 -2
  115. package/src/layout/neato/poly.ts +3 -2
  116. package/src/layout/neato/sgd.ts +5 -2
  117. package/src/layout/neato/start.ts +14 -10
  118. package/src/ortho/index.ts +3 -1
  119. package/src/parser/dot.js +4 -1
  120. package/src/parser/dot.pegjs +5 -1
  121. package/src/parser/index.ts +4 -3
  122. package/src/render/color-resolve.ts +193 -4
  123. package/src/render/public.ts +2 -0
  124. package/src/render/svg-edge-split.ts +4 -2
  125. 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);
@@ -10612,14 +11044,14 @@ function tagEdge(text, i) {
10612
11044
  if (i + 1 >= text.length) return PARTIAL;
10613
11045
  return text[i + 1] === ">" ? COMPLETE_END(i + 2) : void 0;
10614
11046
  }
10615
- function storeAttError(text, p, at, pair, seen) {
10616
- if (seen.has(pair.name)) return { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: at };
10617
- 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);
10618
11050
  const err = attValueError(text.slice(pair.value.start, pair.value.end), pair.value.start);
10619
11051
  return err === void 0 ? void 0 : { message: err.message, offset: err.offset ?? p };
10620
11052
  }
10621
11053
  function scanAttributes(text, p, from) {
10622
- const seen = /* @__PURE__ */ new Set();
11054
+ const seen2 = /* @__PURE__ */ new Set();
10623
11055
  let attError;
10624
11056
  let i = skipSpace(text, from);
10625
11057
  for (; ; ) {
@@ -10628,7 +11060,7 @@ function scanAttributes(text, p, from) {
10628
11060
  if (edge !== void 0) return edge;
10629
11061
  const pair = scanPair(text, i);
10630
11062
  if ("kind" in pair) return pair;
10631
- attError ??= storeAttError(text, p, i, pair, seen);
11063
+ attError ??= storeAttError(text, p, i, pair, seen2);
10632
11064
  i = pair.next;
10633
11065
  }
10634
11066
  }
@@ -10696,9 +11128,11 @@ function scanCdata(text, p, base, dataOf, tokens) {
10696
11128
  }
10697
11129
  function scanText(text, p, base, tokens) {
10698
11130
  const e = text.indexOf("<", p);
10699
- const end = e < 0 ? text.length : e;
10700
- tokens.push({ kind: "text", start: base + p, end: base + end });
10701
- 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 };
10702
11136
  }
10703
11137
  function scanContent(text, base, inCdata, dataOf) {
10704
11138
  const tokens = [];
@@ -10713,7 +11147,9 @@ function scanContent(text, base, inCdata, dataOf) {
10713
11147
  continue;
10714
11148
  }
10715
11149
  if (text[p] !== "<") {
10716
- 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;
10717
11153
  continue;
10718
11154
  }
10719
11155
  const { scan, kind } = scanMarkup(text, p);
@@ -10813,24 +11249,44 @@ var ExpatFeed = class {
10813
11249
  }
10814
11250
  };
10815
11251
  var XML_PREDEFINED_ENTITIES = /* @__PURE__ */ new Set(["lt", "gt", "amp", "quot", "apos"]);
10816
- var ENTITY_NAME = /^[A-Za-z_:][\w.:-]*$/;
10817
- var CHAR_REF = /^&#(?:x[0-9A-Fa-f]+|[0-9]+);/;
10818
- function textRefError(text) {
10819
- for (let t = text.indexOf("&"); t >= 0; t = text.indexOf("&", t + 1)) {
10820
- if (text[t + 1] === "#") {
10821
- const ref = CHAR_REF.exec(text.slice(t))?.[0];
10822
- if (ref !== void 0 && charRefNumber(ref) < 0) return { message: XML_ERROR_BAD_CHAR_REF, offset: t };
10823
- 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
+ }
10824
11269
  }
10825
- const semi = text.indexOf(";", t + 1);
10826
- if (semi < 0) continue;
10827
- const key = text.slice(t + 1, semi);
10828
- if (ENTITY_NAME.test(key) && !Object.hasOwn(HTML_ENTITIES, key) && !XML_PREDEFINED_ENTITIES.has(key)) {
10829
- 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 };
10830
11277
  }
11278
+ t = text.indexOf("&", ref.end);
10831
11279
  }
10832
11280
  return void 0;
10833
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
+ }
10834
11290
  function parseTagChunk(chunk) {
10835
11291
  if (!chunk.endsWith(">")) return void 0;
10836
11292
  const body = chunk.slice(1, -1);
@@ -11863,30 +12319,23 @@ var splitSizedLines = (texts, measurer, env) => {
11863
12319
  return lines;
11864
12320
  };
11865
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;
11866
- var htmlTextIsSimple = (texts, env) => {
12322
+ var htmlTextIsSimple = (lines, env) => {
11867
12323
  let prevFs = -1;
11868
12324
  let prevFace = null;
11869
- let count = 0;
11870
- for (const txt of texts) {
11871
- for (const item of txt.items) {
11872
- if (item.br) {
11873
- count = 0;
11874
- continue;
11875
- }
11876
- if (item.text === void 0) continue;
11877
- if (++count > 1 || itemHasFlags(item)) return false;
11878
- const { fs, face } = itemFont(item, env);
11879
- if (prevFs < 0) prevFs = fs;
11880
- else if (fs !== prevFs) return false;
11881
- if (prevFace === null) prevFace = face;
11882
- else if (face !== prevFace) return false;
11883
- }
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;
11884
12333
  }
11885
12334
  return true;
11886
12335
  };
11887
12336
  var sizeTextContent = (texts, measurer, env = defaultSizeEnv()) => {
11888
12337
  const lines = splitSizedLines(texts, measurer, env);
11889
- const simple = htmlTextIsSimple(texts, env);
12338
+ const simple = htmlTextIsSimple(lines, env);
11890
12339
  let w = 0;
11891
12340
  let h = 0;
11892
12341
  for (const ln of lines) {
@@ -16958,6 +17407,7 @@ function normalizeFontName(name) {
16958
17407
  return result;
16959
17408
  }
16960
17409
  var warnedFontNames = /* @__PURE__ */ new Set();
17410
+ registerRenderState(() => warnedFontNames.clear());
16961
17411
  function getFamilyMetrics(fontName) {
16962
17412
  const key = normalizeFontName(fontName);
16963
17413
  for (const family of ALL_FONT_METRICS) {
@@ -16965,8 +17415,8 @@ function getFamilyMetrics(fontName) {
16965
17415
  }
16966
17416
  if (!warnedFontNames.has(fontName)) {
16967
17417
  warnedFontNames.add(fontName);
16968
- console.warn(
16969
- `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`
16970
17420
  );
16971
17421
  }
16972
17422
  return TIMES_FALLBACK;
@@ -17125,10 +17575,37 @@ function getVariantWidths(family, bold, italic) {
17125
17575
  return family.regular;
17126
17576
  }
17127
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
+ }
17128
17597
  function charWidthUnits(widths, charCode) {
17129
- 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
+ }
17130
17603
  const w = widths[code] ?? -1;
17131
- return w < 0 ? 0 : w;
17604
+ if (w < 0) {
17605
+ warnAscii(code);
17606
+ return 0;
17607
+ }
17608
+ return w;
17132
17609
  }
17133
17610
  var utf8Encoder = new TextEncoder();
17134
17611
  function utf8Bytes(text) {
@@ -17811,7 +18288,7 @@ function preprocessTooltip(s) {
17811
18288
  // src/common/make-label.ts
17812
18289
  var DEFAULT_FONTSIZE2 = 14;
17813
18290
  var DEFAULT_FONTNAME = "Times-Roman";
17814
- var DEFAULT_COLOR = "black";
18291
+ var DEFAULT_COLOR3 = "black";
17815
18292
  function getPenColor(obj) {
17816
18293
  if (obj === void 0) return void 0;
17817
18294
  const pc = obj.attrs.get("pencolor");
@@ -18433,252 +18910,6 @@ function assembleResult(p, dimen, grown, fixedshape) {
18433
18910
  };
18434
18911
  }
18435
18912
 
18436
- // src/common/multicolor.ts
18437
- var EPS = 1e-5;
18438
- function aeq0(x) {
18439
- return x < EPS && x > -EPS;
18440
- }
18441
- function getSegLen(token) {
18442
- const semi = token.indexOf(";");
18443
- if (semi === -1) return { color: token, v: 0 };
18444
- const color = token.slice(0, semi);
18445
- const rest = token.slice(semi + 1);
18446
- if (rest.length === 0) return { color, v: -1 };
18447
- const parsed = parseFloat(rest);
18448
- return !isNaN(parsed) && parsed >= 0 ? { color, v: parsed } : { color, v: -1 };
18449
- }
18450
- function appendSeg(token, left2, segs, warnedExceeded) {
18451
- const { color, v } = getSegLen(token);
18452
- if (v < 0) return null;
18453
- let t = v;
18454
- let rval = 0;
18455
- const del = t - left2;
18456
- if (del > 0) {
18457
- if (!aeq0(del) && !warnedExceeded.v) {
18458
- warnedExceeded.v = true;
18459
- rval = 3;
18460
- }
18461
- t = left2;
18462
- }
18463
- left2 -= t;
18464
- segs.push({ color: color.length > 0 ? color : null, t, hasFraction: t > 0 && v > 0 });
18465
- return { left: left2, rval };
18466
- }
18467
- function distributeLeft(segs, left2) {
18468
- if (left2 <= 0) return;
18469
- const zeroCount = segs.filter((s) => s.t <= 0).length;
18470
- if (zeroCount > 0) {
18471
- const delta2 = left2 / zeroCount;
18472
- for (const s of segs) {
18473
- if (s.t <= 0) s.t = delta2;
18474
- }
18475
- } else if (segs.length > 0) {
18476
- segs[segs.length - 1].t += left2;
18477
- }
18478
- }
18479
- function trimTrailing(segs) {
18480
- while (segs.length > 0 && (segs[segs.length - 1]?.t ?? 0) <= 0) {
18481
- segs.pop();
18482
- }
18483
- }
18484
- function parseSegs(colorlist) {
18485
- const segs = [];
18486
- let left2 = 1;
18487
- let rval = 0;
18488
- let badFloatCount = 0;
18489
- const warnedExceeded = { v: false };
18490
- for (const token of colorlist.split(":")) {
18491
- const result = appendSeg(token, left2, segs, warnedExceeded);
18492
- if (result === null) {
18493
- const errCode = badFloatCount === 0 ? 2 : 1;
18494
- badFloatCount++;
18495
- return { segs: [], error: errCode };
18496
- }
18497
- if (result.rval === 3) rval = 3;
18498
- left2 = result.left;
18499
- if (aeq0(left2)) {
18500
- left2 = 0;
18501
- break;
18502
- }
18503
- }
18504
- distributeLeft(segs, left2);
18505
- trimTrailing(segs);
18506
- return { segs, error: rval };
18507
- }
18508
-
18509
- // src/common/style-resolve.ts
18510
- var DEFAULT_COLOR2 = "black";
18511
- var DEFAULT_FILL = "lightgrey";
18512
- var PENWIDTH_BOLD = 2;
18513
- var TOKEN_FLAG = {
18514
- filled: "filled",
18515
- dashed: "dashed",
18516
- dotted: "dotted",
18517
- bold: "bold",
18518
- invis: "invis",
18519
- diagonals: "diagonals",
18520
- rounded: "rounded",
18521
- striped: "striped",
18522
- wedged: "wedged",
18523
- underline: "underline"
18524
- };
18525
- function zeroFlags() {
18526
- return {
18527
- filled: false,
18528
- dashed: false,
18529
- dotted: false,
18530
- bold: false,
18531
- invis: false,
18532
- diagonals: false,
18533
- rounded: false,
18534
- radial: false,
18535
- striped: false,
18536
- wedged: false,
18537
- underline: false,
18538
- setLineWidth: null
18539
- };
18540
- }
18541
- var FUNLIMIT = 64;
18542
- function styleTokens2(style2) {
18543
- if (!style2) return [];
18544
- const out = [];
18545
- let fun = 0;
18546
- for (const raw of style2.split(",")) {
18547
- const token = raw.trim();
18548
- if (token.length === 0) continue;
18549
- if (fun === FUNLIMIT - 1) return [];
18550
- fun++;
18551
- out.push(token);
18552
- }
18553
- return out;
18554
- }
18555
- function parseSetLineWidth(token) {
18556
- const m = /^setlinewidth\s*\(\s*([^)]*)\)\s*$/.exec(token);
18557
- if (m === null) return null;
18558
- const v = parseFloat(m[1]);
18559
- return Number.isNaN(v) ? 0 : v;
18560
- }
18561
- function applyToken(flags, token) {
18562
- if (token === "radial") {
18563
- flags.radial = true;
18564
- flags.filled = true;
18565
- return;
18566
- }
18567
- const key = TOKEN_FLAG[token];
18568
- if (key !== void 0) flags[key] = true;
18569
- }
18570
- function nonEmpty(s) {
18571
- return s !== void 0 && s.length > 0;
18572
- }
18573
- function orElse(s, fallback) {
18574
- return nonEmpty(s) ? s : fallback;
18575
- }
18576
- function firstSolidColor(raw) {
18577
- const grad = parseGradientSpec(raw);
18578
- return grad !== null ? grad[0] : raw;
18579
- }
18580
- function parseStyleFlags(style2) {
18581
- const flags = zeroFlags();
18582
- if (!style2) return flags;
18583
- let fun = 0;
18584
- for (const raw of style2.split(",")) {
18585
- const token = raw.trim();
18586
- if (token.length === 0) continue;
18587
- if (fun === FUNLIMIT - 1) return zeroFlags();
18588
- fun++;
18589
- const lw = parseSetLineWidth(token);
18590
- if (lw !== null) {
18591
- flags.setLineWidth = lw;
18592
- continue;
18593
- }
18594
- if (!token.includes("(")) applyToken(flags, token);
18595
- }
18596
- return flags;
18597
- }
18598
- function styleHasInvisibleAlias(style2) {
18599
- if (!style2) return false;
18600
- let fun = 0;
18601
- for (const raw of style2.split(",")) {
18602
- const token = raw.trim();
18603
- if (token.length === 0) continue;
18604
- if (fun === FUNLIMIT - 1) return false;
18605
- fun++;
18606
- if (token === "invisible") return true;
18607
- }
18608
- return false;
18609
- }
18610
- function resolvePenType(flags) {
18611
- if (flags.invis) return 0 /* None */;
18612
- if (flags.dashed) return 1 /* Dashed */;
18613
- if (flags.dotted) return 2 /* Dotted */;
18614
- return 3 /* Solid */;
18615
- }
18616
- function resolvePenWidth(flags, penwidthAttr) {
18617
- if (penwidthAttr && penwidthAttr.length > 0) {
18618
- const v = parseFloat(penwidthAttr);
18619
- if (isFinite(v)) return v;
18620
- }
18621
- if (flags.setLineWidth !== null) return flags.setLineWidth;
18622
- if (flags.bold) return PENWIDTH_BOLD;
18623
- return 1;
18624
- }
18625
- function resolvePenColor(colorAttr) {
18626
- if (!colorAttr || colorAttr.length === 0) return DEFAULT_COLOR2;
18627
- return firstSolidColor(colorAttr);
18628
- }
18629
- function clusterColorAttrs(attrs) {
18630
- const base = nonEmpty(attrs.color) ? attrs.color : void 0;
18631
- const pencolor = orElse(attrs.pencolor, base ?? "");
18632
- const fillcolor = orElse(attrs.fillcolor, base ?? "");
18633
- return {
18634
- fillcolor: nonEmpty(fillcolor) ? fillcolor : void 0,
18635
- pencolor: nonEmpty(pencolor) ? pencolor : void 0
18636
- };
18637
- }
18638
- function applyBgcolor(attrs, filled, fillcolor) {
18639
- if ((!filled || !fillcolor) && nonEmpty(attrs.bgcolor)) {
18640
- return { filled: true, fillcolor: attrs.bgcolor };
18641
- }
18642
- return { filled, fillcolor };
18643
- }
18644
- function findStopColor(colorlist) {
18645
- const { segs, error } = parseSegs(colorlist);
18646
- if (error === 1 || error === 2) return null;
18647
- if (segs.length < 2) return null;
18648
- const seg0 = segs[0];
18649
- const seg1 = segs[1];
18650
- if (seg0.color === null) return null;
18651
- const fillColor = seg0.color;
18652
- const stopColor = seg1.color ?? DEFAULT_COLOR2;
18653
- const frac = seg0.hasFraction ? seg0.t : seg1.hasFraction ? 1 - seg1.t : 0;
18654
- return { fillColor, stopColor, frac };
18655
- }
18656
- function parseAngle(gradientangle2) {
18657
- if (!gradientangle2 || gradientangle2.length === 0) return 0;
18658
- const v = parseInt(gradientangle2, 10);
18659
- return isFinite(v) ? v : 0;
18660
- }
18661
- function buildResolvedFill(rawColor, flags, angle) {
18662
- const stop = findStopColor(rawColor);
18663
- if (stop === null) return { kind: "solid", color: rawColor };
18664
- const kind = flags.radial ? "radial" : "linear";
18665
- return { kind, fillColor: stop.fillColor, stopColor: stop.stopColor, frac: stop.frac, angle };
18666
- }
18667
- function resolveNodeFillEx(attrs) {
18668
- const flags = parseStyleFlags(attrs.style);
18669
- if (!flags.filled) return { kind: "none" };
18670
- const raw = nonEmpty(attrs.fillcolor) ? attrs.fillcolor : nonEmpty(attrs.color) ? attrs.color : DEFAULT_FILL;
18671
- return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
18672
- }
18673
- function resolveClusterFillEx(attrs) {
18674
- const flags = parseStyleFlags(attrs.style);
18675
- const colors = clusterColorAttrs(attrs);
18676
- const bg = applyBgcolor(attrs, flags.filled, colors.fillcolor);
18677
- if (!bg.filled) return { kind: "none" };
18678
- const raw = bg.fillcolor ?? DEFAULT_FILL;
18679
- return buildResolvedFill(raw, flags, parseAngle(attrs.gradientangle));
18680
- }
18681
-
18682
18913
  // src/layout/dot/fastgr.ts
18683
18914
  var VIRTUAL = 1;
18684
18915
  var NORMAL = 0;
@@ -18895,10 +19126,10 @@ var SMALL2 = 1e-10;
18895
19126
  function ptToLine2(a, b, p) {
18896
19127
  const dx = b.x - a.x;
18897
19128
  const dy = b.y - a.y;
18898
- 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)));
18899
19130
  a2 *= a2;
18900
19131
  if (a2 < SMALL2) return 0;
18901
- return a2 / (dx * dx + dy * dy);
19132
+ return a2 / fma(dx, dx, dy * dy);
18902
19133
  }
18903
19134
  function checkControlPoints(cp) {
18904
19135
  const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
@@ -19355,10 +19586,14 @@ function cubicHalf(c, rightHalf) {
19355
19586
  function curveControlPoints(p, v, w, flag) {
19356
19587
  const AF0 = { x: p.x + v.x + w.x, y: p.y + v.y + w.y };
19357
19588
  const AF3 = { x: p.x - v.x + w.x, y: p.y - v.y + w.y };
19358
- const s = flag & ARR_MOD_INV ? 1 : -1;
19359
- const AF1 = { x: p.x + 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF0.y + s * w.y * (4 / 3) };
19360
- const AF2 = { x: p.x - 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF3.y + s * w.y * (4 / 3) };
19361
- 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];
19362
19597
  }
19363
19598
  function genCurve(p0, u, _arrowsize, penwidth, flag, rankdir = 0) {
19364
19599
  if (rankdir !== 0) {
@@ -19661,13 +19896,14 @@ function bezierClipNode(sp, cx, cy, insideFn, leftInside) {
19661
19896
  y: p.y + cy
19662
19897
  }));
19663
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
+ }
19664
19904
  function arrowEndClip(path4, arrowTip, elen) {
19665
- if (elen <= 0) return path4;
19666
19905
  const sp = [arrowTip, path4[2], path4[1], path4[0]];
19667
- const insideSphere = (lx, ly) => Math.hypot(lx, ly) <= elen;
19668
- const spRel = sp.map((p) => ({ x: p.x - arrowTip.x, y: p.y - arrowTip.y }));
19669
- const clippedRel = bezierClipLocal(spRel, insideSphere, true);
19670
- 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;
19671
19907
  return [clipped[3], clipped[2], clipped[1], clipped[0]];
19672
19908
  }
19673
19909
  function arrowClipLength(arrowName, arrowsize, penwidth) {
@@ -20788,7 +21024,7 @@ function readFontParams(sg) {
20788
21024
  return {
20789
21025
  fontsize: parseFloat(graphAttrInherited(sg, "fontsize") ?? "") || DEFAULT_FONTSIZE2,
20790
21026
  fontname: graphAttrInherited(sg, "fontname") ?? DEFAULT_FONTNAME,
20791
- fontcolor: graphAttrInherited(sg, "fontcolor") ?? DEFAULT_COLOR
21027
+ fontcolor: graphAttrInherited(sg, "fontcolor") ?? DEFAULT_COLOR3
20792
21028
  };
20793
21029
  }
20794
21030
  function applyLabelBorder(sg, dimen) {
@@ -20892,6 +21128,9 @@ function decompSearch(g, start, cmark) {
20892
21128
  }
20893
21129
  }
20894
21130
  var _dc = { cmark: 0 };
21131
+ registerRenderState(() => {
21132
+ _dc.cmark = 0;
21133
+ });
20895
21134
  function resolveNode(n, pass) {
20896
21135
  if (pass > 0) {
20897
21136
  const subg = n.info.clust;
@@ -22666,6 +22905,9 @@ function makeInterclustChain(from, to, orig) {
22666
22905
 
22667
22906
  // src/layout/dot/mincross-cross.ts
22668
22907
  var reMincross = false;
22908
+ registerRenderState(() => {
22909
+ reMincross = false;
22910
+ });
22669
22911
  function setReMincross(b) {
22670
22912
  reMincross = b;
22671
22913
  }
@@ -23116,6 +23358,9 @@ function allocateRanks(g) {
23116
23358
  g.info.rank = rt;
23117
23359
  }
23118
23360
  var fillSeq = 0;
23361
+ registerRenderState(() => {
23362
+ fillSeq = 0;
23363
+ });
23119
23364
  function makeFillNode(sg, rank3, seq2) {
23120
23365
  const n = agnode(sg, `__fill_${rank3}_${seq2}`, true);
23121
23366
  agsubnode(sg, n, true);
@@ -23473,7 +23718,7 @@ function pruneForeignClusterNodes(par, clust) {
23473
23718
  }
23474
23719
  function markClusterNode(clust, n, g) {
23475
23720
  if ((n.info.ranktype ?? 0) !== 0) {
23476
- 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");
23477
23722
  agDeleteFromCluster(clust, n);
23478
23723
  return;
23479
23724
  }
@@ -23938,6 +24183,9 @@ var clType = LOCAL;
23938
24183
  function setClType(t) {
23939
24184
  clType = t;
23940
24185
  }
24186
+ registerRenderState(() => {
24187
+ clType = LOCAL;
24188
+ });
23941
24189
  function mapbool2(s) {
23942
24190
  if (!s || s === "") return false;
23943
24191
  const l = s.toLowerCase();
@@ -24705,7 +24953,7 @@ function readFontAttrs(n, g) {
24705
24953
  return {
24706
24954
  fontname: nodeAttr(n, g, "fontname") ?? DEFAULT_FONTNAME,
24707
24955
  fontsize: parseFloat(nodeAttr(n, g, "fontsize") ?? String(DEFAULT_FONTSIZE2)),
24708
- fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR
24956
+ fontcolor: nodeAttr(n, g, "fontcolor") ?? DEFAULT_COLOR3
24709
24957
  };
24710
24958
  }
24711
24959
  function assignShapeInfo(n, polyDesc) {
@@ -24730,7 +24978,7 @@ function polyInit(n, g, measurer) {
24730
24978
  const shapefile = nodeAttr(n, g, "shapefile");
24731
24979
  n.info.shape = bindShape(shapeName2, shapefile);
24732
24980
  if (shapefile !== void 0 && shapefile !== "" && shapeName2 !== "epsf") {
24733
- console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
24981
+ agwarningf(`No or improper shapefile="${shapefile}" for node "${n.name}"`, "error");
24734
24982
  }
24735
24983
  if (n.info.shape.kind === 2 /* SH_RECORD */) {
24736
24984
  if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
@@ -25101,20 +25349,36 @@ function applyClusterObjState(sg, job) {
25101
25349
  if (job.obj === null) return false;
25102
25350
  const obj = job.obj;
25103
25351
  return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
25352
+ const filled = applyClusterFill(obj, fillRes);
25104
25353
  applyClusterPenState(obj, sg);
25105
- if (fillRes.kind === "none") {
25106
- obj.fill = 0 /* None */;
25107
- return false;
25108
- }
25109
- if (fillRes.kind === "solid") {
25110
- obj.fill = 1 /* Solid */;
25111
- obj.fillColor = resolveRenderColor(fillRes.color);
25112
- return true;
25113
- }
25114
- applyClusterGradient(obj, fillRes);
25115
- return true;
25354
+ reportColorNames(stripedClusterColors(sg));
25355
+ return filled;
25116
25356
  });
25117
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
+ }
25118
25382
 
25119
25383
  // src/render/svg-id.ts
25120
25384
  function svgClass(kind, classAttr) {
@@ -25202,6 +25466,7 @@ function renderPeripheries(poly, coord, filled, ctx) {
25202
25466
  }
25203
25467
  function renderLabel(label, coord, renderer, job) {
25204
25468
  if (label.u.kind !== "txt" || label.u.nspans < 1) return;
25469
+ reportColorNames([label.fontcolor]);
25205
25470
  label.pos = coord;
25206
25471
  label.set = true;
25207
25472
  const VALIGN_TOP2 = "t".charCodeAt(0);
@@ -25221,6 +25486,7 @@ function renderNodeLabel(n, coord, renderer, job) {
25221
25486
  label.pos = coord;
25222
25487
  label.set = true;
25223
25488
  const html = label.u.html;
25489
+ reportColorNames(htmlLabelColors(html));
25224
25490
  withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
25225
25491
  } else {
25226
25492
  renderLabel(label, coord, renderer, job);
@@ -25295,13 +25561,18 @@ function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
25295
25561
  obj.penColor = resolveRenderColor(resolvePenColor(colorAttr));
25296
25562
  obj.pen = resolvePenType(flags);
25297
25563
  obj.penWidth = resolvePenWidth(flags, penwidthAttr);
25298
- obj.rawStyle = styleTokens2(styleAttr);
25564
+ obj.rawStyle = styleTokens(styleAttr);
25299
25565
  }
25300
25566
  function applyNodeStyle(obj, n, job) {
25301
25567
  const styleAttr = nodeAttr(n, n.root, "style");
25302
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
+ }
25303
25574
  const filled = applyFillState(obj, n, job);
25304
- applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
25575
+ applyPenState(obj, styleAttr, colorAttr, penwidth);
25305
25576
  return filled;
25306
25577
  }
25307
25578
  function prepareDrawPoly(poly, filled, obj) {
@@ -25518,7 +25789,7 @@ function initFontEdgeAttr(e) {
25518
25789
  return {
25519
25790
  fontsize: lateDouble(e.attrs.get("fontsize"), DEFAULT_FONTSIZE2, MIN_FONTSIZE),
25520
25791
  fontname: e.attrs.get("fontname") || DEFAULT_FONTNAME,
25521
- fontcolor: e.attrs.get("fontcolor") || DEFAULT_COLOR
25792
+ fontcolor: e.attrs.get("fontcolor") || DEFAULT_COLOR3
25522
25793
  };
25523
25794
  }
25524
25795
  function initFontLabelEdgeAttr(e, fi) {
@@ -25644,7 +25915,7 @@ function findCharset(g) {
25644
25915
  }
25645
25916
  if (p === "big-5" || p === "big5") return CHAR_BIG5;
25646
25917
  if (p === "utf-8" || p === "utf8") return CHAR_UTF8;
25647
- console.error(`Warning: Unsupported charset "${raw}" - assuming utf-8`);
25918
+ agwarningf(`Unsupported charset "${raw}" - assuming utf-8`, "error");
25648
25919
  return CHAR_UTF8;
25649
25920
  }
25650
25921
  function maptoken(p, names, vals) {
@@ -27293,7 +27564,7 @@ function advanceTmpList(tmplist, offlist) {
27293
27564
  // src/render/svg-parallel-edge.ts
27294
27565
  var PENWIDTH_NORMAL2 = 1;
27295
27566
  var PENWIDTH_THRESHOLD2 = 5e-3;
27296
- var DEFAULT_COLOR3 = "black";
27567
+ var DEFAULT_COLOR4 = "black";
27297
27568
  function emitOffsetBezier(tmplist, job, color) {
27298
27569
  const obj = job.obj;
27299
27570
  const resolved = resolveRenderColor(color);
@@ -27335,11 +27606,11 @@ function emitParallelEdgePaths(e, job, colorList) {
27335
27606
  const spl = e.info.spl;
27336
27607
  const numc = (colorList.match(/:/g) ?? []).length;
27337
27608
  const segData = buildSegData(spl?.list ?? [], (2 + numc) / 2);
27338
- const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR3);
27609
+ const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR4);
27339
27610
  emitColorPasses(segData, colors, job);
27340
27611
  return {
27341
- headColor: colors[0] ?? DEFAULT_COLOR3,
27342
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR3
27612
+ headColor: colors[0] ?? DEFAULT_COLOR4,
27613
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR4
27343
27614
  };
27344
27615
  }
27345
27616
 
@@ -27851,7 +28122,6 @@ function beginAnchorIf(renderer, job) {
27851
28122
  }
27852
28123
  var DFLT_SAMPLE = 20;
27853
28124
  var MAP_HW = 2;
27854
- var MAP_SMALL = 1e-10;
27855
28125
  function mapTransform(p, ctx) {
27856
28126
  return {
27857
28127
  x: (p.x + ctx.pad.x - ctx.bb.ll.x) * ctx.scale + ctx.marginOff.x,
@@ -27968,16 +28238,8 @@ function computeLabelRectMap(lab, obj, ctx) {
27968
28238
  mapTransform({ x: lab.pos.x + dx, y: lab.pos.y + dy }, ctx)
27969
28239
  ];
27970
28240
  }
27971
- function ptToLine22(a, b, p) {
27972
- const dx = b.x - a.x;
27973
- const dy = b.y - a.y;
27974
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
27975
- a2 *= a2;
27976
- if (a2 < MAP_SMALL) return 0;
27977
- return a2 / (dx * dx + dy * dy);
27978
- }
27979
28241
  function checkControlPoints2(cp) {
27980
- 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;
27981
28243
  }
27982
28244
  function bezierHalf(v) {
27983
28245
  const left2 = [];
@@ -28212,9 +28474,20 @@ function labelSpanX(lp, just) {
28212
28474
  if (just === "r") return lp.pos.x + lp.space.x / 2;
28213
28475
  return lp.pos.x;
28214
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
+ }
28215
28487
  function renderOneLabel(lp, renderer, job, requireSet = true) {
28216
28488
  if (!lp) return;
28217
28489
  if (requireSet && !lp.set) return;
28490
+ reportColorNames(labelColorNames(lp));
28218
28491
  if (lp.html) {
28219
28492
  if (lp.u.kind === "html") {
28220
28493
  const html = lp.u.html;
@@ -28323,11 +28596,11 @@ function setEdgePen(e, job) {
28323
28596
  const flags = parseStyleFlags(e.attrs.get("style"));
28324
28597
  obj.penColor = withColorScheme(
28325
28598
  e.attrs.get("colorscheme"),
28326
- () => resolveRenderColor(resolvePenColor(e.attrs.get("color")))
28599
+ () => resolveRenderColor(resolvePenColor(e.attrs.get("color")), false)
28327
28600
  );
28328
28601
  obj.pen = resolvePenType(flags);
28329
28602
  obj.penWidth = resolvePenWidth(flags, e.attrs.get("penwidth"));
28330
- obj.rawStyle = styleTokens2(e.attrs.get("style"));
28603
+ obj.rawStyle = styleTokens(e.attrs.get("style"));
28331
28604
  }
28332
28605
  function renderEdge(e, renderer, job) {
28333
28606
  emitEdgeComments(e, renderer, job);
@@ -28342,6 +28615,8 @@ function renderEdge(e, renderer, job) {
28342
28615
  resolveEdgeAnchor(e, svgEdgeId(e, job), obj);
28343
28616
  withColorScheme(e.attrs.get("colorscheme"), () => {
28344
28617
  renderer.beginEdge(e, job);
28618
+ reportEdgeColors(e);
28619
+ reportEdgeLabelColors(e);
28345
28620
  renderer.endEdge(e, job);
28346
28621
  });
28347
28622
  } finally {
@@ -28425,8 +28700,11 @@ function renderPage(g, renderer, job, info) {
28425
28700
  resolveObjAnchor(g, labelTextOf2(g.info.label), svgGraphId(g, job), job.obj);
28426
28701
  }
28427
28702
  const anchored = beginAnchorIf(renderer, job);
28428
- renderer.pageBackground?.(g, job);
28429
- 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
+ });
28430
28708
  if (anchored) renderer.endAnchor?.(job);
28431
28709
  const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
28432
28710
  if (!clustersLast) renderClusters(g, renderer, job);
@@ -28458,6 +28736,7 @@ function render(ctx, g, format, inlineImages = false) {
28458
28736
  job.scale = { x: z * dpiScale, y: z * dpiScale };
28459
28737
  job.rotation = parseLandscape(g) ? 90 : 0;
28460
28738
  job.renderer = renderer;
28739
+ setRendererKnownColors(renderer.type === "svg");
28461
28740
  resetHtmlAnchorIds();
28462
28741
  for (const n of g.nodes.values()) polyInit(n, g, job.measurer);
28463
28742
  return renderGraph(g, job, renderer);
@@ -29729,20 +30008,20 @@ function fillRankVlist(g, r, root) {
29729
30008
  const rankArr = g.info.rank;
29730
30009
  const lead = g.info.rankleader[r];
29731
30010
  if (lead === void 0 || lead === null) {
29732
- console.error(`Error: rebuild_vlists: lead is null for rank ${r}`);
30011
+ agerrorf(`rebuild_vlists: lead is null for rank ${r}`);
29733
30012
  return -1;
29734
30013
  }
29735
30014
  const rootRank = root.info.rank[r];
29736
30015
  if (rootRank.v[lead.info.order ?? 0] !== lead) {
29737
- console.error(
29738
- `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}`
29739
30018
  );
29740
30019
  return -1;
29741
30020
  }
29742
30021
  rankArr[r].v = rootRank.v;
29743
30022
  rankArr[r].vStart = lead.info.order ?? 0;
29744
30023
  const maxi = computeMaxi(g, r);
29745
- if (maxi === -1) console.error(`Warning: degenerate concentrated rank ${g.name},${r}`);
30024
+ if (maxi === -1) agwarningf(`degenerate concentrated rank ${g.name},${r}`, "error");
29746
30025
  rankArr[r].n = maxi + 1;
29747
30026
  return 0;
29748
30027
  }
@@ -29831,7 +30110,7 @@ function dotConcentrate(g) {
29831
30110
  const clust = g.info.clust ?? [];
29832
30111
  for (let c = 0; c < nCluster; c++) {
29833
30112
  if (rebuildVlists(clust[c]) !== 0) {
29834
- console.error("concentrate=true may not work correctly.");
30113
+ agerr("prev", "concentrate=true may not work correctly.");
29835
30114
  return -1;
29836
30115
  }
29837
30116
  }
@@ -32561,7 +32840,7 @@ function routeSplinesInternal(pp, polyline) {
32561
32840
  ];
32562
32841
  const pl = shortestPath(poly, eps);
32563
32842
  if (pl === null) {
32564
- console.warn("in routesplines, Pshortestpath failed");
32843
+ agerrLineOn("warn", "in routesplines, Pshortestpath failed");
32565
32844
  return null;
32566
32845
  }
32567
32846
  emitDump("S3_POLY", dumpNames, () => ({
@@ -34880,6 +35159,10 @@ function addXLabels(gp) {
34880
35159
  var IGNORED_EDGE = 6;
34881
35160
  var Rankdir = 0;
34882
35161
  var Offset = { x: 0, y: 0 };
35162
+ registerRenderState(() => {
35163
+ Rankdir = 0;
35164
+ Offset = { x: 0, y: 0 };
35165
+ });
34883
35166
  function mapPoint(p) {
34884
35167
  const r = ccwrotatepf(p, Rankdir * 90);
34885
35168
  return { x: r.x - Offset.x, y: r.y - Offset.y };
@@ -34967,7 +35250,7 @@ function translateDrawing(g) {
34967
35250
  if (e.tail !== v) continue;
34968
35251
  if (e.info.spl === void 0) {
34969
35252
  if (!(g.info.concentrate ?? false) && (e.info.edge_type ?? 0) !== IGNORED_EDGE) {
34970
- console.warn(`lost ${e.tail.name} ${e.head.name} edge`);
35253
+ agerrLineOn("warn", `lost ${e.tail.name} ${e.head.name} edge`);
34971
35254
  }
34972
35255
  continue;
34973
35256
  }
@@ -36080,7 +36363,11 @@ var A = BigInt("0x5deece66d");
36080
36363
  var C = BigInt("0xb");
36081
36364
  var MASK48 = (1n << 48n) - 1n;
36082
36365
  var TWO48 = 2 ** 48;
36083
- var state = 0x330en;
36366
+ var UNSEEDED_STATE = 0x1234abcd330en;
36367
+ var state = UNSEEDED_STATE;
36368
+ registerRenderState(() => {
36369
+ state = UNSEEDED_STATE;
36370
+ });
36084
36371
  function srand48(seed) {
36085
36372
  const s = BigInt(Math.trunc(seed)) & 0xffffffffn;
36086
36373
  state = (s << 16n | 0x330en) & MASK48;
@@ -38267,7 +38554,8 @@ function ensureDummyNodes(sg, gstart) {
38267
38554
  }
38268
38555
  function orthoEdges(g, useLbls, clipAndInstall2) {
38269
38556
  if (useLbls) {
38270
- console.warn(
38557
+ agerrLineOn(
38558
+ "warn",
38271
38559
  "Orthogonal edges do not currently handle edge labels. Try using xlabels.\n"
38272
38560
  );
38273
38561
  useLbls = false;
@@ -38627,12 +38915,12 @@ function origSeq(e) {
38627
38915
  return resolveOrigEdge(e).seq;
38628
38916
  }
38629
38917
  function dedupByOrig(group) {
38630
- const seen = /* @__PURE__ */ new Set();
38918
+ const seen2 = /* @__PURE__ */ new Set();
38631
38919
  const out = [];
38632
38920
  for (const e of group) {
38633
38921
  const o = resolveOrigEdge(e);
38634
- if (seen.has(o)) continue;
38635
- seen.add(o);
38922
+ if (seen2.has(o)) continue;
38923
+ seen2.add(o);
38636
38924
  out.push(o);
38637
38925
  }
38638
38926
  return out;
@@ -38949,7 +39237,7 @@ function orthoDispatch(g) {
38949
39237
  function curvedTop(g) {
38950
39238
  resetRW(g);
38951
39239
  if (((g.root.info.has_labels ?? 0) & EDGE_LABEL) !== 0) {
38952
- 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");
38953
39241
  }
38954
39242
  }
38955
39243
  function finalizeSplines(g, et, normalize) {
@@ -40597,7 +40885,7 @@ function lenattr(ep, g) {
40597
40885
  const val2 = /^\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(s);
40598
40886
  const len = val2 === null ? Number.NaN : parseFloat(val2[0]);
40599
40887
  if (Number.isNaN(len) || len < 0 || len === 0) {
40600
- 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)}`);
40601
40889
  return DEFAULT_EDGE_LEN;
40602
40890
  }
40603
40891
  return len;
@@ -40694,7 +40982,10 @@ var START_KEYWORDS = [
40694
40982
  ];
40695
40983
  var WARN_POS_IGNORED = "node positions are ignored unless start=random";
40696
40984
  var WARN_SELF_IGNORED = "start=0 not supported with mode=self - ignored";
40697
- var selfWarned = /* @__PURE__ */ new WeakSet();
40985
+ var selfOnce = { warned: false };
40986
+ registerRenderState(() => {
40987
+ selfOnce.warned = false;
40988
+ });
40698
40989
  var circuitWarned = /* @__PURE__ */ new WeakSet();
40699
40990
  function parseStart(p, dflt) {
40700
40991
  let init = dflt;
@@ -40725,7 +41016,7 @@ function initRegular(g, nG) {
40725
41016
  function checkStart(g, nG = g.nodes.size, dflt = INIT_RANDOM) {
40726
41017
  const { init, seed } = parseStart(g.root.attrs.get("start"), dflt);
40727
41018
  if (init !== INIT_RANDOM && [...g.nodes.values()].some((n) => n.attrs.has("pos"))) {
40728
- console.warn(WARN_POS_IGNORED);
41019
+ agerrLineOn("warn", WARN_POS_IGNORED);
40729
41020
  }
40730
41021
  if (init === INIT_REGULAR) initRegular(g, nG);
40731
41022
  srand48(seed);
@@ -40758,7 +41049,7 @@ function neatoMode(g) {
40758
41049
  if (str === void 0 || str === "") return MODE_MAJOR;
40759
41050
  const mode = modeByName().get(str);
40760
41051
  if (mode !== void 0) return mode;
40761
- 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`);
40762
41053
  return MODE_MAJOR;
40763
41054
  }
40764
41055
  function checkMode(g, mode) {
@@ -40772,9 +41063,9 @@ function checkStartAttr(g, mode) {
40772
41063
  const value = g.root.attrs.get("start");
40773
41064
  if (parseStart(value, INIT_RANDOM).init !== INIT_SELF) return;
40774
41065
  if (mode === MODE_MAJOR || mode === MODE_IPSEP) unsupported("start", value ?? "", "smart initialisation");
40775
- if ((mode === MODE_KK || mode === MODE_SGD) && !selfWarned.has(g.root)) {
40776
- selfWarned.add(g.root);
40777
- 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);
40778
41069
  }
40779
41070
  }
40780
41071
  function isConnected(g) {
@@ -40785,15 +41076,15 @@ function isConnected(g) {
40785
41076
  adj.get(e.tail)?.push(e.head);
40786
41077
  adj.get(e.head)?.push(e.tail);
40787
41078
  }
40788
- const seen = /* @__PURE__ */ new Set([nodes[0]]);
41079
+ const seen2 = /* @__PURE__ */ new Set([nodes[0]]);
40789
41080
  const stack = [nodes[0]];
40790
41081
  for (let n = stack.pop(); n !== void 0; n = stack.pop()) {
40791
- for (const m of adj.get(n) ?? []) if (!seen.has(m)) {
40792
- seen.add(m);
41082
+ for (const m of adj.get(n) ?? []) if (!seen2.has(m)) {
41083
+ seen2.add(m);
40793
41084
  stack.push(m);
40794
41085
  }
40795
41086
  }
40796
- return seen.size === nodes.length;
41087
+ return seen2.size === nodes.length;
40797
41088
  }
40798
41089
  function kkCircuitFallsBack(g) {
40799
41090
  const packed = getPack(g.root, -1, 0) >= 0 || (g.root.attrs.get("packmode") ?? "") !== "";
@@ -40802,7 +41093,8 @@ function kkCircuitFallsBack(g) {
40802
41093
  function warnCircuitDisconnected(g) {
40803
41094
  if (circuitWarned.has(g.root)) return;
40804
41095
  circuitWarned.add(g.root);
40805
- console.warn(
41096
+ agerrLineOn(
41097
+ "warn",
40806
41098
  `graph ${g.root.name} is disconnected. Hence, the circuit model
40807
41099
  is undefined. Reverting to the shortest path model.
40808
41100
  Alternatively, consider running neato using -Gpack=true or decomposing
@@ -41021,13 +41313,15 @@ function buildUnfixed(g, n) {
41021
41313
  }
41022
41314
  function resolveModel(model) {
41023
41315
  if (model === MODEL_CIRCUIT2) {
41024
- console.warn(
41316
+ agerrLineOn(
41317
+ "warn",
41025
41318
  "circuit model not yet supported in Gmode=sgd, reverting to shortpath model"
41026
41319
  );
41027
41320
  return MODEL_SHORTPATH;
41028
41321
  }
41029
41322
  if (model === MODEL_MDS) {
41030
- console.warn(
41323
+ agerrLineOn(
41324
+ "warn",
41031
41325
  "mds model not yet supported in Gmode=sgd, reverting to shortpath model"
41032
41326
  );
41033
41327
  return MODEL_SHORTPATH;
@@ -41412,7 +41706,7 @@ function moveNode(st, m) {
41412
41706
  function solveModel(g, st) {
41413
41707
  for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
41414
41708
  if (st.move === st.maxIter) {
41415
- console.warn(`Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
41709
+ agerrLineOn("warn", `Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
41416
41710
  }
41417
41711
  }
41418
41712
  function mdsEdges(g, nodes, lens) {
@@ -41871,6 +42165,7 @@ var MODE_MAJOR = 1;
41871
42165
  var MODE_HIER = 2;
41872
42166
  var MODE_IPSEP = 3;
41873
42167
  var MODE_SGD = 4;
42168
+ var SGD_ITERATIONS = 30;
41874
42169
  var MODEL_SHORTPATH2 = 0;
41875
42170
  var MODEL_CIRCUIT = 1;
41876
42171
  var MODEL_SUBSET = 2;
@@ -41910,6 +42205,11 @@ function assignNodeIds2(g) {
41910
42205
  }
41911
42206
  return nodeList;
41912
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
+ }
41913
42213
  function runMajorization(g, mode, model) {
41914
42214
  void model;
41915
42215
  const nodeList = assignNodeIds2(g);
@@ -41917,7 +42217,7 @@ function runMajorization(g, mode, model) {
41917
42217
  const haveLen = graphHasLen(g);
41918
42218
  const vtx = makeGraphDataC(g, nodeList, haveLen, mode === MODE_HIER || mode === MODE_IPSEP);
41919
42219
  checkStart(g);
41920
- const maxi = lateDouble(g.attrs.get("maxiter"), DFLT_ITERATIONS, 0);
42220
+ const maxi = neatoMaxIter(g.attrs.get("maxiter"), mode, n);
41921
42221
  const epsilon = lateDouble(g.attrs.get("epsilon"), 1e-4, 0);
41922
42222
  const weighted = haveLen && mode !== MODE_IPSEP;
41923
42223
  const Dij = weighted ? computeWeightedApspPacked2(vtx, n) : computeApspPacked2(vtx, n);
@@ -41947,18 +42247,18 @@ function makeGraphDataC(g, nodeList, haveLen, haveDir) {
41947
42247
  for (const np of nodeList) {
41948
42248
  const i = np.info.id;
41949
42249
  const entry = vtx[i];
41950
- const seen = /* @__PURE__ */ new Map();
42250
+ const seen2 = /* @__PURE__ */ new Map();
41951
42251
  for (const ep of [...np.outEdges(g), ...np.inEdges(g)]) {
41952
42252
  if (ep.head === ep.tail) continue;
41953
42253
  const vp = ep.tail === np ? ep.head : ep.tail;
41954
42254
  const vid = vp.info.id;
41955
42255
  const dist4 = haveLen ? lateDouble(ep.attrs.get("len"), 1, 0) : 1;
41956
- const idx = seen.get(vid);
42256
+ const idx = seen2.get(vid);
41957
42257
  if (idx !== void 0) {
41958
42258
  if (haveLen) entry.ewgts[idx] = Math.max(entry.ewgts[idx], dist4);
41959
42259
  continue;
41960
42260
  }
41961
- seen.set(vid, entry.nedges);
42261
+ seen2.set(vid, entry.nedges);
41962
42262
  entry.edges.push(vid);
41963
42263
  if (haveLen || haveDir) entry.ewgts.push(dist4);
41964
42264
  entry.nedges++;
@@ -42305,15 +42605,15 @@ function delaunayTri(xv, yv, n) {
42305
42605
  for (let i = 1; i < n; i++) edges2.push(vs[i - 1], vs[i]);
42306
42606
  return edges2;
42307
42607
  }
42308
- const seen = /* @__PURE__ */ new Set();
42608
+ const seen2 = /* @__PURE__ */ new Set();
42309
42609
  const pairs = [];
42310
42610
  for (const t of tris) {
42311
42611
  for (const [u, v] of [[t.a, t.b], [t.b, t.c], [t.c, t.a]]) {
42312
42612
  const i = Math.min(u, v);
42313
42613
  const j = Math.max(u, v);
42314
42614
  const key = i * 1048576 + j;
42315
- if (!seen.has(key)) {
42316
- seen.add(key);
42615
+ if (!seen2.has(key)) {
42616
+ seen2.add(key);
42317
42617
  pairs.push([i, j]);
42318
42618
  }
42319
42619
  }
@@ -42598,8 +42898,8 @@ var Cdt = class {
42598
42898
  const en = this.edgeOrNew(v3, v4);
42599
42899
  this.removeFace(f1);
42600
42900
  this.removeFace(f2);
42601
- const f3 = this.addFace([v4, v2, v3], [e5, e2, en]);
42602
- 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]);
42603
42903
  this.swapIfInCircle(f3, v4, v2, v3, e5, e2, en);
42604
42904
  this.swapIfInCircle(f4, v1, v4, v3, e4, en, e3);
42605
42905
  }
@@ -42901,10 +43201,7 @@ function sharedEdge(faces, p3, q3) {
42901
43201
  return { i: p1, j: p2 };
42902
43202
  }
42903
43203
  function addTriEdge(g, t, h, seg2) {
42904
- const dist4 = Math.hypot(
42905
- g.nodes[t].ctr.x - g.nodes[h].ctr.x,
42906
- g.nodes[t].ctr.y - g.nodes[h].ctr.y
42907
- );
43204
+ const dist4 = Math.sqrt(dist2(g.nodes[t].ctr, g.nodes[h].ctr));
42908
43205
  const idx = g.edges.length;
42909
43206
  g.edges.push({ t, h, seg: seg2, dist: dist4 });
42910
43207
  g.nodes[t].edges.push(idx);
@@ -43231,7 +43528,7 @@ var SEP = 15;
43231
43528
  function bisectorTarget(v, cosTheta, sinTheta) {
43232
43529
  return { x: fma(cosTheta, 100, v.x), y: fma(sinTheta, 100, v.y) };
43233
43530
  }
43234
- function distFused(p, q) {
43531
+ function distFused2(p, q) {
43235
43532
  const dx = p.x - q.x;
43236
43533
  const dy = p.y - q.y;
43237
43534
  return Math.sqrt(fma(dx, dx, dy * dy));
@@ -43256,7 +43553,7 @@ function mkCtrlPts(s, mult, prev, v, nxt, trip) {
43256
43553
  }
43257
43554
  const q = triPoint(trip, idx, v, w);
43258
43555
  if (q === null) return null;
43259
- const d = distFused(q, v);
43556
+ const d = distFused2(q, v);
43260
43557
  const sep = d >= mult * SEP ? SEP : d / mult;
43261
43558
  const ps = new Array(mult);
43262
43559
  if (idx < s) {
@@ -43385,8 +43682,8 @@ function chainOf(e) {
43385
43682
  return list;
43386
43683
  }
43387
43684
  function warnNoControlPoints(e) {
43388
- console.warn(
43389
- `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})`
43390
43687
  );
43391
43688
  return 1;
43392
43689
  }
@@ -46049,7 +46346,11 @@ function armPow(x, y) {
46049
46346
 
46050
46347
  // src/common/crand.ts
46051
46348
  var C_RAND_MAX = 2147483647;
46052
- var state2 = 1;
46349
+ var UNSEEDED_STATE2 = 1;
46350
+ var state2 = UNSEEDED_STATE2;
46351
+ registerRenderState(() => {
46352
+ state2 = UNSEEDED_STATE2;
46353
+ });
46053
46354
  function csrand(seed) {
46054
46355
  state2 = seed;
46055
46356
  }
@@ -47989,7 +48290,7 @@ function makeAddPoly(n, xmargin, ymargin) {
47989
48290
  case 3 /* SH_POINT */:
47990
48291
  return finishPoly(genRound(n, xmargin, ymargin), POLY_CIRCLE);
47991
48292
  default:
47992
- console.error(`Error: makeAddPoly: unknown shape type ${shapeName(n)}
48293
+ agerrorf(`makeAddPoly: unknown shape type ${shapeName(n)}
47993
48294
  `);
47994
48295
  return null;
47995
48296
  }
@@ -48022,7 +48323,7 @@ function baseShape(n) {
48022
48323
  case 3 /* SH_POINT */:
48023
48324
  return { verts: genRound(n, 0, 0), kind: POLY_CIRCLE };
48024
48325
  default:
48025
- console.error(`Error: makePoly: unknown shape type ${shapeName(n)}
48326
+ agerrorf(`makePoly: unknown shape type ${shapeName(n)}
48026
48327
  `);
48027
48328
  return null;
48028
48329
  }
@@ -49404,7 +49705,7 @@ function warnUnrecognizedOverlap(flag) {
49404
49705
  const s = flag.toLowerCase();
49405
49706
  if (s.startsWith("prism") || NAMED_MODES.has(s)) return;
49406
49707
  if (mapBoolDflt(flag, false) === mapBoolDflt(flag, true)) return;
49407
- console.warn(`Unrecognized overlap value "${flag}" - using false`);
49708
+ agerrLineOn("warn", `Unrecognized overlap value "${flag}" - using false`);
49408
49709
  }
49409
49710
  function getAdjustMode(flag) {
49410
49711
  warnUnrecognizedOverlap(flag);
@@ -49437,7 +49738,7 @@ function adjustLate(g, am) {
49437
49738
  case AM_VPSC:
49438
49739
  return vpscAdjust(g);
49439
49740
  default:
49440
- console.warn(`Unhandled adjust option ${am.print}`);
49741
+ agerrLineOn("warn", `Unhandled adjust option ${am.print}`);
49441
49742
  return 0;
49442
49743
  }
49443
49744
  }
@@ -49656,20 +49957,20 @@ function setSubtreeSize(g) {
49656
49957
  walkAncestorChain(n);
49657
49958
  }
49658
49959
  }
49659
- function applySpanToChild(g, n, next, ratio, seen) {
49960
+ function applySpanToChild(g, n, next, ratio, seen2) {
49660
49961
  const nd2 = rdata(next);
49661
- if (nd2.parent !== n || nd2.span !== 0 || seen.has(next)) return;
49662
- seen.add(next);
49962
+ if (nd2.parent !== n || nd2.span !== 0 || seen2.has(next)) return;
49963
+ seen2.add(next);
49663
49964
  nd2.span = ratio * nd2.subtreeSize;
49664
49965
  if (nd2.nChildren > 0) setChildSubtreeSpans(g, next);
49665
49966
  }
49666
49967
  function setChildSubtreeSpans(g, n) {
49667
49968
  const nd = rdata(n);
49668
49969
  const ratio = nd.span / nd.subtreeSize;
49669
- const seen = /* @__PURE__ */ new Set();
49970
+ const seen2 = /* @__PURE__ */ new Set();
49670
49971
  for (const ep of incidentEdges2(g, n)) {
49671
49972
  const next = neighborOf(ep, n);
49672
- if (next !== null) applySpanToChild(g, n, next, ratio, seen);
49973
+ if (next !== null) applySpanToChild(g, n, next, ratio, seen2);
49673
49974
  }
49674
49975
  }
49675
49976
  function setSubtreeSpans(sg, center) {
@@ -49938,7 +50239,7 @@ var fdpParms = {
49938
50239
  * equivalent). @see lib/fdpgen/fdp.h:fdpParms_s.Mlimit */
49939
50240
  Mlimit: Infinity
49940
50241
  };
49941
- var parms = {
50242
+ var PARMS_INIT = {
49942
50243
  useGrid: 0,
49943
50244
  useNew: 0,
49944
50245
  seed: 0,
@@ -49956,6 +50257,10 @@ var parms = {
49956
50257
  pass1: 0,
49957
50258
  loopcnt: 0
49958
50259
  };
50260
+ var parms = { ...PARMS_INIT };
50261
+ registerRenderState(() => {
50262
+ Object.assign(parms, PARMS_INIT);
50263
+ });
49959
50264
  function cool(t) {
49960
50265
  return parms.T0 * (parms.maxIters - t) / parms.maxIters;
49961
50266
  }
@@ -50600,14 +50905,19 @@ function fdpTLayout(g, xpms) {
50600
50905
  // src/layout/fdp/xlayout.ts
50601
50906
  var DFLT_OVERLAP = "9:prism";
50602
50907
  var PS2INCH3 = (x) => x / 72;
50603
- var xParams = {
50908
+ var XPARAMS_INIT = {
50604
50909
  numIters: 60,
50605
50910
  T0: 0,
50606
50911
  K: 0.3,
50607
50912
  C: 1.5,
50608
50913
  loopcnt: 0
50609
50914
  };
50915
+ var xParams = { ...XPARAMS_INIT };
50610
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
+ });
50611
50921
  function wd2(n) {
50612
50922
  return xMarg.doAdd ? n.info.width / 2 + xMarg.x : n.info.width * xMarg.x / 2;
50613
50923
  }
@@ -51469,7 +51779,7 @@ function fdpSplines(g) {
51469
51779
  );
51470
51780
  }
51471
51781
  if (g.info.n_cluster_edges) {
51472
- console.warn(CLUSTER_EDGE_WARNING);
51782
+ agerrLineOn("warn", CLUSTER_EDGE_WARNING);
51473
51783
  et = EDGETYPE_LINE;
51474
51784
  } else {
51475
51785
  splineEdges1(g, et);
@@ -52891,7 +53201,7 @@ function buildDerivedGraph(g) {
52891
53201
  }
52892
53202
  function buildDerivedEdges(g, dg) {
52893
53203
  const edges = [];
52894
- const seen = /* @__PURE__ */ new Set();
53204
+ const seen2 = /* @__PURE__ */ new Set();
52895
53205
  for (const n of nodesInSeq(g)) {
52896
53206
  for (const e of n.outEdges(g)) {
52897
53207
  if (e.tail === e.head) continue;
@@ -52899,8 +53209,8 @@ function buildDerivedEdges(g, dg) {
52899
53209
  const head = dg.nodes.get(e.head.name);
52900
53210
  if (!tail || !head) continue;
52901
53211
  const key = [tail.name, head.name].sort().join("\0");
52902
- if (seen.has(key)) continue;
52903
- seen.add(key);
53212
+ if (seen2.has(key)) continue;
53213
+ seen2.add(key);
52904
53214
  edges.push({ tail, head, order: 0, origEdge: e });
52905
53215
  }
52906
53216
  }
@@ -53744,12 +54054,12 @@ function svgEndCluster(job) {
53744
54054
  }
53745
54055
 
53746
54056
  // src/render/svg-edge-split.ts
53747
- var DEFAULT_COLOR4 = "black";
54057
+ var DEFAULT_COLOR5 = "black";
53748
54058
  var PENWIDTH_NORMAL4 = 1;
53749
54059
  var PENWIDTH_THRESHOLD4 = 5e-3;
53750
54060
  var EPS3 = 1e-5;
53751
54061
  function dist3(a, b) {
53752
- return Math.hypot(a.x - b.x, a.y - b.y);
54062
+ return Math.sqrt(dist2(a, b));
53753
54063
  }
53754
54064
  function approxLen(list, off) {
53755
54065
  return dist3(list[off], list[off + 1]) + dist3(list[off + 1], list[off + 2]) + dist3(list[off + 2], list[off + 3]);
@@ -53798,7 +54108,7 @@ function emitCurve(list, color, job) {
53798
54108
  }
53799
54109
  function stepSegment(list, s, st, out) {
53800
54110
  if (Math.abs(s.t) < EPS3) return;
53801
- const color = s.color ?? DEFAULT_COLOR4;
54111
+ const color = s.color ?? DEFAULT_COLOR5;
53802
54112
  st.left -= s.t;
53803
54113
  st.endColor = color;
53804
54114
  if (st.first) {
@@ -53817,7 +54127,7 @@ function stepSegment(list, s, st, out) {
53817
54127
  }
53818
54128
  }
53819
54129
  function splitSplineByColor(list, segs) {
53820
- 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 };
53821
54131
  const curves = [];
53822
54132
  for (const s of segs) {
53823
54133
  stepSegment(list, s, st, curves);
@@ -53832,16 +54142,16 @@ function drawSplitSpline(list, segs, job) {
53832
54142
  }
53833
54143
  function emitSplitEdgePaths(e, job, colorList) {
53834
54144
  const segs = parseSegs(colorList).segs;
53835
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR4;
54145
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR5;
53836
54146
  const spl = e.info.spl;
53837
- let endColor = firstColor;
53838
- if (spl === void 0) return { firstColor, endColor };
54147
+ let endColor = firstColor2;
54148
+ if (spl === void 0) return { firstColor: firstColor2, endColor };
53839
54149
  for (let si = 0; si < spl.size; si++) {
53840
54150
  const bz = spl.list[si];
53841
54151
  if (bz === void 0 || bz.size < 4) continue;
53842
54152
  endColor = drawSplitSpline(bz.list, segs, job);
53843
54153
  }
53844
- return { firstColor, endColor };
54154
+ return { firstColor: firstColor2, endColor };
53845
54155
  }
53846
54156
 
53847
54157
  // src/common/taper.ts
@@ -55286,7 +55596,7 @@ var DotWriterBase = class {
55286
55596
  };
55287
55597
 
55288
55598
  // src/render/dot/edge-draw.ts
55289
- var DEFAULT_COLOR5 = "black";
55599
+ var DEFAULT_COLOR6 = "black";
55290
55600
  var DEFAULT_LINE_STYLE = ["solid", "setlinewidth(1)"];
55291
55601
  function emitArrowOp(buf, op, pen) {
55292
55602
  switch (op.kind) {
@@ -55379,8 +55689,8 @@ var EdgeDrawBase = class extends DotWriterBase {
55379
55689
  */
55380
55690
  emitSplitSpline(bzList, colorAttr, edraw, job) {
55381
55691
  const segs = parseSegs(colorAttr).segs;
55382
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR5;
55383
- let endColor = firstColor;
55692
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR6;
55693
+ let endColor = firstColor2;
55384
55694
  for (const bz of bzList) {
55385
55695
  if (bz === void 0 || bz.size < 4) continue;
55386
55696
  const split = splitSplineByColor(bz.list.slice(0, bz.size), segs);
@@ -55389,7 +55699,7 @@ var EdgeDrawBase = class extends DotWriterBase {
55389
55699
  edraw.push(this.styleOp(job), xdotPenColor(resolveRenderColor(c.color)), xdotPoints("B", c.points));
55390
55700
  }
55391
55701
  }
55392
- return { firstColor, endColor };
55702
+ return { firstColor: firstColor2, endColor };
55393
55703
  }
55394
55704
  /**
55395
55705
  * Emit the parallel-multicolor edge spline: one offset Bézier per color,
@@ -55401,7 +55711,7 @@ var EdgeDrawBase = class extends DotWriterBase {
55401
55711
  const segData = bzList.map(
55402
55712
  (bz) => bz !== void 0 && bz.size >= 4 ? buildOffsetLists(bz.list, (2 + numc) / 2) : { offlist: [], tmplist: [] }
55403
55713
  );
55404
- const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR5);
55714
+ const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR6);
55405
55715
  for (const color of colors) {
55406
55716
  const pen = xdotPenColor(resolveRenderColor(color));
55407
55717
  for (const sd of segData) {
@@ -55411,8 +55721,8 @@ var EdgeDrawBase = class extends DotWriterBase {
55411
55721
  }
55412
55722
  }
55413
55723
  return {
55414
- headColor: colors[0] ?? DEFAULT_COLOR5,
55415
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR5
55724
+ headColor: colors[0] ?? DEFAULT_COLOR6,
55725
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR6
55416
55726
  };
55417
55727
  }
55418
55728
  /** Emit one arrow's primitive ops into `buf` (pen/fill from the edge color).
@@ -55929,8 +56239,8 @@ var SvgRenderer = class {
55929
56239
  const numc = (colorAttr.match(/:/g) ?? []).length;
55930
56240
  const numsemi = (colorAttr.match(/;/g) ?? []).length;
55931
56241
  if (numsemi > 0 && numc > 0) {
55932
- const { firstColor, endColor } = emitSplitEdgePaths(e, job, colorAttr);
55933
- emitMulticolorArrows(e, job, endColor, firstColor);
56242
+ const { firstColor: firstColor2, endColor } = emitSplitEdgePaths(e, job, colorAttr);
56243
+ emitMulticolorArrows(e, job, endColor, firstColor2);
55934
56244
  } else if (edgeIsTapered(e)) {
55935
56245
  svgTaperedEdge(e, job);
55936
56246
  } else if (numc > 0) {
@@ -57198,6 +57508,7 @@ function checkRenderArgs(g, format, opts) {
57198
57508
  }
57199
57509
  function render2(g, format, opts) {
57200
57510
  checkRenderArgs(g, format, opts);
57511
+ resetRenderState();
57201
57512
  const engine = opts?.engine ?? "dot";
57202
57513
  const inlineImages = opts?.inlineImages ?? false;
57203
57514
  const ctx = createDefaultContext();
@@ -57394,6 +57705,7 @@ async function renderAsync(g, format, opts) {
57394
57705
  const engine = opts?.engine ?? "dot";
57395
57706
  try {
57396
57707
  const { fontIssues, sizes, bytes } = await prefetchAll(g, opts);
57708
+ resetRenderState();
57397
57709
  const ctx = createDefaultContext();
57398
57710
  if (opts?.imageSizer !== void 0) {
57399
57711
  const sizer = (src) => sizes.get(src) ?? null;
@@ -57470,6 +57782,7 @@ function layoutAndRenderXdot(g, engine) {
57470
57782
  }
57471
57783
  function getDrawOps(g, opts) {
57472
57784
  checkDrawOpsArgs(g, opts);
57785
+ resetRenderState();
57473
57786
  const engine = opts?.engine ?? DEFAULT_DRAW_ENGINE;
57474
57787
  return collectGraphOps(parse(layoutAndRenderXdot(g, engine)));
57475
57788
  }
@@ -57628,6 +57941,7 @@ function classifyError(err) {
57628
57941
  }
57629
57942
  function renderSvg(dotSource, engine) {
57630
57943
  checkRenderArgs2(dotSource, engine);
57944
+ resetRenderState();
57631
57945
  const ctx = createDefaultContext();
57632
57946
  try {
57633
57947
  const g = parse(dotSource);