@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/render.js CHANGED
@@ -5079,6 +5079,57 @@ var ALL_FONT_METRICS = [
5079
5079
  CALIBRI_FAMILY
5080
5080
  ];
5081
5081
 
5082
+ // src/common/render-state.ts
5083
+ var resets = [];
5084
+ function registerRenderState(reset2) {
5085
+ resets.push(reset2);
5086
+ }
5087
+ function resetRenderState() {
5088
+ for (const reset2 of resets) reset2();
5089
+ }
5090
+
5091
+ // src/common/agerr.ts
5092
+ var PREFIX_ERROR = "Error";
5093
+ var PREFIX_WARNING = "Warning";
5094
+ var PREFIX_SEP = ": ";
5095
+ var DEL = 127;
5096
+ var LAST_CNTRL = 31;
5097
+ var WHITESPACE = /* @__PURE__ */ new Set([9, 10, 11, 12, 13]);
5098
+ var OCTAL_WIDTH = 3;
5099
+ var OCTAL_RADIX = 8;
5100
+ var lastLevel = "warning";
5101
+ registerRenderState(() => {
5102
+ lastLevel = "warning";
5103
+ });
5104
+ function escapeControl(message) {
5105
+ let out = "";
5106
+ for (const ch of message) {
5107
+ const c = ch.codePointAt(0);
5108
+ if ((c <= LAST_CNTRL || c === DEL) && !WHITESPACE.has(c)) {
5109
+ out += `\\${c.toString(OCTAL_RADIX).padStart(OCTAL_WIDTH, "0")}`;
5110
+ } else out += ch;
5111
+ }
5112
+ return out;
5113
+ }
5114
+ function agerrLineOn(channel, line) {
5115
+ if (channel === "warn") console.warn(escapeControl(line));
5116
+ else console.error(escapeControl(line));
5117
+ }
5118
+ function agerr(level, msg, channel) {
5119
+ if (level === "prev") {
5120
+ agerrLineOn(channel ?? (lastLevel === "warning" ? "warn" : "error"), msg);
5121
+ return;
5122
+ }
5123
+ lastLevel = level;
5124
+ const prefix = level === "error" ? PREFIX_ERROR : PREFIX_WARNING;
5125
+ agerrLineOn(channel ?? (level === "warning" ? "warn" : "error"), `${prefix}${PREFIX_SEP}${msg}`);
5126
+ }
5127
+ var agerrorf = (msg, channel) => agerr("error", msg, channel);
5128
+ var agwarningf = (msg, channel) => agerr("warning", msg, channel);
5129
+ function agerrFinished(line, channel) {
5130
+ agerrLineOn(channel ?? (line.startsWith(PREFIX_WARNING) ? "warn" : "error"), line);
5131
+ }
5132
+
5082
5133
  // src/common/textmeasure-lookup.ts
5083
5134
  var TIMES_FALLBACK = ALL_FONT_METRICS[0];
5084
5135
  function normalizeFontName(name) {
@@ -5092,6 +5143,7 @@ function normalizeFontName(name) {
5092
5143
  return result;
5093
5144
  }
5094
5145
  var warnedFontNames = /* @__PURE__ */ new Set();
5146
+ registerRenderState(() => warnedFontNames.clear());
5095
5147
  function getFamilyMetrics(fontName) {
5096
5148
  const key = normalizeFontName(fontName);
5097
5149
  for (const family of ALL_FONT_METRICS) {
@@ -5099,8 +5151,8 @@ function getFamilyMetrics(fontName) {
5099
5151
  }
5100
5152
  if (!warnedFontNames.has(fontName)) {
5101
5153
  warnedFontNames.add(fontName);
5102
- console.warn(
5103
- `Warning: no hard-coded metrics for '${fontName}'. Falling back to 'Times' metrics`
5154
+ agwarningf(
5155
+ `no hard-coded metrics for '${fontName}'. Falling back to 'Times' metrics`
5104
5156
  );
5105
5157
  }
5106
5158
  return TIMES_FALLBACK;
@@ -5285,10 +5337,37 @@ function getVariantWidths(family, bold, italic) {
5285
5337
  return family.regular;
5286
5338
  }
5287
5339
  var SPACE_CHAR_CODE = 32;
5340
+ var FIRST_NON_ASCII = 128;
5341
+ var warned = /* @__PURE__ */ new Set();
5342
+ var NON_ASCII_FLAG = "non-ascii";
5343
+ var ASCII_FLAG = "ascii";
5344
+ registerRenderState(() => warned.clear());
5345
+ function warnNonAscii(character) {
5346
+ if (warned.has(NON_ASCII_FLAG)) return;
5347
+ warned.add(NON_ASCII_FLAG);
5348
+ agwarningf(
5349
+ `Warning: no value for width of non-ASCII character ${character}. Falling back to width of space character`
5350
+ );
5351
+ }
5352
+ function warnAscii(character) {
5353
+ if (warned.has(ASCII_FLAG)) return;
5354
+ warned.add(ASCII_FLAG);
5355
+ agwarningf(
5356
+ `Warning: no value for width of ASCII character ${character}. Falling back to 0`
5357
+ );
5358
+ }
5288
5359
  function charWidthUnits(widths, charCode) {
5289
- const code = charCode >= 128 ? SPACE_CHAR_CODE : charCode;
5360
+ let code = charCode;
5361
+ if (code >= FIRST_NON_ASCII) {
5362
+ warnNonAscii(code);
5363
+ code = SPACE_CHAR_CODE;
5364
+ }
5290
5365
  const w = widths[code] ?? -1;
5291
- return w < 0 ? 0 : w;
5366
+ if (w < 0) {
5367
+ warnAscii(code);
5368
+ return 0;
5369
+ }
5370
+ return w;
5292
5371
  }
5293
5372
  var utf8Encoder = new TextEncoder();
5294
5373
  function utf8Bytes(text) {
@@ -5665,10 +5744,7 @@ var StderrLines = class {
5665
5744
  this.pending = "";
5666
5745
  }
5667
5746
  };
5668
- var consoleLine = (line) => {
5669
- if (line.startsWith("Warning")) console.warn(line);
5670
- else console.error(line);
5671
- };
5747
+ var consoleLine = (line) => agerrFinished(line);
5672
5748
  var labelStderr = () => new StderrLines(consoleLine);
5673
5749
  var agerrLine = (out, msg) => {
5674
5750
  if (out === void 0) consoleLine(msg);
@@ -6128,14 +6204,14 @@ function tagEdge(text, i) {
6128
6204
  if (i + 1 >= text.length) return PARTIAL;
6129
6205
  return text[i + 1] === ">" ? COMPLETE_END(i + 2) : void 0;
6130
6206
  }
6131
- function storeAttError(text, p, at, pair, seen) {
6132
- if (seen.has(pair.name)) return { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: at };
6133
- seen.add(pair.name);
6207
+ function storeAttError(text, p, at, pair, seen2) {
6208
+ if (seen2.has(pair.name)) return { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: at };
6209
+ seen2.add(pair.name);
6134
6210
  const err = attValueError(text.slice(pair.value.start, pair.value.end), pair.value.start);
6135
6211
  return err === void 0 ? void 0 : { message: err.message, offset: err.offset ?? p };
6136
6212
  }
6137
6213
  function scanAttributes(text, p, from) {
6138
- const seen = /* @__PURE__ */ new Set();
6214
+ const seen2 = /* @__PURE__ */ new Set();
6139
6215
  let attError;
6140
6216
  let i = skipSpace(text, from);
6141
6217
  for (; ; ) {
@@ -6144,7 +6220,7 @@ function scanAttributes(text, p, from) {
6144
6220
  if (edge !== void 0) return edge;
6145
6221
  const pair = scanPair(text, i);
6146
6222
  if ("kind" in pair) return pair;
6147
- attError ??= storeAttError(text, p, i, pair, seen);
6223
+ attError ??= storeAttError(text, p, i, pair, seen2);
6148
6224
  i = pair.next;
6149
6225
  }
6150
6226
  }
@@ -6212,9 +6288,11 @@ function scanCdata(text, p, base, dataOf, tokens) {
6212
6288
  }
6213
6289
  function scanText(text, p, base, tokens) {
6214
6290
  const e = text.indexOf("<", p);
6215
- const end = e < 0 ? text.length : e;
6216
- tokens.push({ kind: "text", start: base + p, end: base + end });
6217
- return end;
6291
+ const slice = text.slice(p, e < 0 ? text.length : e);
6292
+ const from = e < 0 ? heldRefStart(slice) : void 0;
6293
+ const end = from === void 0 ? p + slice.length : p + from;
6294
+ if (end > p) tokens.push({ kind: "text", start: base + p, end: base + end });
6295
+ return { at: end, held: from !== void 0 };
6218
6296
  }
6219
6297
  function scanContent(text, base, inCdata, dataOf) {
6220
6298
  const tokens = [];
@@ -6229,7 +6307,9 @@ function scanContent(text, base, inCdata, dataOf) {
6229
6307
  continue;
6230
6308
  }
6231
6309
  if (text[p] !== "<") {
6232
- p = scanText(text, p, base, tokens);
6310
+ const scanned = scanText(text, p, base, tokens);
6311
+ if (scanned.held) return { tokens, consumed: scanned.at, inCdata: false };
6312
+ p = scanned.at;
6233
6313
  continue;
6234
6314
  }
6235
6315
  const { scan, kind } = scanMarkup(text, p);
@@ -6329,24 +6409,44 @@ var ExpatFeed = class {
6329
6409
  }
6330
6410
  };
6331
6411
  var XML_PREDEFINED_ENTITIES = /* @__PURE__ */ new Set(["lt", "gt", "amp", "quot", "apos"]);
6332
- var ENTITY_NAME = /^[A-Za-z_:][\w.:-]*$/;
6333
- var CHAR_REF = /^&#(?:x[0-9A-Fa-f]+|[0-9]+);/;
6334
- function textRefError(text) {
6335
- for (let t = text.indexOf("&"); t >= 0; t = text.indexOf("&", t + 1)) {
6336
- if (text[t + 1] === "#") {
6337
- const ref = CHAR_REF.exec(text.slice(t))?.[0];
6338
- if (ref !== void 0 && charRefNumber(ref) < 0) return { message: XML_ERROR_BAD_CHAR_REF, offset: t };
6339
- continue;
6412
+ var SCANNED_ENTITY = /^&([^;&<]*);/;
6413
+ function contentRef(text, t) {
6414
+ const semi = text.indexOf(";", t);
6415
+ const ref = text.slice(t, semi < 0 ? text.length : semi + 1);
6416
+ const scan = scanAttValue(`"${ref}"`, 0);
6417
+ if ("close" in scan) return { end: t + scan.close - 1 };
6418
+ return { invalid: "invalid" in scan ? t + scan.invalid - 1 : text.length };
6419
+ }
6420
+ function firstRefProblem(text) {
6421
+ let t = text.indexOf("&");
6422
+ while (t >= 0) {
6423
+ if (text[t + 1] !== "#") {
6424
+ const name = SCANNED_ENTITY.exec(text.slice(t))?.[1];
6425
+ if (name !== void 0 && name.length >= 2 && Object.hasOwn(HTML_ENTITIES, name)) {
6426
+ t = text.indexOf("&", t + name.length + 2);
6427
+ continue;
6428
+ }
6340
6429
  }
6341
- const semi = text.indexOf(";", t + 1);
6342
- if (semi < 0) continue;
6343
- const key = text.slice(t + 1, semi);
6344
- if (ENTITY_NAME.test(key) && !Object.hasOwn(HTML_ENTITIES, key) && !XML_PREDEFINED_ENTITIES.has(key)) {
6345
- return { message: XML_ERROR_UNDEFINED_ENTITY, offset: t };
6430
+ const ref = contentRef(text, t);
6431
+ if ("invalid" in ref) return { message: XML_ERROR_INVALID_TOKEN, offset: ref.invalid, from: t };
6432
+ const key = text.slice(t + 1, ref.end - 1);
6433
+ if (text[t + 1] === "#") {
6434
+ if (charRefNumber(`&${key};`) < 0) return { message: XML_ERROR_BAD_CHAR_REF, offset: t, from: t };
6435
+ } else if (!XML_PREDEFINED_ENTITIES.has(key)) {
6436
+ return { message: XML_ERROR_UNDEFINED_ENTITY, offset: t, from: t };
6346
6437
  }
6438
+ t = text.indexOf("&", ref.end);
6347
6439
  }
6348
6440
  return void 0;
6349
6441
  }
6442
+ function textRefError(text) {
6443
+ const problem = firstRefProblem(text);
6444
+ return problem === void 0 ? void 0 : { message: problem.message, offset: problem.offset };
6445
+ }
6446
+ function heldRefStart(text) {
6447
+ const problem = firstRefProblem(text);
6448
+ return problem?.message === XML_ERROR_INVALID_TOKEN && problem.offset === text.length ? problem.from : void 0;
6449
+ }
6350
6450
  function parseTagChunk(chunk) {
6351
6451
  if (!chunk.endsWith(">")) return void 0;
6352
6452
  const body = chunk.slice(1, -1);
@@ -7373,30 +7473,23 @@ var splitSizedLines = (texts, measurer, env) => {
7373
7473
  return lines;
7374
7474
  };
7375
7475
  var itemHasFlags = (i) => i.bold === true || i.italic === true || i.underline === true || i.strikethrough === true || i.overline === true || i.subscript === true || i.superscript === true;
7376
- var htmlTextIsSimple = (texts, env) => {
7476
+ var htmlTextIsSimple = (lines, env) => {
7377
7477
  let prevFs = -1;
7378
7478
  let prevFace = null;
7379
- let count = 0;
7380
- for (const txt of texts) {
7381
- for (const item of txt.items) {
7382
- if (item.br) {
7383
- count = 0;
7384
- continue;
7385
- }
7386
- if (item.text === void 0) continue;
7387
- if (++count > 1 || itemHasFlags(item)) return false;
7388
- const { fs, face } = itemFont(item, env);
7389
- if (prevFs < 0) prevFs = fs;
7390
- else if (fs !== prevFs) return false;
7391
- if (prevFace === null) prevFace = face;
7392
- else if (face !== prevFace) return false;
7393
- }
7479
+ for (const ln of lines) {
7480
+ const item = ln.items[0];
7481
+ if (ln.items.length > 1 || itemHasFlags(item)) return false;
7482
+ const { fs, face } = itemFont(item, env);
7483
+ if (prevFs < 0) prevFs = fs;
7484
+ else if (fs !== prevFs) return false;
7485
+ if (prevFace === null) prevFace = face;
7486
+ else if (face !== prevFace) return false;
7394
7487
  }
7395
7488
  return true;
7396
7489
  };
7397
7490
  var sizeTextContent = (texts, measurer, env = defaultSizeEnv()) => {
7398
7491
  const lines = splitSizedLines(texts, measurer, env);
7399
- const simple = htmlTextIsSimple(texts, env);
7492
+ const simple = htmlTextIsSimple(lines, env);
7400
7493
  let w = 0;
7401
7494
  let h = 0;
7402
7495
  for (const ln of lines) {
@@ -8976,10 +9069,10 @@ var SMALL = 1e-10;
8976
9069
  function ptToLine2(a, b, p) {
8977
9070
  const dx = b.x - a.x;
8978
9071
  const dy = b.y - a.y;
8979
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
9072
+ let a2 = fma(p.y - a.y, dx, -(dy * (p.x - a.x)));
8980
9073
  a2 *= a2;
8981
9074
  if (a2 < SMALL) return 0;
8982
- return a2 / (dx * dx + dy * dy);
9075
+ return a2 / fma(dx, dx, dy * dy);
8983
9076
  }
8984
9077
  function checkControlPoints(cp) {
8985
9078
  const dis1 = ptToLine2(cp[0], cp[3], cp[1]);
@@ -9470,10 +9563,14 @@ function cubicHalf(c, rightHalf) {
9470
9563
  function curveControlPoints(p, v, w, flag) {
9471
9564
  const AF0 = { x: p.x + v.x + w.x, y: p.y + v.y + w.y };
9472
9565
  const AF3 = { x: p.x - v.x + w.x, y: p.y - v.y + w.y };
9473
- const s = flag & ARR_MOD_INV ? 1 : -1;
9474
- const AF1 = { x: p.x + 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF0.y + s * w.y * (4 / 3) };
9475
- const AF2 = { x: p.x - 0.95 * v.x + w.x + s * w.x * (4 / 3), y: AF3.y + s * w.y * (4 / 3) };
9476
- return [AF0, AF1, AF2, AF3];
9566
+ const bulgeX = w.x * 4 / 3;
9567
+ const bulgeY = w.y * 4 / 3;
9568
+ const x1 = fma(v.x, 0.95, p.x) + w.x;
9569
+ const x2 = fma(v.x, -0.95, p.x) + w.x;
9570
+ if (flag & ARR_MOD_INV) {
9571
+ return [AF0, { x: x1 + bulgeX, y: AF0.y + bulgeY }, { x: x2 + bulgeX, y: AF3.y + bulgeY }, AF3];
9572
+ }
9573
+ return [AF0, { x: x1 - bulgeX, y: AF0.y - bulgeY }, { x: x2 - bulgeX, y: AF3.y - bulgeY }, AF3];
9477
9574
  }
9478
9575
  function genCurve(p0, u, _arrowsize, penwidth, flag, rankdir = 0) {
9479
9576
  if (rankdir !== 0) {
@@ -9776,13 +9873,14 @@ function bezierClipNode(sp, cx, cy, insideFn, leftInside) {
9776
9873
  y: p.y + cy
9777
9874
  }));
9778
9875
  }
9876
+ function distFused(p, q) {
9877
+ const dx = p.x - q.x;
9878
+ const dy = p.y - q.y;
9879
+ return Math.sqrt(fma(dx, dx, dy * dy));
9880
+ }
9779
9881
  function arrowEndClip(path4, arrowTip, elen) {
9780
- if (elen <= 0) return path4;
9781
9882
  const sp = [arrowTip, path4[2], path4[1], path4[0]];
9782
- const insideSphere = (lx, ly) => Math.hypot(lx, ly) <= elen;
9783
- const spRel = sp.map((p) => ({ x: p.x - arrowTip.x, y: p.y - arrowTip.y }));
9784
- const clippedRel = bezierClipLocal(spRel, insideSphere, true);
9785
- const clipped = clippedRel.map((p) => ({ x: p.x + arrowTip.x, y: p.y + arrowTip.y }));
9883
+ const clipped = elen > 0 ? bezierClipNode(sp, 0, 0, (x, y) => distFused({ x, y }, arrowTip) <= elen, true) : sp;
9786
9884
  return [clipped[3], clipped[2], clipped[1], clipped[0]];
9787
9885
  }
9788
9886
  function arrowClipLength(arrowName, arrowsize, penwidth) {
@@ -11444,6 +11542,7 @@ function resetHtmlAnchorIds() {
11444
11542
  anchorEnv.objLabel = null;
11445
11543
  anchorEnv.imgscale = "false";
11446
11544
  }
11545
+ registerRenderState(resetHtmlAnchorIds);
11447
11546
  function initHtmlAnchor(data, box, renderer, job) {
11448
11547
  if (data.href === void 0 && data.title === void 0 && data.target === void 0) {
11449
11548
  return false;
@@ -12570,7 +12669,7 @@ function polyInit(n, g, measurer) {
12570
12669
  const shapefile = nodeAttr(n, g, "shapefile");
12571
12670
  n.info.shape = bindShape(shapeName2, shapefile);
12572
12671
  if (shapefile !== void 0 && shapefile !== "" && shapeName2 !== "epsf") {
12573
- console.error(`Warning: No or improper shapefile="${shapefile}" for node "${n.name}"`);
12672
+ agwarningf(`No or improper shapefile="${shapefile}" for node "${n.name}"`, "error");
12574
12673
  }
12575
12674
  if (n.info.shape.kind === 2 /* SH_RECORD */) {
12576
12675
  if (n.info.shape_info === void 0) recordNodeInit(n, g, measurer);
@@ -15196,6 +15295,9 @@ var COLOR_LIB = [
15196
15295
 
15197
15296
  // src/common/color.ts
15198
15297
  var colorScheme = "";
15298
+ registerRenderState(() => {
15299
+ colorScheme = "";
15300
+ });
15199
15301
  function setColorScheme(scheme) {
15200
15302
  colorScheme = scheme;
15201
15303
  }
@@ -15325,18 +15427,28 @@ function setBlackOpaque(color, targetType) {
15325
15427
  if (targetType === "rgba") setRgba(color, 0, 0, 0, 255);
15326
15428
  else if (targetType === "hsva") setHsvaDirect(color, 0, 0, 0, 1);
15327
15429
  }
15430
+ var SSCANF_SPACE = /* @__PURE__ */ new Set([" ", " ", "\n", "\v", "\f", "\r"]);
15431
+ function scanHexGroups(p, width2, max) {
15432
+ const out = [];
15433
+ if (p.charAt(0) !== "#") return out;
15434
+ let i = 1;
15435
+ while (out.length < max) {
15436
+ while (SSCANF_SPACE.has(p.charAt(i))) i++;
15437
+ let j = i;
15438
+ while (j < p.length && j - i < width2 && /[0-9a-fA-F]/.test(p.charAt(j))) j++;
15439
+ if (j === i) break;
15440
+ out.push(parseInt(p.slice(i, j), 16));
15441
+ i = j;
15442
+ }
15443
+ return out;
15444
+ }
15328
15445
  function parseHexColor(p) {
15329
- if (p.charAt(0) !== "#") return null;
15330
- const m8 = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(p);
15331
- if (m8) return { r: parseInt(m8[1], 16), g: parseInt(m8[2], 16), b: parseInt(m8[3], 16), a: parseInt(m8[4], 16) };
15332
- const m6 = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(p);
15333
- if (m6) return { r: parseInt(m6[1], 16), g: parseInt(m6[2], 16), b: parseInt(m6[3], 16), a: 255 };
15334
- const m3 = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/.exec(p);
15335
- if (!m3) return null;
15336
- const r = parseInt(m3[1], 16);
15337
- const g = parseInt(m3[2], 16);
15338
- const b = parseInt(m3[3], 16);
15339
- return { r: r | r << 4, g: g | g << 4, b: b | b << 4, a: 255 };
15446
+ const g = scanHexGroups(p, 2, 4);
15447
+ if (g.length >= 3) return { r: g[0], g: g[1], b: g[2], a: g[3] ?? 255 };
15448
+ const short = p.length === 4 ? scanHexGroups(p, 1, 3) : [];
15449
+ if (short.length !== 3) return null;
15450
+ const [r, gg, b] = short;
15451
+ return { r: r | r << 4, g: gg | gg << 4, b: b | b << 4, a: 255 };
15340
15452
  }
15341
15453
  function clamp01(x) {
15342
15454
  return Math.max(0, Math.min(1, x));
@@ -15382,6 +15494,17 @@ function colorxlate(str, color, targetType) {
15382
15494
  return 1 /* ColorUnknown */;
15383
15495
  }
15384
15496
 
15497
+ // src/common/emit-once.ts
15498
+ var seen = /* @__PURE__ */ new Set();
15499
+ registerRenderState(() => {
15500
+ seen.clear();
15501
+ });
15502
+ function emitOnce(str) {
15503
+ if (seen.has(str)) return false;
15504
+ seen.add(str);
15505
+ return true;
15506
+ }
15507
+
15385
15508
  // src/render/color-resolve.ts
15386
15509
  var SVG_KNOWN_COLORS = [
15387
15510
  "aliceblue",
@@ -15534,12 +15657,33 @@ var SVG_KNOWN_COLORS = [
15534
15657
  "yellowgreen"
15535
15658
  ];
15536
15659
  var KNOWN_COLORS = new Set(SVG_KNOWN_COLORS);
15537
- function resolveRenderColor(raw) {
15660
+ var rendererColors = { hasKnownList: true };
15661
+ registerRenderState(() => {
15662
+ rendererColors.hasKnownList = true;
15663
+ });
15664
+ function setRendererKnownColors(hasList) {
15665
+ rendererColors.hasKnownList = hasList;
15666
+ }
15667
+ function firstColor(name) {
15668
+ const i = name.indexOf(":");
15669
+ return i < 0 ? name : name.slice(0, i);
15670
+ }
15671
+ function resolveRenderColor(raw, report = true) {
15538
15672
  if (raw === "" || raw === "none") return { type: "none" };
15539
- if (KNOWN_COLORS.has(raw.toLowerCase())) return { type: "string", s: raw };
15673
+ const known = KNOWN_COLORS.has(raw.toLowerCase());
15674
+ if (known && (rendererColors.hasKnownList || !report)) return { type: "string", s: raw };
15540
15675
  const color = { type: "rgba", r: 0, g: 0, b: 0, a: 0 };
15541
- colorxlate(raw, color, "rgba");
15542
- return color;
15676
+ const rc = colorxlate(raw, color, "rgba");
15677
+ if (report) reportColorxlate(raw, rc);
15678
+ return known ? { type: "string", s: raw } : color;
15679
+ }
15680
+ function reportColorxlate(name, rc) {
15681
+ if (rc === 0 /* ColorOk */) return;
15682
+ if (rc === 1 /* ColorUnknown */) {
15683
+ if (emitOnce(`color ${name}`)) agwarningf(`${name} is not a known color.`);
15684
+ } else {
15685
+ agerrorf("error in colorxlate()");
15686
+ }
15543
15687
  }
15544
15688
  function withColorScheme(scheme, fn) {
15545
15689
  const prev = getColorScheme();
@@ -15586,6 +15730,72 @@ function textFillAttrs(fontColor) {
15586
15730
  if (byte < 255) out += ' fill-opacity="' + (byte / 255).toFixed(6) + '"';
15587
15731
  return out;
15588
15732
  }
15733
+ var DEFAULT_COLOR2 = "black";
15734
+ var SEG_EPS = 1e-5;
15735
+ function reportColorNames(names) {
15736
+ for (const name of names) resolveRenderColor(firstColor(name));
15737
+ }
15738
+ function countChar(s, ch) {
15739
+ return s.split(ch).length - 1;
15740
+ }
15741
+ function multicolorNames(color, arrows) {
15742
+ const { segs, error } = parseSegs(color);
15743
+ if (error === 1 || error === 2) return null;
15744
+ const out = [];
15745
+ const front = segs[0]?.color ?? null;
15746
+ for (const bz of arrows) {
15747
+ let endcolor = null;
15748
+ for (const seg2 of segs) {
15749
+ if (seg2.color === null) break;
15750
+ if (Math.abs(seg2.t) < SEG_EPS) continue;
15751
+ out.push(seg2.color);
15752
+ endcolor = seg2.color;
15753
+ }
15754
+ if (bz.sflag && front !== null) out.push(front);
15755
+ if (bz.eflag && endcolor !== null) out.push(endcolor);
15756
+ }
15757
+ return out;
15758
+ }
15759
+ function taperedNames(color, fillcolor, hasFill) {
15760
+ const pen = color === "" ? DEFAULT_COLOR2 : color;
15761
+ return hasFill ? [pen, fillcolor === "" ? DEFAULT_COLOR2 : fillcolor] : [pen];
15762
+ }
15763
+ function edgeGraphicsColors(spec) {
15764
+ const numc = countChar(spec.color, ":");
15765
+ let color = spec.color;
15766
+ if (countChar(color, ";") > 0 && numc > 0) {
15767
+ const multi = multicolorNames(color, spec.arrows);
15768
+ if (multi !== null) return multi;
15769
+ color = DEFAULT_COLOR2;
15770
+ }
15771
+ const hasFill = spec.fillcolor !== "";
15772
+ const early = hasFill ? [spec.fillcolor] : [];
15773
+ if (spec.tapered) return [...early, ...taperedNames(color, spec.fillcolor, hasFill)];
15774
+ if (numc > 0) return [...early, ...color.split(":").filter((c) => c !== "")];
15775
+ const fill = hasFill ? spec.fillcolor : color;
15776
+ if (color !== "") return [...early, color, fill];
15777
+ return [...early, DEFAULT_COLOR2, fill !== "" ? fill : DEFAULT_COLOR2];
15778
+ }
15779
+ function reportEdgeColors(e) {
15780
+ const spl = e.info.spl;
15781
+ if (!spl) return;
15782
+ const color = e.attrs.get("color") ?? "";
15783
+ reportColorNames(edgeGraphicsColors({
15784
+ color,
15785
+ fillcolor: e.attrs.get("fillcolor") ?? "",
15786
+ tapered: styleTokens2(e.attrs.get("style")).includes("tapered"),
15787
+ arrows: spl.list.map((bz) => ({ sflag: bz.sflag !== 0, eflag: bz.eflag !== 0 }))
15788
+ }));
15789
+ }
15790
+ function backgroundColors(bgcolor, truecolor) {
15791
+ let str = bgcolor !== void 0 && bgcolor !== "" ? bgcolor : "white";
15792
+ if (str === "transparent") {
15793
+ if (truecolor) return [];
15794
+ str = "white";
15795
+ }
15796
+ const stop = findStopColor(str);
15797
+ return stop === null ? [str, "transparent"] : [stop.fillColor, "transparent", stop.stopColor];
15798
+ }
15589
15799
 
15590
15800
  // src/render/svg-multicolor.ts
15591
15801
  var THIN_LINE = 0.5;
@@ -15946,20 +16156,36 @@ function applyClusterObjState(sg, job) {
15946
16156
  if (job.obj === null) return false;
15947
16157
  const obj = job.obj;
15948
16158
  return withColorScheme(clusterAttr(sg, "colorscheme"), () => {
16159
+ const filled = applyClusterFill(obj, fillRes);
15949
16160
  applyClusterPenState(obj, sg);
15950
- if (fillRes.kind === "none") {
15951
- obj.fill = 0 /* None */;
15952
- return false;
15953
- }
15954
- if (fillRes.kind === "solid") {
15955
- obj.fill = 1 /* Solid */;
15956
- obj.fillColor = resolveRenderColor(fillRes.color);
15957
- return true;
15958
- }
15959
- applyClusterGradient(obj, fillRes);
15960
- return true;
16161
+ reportColorNames(stripedClusterColors(sg));
16162
+ return filled;
15961
16163
  });
15962
16164
  }
16165
+ function stripedClusterColors(sg) {
16166
+ const flags = parseStyleFlags(clusterStyle(sg));
16167
+ if (!flags.striped || flags.rounded) return [];
16168
+ const color = clusterAttr(sg, "color") ?? "";
16169
+ let fill = clusterAttr(sg, "fillcolor") || color;
16170
+ const bg = clusterAttr(sg, "bgcolor") ?? "";
16171
+ if ((!flags.filled || fill === "") && bg !== "") fill = bg;
16172
+ const { segs, error } = parseSegs(fill === "" ? "lightgrey" : fill);
16173
+ if (error === 1 || error === 2) return [];
16174
+ return segs.flatMap((seg2) => seg2.color !== null && seg2.t > 0 ? [seg2.color] : []);
16175
+ }
16176
+ function applyClusterFill(obj, fillRes) {
16177
+ if (fillRes.kind === "none") {
16178
+ obj.fill = 0 /* None */;
16179
+ return false;
16180
+ }
16181
+ if (fillRes.kind === "solid") {
16182
+ obj.fill = 1 /* Solid */;
16183
+ obj.fillColor = resolveRenderColor(fillRes.color);
16184
+ return true;
16185
+ }
16186
+ applyClusterGradient(obj, fillRes);
16187
+ return true;
16188
+ }
15963
16189
 
15964
16190
  // src/render/svg-id.ts
15965
16191
  function svgClass(kind, classAttr) {
@@ -16047,6 +16273,7 @@ function renderPeripheries(poly, coord, filled, ctx) {
16047
16273
  }
16048
16274
  function renderLabel(label, coord, renderer, job) {
16049
16275
  if (label.u.kind !== "txt" || label.u.nspans < 1) return;
16276
+ reportColorNames([label.fontcolor]);
16050
16277
  label.pos = coord;
16051
16278
  label.set = true;
16052
16279
  const VALIGN_TOP2 = "t".charCodeAt(0);
@@ -16066,6 +16293,7 @@ function renderNodeLabel(n, coord, renderer, job) {
16066
16293
  label.pos = coord;
16067
16294
  label.set = true;
16068
16295
  const html = label.u.html;
16296
+ reportColorNames(htmlLabelColors(html));
16069
16297
  withLabelEmitState(job, () => emitHtmlLabel(html, coord, renderer, job));
16070
16298
  } else {
16071
16299
  renderLabel(label, coord, renderer, job);
@@ -16145,8 +16373,13 @@ function applyPenState(obj, styleAttr, colorAttr, penwidthAttr) {
16145
16373
  function applyNodeStyle(obj, n, job) {
16146
16374
  const styleAttr = nodeAttr(n, n.root, "style");
16147
16375
  const colorAttr = nodeAttr(n, n.root, "color");
16376
+ const penwidth = nodeAttr(n, n.root, "penwidth");
16377
+ if (n.info.shape?.kind === 2 /* SH_RECORD */) {
16378
+ applyPenState(obj, styleAttr, colorAttr, penwidth);
16379
+ return applyFillState(obj, n, job);
16380
+ }
16148
16381
  const filled = applyFillState(obj, n, job);
16149
- applyPenState(obj, styleAttr, colorAttr, nodeAttr(n, n.root, "penwidth"));
16382
+ applyPenState(obj, styleAttr, colorAttr, penwidth);
16150
16383
  return filled;
16151
16384
  }
16152
16385
  function prepareDrawPoly(poly, filled, obj) {
@@ -16426,6 +16659,9 @@ function decompSearch(g, start, cmark) {
16426
16659
  }
16427
16660
  }
16428
16661
  var _dc = { cmark: 0 };
16662
+ registerRenderState(() => {
16663
+ _dc.cmark = 0;
16664
+ });
16429
16665
  function resolveNode(n, pass) {
16430
16666
  if (pass > 0) {
16431
16667
  const subg = n.info.clust;
@@ -16658,6 +16894,9 @@ function makeInterclustChain(from, to, orig) {
16658
16894
 
16659
16895
  // src/layout/dot/mincross-cross.ts
16660
16896
  var reMincross = false;
16897
+ registerRenderState(() => {
16898
+ reMincross = false;
16899
+ });
16661
16900
  function setReMincross(b) {
16662
16901
  reMincross = b;
16663
16902
  }
@@ -17174,6 +17413,9 @@ function allocateRanks(g) {
17174
17413
  g.info.rank = rt;
17175
17414
  }
17176
17415
  var fillSeq = 0;
17416
+ registerRenderState(() => {
17417
+ fillSeq = 0;
17418
+ });
17177
17419
  function makeFillNode(sg, rank3, seq2) {
17178
17420
  const n = agnode(sg, `__fill_${rank3}_${seq2}`, true);
17179
17421
  agsubnode(sg, n, true);
@@ -17531,7 +17773,7 @@ function pruneForeignClusterNodes(par, clust) {
17531
17773
  }
17532
17774
  function markClusterNode(clust, n, g) {
17533
17775
  if ((n.info.ranktype ?? 0) !== 0) {
17534
- console.error(`Warning: ${n.name} was already in a rankset, deleted from cluster ${g.name}`);
17776
+ agwarningf(`${n.name} was already in a rankset, deleted from cluster ${g.name}`, "error");
17535
17777
  agDeleteFromCluster(clust, n);
17536
17778
  return;
17537
17779
  }
@@ -18110,7 +18352,7 @@ function findCharset(g) {
18110
18352
  }
18111
18353
  if (p === "big-5" || p === "big5") return CHAR_BIG5;
18112
18354
  if (p === "utf-8" || p === "utf8") return CHAR_UTF8;
18113
- console.error(`Warning: Unsupported charset "${raw}" - assuming utf-8`);
18355
+ agwarningf(`Unsupported charset "${raw}" - assuming utf-8`, "error");
18114
18356
  return CHAR_UTF8;
18115
18357
  }
18116
18358
  function maptoken(p, names, vals) {
@@ -19759,7 +20001,7 @@ function advanceTmpList(tmplist, offlist) {
19759
20001
  // src/render/svg-parallel-edge.ts
19760
20002
  var PENWIDTH_NORMAL2 = 1;
19761
20003
  var PENWIDTH_THRESHOLD2 = 5e-3;
19762
- var DEFAULT_COLOR2 = "black";
20004
+ var DEFAULT_COLOR3 = "black";
19763
20005
  function emitOffsetBezier(tmplist, job, color) {
19764
20006
  const obj = job.obj;
19765
20007
  const resolved = resolveRenderColor(color);
@@ -19801,11 +20043,11 @@ function emitParallelEdgePaths(e, job, colorList) {
19801
20043
  const spl = e.info.spl;
19802
20044
  const numc = (colorList.match(/:/g) ?? []).length;
19803
20045
  const segData = buildSegData(spl?.list ?? [], (2 + numc) / 2);
19804
- const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR2);
20046
+ const colors = parseSegs(colorList).segs.map((s) => s.color ?? DEFAULT_COLOR3);
19805
20047
  emitColorPasses(segData, colors, job);
19806
20048
  return {
19807
- headColor: colors[0] ?? DEFAULT_COLOR2,
19808
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR2
20049
+ headColor: colors[0] ?? DEFAULT_COLOR3,
20050
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR3
19809
20051
  };
19810
20052
  }
19811
20053
 
@@ -20317,7 +20559,6 @@ function beginAnchorIf(renderer, job) {
20317
20559
  }
20318
20560
  var DFLT_SAMPLE = 20;
20319
20561
  var MAP_HW = 2;
20320
- var MAP_SMALL = 1e-10;
20321
20562
  function mapTransform(p, ctx) {
20322
20563
  return {
20323
20564
  x: (p.x + ctx.pad.x - ctx.bb.ll.x) * ctx.scale + ctx.marginOff.x,
@@ -20434,16 +20675,8 @@ function computeLabelRectMap(lab, obj, ctx) {
20434
20675
  mapTransform({ x: lab.pos.x + dx, y: lab.pos.y + dy }, ctx)
20435
20676
  ];
20436
20677
  }
20437
- function ptToLine22(a, b, p) {
20438
- const dx = b.x - a.x;
20439
- const dy = b.y - a.y;
20440
- let a2 = (p.y - a.y) * dx - (p.x - a.x) * dy;
20441
- a2 *= a2;
20442
- if (a2 < MAP_SMALL) return 0;
20443
- return a2 / (dx * dx + dy * dy);
20444
- }
20445
20678
  function checkControlPoints2(cp) {
20446
- return ptToLine22(cp[0], cp[3], cp[1]) < MAP_HW * MAP_HW && ptToLine22(cp[0], cp[3], cp[2]) < MAP_HW * MAP_HW;
20679
+ return ptToLine2(cp[0], cp[3], cp[1]) < MAP_HW * MAP_HW && ptToLine2(cp[0], cp[3], cp[2]) < MAP_HW * MAP_HW;
20447
20680
  }
20448
20681
  function bezierHalf(v) {
20449
20682
  const left2 = [];
@@ -20678,9 +20911,20 @@ function labelSpanX(lp, just) {
20678
20911
  if (just === "r") return lp.pos.x + lp.space.x / 2;
20679
20912
  return lp.pos.x;
20680
20913
  }
20914
+ function labelColorNames(lp) {
20915
+ if (lp.html) return lp.u.kind === "html" ? htmlLabelColors(lp.u.html) : [];
20916
+ return lp.u.kind === "txt" && lp.u.nspans >= 1 ? [lp.fontcolor] : [];
20917
+ }
20918
+ function reportEdgeLabelColors(e) {
20919
+ const labels = [e.info.label, e.info.xlabel, e.info.head_label, e.info.tail_label];
20920
+ for (const lp of labels) {
20921
+ if (lp?.set) reportColorNames(labelColorNames(lp));
20922
+ }
20923
+ }
20681
20924
  function renderOneLabel(lp, renderer, job, requireSet = true) {
20682
20925
  if (!lp) return;
20683
20926
  if (requireSet && !lp.set) return;
20927
+ reportColorNames(labelColorNames(lp));
20684
20928
  if (lp.html) {
20685
20929
  if (lp.u.kind === "html") {
20686
20930
  const html = lp.u.html;
@@ -20789,7 +21033,7 @@ function setEdgePen(e, job) {
20789
21033
  const flags = parseStyleFlags(e.attrs.get("style"));
20790
21034
  obj.penColor = withColorScheme(
20791
21035
  e.attrs.get("colorscheme"),
20792
- () => resolveRenderColor(resolvePenColor(e.attrs.get("color")))
21036
+ () => resolveRenderColor(resolvePenColor(e.attrs.get("color")), false)
20793
21037
  );
20794
21038
  obj.pen = resolvePenType(flags);
20795
21039
  obj.penWidth = resolvePenWidth(flags, e.attrs.get("penwidth"));
@@ -20808,6 +21052,8 @@ function renderEdge(e, renderer, job) {
20808
21052
  resolveEdgeAnchor(e, svgEdgeId(e, job), obj);
20809
21053
  withColorScheme(e.attrs.get("colorscheme"), () => {
20810
21054
  renderer.beginEdge(e, job);
21055
+ reportEdgeColors(e);
21056
+ reportEdgeLabelColors(e);
20811
21057
  renderer.endEdge(e, job);
20812
21058
  });
20813
21059
  } finally {
@@ -20891,8 +21137,11 @@ function renderPage(g, renderer, job, info) {
20891
21137
  resolveObjAnchor(g, labelTextOf2(g.info.label), svgGraphId(g, job), job.obj);
20892
21138
  }
20893
21139
  const anchored = beginAnchorIf(renderer, job);
20894
- renderer.pageBackground?.(g, job);
20895
- renderGraphLabel(g, renderer, job);
21140
+ withColorScheme(g.attrs.get("colorscheme"), () => {
21141
+ reportColorNames(backgroundColors(g.attrs.get("bgcolor"), renderer.type === "svg"));
21142
+ renderer.pageBackground?.(g, job);
21143
+ renderGraphLabel(g, renderer, job);
21144
+ });
20896
21145
  if (anchored) renderer.endAnchor?.(job);
20897
21146
  const clustersLast = (job.flags & EMIT_CLUSTERS_LAST) !== 0;
20898
21147
  if (!clustersLast) renderClusters(g, renderer, job);
@@ -20924,6 +21173,7 @@ function render(ctx, g, format, inlineImages = false) {
20924
21173
  job.scale = { x: z * dpiScale, y: z * dpiScale };
20925
21174
  job.rotation = parseLandscape(g) ? 90 : 0;
20926
21175
  job.renderer = renderer;
21176
+ setRendererKnownColors(renderer.type === "svg");
20927
21177
  resetHtmlAnchorIds();
20928
21178
  for (const n of g.nodes.values()) polyInit(n, g, job.measurer);
20929
21179
  return renderGraph(g, job, renderer);
@@ -20992,6 +21242,7 @@ function htmlFillPenWidth() {
20992
21242
  function resetHtmlFillPenWidth() {
20993
21243
  htmlFillPen = 1;
20994
21244
  }
21245
+ registerRenderState(resetHtmlFillPenWidth);
20995
21246
  function penTypeOf(style2) {
20996
21247
  const st = htmlStyle(style2);
20997
21248
  if (st.dashed) return 1 /* Dashed */;
@@ -21120,9 +21371,34 @@ function emitSidedPolylines(sides2, corners, renderer, job) {
21120
21371
  renderer.polyline(seq2.map((i) => corners[i]), job);
21121
21372
  }
21122
21373
  }
21374
+ var HTML_DEFAULT_COLOR = "black";
21375
+ function bgNames(bgcolor) {
21376
+ const spec = parseGradientSpec(bgcolor);
21377
+ return spec === null ? [bgcolor] : [spec[0], spec[1]];
21378
+ }
21379
+ function cellNames(cell2) {
21380
+ if (htmlStyle(cell2.style).invisible) return [];
21381
+ const out = cell2.bgcolor !== void 0 ? bgNames(cell2.bgcolor) : [];
21382
+ if (cell2.border > 0) out.push(cell2.color ?? HTML_DEFAULT_COLOR);
21383
+ if (cell2.nested !== void 0) out.push(...tableNames(cell2.nested));
21384
+ else for (const line of cell2.lines) if (line.fontColor !== null) out.push(line.fontColor);
21385
+ return out;
21386
+ }
21387
+ function tableNames(tbl) {
21388
+ if (htmlStyle(tbl.style).invisible) return [];
21389
+ const out = tbl.bgcolor !== void 0 ? bgNames(tbl.bgcolor) : [];
21390
+ const color = tbl.color ?? HTML_DEFAULT_COLOR;
21391
+ if (tbl.cells.some((c) => c.vruled === true || c.hruled === true)) out.push(color);
21392
+ if (tbl.border > 0) out.push(color);
21393
+ for (const cell2 of tbl.cells) out.push(...cellNames(cell2));
21394
+ return out;
21395
+ }
21396
+ function htmlLabelColors(label) {
21397
+ return [label.color ?? HTML_DEFAULT_COLOR, ...tableNames(label)];
21398
+ }
21123
21399
 
21124
21400
  // src/common/style-resolve.ts
21125
- var DEFAULT_COLOR3 = "black";
21401
+ var DEFAULT_COLOR4 = "black";
21126
21402
  var DEFAULT_FILL = "lightgrey";
21127
21403
  var PENWIDTH_BOLD2 = 2;
21128
21404
  var TOKEN_FLAG = {
@@ -21238,7 +21514,7 @@ function resolvePenWidth(flags, penwidthAttr) {
21238
21514
  return 1;
21239
21515
  }
21240
21516
  function resolvePenColor(colorAttr) {
21241
- if (!colorAttr || colorAttr.length === 0) return DEFAULT_COLOR3;
21517
+ if (!colorAttr || colorAttr.length === 0) return DEFAULT_COLOR4;
21242
21518
  return firstSolidColor(colorAttr);
21243
21519
  }
21244
21520
  function clusterColorAttrs(attrs) {
@@ -21264,7 +21540,7 @@ function findStopColor(colorlist) {
21264
21540
  const seg1 = segs[1];
21265
21541
  if (seg0.color === null) return null;
21266
21542
  const fillColor = seg0.color;
21267
- const stopColor = seg1.color ?? DEFAULT_COLOR3;
21543
+ const stopColor = seg1.color ?? DEFAULT_COLOR4;
21268
21544
  const frac = seg0.hasFraction ? seg0.t : seg1.hasFraction ? 1 - seg1.t : 0;
21269
21545
  return { fillColor, stopColor, frac };
21270
21546
  }
@@ -23932,6 +24208,9 @@ var clType = LOCAL;
23932
24208
  function setClType(t) {
23933
24209
  clType = t;
23934
24210
  }
24211
+ registerRenderState(() => {
24212
+ clType = LOCAL;
24213
+ });
23935
24214
  function mapbool2(s) {
23936
24215
  if (!s || s === "") return false;
23937
24216
  const l = s.toLowerCase();
@@ -25515,20 +25794,20 @@ function fillRankVlist(g, r, root) {
25515
25794
  const rankArr = g.info.rank;
25516
25795
  const lead = g.info.rankleader[r];
25517
25796
  if (lead === void 0 || lead === null) {
25518
- console.error(`Error: rebuild_vlists: lead is null for rank ${r}`);
25797
+ agerrorf(`rebuild_vlists: lead is null for rank ${r}`);
25519
25798
  return -1;
25520
25799
  }
25521
25800
  const rootRank = root.info.rank[r];
25522
25801
  if (rootRank.v[lead.info.order ?? 0] !== lead) {
25523
- console.error(
25524
- `Error: rebuild_vlists: rank lead ${lead.name} not in order ${lead.info.order ?? 0} of rank ${r}`
25802
+ agerrorf(
25803
+ `rebuild_vlists: rank lead ${lead.name} not in order ${lead.info.order ?? 0} of rank ${r}`
25525
25804
  );
25526
25805
  return -1;
25527
25806
  }
25528
25807
  rankArr[r].v = rootRank.v;
25529
25808
  rankArr[r].vStart = lead.info.order ?? 0;
25530
25809
  const maxi = computeMaxi(g, r);
25531
- if (maxi === -1) console.error(`Warning: degenerate concentrated rank ${g.name},${r}`);
25810
+ if (maxi === -1) agwarningf(`degenerate concentrated rank ${g.name},${r}`, "error");
25532
25811
  rankArr[r].n = maxi + 1;
25533
25812
  return 0;
25534
25813
  }
@@ -25617,7 +25896,7 @@ function dotConcentrate(g) {
25617
25896
  const clust = g.info.clust ?? [];
25618
25897
  for (let c = 0; c < nCluster; c++) {
25619
25898
  if (rebuildVlists(clust[c]) !== 0) {
25620
- console.error("concentrate=true may not work correctly.");
25899
+ agerr("prev", "concentrate=true may not work correctly.");
25621
25900
  return -1;
25622
25901
  }
25623
25902
  }
@@ -28347,7 +28626,7 @@ function routeSplinesInternal(pp, polyline) {
28347
28626
  ];
28348
28627
  const pl = shortestPath(poly, eps);
28349
28628
  if (pl === null) {
28350
- console.warn("in routesplines, Pshortestpath failed");
28629
+ agerrLineOn("warn", "in routesplines, Pshortestpath failed");
28351
28630
  return null;
28352
28631
  }
28353
28632
  emitDump("S3_POLY", dumpNames, () => ({
@@ -30666,6 +30945,10 @@ function addXLabels(gp) {
30666
30945
  var IGNORED_EDGE = 6;
30667
30946
  var Rankdir = 0;
30668
30947
  var Offset = { x: 0, y: 0 };
30948
+ registerRenderState(() => {
30949
+ Rankdir = 0;
30950
+ Offset = { x: 0, y: 0 };
30951
+ });
30669
30952
  function mapPoint(p) {
30670
30953
  const r = ccwrotatepf(p, Rankdir * 90);
30671
30954
  return { x: r.x - Offset.x, y: r.y - Offset.y };
@@ -30753,7 +31036,7 @@ function translateDrawing(g) {
30753
31036
  if (e.tail !== v) continue;
30754
31037
  if (e.info.spl === void 0) {
30755
31038
  if (!(g.info.concentrate ?? false) && (e.info.edge_type ?? 0) !== IGNORED_EDGE) {
30756
- console.warn(`lost ${e.tail.name} ${e.head.name} edge`);
31039
+ agerrLineOn("warn", `lost ${e.tail.name} ${e.head.name} edge`);
30757
31040
  }
30758
31041
  continue;
30759
31042
  }
@@ -31866,7 +32149,11 @@ var A = BigInt("0x5deece66d");
31866
32149
  var C = BigInt("0xb");
31867
32150
  var MASK48 = (1n << 48n) - 1n;
31868
32151
  var TWO48 = 2 ** 48;
31869
- var state = 0x330en;
32152
+ var UNSEEDED_STATE = 0x1234abcd330en;
32153
+ var state = UNSEEDED_STATE;
32154
+ registerRenderState(() => {
32155
+ state = UNSEEDED_STATE;
32156
+ });
31870
32157
  function srand48(seed) {
31871
32158
  const s = BigInt(Math.trunc(seed)) & 0xffffffffn;
31872
32159
  state = (s << 16n | 0x330en) & MASK48;
@@ -34053,7 +34340,8 @@ function ensureDummyNodes(sg, gstart) {
34053
34340
  }
34054
34341
  function orthoEdges(g, useLbls, clipAndInstall2) {
34055
34342
  if (useLbls) {
34056
- console.warn(
34343
+ agerrLineOn(
34344
+ "warn",
34057
34345
  "Orthogonal edges do not currently handle edge labels. Try using xlabels.\n"
34058
34346
  );
34059
34347
  useLbls = false;
@@ -34413,12 +34701,12 @@ function origSeq(e) {
34413
34701
  return resolveOrigEdge(e).seq;
34414
34702
  }
34415
34703
  function dedupByOrig(group) {
34416
- const seen = /* @__PURE__ */ new Set();
34704
+ const seen2 = /* @__PURE__ */ new Set();
34417
34705
  const out = [];
34418
34706
  for (const e of group) {
34419
34707
  const o = resolveOrigEdge(e);
34420
- if (seen.has(o)) continue;
34421
- seen.add(o);
34708
+ if (seen2.has(o)) continue;
34709
+ seen2.add(o);
34422
34710
  out.push(o);
34423
34711
  }
34424
34712
  return out;
@@ -34735,7 +35023,7 @@ function orthoDispatch(g) {
34735
35023
  function curvedTop(g) {
34736
35024
  resetRW(g);
34737
35025
  if (((g.root.info.has_labels ?? 0) & EDGE_LABEL) !== 0) {
34738
- console.warn("edge labels with splines=curved not supported in dot - use xlabels\n");
35026
+ agerrLineOn("warn", "edge labels with splines=curved not supported in dot - use xlabels\n");
34739
35027
  }
34740
35028
  }
34741
35029
  function finalizeSplines(g, et, normalize) {
@@ -36383,7 +36671,7 @@ function lenattr(ep, g) {
36383
36671
  const val2 = /^\s*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?/.exec(s);
36384
36672
  const len = val2 === null ? Number.NaN : parseFloat(val2[0]);
36385
36673
  if (Number.isNaN(len) || len < 0 || len === 0) {
36386
- console.warn(`bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
36674
+ agerrLineOn("warn", `bad edge len "${s}" in ${g.name} - setting to ${DEFAULT_EDGE_LEN.toFixed(2)}`);
36387
36675
  return DEFAULT_EDGE_LEN;
36388
36676
  }
36389
36677
  return len;
@@ -36480,7 +36768,10 @@ var START_KEYWORDS = [
36480
36768
  ];
36481
36769
  var WARN_POS_IGNORED = "node positions are ignored unless start=random";
36482
36770
  var WARN_SELF_IGNORED = "start=0 not supported with mode=self - ignored";
36483
- var selfWarned = /* @__PURE__ */ new WeakSet();
36771
+ var selfOnce = { warned: false };
36772
+ registerRenderState(() => {
36773
+ selfOnce.warned = false;
36774
+ });
36484
36775
  var circuitWarned = /* @__PURE__ */ new WeakSet();
36485
36776
  function parseStart(p, dflt) {
36486
36777
  let init = dflt;
@@ -36511,7 +36802,7 @@ function initRegular(g, nG) {
36511
36802
  function checkStart(g, nG = g.nodes.size, dflt = INIT_RANDOM) {
36512
36803
  const { init, seed } = parseStart(g.root.attrs.get("start"), dflt);
36513
36804
  if (init !== INIT_RANDOM && [...g.nodes.values()].some((n) => n.attrs.has("pos"))) {
36514
- console.warn(WARN_POS_IGNORED);
36805
+ agerrLineOn("warn", WARN_POS_IGNORED);
36515
36806
  }
36516
36807
  if (init === INIT_REGULAR) initRegular(g, nG);
36517
36808
  srand48(seed);
@@ -36544,7 +36835,7 @@ function neatoMode(g) {
36544
36835
  if (str === void 0 || str === "") return MODE_MAJOR;
36545
36836
  const mode = modeByName().get(str);
36546
36837
  if (mode !== void 0) return mode;
36547
- console.warn(`Illegal value ${str} for attribute "mode" in graph ${g.root.name} - ignored`);
36838
+ agerrLineOn("warn", `Illegal value ${str} for attribute "mode" in graph ${g.root.name} - ignored`);
36548
36839
  return MODE_MAJOR;
36549
36840
  }
36550
36841
  function checkMode(g, mode) {
@@ -36558,9 +36849,9 @@ function checkStartAttr(g, mode) {
36558
36849
  const value = g.root.attrs.get("start");
36559
36850
  if (parseStart(value, INIT_RANDOM).init !== INIT_SELF) return;
36560
36851
  if (mode === MODE_MAJOR || mode === MODE_IPSEP) unsupported("start", value ?? "", "smart initialisation");
36561
- if ((mode === MODE_KK || mode === MODE_SGD) && !selfWarned.has(g.root)) {
36562
- selfWarned.add(g.root);
36563
- console.warn(WARN_SELF_IGNORED);
36852
+ if ((mode === MODE_KK || mode === MODE_SGD) && !selfOnce.warned) {
36853
+ selfOnce.warned = true;
36854
+ agerrLineOn("warn", WARN_SELF_IGNORED);
36564
36855
  }
36565
36856
  }
36566
36857
  function isConnected(g) {
@@ -36571,15 +36862,15 @@ function isConnected(g) {
36571
36862
  adj.get(e.tail)?.push(e.head);
36572
36863
  adj.get(e.head)?.push(e.tail);
36573
36864
  }
36574
- const seen = /* @__PURE__ */ new Set([nodes[0]]);
36865
+ const seen2 = /* @__PURE__ */ new Set([nodes[0]]);
36575
36866
  const stack = [nodes[0]];
36576
36867
  for (let n = stack.pop(); n !== void 0; n = stack.pop()) {
36577
- for (const m of adj.get(n) ?? []) if (!seen.has(m)) {
36578
- seen.add(m);
36868
+ for (const m of adj.get(n) ?? []) if (!seen2.has(m)) {
36869
+ seen2.add(m);
36579
36870
  stack.push(m);
36580
36871
  }
36581
36872
  }
36582
- return seen.size === nodes.length;
36873
+ return seen2.size === nodes.length;
36583
36874
  }
36584
36875
  function kkCircuitFallsBack(g) {
36585
36876
  const packed = getPack(g.root, -1, 0) >= 0 || (g.root.attrs.get("packmode") ?? "") !== "";
@@ -36588,7 +36879,8 @@ function kkCircuitFallsBack(g) {
36588
36879
  function warnCircuitDisconnected(g) {
36589
36880
  if (circuitWarned.has(g.root)) return;
36590
36881
  circuitWarned.add(g.root);
36591
- console.warn(
36882
+ agerrLineOn(
36883
+ "warn",
36592
36884
  `graph ${g.root.name} is disconnected. Hence, the circuit model
36593
36885
  is undefined. Reverting to the shortest path model.
36594
36886
  Alternatively, consider running neato using -Gpack=true or decomposing
@@ -36807,13 +37099,15 @@ function buildUnfixed(g, n) {
36807
37099
  }
36808
37100
  function resolveModel(model) {
36809
37101
  if (model === MODEL_CIRCUIT2) {
36810
- console.warn(
37102
+ agerrLineOn(
37103
+ "warn",
36811
37104
  "circuit model not yet supported in Gmode=sgd, reverting to shortpath model"
36812
37105
  );
36813
37106
  return MODEL_SHORTPATH;
36814
37107
  }
36815
37108
  if (model === MODEL_MDS) {
36816
- console.warn(
37109
+ agerrLineOn(
37110
+ "warn",
36817
37111
  "mds model not yet supported in Gmode=sgd, reverting to shortpath model"
36818
37112
  );
36819
37113
  return MODEL_SHORTPATH;
@@ -37198,7 +37492,7 @@ function moveNode(st, m) {
37198
37492
  function solveModel(g, st) {
37199
37493
  for (let m = chooseNode(st); m >= 0; m = chooseNode(st)) moveNode(st, m);
37200
37494
  if (st.move === st.maxIter) {
37201
- console.warn(`Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
37495
+ agerrLineOn("warn", `Max. iterations (${st.maxIter}) reached on graph ${g.name}`);
37202
37496
  }
37203
37497
  }
37204
37498
  function mdsEdges(g, nodes, lens) {
@@ -37657,6 +37951,7 @@ var MODE_MAJOR = 1;
37657
37951
  var MODE_HIER = 2;
37658
37952
  var MODE_IPSEP = 3;
37659
37953
  var MODE_SGD = 4;
37954
+ var SGD_ITERATIONS = 30;
37660
37955
  var MODEL_SHORTPATH2 = 0;
37661
37956
  var MODEL_CIRCUIT = 1;
37662
37957
  var MODEL_SUBSET = 2;
@@ -37696,6 +37991,11 @@ function assignNodeIds2(g) {
37696
37991
  }
37697
37992
  return nodeList;
37698
37993
  }
37994
+ function neatoMaxIter(maxiter, mode, n) {
37995
+ if (maxiter !== void 0) return parseInt(maxiter, 10) || 0;
37996
+ if (mode === MODE_MAJOR) return DFLT_ITERATIONS;
37997
+ return mode === MODE_SGD ? SGD_ITERATIONS : 100 * n;
37998
+ }
37699
37999
  function runMajorization(g, mode, model) {
37700
38000
  void model;
37701
38001
  const nodeList = assignNodeIds2(g);
@@ -37703,7 +38003,7 @@ function runMajorization(g, mode, model) {
37703
38003
  const haveLen = graphHasLen(g);
37704
38004
  const vtx = makeGraphDataC(g, nodeList, haveLen, mode === MODE_HIER || mode === MODE_IPSEP);
37705
38005
  checkStart(g);
37706
- const maxi = lateDouble(g.attrs.get("maxiter"), DFLT_ITERATIONS, 0);
38006
+ const maxi = neatoMaxIter(g.attrs.get("maxiter"), mode, n);
37707
38007
  const epsilon = lateDouble(g.attrs.get("epsilon"), 1e-4, 0);
37708
38008
  const weighted = haveLen && mode !== MODE_IPSEP;
37709
38009
  const Dij = weighted ? computeWeightedApspPacked2(vtx, n) : computeApspPacked2(vtx, n);
@@ -37733,18 +38033,18 @@ function makeGraphDataC(g, nodeList, haveLen, haveDir) {
37733
38033
  for (const np of nodeList) {
37734
38034
  const i = np.info.id;
37735
38035
  const entry = vtx[i];
37736
- const seen = /* @__PURE__ */ new Map();
38036
+ const seen2 = /* @__PURE__ */ new Map();
37737
38037
  for (const ep of [...np.outEdges(g), ...np.inEdges(g)]) {
37738
38038
  if (ep.head === ep.tail) continue;
37739
38039
  const vp = ep.tail === np ? ep.head : ep.tail;
37740
38040
  const vid = vp.info.id;
37741
38041
  const dist4 = haveLen ? lateDouble(ep.attrs.get("len"), 1, 0) : 1;
37742
- const idx = seen.get(vid);
38042
+ const idx = seen2.get(vid);
37743
38043
  if (idx !== void 0) {
37744
38044
  if (haveLen) entry.ewgts[idx] = Math.max(entry.ewgts[idx], dist4);
37745
38045
  continue;
37746
38046
  }
37747
- seen.set(vid, entry.nedges);
38047
+ seen2.set(vid, entry.nedges);
37748
38048
  entry.edges.push(vid);
37749
38049
  if (haveLen || haveDir) entry.ewgts.push(dist4);
37750
38050
  entry.nedges++;
@@ -38091,15 +38391,15 @@ function delaunayTri(xv, yv, n) {
38091
38391
  for (let i = 1; i < n; i++) edges2.push(vs[i - 1], vs[i]);
38092
38392
  return edges2;
38093
38393
  }
38094
- const seen = /* @__PURE__ */ new Set();
38394
+ const seen2 = /* @__PURE__ */ new Set();
38095
38395
  const pairs = [];
38096
38396
  for (const t of tris) {
38097
38397
  for (const [u, v] of [[t.a, t.b], [t.b, t.c], [t.c, t.a]]) {
38098
38398
  const i = Math.min(u, v);
38099
38399
  const j = Math.max(u, v);
38100
38400
  const key = i * 1048576 + j;
38101
- if (!seen.has(key)) {
38102
- seen.add(key);
38401
+ if (!seen2.has(key)) {
38402
+ seen2.add(key);
38103
38403
  pairs.push([i, j]);
38104
38404
  }
38105
38405
  }
@@ -38384,8 +38684,8 @@ var Cdt = class {
38384
38684
  const en = this.edgeOrNew(v3, v4);
38385
38685
  this.removeFace(f1);
38386
38686
  this.removeFace(f2);
38387
- const f3 = this.addFace([v4, v2, v3], [e5, e2, en]);
38388
- const f4 = this.addFace([v1, v4, v3], [e4, en, e3]);
38687
+ const f3 = this.addFace([v3, v4, v2], [en, e5, e2]);
38688
+ const f4 = this.addFace([v4, v3, v1], [en, e3, e4]);
38389
38689
  this.swapIfInCircle(f3, v4, v2, v3, e5, e2, en);
38390
38690
  this.swapIfInCircle(f4, v1, v4, v3, e4, en, e3);
38391
38691
  }
@@ -38687,10 +38987,7 @@ function sharedEdge(faces, p3, q3) {
38687
38987
  return { i: p1, j: p2 };
38688
38988
  }
38689
38989
  function addTriEdge(g, t, h, seg2) {
38690
- const dist4 = Math.hypot(
38691
- g.nodes[t].ctr.x - g.nodes[h].ctr.x,
38692
- g.nodes[t].ctr.y - g.nodes[h].ctr.y
38693
- );
38990
+ const dist4 = Math.sqrt(dist2(g.nodes[t].ctr, g.nodes[h].ctr));
38694
38991
  const idx = g.edges.length;
38695
38992
  g.edges.push({ t, h, seg: seg2, dist: dist4 });
38696
38993
  g.nodes[t].edges.push(idx);
@@ -39017,7 +39314,7 @@ var SEP = 15;
39017
39314
  function bisectorTarget(v, cosTheta, sinTheta) {
39018
39315
  return { x: fma(cosTheta, 100, v.x), y: fma(sinTheta, 100, v.y) };
39019
39316
  }
39020
- function distFused(p, q) {
39317
+ function distFused2(p, q) {
39021
39318
  const dx = p.x - q.x;
39022
39319
  const dy = p.y - q.y;
39023
39320
  return Math.sqrt(fma(dx, dx, dy * dy));
@@ -39042,7 +39339,7 @@ function mkCtrlPts(s, mult, prev, v, nxt, trip) {
39042
39339
  }
39043
39340
  const q = triPoint(trip, idx, v, w);
39044
39341
  if (q === null) return null;
39045
- const d = distFused(q, v);
39342
+ const d = distFused2(q, v);
39046
39343
  const sep = d >= mult * SEP ? SEP : d / mult;
39047
39344
  const ps = new Array(mult);
39048
39345
  if (idx < s) {
@@ -39171,8 +39468,8 @@ function chainOf(e) {
39171
39468
  return list;
39172
39469
  }
39173
39470
  function warnNoControlPoints(e) {
39174
- console.warn(
39175
- `Warning: Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`
39471
+ agwarningf(
39472
+ `Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`
39176
39473
  );
39177
39474
  return 1;
39178
39475
  }
@@ -41835,7 +42132,11 @@ function armPow(x, y) {
41835
42132
 
41836
42133
  // src/common/crand.ts
41837
42134
  var C_RAND_MAX = 2147483647;
41838
- var state2 = 1;
42135
+ var UNSEEDED_STATE2 = 1;
42136
+ var state2 = UNSEEDED_STATE2;
42137
+ registerRenderState(() => {
42138
+ state2 = UNSEEDED_STATE2;
42139
+ });
41839
42140
  function csrand(seed) {
41840
42141
  state2 = seed;
41841
42142
  }
@@ -43775,7 +44076,7 @@ function makeAddPoly(n, xmargin, ymargin) {
43775
44076
  case 3 /* SH_POINT */:
43776
44077
  return finishPoly(genRound(n, xmargin, ymargin), POLY_CIRCLE);
43777
44078
  default:
43778
- console.error(`Error: makeAddPoly: unknown shape type ${shapeName(n)}
44079
+ agerrorf(`makeAddPoly: unknown shape type ${shapeName(n)}
43779
44080
  `);
43780
44081
  return null;
43781
44082
  }
@@ -43808,7 +44109,7 @@ function baseShape(n) {
43808
44109
  case 3 /* SH_POINT */:
43809
44110
  return { verts: genRound(n, 0, 0), kind: POLY_CIRCLE };
43810
44111
  default:
43811
- console.error(`Error: makePoly: unknown shape type ${shapeName(n)}
44112
+ agerrorf(`makePoly: unknown shape type ${shapeName(n)}
43812
44113
  `);
43813
44114
  return null;
43814
44115
  }
@@ -45190,7 +45491,7 @@ function warnUnrecognizedOverlap(flag) {
45190
45491
  const s = flag.toLowerCase();
45191
45492
  if (s.startsWith("prism") || NAMED_MODES.has(s)) return;
45192
45493
  if (mapBoolDflt(flag, false) === mapBoolDflt(flag, true)) return;
45193
- console.warn(`Unrecognized overlap value "${flag}" - using false`);
45494
+ agerrLineOn("warn", `Unrecognized overlap value "${flag}" - using false`);
45194
45495
  }
45195
45496
  function getAdjustMode(flag) {
45196
45497
  warnUnrecognizedOverlap(flag);
@@ -45223,7 +45524,7 @@ function adjustLate(g, am) {
45223
45524
  case AM_VPSC:
45224
45525
  return vpscAdjust(g);
45225
45526
  default:
45226
- console.warn(`Unhandled adjust option ${am.print}`);
45527
+ agerrLineOn("warn", `Unhandled adjust option ${am.print}`);
45227
45528
  return 0;
45228
45529
  }
45229
45530
  }
@@ -45442,20 +45743,20 @@ function setSubtreeSize(g) {
45442
45743
  walkAncestorChain(n);
45443
45744
  }
45444
45745
  }
45445
- function applySpanToChild(g, n, next, ratio, seen) {
45746
+ function applySpanToChild(g, n, next, ratio, seen2) {
45446
45747
  const nd2 = rdata(next);
45447
- if (nd2.parent !== n || nd2.span !== 0 || seen.has(next)) return;
45448
- seen.add(next);
45748
+ if (nd2.parent !== n || nd2.span !== 0 || seen2.has(next)) return;
45749
+ seen2.add(next);
45449
45750
  nd2.span = ratio * nd2.subtreeSize;
45450
45751
  if (nd2.nChildren > 0) setChildSubtreeSpans(g, next);
45451
45752
  }
45452
45753
  function setChildSubtreeSpans(g, n) {
45453
45754
  const nd = rdata(n);
45454
45755
  const ratio = nd.span / nd.subtreeSize;
45455
- const seen = /* @__PURE__ */ new Set();
45756
+ const seen2 = /* @__PURE__ */ new Set();
45456
45757
  for (const ep of incidentEdges2(g, n)) {
45457
45758
  const next = neighborOf(ep, n);
45458
- if (next !== null) applySpanToChild(g, n, next, ratio, seen);
45759
+ if (next !== null) applySpanToChild(g, n, next, ratio, seen2);
45459
45760
  }
45460
45761
  }
45461
45762
  function setSubtreeSpans(sg, center) {
@@ -45724,7 +46025,7 @@ var fdpParms = {
45724
46025
  * equivalent). @see lib/fdpgen/fdp.h:fdpParms_s.Mlimit */
45725
46026
  Mlimit: Infinity
45726
46027
  };
45727
- var parms = {
46028
+ var PARMS_INIT = {
45728
46029
  useGrid: 0,
45729
46030
  useNew: 0,
45730
46031
  seed: 0,
@@ -45742,6 +46043,10 @@ var parms = {
45742
46043
  pass1: 0,
45743
46044
  loopcnt: 0
45744
46045
  };
46046
+ var parms = { ...PARMS_INIT };
46047
+ registerRenderState(() => {
46048
+ Object.assign(parms, PARMS_INIT);
46049
+ });
45745
46050
  function cool(t) {
45746
46051
  return parms.T0 * (parms.maxIters - t) / parms.maxIters;
45747
46052
  }
@@ -46386,14 +46691,19 @@ function fdpTLayout(g, xpms) {
46386
46691
  // src/layout/fdp/xlayout.ts
46387
46692
  var DFLT_OVERLAP = "9:prism";
46388
46693
  var PS2INCH3 = (x) => x / 72;
46389
- var xParams = {
46694
+ var XPARAMS_INIT = {
46390
46695
  numIters: 60,
46391
46696
  T0: 0,
46392
46697
  K: 0.3,
46393
46698
  C: 1.5,
46394
46699
  loopcnt: 0
46395
46700
  };
46701
+ var xParams = { ...XPARAMS_INIT };
46396
46702
  var xMarg = { x: 0, y: 0, doAdd: false };
46703
+ registerRenderState(() => {
46704
+ Object.assign(xParams, XPARAMS_INIT);
46705
+ xMarg = { x: 0, y: 0, doAdd: false };
46706
+ });
46397
46707
  function wd2(n) {
46398
46708
  return xMarg.doAdd ? n.info.width / 2 + xMarg.x : n.info.width * xMarg.x / 2;
46399
46709
  }
@@ -47255,7 +47565,7 @@ function fdpSplines(g) {
47255
47565
  );
47256
47566
  }
47257
47567
  if (g.info.n_cluster_edges) {
47258
- console.warn(CLUSTER_EDGE_WARNING);
47568
+ agerrLineOn("warn", CLUSTER_EDGE_WARNING);
47259
47569
  et = EDGETYPE_LINE;
47260
47570
  } else {
47261
47571
  splineEdges1(g, et);
@@ -48677,7 +48987,7 @@ function buildDerivedGraph(g) {
48677
48987
  }
48678
48988
  function buildDerivedEdges(g, dg) {
48679
48989
  const edges = [];
48680
- const seen = /* @__PURE__ */ new Set();
48990
+ const seen2 = /* @__PURE__ */ new Set();
48681
48991
  for (const n of nodesInSeq(g)) {
48682
48992
  for (const e of n.outEdges(g)) {
48683
48993
  if (e.tail === e.head) continue;
@@ -48685,8 +48995,8 @@ function buildDerivedEdges(g, dg) {
48685
48995
  const head = dg.nodes.get(e.head.name);
48686
48996
  if (!tail || !head) continue;
48687
48997
  const key = [tail.name, head.name].sort().join("\0");
48688
- if (seen.has(key)) continue;
48689
- seen.add(key);
48998
+ if (seen2.has(key)) continue;
48999
+ seen2.add(key);
48690
49000
  edges.push({ tail, head, order: 0, origEdge: e });
48691
49001
  }
48692
49002
  }
@@ -49530,12 +49840,12 @@ function svgEndCluster(job) {
49530
49840
  }
49531
49841
 
49532
49842
  // src/render/svg-edge-split.ts
49533
- var DEFAULT_COLOR4 = "black";
49843
+ var DEFAULT_COLOR5 = "black";
49534
49844
  var PENWIDTH_NORMAL4 = 1;
49535
49845
  var PENWIDTH_THRESHOLD4 = 5e-3;
49536
49846
  var EPS3 = 1e-5;
49537
49847
  function dist3(a, b) {
49538
- return Math.hypot(a.x - b.x, a.y - b.y);
49848
+ return Math.sqrt(dist2(a, b));
49539
49849
  }
49540
49850
  function approxLen(list, off) {
49541
49851
  return dist3(list[off], list[off + 1]) + dist3(list[off + 1], list[off + 2]) + dist3(list[off + 2], list[off + 3]);
@@ -49584,7 +49894,7 @@ function emitCurve(list, color, job) {
49584
49894
  }
49585
49895
  function stepSegment(list, s, st, out) {
49586
49896
  if (Math.abs(s.t) < EPS3) return;
49587
- const color = s.color ?? DEFAULT_COLOR4;
49897
+ const color = s.color ?? DEFAULT_COLOR5;
49588
49898
  st.left -= s.t;
49589
49899
  st.endColor = color;
49590
49900
  if (st.first) {
@@ -49603,7 +49913,7 @@ function stepSegment(list, s, st, out) {
49603
49913
  }
49604
49914
  }
49605
49915
  function splitSplineByColor(list, segs) {
49606
- const st = { left: 1, first: true, bzR: list, done: false, endColor: DEFAULT_COLOR4 };
49916
+ const st = { left: 1, first: true, bzR: list, done: false, endColor: DEFAULT_COLOR5 };
49607
49917
  const curves = [];
49608
49918
  for (const s of segs) {
49609
49919
  stepSegment(list, s, st, curves);
@@ -49618,16 +49928,16 @@ function drawSplitSpline(list, segs, job) {
49618
49928
  }
49619
49929
  function emitSplitEdgePaths(e, job, colorList) {
49620
49930
  const segs = parseSegs(colorList).segs;
49621
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR4;
49931
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR5;
49622
49932
  const spl = e.info.spl;
49623
- let endColor = firstColor;
49624
- if (spl === void 0) return { firstColor, endColor };
49933
+ let endColor = firstColor2;
49934
+ if (spl === void 0) return { firstColor: firstColor2, endColor };
49625
49935
  for (let si = 0; si < spl.size; si++) {
49626
49936
  const bz = spl.list[si];
49627
49937
  if (bz === void 0 || bz.size < 4) continue;
49628
49938
  endColor = drawSplitSpline(bz.list, segs, job);
49629
49939
  }
49630
- return { firstColor, endColor };
49940
+ return { firstColor: firstColor2, endColor };
49631
49941
  }
49632
49942
 
49633
49943
  // src/common/taper.ts
@@ -51072,7 +51382,7 @@ var DotWriterBase = class {
51072
51382
  };
51073
51383
 
51074
51384
  // src/render/dot/edge-draw.ts
51075
- var DEFAULT_COLOR5 = "black";
51385
+ var DEFAULT_COLOR6 = "black";
51076
51386
  var DEFAULT_LINE_STYLE = ["solid", "setlinewidth(1)"];
51077
51387
  function emitArrowOp(buf, op, pen) {
51078
51388
  switch (op.kind) {
@@ -51165,8 +51475,8 @@ var EdgeDrawBase = class extends DotWriterBase {
51165
51475
  */
51166
51476
  emitSplitSpline(bzList, colorAttr, edraw, job) {
51167
51477
  const segs = parseSegs(colorAttr).segs;
51168
- const firstColor = segs[0]?.color ?? DEFAULT_COLOR5;
51169
- let endColor = firstColor;
51478
+ const firstColor2 = segs[0]?.color ?? DEFAULT_COLOR6;
51479
+ let endColor = firstColor2;
51170
51480
  for (const bz of bzList) {
51171
51481
  if (bz === void 0 || bz.size < 4) continue;
51172
51482
  const split = splitSplineByColor(bz.list.slice(0, bz.size), segs);
@@ -51175,7 +51485,7 @@ var EdgeDrawBase = class extends DotWriterBase {
51175
51485
  edraw.push(this.styleOp(job), xdotPenColor(resolveRenderColor(c.color)), xdotPoints("B", c.points));
51176
51486
  }
51177
51487
  }
51178
- return { firstColor, endColor };
51488
+ return { firstColor: firstColor2, endColor };
51179
51489
  }
51180
51490
  /**
51181
51491
  * Emit the parallel-multicolor edge spline: one offset Bézier per color,
@@ -51187,7 +51497,7 @@ var EdgeDrawBase = class extends DotWriterBase {
51187
51497
  const segData = bzList.map(
51188
51498
  (bz) => bz !== void 0 && bz.size >= 4 ? buildOffsetLists(bz.list, (2 + numc) / 2) : { offlist: [], tmplist: [] }
51189
51499
  );
51190
- const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR5);
51500
+ const colors = parseSegs(colorAttr).segs.map((s) => s.color ?? DEFAULT_COLOR6);
51191
51501
  for (const color of colors) {
51192
51502
  const pen = xdotPenColor(resolveRenderColor(color));
51193
51503
  for (const sd of segData) {
@@ -51197,8 +51507,8 @@ var EdgeDrawBase = class extends DotWriterBase {
51197
51507
  }
51198
51508
  }
51199
51509
  return {
51200
- headColor: colors[0] ?? DEFAULT_COLOR5,
51201
- tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR5
51510
+ headColor: colors[0] ?? DEFAULT_COLOR6,
51511
+ tailColor: colors[1] ?? colors[0] ?? DEFAULT_COLOR6
51202
51512
  };
51203
51513
  }
51204
51514
  /** Emit one arrow's primitive ops into `buf` (pen/fill from the edge color).
@@ -51709,8 +52019,8 @@ var SvgRenderer = class {
51709
52019
  const numc = (colorAttr.match(/:/g) ?? []).length;
51710
52020
  const numsemi = (colorAttr.match(/;/g) ?? []).length;
51711
52021
  if (numsemi > 0 && numc > 0) {
51712
- const { firstColor, endColor } = emitSplitEdgePaths(e, job, colorAttr);
51713
- emitMulticolorArrows(e, job, endColor, firstColor);
52022
+ const { firstColor: firstColor2, endColor } = emitSplitEdgePaths(e, job, colorAttr);
52023
+ emitMulticolorArrows(e, job, endColor, firstColor2);
51714
52024
  } else if (edgeIsTapered(e)) {
51715
52025
  svgTaperedEdge(e, job);
51716
52026
  } else if (numc > 0) {
@@ -52054,7 +52364,7 @@ function peg$parse(input, options) {
52054
52364
  return s;
52055
52365
  }
52056
52366
  function peg$f13(t, m, attrs) {
52057
- if (m) console.error("Warning: attribute macros not implemented");
52367
+ if (m) agwarningf("attribute macros not implemented", "error");
52058
52368
  return { type: "attr", target: t, attrs };
52059
52369
  }
52060
52370
  function peg$f14(a) {
@@ -55488,8 +55798,8 @@ var StmtProcessor = class _StmtProcessor {
55488
55798
  resolveEndpoint(item, root, scope, directed) {
55489
55799
  if ("type" in item && item.type === "subgraph") {
55490
55800
  this.processSubgraph(item, scope, root, directed);
55491
- const seen = /* @__PURE__ */ new Set();
55492
- 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));
55801
+ const seen2 = /* @__PURE__ */ new Set();
55802
+ 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));
55493
55803
  return nodes.sort((a, b) => a.id - b.id);
55494
55804
  }
55495
55805
  return [this.registry.ensure(item.id, root, scope)];
@@ -55733,22 +56043,22 @@ function countNewlines(s, from, to) {
55733
56043
  return n;
55734
56044
  }
55735
56045
  var HEADER_KEYWORDS = ["strict", "graph", "digraph"];
55736
- function isTruncatedHeaderKeyword(src, step, offset, seen) {
55737
- if (offset !== src.length || step.end !== offset || seen.length > 1) return false;
55738
- if (seen.length === 1 && seen[0].toLowerCase() !== "strict") return false;
56046
+ function isTruncatedHeaderKeyword(src, step, offset, seen2) {
56047
+ if (offset !== src.length || step.end !== offset || seen2.length > 1) return false;
56048
+ if (seen2.length === 1 && seen2[0].toLowerCase() !== "strict") return false;
55739
56049
  const word = step.text.toLowerCase();
55740
56050
  return HEADER_KEYWORDS.some((k) => k.length > word.length && k.startsWith(word));
55741
56051
  }
55742
- function reachesOffset(src, step, offset, seen) {
56052
+ function reachesOffset(src, step, offset, seen2) {
55743
56053
  if (step.end > offset) return true;
55744
- if (isTruncatedHeaderKeyword(src, step, offset, seen)) return true;
56054
+ if (isTruncatedHeaderKeyword(src, step, offset, seen2)) return true;
55745
56055
  if (step.text !== "-" && step.text !== ".") return false;
55746
56056
  return offset <= step.end + (step.text === "-" && src[step.end] === "." ? 1 : 0);
55747
56057
  }
55748
56058
  function scanAtError(src, offset) {
55749
56059
  let line = 1;
55750
56060
  let i = 0;
55751
- const seen = [];
56061
+ const seen2 = [];
55752
56062
  while (i < src.length) {
55753
56063
  const step = lexStep(src, i);
55754
56064
  if (step.kind === "open") {
@@ -55757,10 +56067,10 @@ function scanAtError(src, offset) {
55757
56067
  }
55758
56068
  if (step.kind === "skip" && step.line !== void 0) line = step.line;
55759
56069
  line += countNewlines(src, i, step.end);
55760
- if (step.kind === "token" && reachesOffset(src, step, offset, seen)) {
56070
+ if (step.kind === "token" && reachesOffset(src, step, offset, seen2)) {
55761
56071
  return { state: "INITIAL", text: step.text, line, buffer: "" };
55762
56072
  }
55763
- if (step.kind === "token") seen.push(step.text);
56073
+ if (step.kind === "token") seen2.push(step.text);
55764
56074
  i = step.end;
55765
56075
  }
55766
56076
  return { state: "INITIAL", text: "", line, buffer: "" };
@@ -55953,7 +56263,7 @@ function isPeggyError(err) {
55953
56263
  function warnNumberAmbiguities(src, upTo) {
55954
56264
  for (const a of scanNumberAmbiguities(src, Stripper.strip(src))) {
55955
56265
  if (a.offset > upTo) break;
55956
- console.error(numberAmbiguityMessage(a));
56266
+ agerrFinished(numberAmbiguityMessage(a), "error");
55957
56267
  }
55958
56268
  }
55959
56269
  function parse(src) {
@@ -55967,7 +56277,7 @@ function parse(src) {
55967
56277
  if (isPeggyError(err)) {
55968
56278
  const start = err.location.start;
55969
56279
  warnNumberAmbiguities(src, start.offset);
55970
- console.error(syntaxErrorMessage(src, start.offset));
56280
+ agerrFinished(syntaxErrorMessage(src, start.offset));
55971
56281
  const code = err.found === null ? "SYNTAX_UNEXPECTED_EOF" : "SYNTAX_ERROR";
55972
56282
  throw new ParseError(
55973
56283
  err instanceof Error ? err.message : String(err),
@@ -55992,7 +56302,7 @@ function parse(src) {
55992
56302
  const offset = err instanceof ParseError ? err.location.offset : void 0;
55993
56303
  if (offset !== void 0) {
55994
56304
  warnNumberAmbiguities(src, offset);
55995
- console.error(syntaxErrorMessage(src, offset));
56305
+ agerrFinished(syntaxErrorMessage(src, offset));
55996
56306
  }
55997
56307
  throw err;
55998
56308
  }
@@ -56835,6 +57145,7 @@ function checkRenderArgs(g, format, opts) {
56835
57145
  }
56836
57146
  function render2(g, format, opts) {
56837
57147
  checkRenderArgs(g, format, opts);
57148
+ resetRenderState();
56838
57149
  const engine = opts?.engine ?? "dot";
56839
57150
  const inlineImages = opts?.inlineImages ?? false;
56840
57151
  const ctx = createDefaultContext();
@@ -57031,6 +57342,7 @@ async function renderAsync(g, format, opts) {
57031
57342
  const engine = opts?.engine ?? "dot";
57032
57343
  try {
57033
57344
  const { fontIssues, sizes, bytes } = await prefetchAll(g, opts);
57345
+ resetRenderState();
57034
57346
  const ctx = createDefaultContext();
57035
57347
  if (opts?.imageSizer !== void 0) {
57036
57348
  const sizer = (src) => sizes.get(src) ?? null;
@@ -57095,6 +57407,7 @@ function layoutAndRenderXdot(g, engine) {
57095
57407
  }
57096
57408
  function getDrawOps(g, opts) {
57097
57409
  checkDrawOpsArgs(g, opts);
57410
+ resetRenderState();
57098
57411
  const engine = opts?.engine ?? DEFAULT_DRAW_ENGINE;
57099
57412
  return collectGraphOps(parse(layoutAndRenderXdot(g, engine)));
57100
57413
  }