@knowvah/dot-engine 2.6.2 → 2.6.4
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.
- package/dist/common/htmltable-lex.d.ts +38 -0
- package/dist/common/htmltable-lex.d.ts.map +1 -1
- package/dist/common/htmltable-parse-attrs.d.ts +41 -0
- package/dist/common/htmltable-parse-attrs.d.ts.map +1 -0
- package/dist/common/htmltable-parse.d.ts +3 -0
- package/dist/common/htmltable-parse.d.ts.map +1 -1
- package/dist/common/htmltable-pos.d.ts +17 -0
- package/dist/common/htmltable-pos.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +13 -1
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/make-label.d.ts.map +1 -1
- package/dist/common/spline-midpoint.d.ts +8 -0
- package/dist/common/spline-midpoint.d.ts.map +1 -1
- package/dist/index.js +621 -323
- package/dist/index.js.map +4 -4
- package/dist/label/node.d.ts +7 -1
- package/dist/label/node.d.ts.map +1 -1
- package/dist/layout/circo/position-helpers.d.ts +15 -3
- package/dist/layout/circo/position-helpers.d.ts.map +1 -1
- package/dist/layout/circo/position.d.ts +17 -1
- package/dist/layout/circo/position.d.ts.map +1 -1
- package/dist/layout/dot/ortho-adapter.d.ts.map +1 -1
- package/dist/layout/dot/splines-flat-labeled.d.ts.map +1 -1
- package/dist/layout/neato/multispline.d.ts.map +1 -1
- package/dist/layout/pack/poly-pack.d.ts +2 -18
- package/dist/layout/pack/poly-pack.d.ts.map +1 -1
- package/dist/pathplan/shortest.d.ts.map +1 -1
- package/dist/render.js +774 -476
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/common/htmltable-lex.ts +265 -5
- package/src/common/htmltable-parse-attrs.ts +166 -0
- package/src/common/htmltable-parse.ts +262 -242
- package/src/common/htmltable-pos.ts +37 -38
- package/src/common/htmltable.ts +139 -45
- package/src/common/make-label.ts +19 -3
- package/src/common/spline-midpoint.ts +30 -9
- package/src/label/node.ts +8 -2
- package/src/layout/circo/position-helpers.ts +28 -17
- package/src/layout/circo/position.ts +28 -7
- package/src/layout/dot/__fixtures__/2796-flat-labeled-lost.dot +161 -0
- package/src/layout/dot/ortho-adapter.ts +20 -9
- package/src/layout/dot/splines-flat-labeled.ts +3 -1
- package/src/layout/neato/multispline.ts +17 -5
- package/src/layout/pack/poly-pack.ts +5 -31
- package/src/pathplan/shortest.ts +15 -2
package/dist/render.js
CHANGED
|
@@ -5854,16 +5854,152 @@ function parseOpenToken(inner) {
|
|
|
5854
5854
|
checkTag(tag);
|
|
5855
5855
|
return { type: "open", tag: normalizeTag(tag), attrs: parseAttrs(inner.slice(sp + 1)) };
|
|
5856
5856
|
}
|
|
5857
|
-
|
|
5857
|
+
var XML_ERROR_UNDEFINED_ENTITY = "undefined entity";
|
|
5858
|
+
var XML_ERROR_TAG_MISMATCH = "mismatched tag";
|
|
5859
|
+
var XML_ERROR_INVALID_TOKEN = "not well-formed (invalid token)";
|
|
5860
|
+
var XML_ERROR_DUPLICATE_ATTRIBUTE = "duplicate attribute";
|
|
5861
|
+
var XML_PREDEFINED_ENTITIES = /* @__PURE__ */ new Set(["lt", "gt", "amp", "quot", "apos"]);
|
|
5862
|
+
var XML_NAME = /^[A-Za-z_:][\w.:-]*$/;
|
|
5863
|
+
var HtmlLexError = class extends HtmlParseError {
|
|
5864
|
+
diagnostics;
|
|
5865
|
+
constructor(tag, message, diagnostics) {
|
|
5866
|
+
super(tag);
|
|
5867
|
+
this.message = message;
|
|
5868
|
+
this.diagnostics = diagnostics;
|
|
5869
|
+
}
|
|
5870
|
+
};
|
|
5871
|
+
function htmlErrorInLine(message, line, context) {
|
|
5872
|
+
const text = `${message} in line ${line} `;
|
|
5873
|
+
return new HtmlLexError(message, text, [`Error: ${text}`, `... ${context} ...`]);
|
|
5874
|
+
}
|
|
5875
|
+
var chunkInfo = /* @__PURE__ */ new WeakMap();
|
|
5876
|
+
function lineAt(src, pos) {
|
|
5877
|
+
let line = 1;
|
|
5878
|
+
for (let k = 0; k < pos; k++) {
|
|
5879
|
+
if (src[k] === "\n" || src[k] === "\r" && src[k + 1] !== "\n") line++;
|
|
5880
|
+
}
|
|
5881
|
+
return line;
|
|
5882
|
+
}
|
|
5883
|
+
function chunkLine(info) {
|
|
5884
|
+
if (info.src[info.pos] === "<") return lineAt(info.src, info.pos);
|
|
5885
|
+
const last = info.src.lastIndexOf("\n", info.end - 1);
|
|
5886
|
+
if (last < info.pos) return lineAt(info.src, info.pos);
|
|
5887
|
+
return lineAt(info.src, last === info.end - 1 ? last : last + 1);
|
|
5888
|
+
}
|
|
5889
|
+
function htmlErrorAtToken(message, tok) {
|
|
5890
|
+
const info = tok === void 0 ? void 0 : chunkInfo.get(tok);
|
|
5891
|
+
if (info === void 0) return void 0;
|
|
5892
|
+
return htmlErrorInLine(message, chunkLine(info), info.context);
|
|
5893
|
+
}
|
|
5894
|
+
function chunkEnd(src, i) {
|
|
5895
|
+
const j = src[i] === "<" ? src.indexOf(">", i + 1) : src.indexOf("<", i);
|
|
5896
|
+
if (j < 0) return src.length;
|
|
5897
|
+
return src[i] === "<" ? j + 1 : j;
|
|
5898
|
+
}
|
|
5899
|
+
function findUndefinedEntity(text) {
|
|
5900
|
+
for (let t = text.indexOf("&"); t >= 0; t = text.indexOf("&", t + 1)) {
|
|
5901
|
+
if (text[t + 1] === "#") continue;
|
|
5902
|
+
const semi = text.indexOf(";", t + 1);
|
|
5903
|
+
if (semi < 0) continue;
|
|
5904
|
+
const key = text.slice(t + 1, semi);
|
|
5905
|
+
if (XML_NAME.test(key) && !Object.hasOwn(HTML_ENTITIES, key) && !XML_PREDEFINED_ENTITIES.has(key)) {
|
|
5906
|
+
return t;
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
return -1;
|
|
5910
|
+
}
|
|
5911
|
+
function parseTagChunk(chunk) {
|
|
5912
|
+
if (!chunk.endsWith(">")) return void 0;
|
|
5913
|
+
const body = chunk.slice(1, -1);
|
|
5914
|
+
if (body.startsWith("!")) return void 0;
|
|
5915
|
+
const close = body.startsWith("/");
|
|
5916
|
+
const name = /^[^\s/>]*/.exec(close ? body.slice(1) : body)?.[0] ?? "";
|
|
5917
|
+
return { close, selfClose: !close && body.endsWith("/"), name };
|
|
5918
|
+
}
|
|
5919
|
+
var ATTR_NAME = /^[A-Za-z_:][\w.:-]*/;
|
|
5920
|
+
var isSpace = (c) => c !== void 0 && /\s/.test(c);
|
|
5921
|
+
var invalidToken = (offset) => ({ message: XML_ERROR_INVALID_TOKEN, offset });
|
|
5922
|
+
function skipSpace(chunk, i) {
|
|
5923
|
+
let j = i;
|
|
5924
|
+
while (isSpace(chunk[j])) j++;
|
|
5925
|
+
return j;
|
|
5926
|
+
}
|
|
5927
|
+
function readAttrPair(chunk, i) {
|
|
5928
|
+
const name = ATTR_NAME.exec(chunk.slice(i))?.[0];
|
|
5929
|
+
if (name === void 0) return invalidToken(i);
|
|
5930
|
+
let j = skipSpace(chunk, i + name.length);
|
|
5931
|
+
if (chunk[j] !== "=") return invalidToken(j);
|
|
5932
|
+
j = skipSpace(chunk, j + 1);
|
|
5933
|
+
const q = chunk[j];
|
|
5934
|
+
if (q !== '"' && q !== "'") return invalidToken(j);
|
|
5935
|
+
const end = chunk.indexOf(q, j + 1);
|
|
5936
|
+
return end < 0 ? void 0 : { name, next: end + 1 };
|
|
5937
|
+
}
|
|
5938
|
+
function findAttrError(chunk, from) {
|
|
5939
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5940
|
+
let dup;
|
|
5941
|
+
let i = skipSpace(chunk, from);
|
|
5942
|
+
while (chunk[i] !== ">" && !(chunk[i] === "/" && chunk[i + 1] === ">")) {
|
|
5943
|
+
const pair = readAttrPair(chunk, i);
|
|
5944
|
+
if (pair === void 0) return void 0;
|
|
5945
|
+
if ("message" in pair) return pair;
|
|
5946
|
+
if (seen.has(pair.name) && dup === void 0) dup = { message: XML_ERROR_DUPLICATE_ATTRIBUTE, offset: i };
|
|
5947
|
+
seen.add(pair.name);
|
|
5948
|
+
i = skipSpace(chunk, pair.next);
|
|
5949
|
+
}
|
|
5950
|
+
return dup;
|
|
5951
|
+
}
|
|
5952
|
+
function checkTagChunk(src, start, st) {
|
|
5953
|
+
const tag = parseTagChunk(st.curr);
|
|
5954
|
+
if (tag === void 0) return;
|
|
5955
|
+
if (tag.close) {
|
|
5956
|
+
if (st.stack.length > 0 && st.stack.pop() !== tag.name) {
|
|
5957
|
+
throw htmlErrorInLine(XML_ERROR_TAG_MISMATCH, lineAt(src, start), st.prev + st.curr);
|
|
5958
|
+
}
|
|
5959
|
+
} else {
|
|
5960
|
+
const bad = findAttrError(st.curr, 1 + tag.name.length);
|
|
5961
|
+
if (bad !== void 0) {
|
|
5962
|
+
throw htmlErrorInLine(bad.message, lineAt(src, start + bad.offset), st.prev + st.curr);
|
|
5963
|
+
}
|
|
5964
|
+
if (!tag.selfClose) st.stack.push(tag.name);
|
|
5965
|
+
}
|
|
5966
|
+
if (KNOWN_TAGS.has(tag.name.toUpperCase())) return;
|
|
5967
|
+
const text = `Unknown HTML element <${tag.name}> on line ${lineAt(src, start)} `;
|
|
5968
|
+
throw new HtmlLexError(tag.name.toUpperCase(), text, [`Error: ${text}`]);
|
|
5969
|
+
}
|
|
5970
|
+
function checkChunk(src, start, st) {
|
|
5971
|
+
if (st.curr.startsWith("<")) {
|
|
5972
|
+
checkTagChunk(src, start, st);
|
|
5973
|
+
return;
|
|
5974
|
+
}
|
|
5975
|
+
const off = findUndefinedEntity(st.curr);
|
|
5976
|
+
if (off >= 0) {
|
|
5977
|
+
throw htmlErrorInLine(XML_ERROR_UNDEFINED_ENTITY, lineAt(src, start + off), st.prev + st.curr);
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
function tokenizeDeferred(src) {
|
|
5858
5981
|
const tokens = [];
|
|
5982
|
+
const st = { stack: [], prev: "", curr: "" };
|
|
5859
5983
|
let i = 0;
|
|
5860
|
-
|
|
5861
|
-
|
|
5984
|
+
try {
|
|
5985
|
+
while (i < src.length) {
|
|
5986
|
+
const first = tokens.length;
|
|
5987
|
+
const start = i;
|
|
5988
|
+
st.prev = st.curr;
|
|
5989
|
+
st.curr = src.slice(i, chunkEnd(src, i));
|
|
5990
|
+
checkChunk(src, i, st);
|
|
5991
|
+
i = src[i] === "<" ? scanTag(src, i, tokens) : scanText(src, i, tokens);
|
|
5992
|
+
const info = { src, pos: start, end: i, context: st.prev + st.curr };
|
|
5993
|
+
for (let k = first; k < tokens.length; k++) chunkInfo.set(tokens[k], info);
|
|
5994
|
+
}
|
|
5995
|
+
} catch (e) {
|
|
5996
|
+
if (e instanceof HtmlParseError) return { tokens, error: e };
|
|
5997
|
+
throw e;
|
|
5862
5998
|
}
|
|
5863
|
-
return tokens;
|
|
5999
|
+
return { tokens };
|
|
5864
6000
|
}
|
|
5865
6001
|
|
|
5866
|
-
// src/common/htmltable-parse.ts
|
|
6002
|
+
// src/common/htmltable-parse-attrs.ts
|
|
5867
6003
|
function anchorAttr(v) {
|
|
5868
6004
|
return v === void 0 ? void 0 : htmlEntityUTF8(v);
|
|
5869
6005
|
}
|
|
@@ -5886,6 +6022,81 @@ var num = (s) => {
|
|
|
5886
6022
|
const n = parseInt(s, 10);
|
|
5887
6023
|
return isNaN(n) ? void 0 : n;
|
|
5888
6024
|
};
|
|
6025
|
+
var parseFixedSize = (a) => a["fixedsize"]?.toUpperCase() === "TRUE" ? true : void 0;
|
|
6026
|
+
var parseTitle = (a) => a["title"] !== void 0 ? a["title"] : a["tooltip"];
|
|
6027
|
+
var parseSides = (v) => {
|
|
6028
|
+
if (v === void 0) return void 0;
|
|
6029
|
+
let flags = 0;
|
|
6030
|
+
for (const c of v.toLowerCase()) {
|
|
6031
|
+
if (c === "l") flags |= BORDER_LEFT;
|
|
6032
|
+
else if (c === "t") flags |= BORDER_TOP;
|
|
6033
|
+
else if (c === "r") flags |= BORDER_RIGHT;
|
|
6034
|
+
else if (c === "b") flags |= BORDER_BOTTOM;
|
|
6035
|
+
}
|
|
6036
|
+
if (flags === 0 || flags === BORDER_MASK) return void 0;
|
|
6037
|
+
return flags;
|
|
6038
|
+
};
|
|
6039
|
+
var parseGradientAngle = (v) => {
|
|
6040
|
+
if (v === void 0) return void 0;
|
|
6041
|
+
const n = parseInt(v, 10);
|
|
6042
|
+
if (isNaN(n) || String(n) !== v.trim()) return void 0;
|
|
6043
|
+
if (n < 0 || n > 360) return void 0;
|
|
6044
|
+
return n;
|
|
6045
|
+
};
|
|
6046
|
+
var parseColumns = (v) => v === "*" ? true : void 0;
|
|
6047
|
+
var parseRows = (v) => v === "*" ? true : void 0;
|
|
6048
|
+
var buildCell = (content, a) => ({
|
|
6049
|
+
kind: "cell",
|
|
6050
|
+
content,
|
|
6051
|
+
port: a["port"],
|
|
6052
|
+
align: parseAlign(a["align"] !== void 0 ? a["align"] : ""),
|
|
6053
|
+
valign: parseVAlign(a["valign"] !== void 0 ? a["valign"] : ""),
|
|
6054
|
+
balign: parseAlign(a["balign"] !== void 0 ? a["balign"] : ""),
|
|
6055
|
+
bgcolor: a["bgcolor"],
|
|
6056
|
+
color: a["color"],
|
|
6057
|
+
border: num(a["border"]),
|
|
6058
|
+
cellpadding: num(a["cellpadding"]),
|
|
6059
|
+
cellspacing: num(a["cellspacing"]),
|
|
6060
|
+
sides: parseSides(a["sides"]),
|
|
6061
|
+
gradientangle: parseGradientAngle(a["gradientangle"]),
|
|
6062
|
+
style: a["style"],
|
|
6063
|
+
width: num(a["width"]),
|
|
6064
|
+
height: num(a["height"]),
|
|
6065
|
+
fixedsize: parseFixedSize(a),
|
|
6066
|
+
colspan: num(a["colspan"]),
|
|
6067
|
+
rowspan: num(a["rowspan"]),
|
|
6068
|
+
href: anchorAttr(a["href"]),
|
|
6069
|
+
title: parseTitle(a),
|
|
6070
|
+
target: anchorAttr(a["target"]),
|
|
6071
|
+
id: a["id"]
|
|
6072
|
+
});
|
|
6073
|
+
var buildTable = (rows, a) => ({
|
|
6074
|
+
kind: "table",
|
|
6075
|
+
rows,
|
|
6076
|
+
border: num(a["border"]),
|
|
6077
|
+
cellborder: num(a["cellborder"]),
|
|
6078
|
+
cellspacing: num(a["cellspacing"]),
|
|
6079
|
+
cellpadding: num(a["cellpadding"]),
|
|
6080
|
+
bgcolor: a["bgcolor"],
|
|
6081
|
+
color: a["color"],
|
|
6082
|
+
style: a["style"],
|
|
6083
|
+
align: parseAlign(a["align"] !== void 0 ? a["align"] : ""),
|
|
6084
|
+
valign: parseVAlign(a["valign"] !== void 0 ? a["valign"] : ""),
|
|
6085
|
+
fixedsize: parseFixedSize(a),
|
|
6086
|
+
width: num(a["width"]),
|
|
6087
|
+
height: num(a["height"]),
|
|
6088
|
+
href: anchorAttr(a["href"]),
|
|
6089
|
+
title: parseTitle(a),
|
|
6090
|
+
target: anchorAttr(a["target"]),
|
|
6091
|
+
id: a["id"],
|
|
6092
|
+
port: a["port"],
|
|
6093
|
+
sides: parseSides(a["sides"]),
|
|
6094
|
+
gradientangle: parseGradientAngle(a["gradientangle"]),
|
|
6095
|
+
vrule: parseColumns(a["columns"]),
|
|
6096
|
+
hrule: parseRows(a["rows"])
|
|
6097
|
+
});
|
|
6098
|
+
|
|
6099
|
+
// src/common/htmltable-parse.ts
|
|
5889
6100
|
var definedOf = (s) => Object.fromEntries(
|
|
5890
6101
|
Object.entries(s).filter(([, v]) => v !== void 0)
|
|
5891
6102
|
);
|
|
@@ -5909,6 +6120,11 @@ var fontItemProps = (f) => {
|
|
|
5909
6120
|
if (f.fontSize !== void 0) out.fontSize = f.fontSize;
|
|
5910
6121
|
return out;
|
|
5911
6122
|
};
|
|
6123
|
+
var MSG_SYNTAX_ERROR = "syntax error";
|
|
6124
|
+
var MSG_TEXT_BEFORE_TABLE = "Syntax error: non-space string used before <TABLE>";
|
|
6125
|
+
var MSG_TEXT_AFTER_TABLE = "Syntax error: non-space string used after </TABLE>";
|
|
6126
|
+
var nonSpace = (text) => /[^ \t\n\r]/.test(text);
|
|
6127
|
+
var parseError = (s, tok, message) => (tok === void 0 ? s.pending : htmlErrorAtToken(message, tok)) ?? new HtmlParseError(message);
|
|
5912
6128
|
var peek = (s) => s.tokens[s.pos];
|
|
5913
6129
|
var consume = (s) => {
|
|
5914
6130
|
const t = s.tokens[s.pos];
|
|
@@ -5927,12 +6143,20 @@ var inlineFontState = (tag, _attrs) => {
|
|
|
5927
6143
|
if (tag === "SUP") fs.superscript = true;
|
|
5928
6144
|
return fs;
|
|
5929
6145
|
};
|
|
6146
|
+
var consumeClose = (s, tag) => {
|
|
6147
|
+
const nxt = peek(s);
|
|
6148
|
+
if (nxt === void 0) return;
|
|
6149
|
+
if (nxt.type === "close" && nxt.tag === tag) {
|
|
6150
|
+
consume(s);
|
|
6151
|
+
return;
|
|
6152
|
+
}
|
|
6153
|
+
throw parseError(s, nxt, MSG_SYNTAX_ERROR);
|
|
6154
|
+
};
|
|
5930
6155
|
var applyBrTag = (s, t, fontStack, items) => {
|
|
5931
6156
|
consume(s);
|
|
5932
6157
|
const font = fontStack[fontStack.length - 1] ?? {};
|
|
5933
6158
|
items.push({ br: true, brAlign: parseAlign(t.attrs["align"] ?? ""), ...fontItemProps(font) });
|
|
5934
|
-
|
|
5935
|
-
if (nxt?.type === "close" && nxt.tag === "BR") consume(s);
|
|
6159
|
+
consumeClose(s, "BR");
|
|
5936
6160
|
};
|
|
5937
6161
|
var applyFontTag = (s, t, fontStack, items) => {
|
|
5938
6162
|
consume(s);
|
|
@@ -5989,12 +6213,6 @@ var parseText = (s, fontStack) => {
|
|
|
5989
6213
|
}
|
|
5990
6214
|
return { kind: "text", items };
|
|
5991
6215
|
};
|
|
5992
|
-
var parseHrContent = (s) => {
|
|
5993
|
-
consume(s);
|
|
5994
|
-
const nxt = peek(s);
|
|
5995
|
-
if (nxt?.type === "close" && nxt.tag === "HR") consume(s);
|
|
5996
|
-
return { kind: "hr" };
|
|
5997
|
-
};
|
|
5998
6216
|
var parseImgContent = (s, t, cellAttrs) => {
|
|
5999
6217
|
consume(s);
|
|
6000
6218
|
const img = {
|
|
@@ -6002,24 +6220,54 @@ var parseImgContent = (s, t, cellAttrs) => {
|
|
|
6002
6220
|
src: cellAttrs["src"] ?? t.attrs["src"] ?? "",
|
|
6003
6221
|
scale: t.attrs["scale"]
|
|
6004
6222
|
};
|
|
6005
|
-
|
|
6006
|
-
if (nxt?.type === "close" && nxt.tag === "IMG") consume(s);
|
|
6223
|
+
consumeClose(s, "IMG");
|
|
6007
6224
|
return img;
|
|
6008
6225
|
};
|
|
6009
|
-
var
|
|
6010
|
-
if (
|
|
6011
|
-
if (
|
|
6012
|
-
|
|
6226
|
+
var scanCellTable = (s, t, fontStack, st) => {
|
|
6227
|
+
if (st.kind === "image" || st.kind === "table") throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6228
|
+
if (st.textNonSpace) throw parseError(s, t, MSG_TEXT_BEFORE_TABLE);
|
|
6229
|
+
const tbl = parseTable(s, fontStack);
|
|
6230
|
+
st.kind = "table";
|
|
6231
|
+
return [tbl];
|
|
6232
|
+
};
|
|
6233
|
+
var scanCellText = (s, t, fontStack, st) => {
|
|
6234
|
+
const start = s.pos;
|
|
6013
6235
|
const txt = parseText(s, fontStack);
|
|
6236
|
+
if (s.pos === start) throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6237
|
+
if (txt.items.some((i) => i.text !== void 0 && nonSpace(i.text))) st.textNonSpace = true;
|
|
6238
|
+
st.kind = "text";
|
|
6014
6239
|
return txt.items.length > 0 ? [txt] : [];
|
|
6015
6240
|
};
|
|
6241
|
+
var scanAfterTable = (s, t, st) => {
|
|
6242
|
+
if (t.type !== "text") throw parseError(s, t, st.afterNonSpace ? MSG_TEXT_AFTER_TABLE : MSG_SYNTAX_ERROR);
|
|
6243
|
+
consume(s);
|
|
6244
|
+
if (nonSpace(t.value)) st.afterNonSpace = true;
|
|
6245
|
+
return [];
|
|
6246
|
+
};
|
|
6247
|
+
var scanCellImage = (s, t, cellAttrs, st) => {
|
|
6248
|
+
if (st.kind !== "none") throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6249
|
+
st.kind = "image";
|
|
6250
|
+
return [parseImgContent(s, t, cellAttrs)];
|
|
6251
|
+
};
|
|
6252
|
+
var scanCellItem = (s, t, cellAttrs, fontStack, st) => {
|
|
6253
|
+
if (st.kind === "table") return scanAfterTable(s, t, st);
|
|
6254
|
+
if (t.type === "open" && t.tag === "TABLE") return scanCellTable(s, t, fontStack, st);
|
|
6255
|
+
if (t.type === "open" && t.tag === "IMG") return scanCellImage(s, t, cellAttrs, st);
|
|
6256
|
+
if (st.kind === "image") throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6257
|
+
return scanCellText(s, t, fontStack, st);
|
|
6258
|
+
};
|
|
6259
|
+
var endsCell = (s, t, st) => {
|
|
6260
|
+
if (t.type !== "close") return false;
|
|
6261
|
+
const afterText = st.kind === "table" && st.afterNonSpace;
|
|
6262
|
+
if (t.tag === "TD" && !afterText) return true;
|
|
6263
|
+
throw parseError(s, t, afterText ? MSG_TEXT_AFTER_TABLE : MSG_SYNTAX_ERROR);
|
|
6264
|
+
};
|
|
6016
6265
|
var parseCellContent = (s, cellAttrs, fontStack) => {
|
|
6017
6266
|
const content = [];
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
if (
|
|
6021
|
-
|
|
6022
|
-
content.push(...parseCellItem(s, t, cellAttrs, fontStack));
|
|
6267
|
+
const st = { kind: "none", textNonSpace: false, afterNonSpace: false };
|
|
6268
|
+
for (let t = peek(s); t !== void 0; t = peek(s)) {
|
|
6269
|
+
if (endsCell(s, t, st)) break;
|
|
6270
|
+
content.push(...scanCellItem(s, t, cellAttrs, fontStack, st));
|
|
6023
6271
|
}
|
|
6024
6272
|
const nxt = peek(s);
|
|
6025
6273
|
if (nxt?.type === "close" && nxt.tag === "TD") consume(s);
|
|
@@ -6027,134 +6275,85 @@ var parseCellContent = (s, cellAttrs, fontStack) => {
|
|
|
6027
6275
|
if (tbl !== void 0) return [tbl];
|
|
6028
6276
|
return content;
|
|
6029
6277
|
};
|
|
6030
|
-
var parseFixedSize = (a) => a["fixedsize"]?.toUpperCase() === "TRUE" ? true : void 0;
|
|
6031
|
-
var parseTitle = (a) => a["title"] !== void 0 ? a["title"] : a["tooltip"];
|
|
6032
|
-
var parseSides = (v) => {
|
|
6033
|
-
if (v === void 0) return void 0;
|
|
6034
|
-
let flags = 0;
|
|
6035
|
-
for (const c of v.toLowerCase()) {
|
|
6036
|
-
if (c === "l") flags |= BORDER_LEFT;
|
|
6037
|
-
else if (c === "t") flags |= BORDER_TOP;
|
|
6038
|
-
else if (c === "r") flags |= BORDER_RIGHT;
|
|
6039
|
-
else if (c === "b") flags |= BORDER_BOTTOM;
|
|
6040
|
-
}
|
|
6041
|
-
if (flags === 0 || flags === BORDER_MASK) return void 0;
|
|
6042
|
-
return flags;
|
|
6043
|
-
};
|
|
6044
|
-
var parseGradientAngle = (v) => {
|
|
6045
|
-
if (v === void 0) return void 0;
|
|
6046
|
-
const n = parseInt(v, 10);
|
|
6047
|
-
if (isNaN(n) || String(n) !== v.trim()) return void 0;
|
|
6048
|
-
if (n < 0 || n > 360) return void 0;
|
|
6049
|
-
return n;
|
|
6050
|
-
};
|
|
6051
|
-
var parseColumns = (v) => v === "*" ? true : void 0;
|
|
6052
|
-
var parseRows = (v) => v === "*" ? true : void 0;
|
|
6053
|
-
var buildCell = (content, a) => ({
|
|
6054
|
-
kind: "cell",
|
|
6055
|
-
content,
|
|
6056
|
-
port: a["port"],
|
|
6057
|
-
align: parseAlign(a["align"] !== void 0 ? a["align"] : ""),
|
|
6058
|
-
valign: parseVAlign(a["valign"] !== void 0 ? a["valign"] : ""),
|
|
6059
|
-
balign: parseAlign(a["balign"] !== void 0 ? a["balign"] : ""),
|
|
6060
|
-
bgcolor: a["bgcolor"],
|
|
6061
|
-
color: a["color"],
|
|
6062
|
-
border: num(a["border"]),
|
|
6063
|
-
cellpadding: num(a["cellpadding"]),
|
|
6064
|
-
cellspacing: num(a["cellspacing"]),
|
|
6065
|
-
sides: parseSides(a["sides"]),
|
|
6066
|
-
gradientangle: parseGradientAngle(a["gradientangle"]),
|
|
6067
|
-
style: a["style"],
|
|
6068
|
-
width: num(a["width"]),
|
|
6069
|
-
height: num(a["height"]),
|
|
6070
|
-
fixedsize: parseFixedSize(a),
|
|
6071
|
-
colspan: num(a["colspan"]),
|
|
6072
|
-
rowspan: num(a["rowspan"]),
|
|
6073
|
-
href: anchorAttr(a["href"]),
|
|
6074
|
-
title: parseTitle(a),
|
|
6075
|
-
target: anchorAttr(a["target"]),
|
|
6076
|
-
id: a["id"]
|
|
6077
|
-
});
|
|
6078
6278
|
var parseCell = (s, attrs, fontStack) => buildCell(parseCellContent(s, attrs, fontStack), attrs);
|
|
6079
|
-
var
|
|
6279
|
+
var parseRowVr = (s, t, cells) => {
|
|
6280
|
+
const prev = cells[cells.length - 1];
|
|
6281
|
+
if (prev === void 0) throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6282
|
+
consume(s);
|
|
6283
|
+
consumeClose(s, "VR");
|
|
6284
|
+
prev.vruled = true;
|
|
6285
|
+
};
|
|
6286
|
+
var scanRowCell = (s, t, fontStack, rs) => {
|
|
6080
6287
|
if (t.type === "open" && t.tag === "TD") {
|
|
6081
6288
|
consume(s);
|
|
6082
|
-
cells.push(parseCell(s, t.attrs, fontStack));
|
|
6083
|
-
|
|
6289
|
+
rs.cells.push(parseCell(s, t.attrs, fontStack));
|
|
6290
|
+
rs.needCell = false;
|
|
6291
|
+
} else if (t.type === "open" && t.tag === "VR" && !rs.needCell) {
|
|
6292
|
+
parseRowVr(s, t, rs.cells);
|
|
6293
|
+
rs.needCell = true;
|
|
6294
|
+
} else {
|
|
6295
|
+
throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6084
6296
|
}
|
|
6085
|
-
|
|
6297
|
+
};
|
|
6298
|
+
var scanRowToken = (s, t, fontStack, rs) => {
|
|
6299
|
+
if (t.type === "text") {
|
|
6086
6300
|
consume(s);
|
|
6087
|
-
|
|
6088
|
-
if (nxt?.type === "close" && nxt.tag === "VR") consume(s);
|
|
6089
|
-
const prev = cells[cells.length - 1];
|
|
6090
|
-
if (prev === void 0) throw new HtmlParseError("VR");
|
|
6091
|
-
prev.vruled = true;
|
|
6092
|
-
return;
|
|
6301
|
+
return false;
|
|
6093
6302
|
}
|
|
6094
|
-
|
|
6303
|
+
if (t.type !== "close" || t.tag !== "TR") {
|
|
6304
|
+
scanRowCell(s, t, fontStack, rs);
|
|
6305
|
+
return false;
|
|
6306
|
+
}
|
|
6307
|
+
if (rs.cells.length === 0 || rs.needCell) throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6308
|
+
return true;
|
|
6095
6309
|
};
|
|
6096
6310
|
var parseRow = (s, fontStack) => {
|
|
6097
|
-
const
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
if (!t) break;
|
|
6101
|
-
if (t.type === "close" && t.tag === "TR") break;
|
|
6102
|
-
processRowToken(s, t, cells, fontStack);
|
|
6311
|
+
const rs = { cells: [], needCell: false };
|
|
6312
|
+
for (let t = peek(s); t !== void 0; t = peek(s)) {
|
|
6313
|
+
if (scanRowToken(s, t, fontStack, rs)) break;
|
|
6103
6314
|
}
|
|
6104
6315
|
const nxt = peek(s);
|
|
6105
6316
|
if (nxt?.type === "close" && nxt.tag === "TR") consume(s);
|
|
6106
|
-
return { cells };
|
|
6317
|
+
return { cells: rs.cells };
|
|
6318
|
+
};
|
|
6319
|
+
var scanTableRow = (s, t, fontStack, ts) => {
|
|
6320
|
+
if (t.type === "open" && t.tag === "TR") {
|
|
6321
|
+
consume(s);
|
|
6322
|
+
ts.rows.push(parseTableRow(s, fontStack, ts));
|
|
6323
|
+
ts.needRow = false;
|
|
6324
|
+
} else if (t.type === "open" && t.tag === "HR" && ts.rows.length > 0 && !ts.needRow) {
|
|
6325
|
+
consumeRowHr(s, ts.rows);
|
|
6326
|
+
ts.needRow = true;
|
|
6327
|
+
} else {
|
|
6328
|
+
throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6329
|
+
}
|
|
6330
|
+
};
|
|
6331
|
+
var scanTableToken = (s, t, fontStack, ts) => {
|
|
6332
|
+
if (t.type === "text") {
|
|
6333
|
+
consume(s);
|
|
6334
|
+
return false;
|
|
6335
|
+
}
|
|
6336
|
+
if (t.type !== "close" || t.tag !== "TABLE") {
|
|
6337
|
+
scanTableRow(s, t, fontStack, ts);
|
|
6338
|
+
return false;
|
|
6339
|
+
}
|
|
6340
|
+
if (ts.rows.length === 0 || ts.needRow) throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
6341
|
+
consume(s);
|
|
6342
|
+
return true;
|
|
6107
6343
|
};
|
|
6108
|
-
var buildTable = (rows, a) => ({
|
|
6109
|
-
kind: "table",
|
|
6110
|
-
rows,
|
|
6111
|
-
border: num(a["border"]),
|
|
6112
|
-
cellborder: num(a["cellborder"]),
|
|
6113
|
-
cellspacing: num(a["cellspacing"]),
|
|
6114
|
-
cellpadding: num(a["cellpadding"]),
|
|
6115
|
-
bgcolor: a["bgcolor"],
|
|
6116
|
-
color: a["color"],
|
|
6117
|
-
style: a["style"],
|
|
6118
|
-
align: parseAlign(a["align"] !== void 0 ? a["align"] : ""),
|
|
6119
|
-
valign: parseVAlign(a["valign"] !== void 0 ? a["valign"] : ""),
|
|
6120
|
-
fixedsize: parseFixedSize(a),
|
|
6121
|
-
width: num(a["width"]),
|
|
6122
|
-
height: num(a["height"]),
|
|
6123
|
-
href: anchorAttr(a["href"]),
|
|
6124
|
-
title: parseTitle(a),
|
|
6125
|
-
target: anchorAttr(a["target"]),
|
|
6126
|
-
id: a["id"],
|
|
6127
|
-
port: a["port"],
|
|
6128
|
-
sides: parseSides(a["sides"]),
|
|
6129
|
-
gradientangle: parseGradientAngle(a["gradientangle"]),
|
|
6130
|
-
vrule: parseColumns(a["columns"]),
|
|
6131
|
-
hrule: parseRows(a["rows"])
|
|
6132
|
-
});
|
|
6133
6344
|
var parseTable = (s, fontStack) => {
|
|
6134
6345
|
const open = consume(s);
|
|
6135
6346
|
if (open.type !== "open" || open.tag !== "TABLE") throw new HtmlParseError("TABLE");
|
|
6136
|
-
const
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
break;
|
|
6145
|
-
}
|
|
6146
|
-
if (t.type === "open" && t.tag === "TR") {
|
|
6147
|
-
consume(s);
|
|
6148
|
-
rows.push(parseTableRow(s, fontStack, { hrule, vrule }));
|
|
6149
|
-
continue;
|
|
6150
|
-
}
|
|
6151
|
-
if (t.type === "open" && t.tag === "HR") {
|
|
6152
|
-
consumeRowHr(s, rows);
|
|
6153
|
-
continue;
|
|
6154
|
-
}
|
|
6155
|
-
consume(s);
|
|
6347
|
+
const ts = {
|
|
6348
|
+
rows: [],
|
|
6349
|
+
needRow: false,
|
|
6350
|
+
hrule: parseRows(open.attrs["rows"]) === true,
|
|
6351
|
+
vrule: parseColumns(open.attrs["columns"]) === true
|
|
6352
|
+
};
|
|
6353
|
+
for (let t = peek(s); t !== void 0; t = peek(s)) {
|
|
6354
|
+
if (scanTableToken(s, t, fontStack, ts)) break;
|
|
6156
6355
|
}
|
|
6157
|
-
return buildTable(rows, open.attrs);
|
|
6356
|
+
return buildTable(ts.rows, open.attrs);
|
|
6158
6357
|
};
|
|
6159
6358
|
var parseTableRow = (s, fontStack, opts) => {
|
|
6160
6359
|
const row = parseRow(s, fontStack);
|
|
@@ -6164,11 +6363,9 @@ var parseTableRow = (s, fontStack, opts) => {
|
|
|
6164
6363
|
};
|
|
6165
6364
|
var consumeRowHr = (s, rows) => {
|
|
6166
6365
|
consume(s);
|
|
6167
|
-
|
|
6168
|
-
if (nxt?.type === "close" && nxt.tag === "HR") consume(s);
|
|
6366
|
+
consumeClose(s, "HR");
|
|
6169
6367
|
const prev = rows[rows.length - 1];
|
|
6170
|
-
if (prev
|
|
6171
|
-
prev.ruled = true;
|
|
6368
|
+
if (prev !== void 0) prev.ruled = true;
|
|
6172
6369
|
};
|
|
6173
6370
|
var findFirstRealToken = (tokens, start) => {
|
|
6174
6371
|
for (let i = start; i < tokens.length; i++) {
|
|
@@ -6184,34 +6381,61 @@ var skipLeadingWs = (s) => {
|
|
|
6184
6381
|
consume(s);
|
|
6185
6382
|
}
|
|
6186
6383
|
};
|
|
6384
|
+
var finishTableLabel = (s) => {
|
|
6385
|
+
let afterNonSpace = false;
|
|
6386
|
+
for (let t = peek(s); t?.type === "text"; t = peek(s)) {
|
|
6387
|
+
consume(s);
|
|
6388
|
+
if (nonSpace(t.value)) afterNonSpace = true;
|
|
6389
|
+
}
|
|
6390
|
+
const nxt = peek(s);
|
|
6391
|
+
if (nxt === void 0) return;
|
|
6392
|
+
if (afterNonSpace) throw parseError(s, nxt, MSG_TEXT_AFTER_TABLE);
|
|
6393
|
+
if (nxt.type !== "close" || nxt.tag !== "HTML") throw parseError(s, nxt, MSG_SYNTAX_ERROR);
|
|
6394
|
+
consume(s);
|
|
6395
|
+
};
|
|
6187
6396
|
var parseTableLabel = (s, fontStack) => {
|
|
6188
6397
|
skipLeadingWs(s);
|
|
6189
6398
|
const table = parseTable(s, fontStack);
|
|
6190
|
-
|
|
6191
|
-
if (nxt?.type === "close" && nxt.tag === "HTML") consume(s);
|
|
6399
|
+
finishTableLabel(s);
|
|
6192
6400
|
return { kind: "table", table };
|
|
6193
6401
|
};
|
|
6194
|
-
var
|
|
6195
|
-
const wrapped = `<HTML>${src}</HTML>`;
|
|
6196
|
-
const tokens = tokenize(wrapped);
|
|
6197
|
-
const s = { tokens, pos: 0 };
|
|
6198
|
-
const fontStack = [{}];
|
|
6199
|
-
const htmlOpen = consume(s);
|
|
6200
|
-
if (htmlOpen.type !== "open" || htmlOpen.tag !== "HTML") throw new HtmlParseError("HTML");
|
|
6201
|
-
const firstReal = findFirstRealToken(tokens, s.pos);
|
|
6202
|
-
if (firstReal?.type === "open" && firstReal.tag === "TABLE") {
|
|
6203
|
-
return parseTableLabel(s, fontStack);
|
|
6204
|
-
}
|
|
6402
|
+
var parseTextLabel = (s, fontStack) => {
|
|
6205
6403
|
const texts = [];
|
|
6206
6404
|
const txt = parseText(s, fontStack);
|
|
6207
6405
|
if (txt.items.length > 0) texts.push(txt);
|
|
6208
6406
|
const nxt = peek(s);
|
|
6209
|
-
if (nxt
|
|
6210
|
-
|
|
6407
|
+
if (nxt === void 0) return { kind: "text", texts };
|
|
6408
|
+
if (nxt.type === "open" && nxt.tag === "TABLE") {
|
|
6409
|
+
if (txt.items.some((i) => i.text !== void 0 && nonSpace(i.text))) {
|
|
6410
|
+
throw parseError(s, nxt, MSG_TEXT_BEFORE_TABLE);
|
|
6411
|
+
}
|
|
6412
|
+
throw new HtmlParseError("TABLE");
|
|
6211
6413
|
}
|
|
6212
|
-
if (nxt
|
|
6414
|
+
if (nxt.type !== "close" || nxt.tag !== "HTML") throw parseError(s, nxt, MSG_SYNTAX_ERROR);
|
|
6415
|
+
consume(s);
|
|
6213
6416
|
return { kind: "text", texts };
|
|
6214
6417
|
};
|
|
6418
|
+
var parseTokens = (s) => {
|
|
6419
|
+
const fontStack = [{}];
|
|
6420
|
+
const htmlOpen = consume(s);
|
|
6421
|
+
if (htmlOpen.type !== "open" || htmlOpen.tag !== "HTML") throw new HtmlParseError("HTML");
|
|
6422
|
+
const firstReal = findFirstRealToken(s.tokens, s.pos);
|
|
6423
|
+
if (firstReal?.type === "open" && firstReal.tag === "TABLE") return parseTableLabel(s, fontStack);
|
|
6424
|
+
return parseTextLabel(s, fontStack);
|
|
6425
|
+
};
|
|
6426
|
+
var parseHtmlLabel = (src) => {
|
|
6427
|
+
const { tokens, error } = tokenizeDeferred(`<HTML>${src}</HTML>`);
|
|
6428
|
+
const s = { tokens, pos: 0, pending: error };
|
|
6429
|
+
let label;
|
|
6430
|
+
try {
|
|
6431
|
+
label = parseTokens(s);
|
|
6432
|
+
} catch (e) {
|
|
6433
|
+
if (error !== void 0 && s.pos >= tokens.length) throw error;
|
|
6434
|
+
throw e;
|
|
6435
|
+
}
|
|
6436
|
+
if (error !== void 0) throw error;
|
|
6437
|
+
return label;
|
|
6438
|
+
};
|
|
6215
6439
|
|
|
6216
6440
|
// src/gvc/usershape.ts
|
|
6217
6441
|
var activeSizer = null;
|
|
@@ -6219,28 +6443,80 @@ function findImageSize(src) {
|
|
|
6219
6443
|
return activeSizer !== null ? activeSizer(src) : null;
|
|
6220
6444
|
}
|
|
6221
6445
|
|
|
6446
|
+
// src/common/pointset.ts
|
|
6447
|
+
function cmpPair(a, b) {
|
|
6448
|
+
if (a.x > b.x) return 1;
|
|
6449
|
+
if (a.x < b.x) return -1;
|
|
6450
|
+
if (a.y > b.y) return 1;
|
|
6451
|
+
if (a.y < b.y) return -1;
|
|
6452
|
+
return 0;
|
|
6453
|
+
}
|
|
6454
|
+
var PointSet = class {
|
|
6455
|
+
byX = /* @__PURE__ */ new Map();
|
|
6456
|
+
n = 0;
|
|
6457
|
+
/**
|
|
6458
|
+
* Insert (x, y). A duplicate keeps the point inserted first, as `dtinsert`
|
|
6459
|
+
* returns the existing object and the new one is freed.
|
|
6460
|
+
* @see lib/common/pointset.c:addPS
|
|
6461
|
+
*/
|
|
6462
|
+
addPS(x, y) {
|
|
6463
|
+
let col = this.byX.get(x);
|
|
6464
|
+
if (col === void 0) {
|
|
6465
|
+
col = /* @__PURE__ */ new Map();
|
|
6466
|
+
this.byX.set(x, col);
|
|
6467
|
+
}
|
|
6468
|
+
if (col.has(y)) return;
|
|
6469
|
+
col.set(y, { x, y });
|
|
6470
|
+
this.n++;
|
|
6471
|
+
}
|
|
6472
|
+
/** @see lib/common/pointset.c:inPS */
|
|
6473
|
+
inPS(pt) {
|
|
6474
|
+
return this.byX.get(pt.x)?.has(pt.y) ?? false;
|
|
6475
|
+
}
|
|
6476
|
+
/** @see lib/common/pointset.c:isInPS */
|
|
6477
|
+
isInPS(x, y) {
|
|
6478
|
+
return this.byX.get(x)?.has(y) ?? false;
|
|
6479
|
+
}
|
|
6480
|
+
/** @see lib/common/pointset.c:sizeOf */
|
|
6481
|
+
sizeOf() {
|
|
6482
|
+
return this.n;
|
|
6483
|
+
}
|
|
6484
|
+
/**
|
|
6485
|
+
* The points in dictionary order (`dtflatten` walks the ordered set).
|
|
6486
|
+
* @see lib/common/pointset.c:pointsOf
|
|
6487
|
+
*/
|
|
6488
|
+
pointsOf() {
|
|
6489
|
+
const pts = [];
|
|
6490
|
+
for (const col of this.byX.values()) {
|
|
6491
|
+
for (const p of col.values()) pts.push({ x: p.x, y: p.y });
|
|
6492
|
+
}
|
|
6493
|
+
return pts.sort(cmpPair);
|
|
6494
|
+
}
|
|
6495
|
+
};
|
|
6496
|
+
|
|
6222
6497
|
// src/common/htmltable.ts
|
|
6223
6498
|
var DEFAULT_BORDER = 1;
|
|
6224
6499
|
var DEFAULT_CELLPADDING = 2;
|
|
6225
6500
|
var DEFAULT_CELLSPACING = 2;
|
|
6226
6501
|
var DEFAULT_FONTSIZE = 14;
|
|
6227
|
-
var findCol = (
|
|
6502
|
+
var findCol = (ps, row, startCol, colspan, rowspan) => {
|
|
6228
6503
|
let col = startCol;
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6504
|
+
let notFound = true;
|
|
6505
|
+
const end = colspan - 1;
|
|
6506
|
+
while (notFound) {
|
|
6507
|
+
const lastc = col + end;
|
|
6508
|
+
let c;
|
|
6509
|
+
for (c = lastc; c >= col; c--) {
|
|
6510
|
+
if (ps.isInPS(c, row)) break;
|
|
6511
|
+
}
|
|
6512
|
+
if (c >= col) col = c + 1;
|
|
6513
|
+
else notFound = false;
|
|
6514
|
+
}
|
|
6515
|
+
for (let j = col; j < col + colspan; j++) {
|
|
6516
|
+
for (let i = row; i < row + rowspan; i++) {
|
|
6517
|
+
ps.addPS(j, i);
|
|
6238
6518
|
}
|
|
6239
|
-
if (!conflict) break;
|
|
6240
6519
|
}
|
|
6241
|
-
for (let c = col; c < col + colspan; c++)
|
|
6242
|
-
for (let r = row; r < row + rowspan; r++)
|
|
6243
|
-
used.add(`${c},${r}`);
|
|
6244
6520
|
return col;
|
|
6245
6521
|
};
|
|
6246
6522
|
var DEFAULT_SIZE_ENV = { fontsize: DEFAULT_FONTSIZE, fontname: "" };
|
|
@@ -6319,29 +6595,32 @@ var sizeTextContent = (texts, measurer, env = DEFAULT_SIZE_ENV) => {
|
|
|
6319
6595
|
if (lines.length === 1) h = lines[0].items.length > 0 ? lines[0].mxysize : DEFAULT_FONTSIZE;
|
|
6320
6596
|
return { w, h };
|
|
6321
6597
|
};
|
|
6598
|
+
var missingImages = /* @__PURE__ */ new WeakSet();
|
|
6322
6599
|
var sizeHtmlImg = (img, imageSizer) => {
|
|
6323
|
-
if (img.width !== void 0 && img.height !== void 0) return;
|
|
6600
|
+
if (img.width !== void 0 && img.height !== void 0) return missingImages.has(img) ? 1 : 0;
|
|
6324
6601
|
const sz = imageSizer !== void 0 ? imageSizer(img.src) : findImageSize(img.src);
|
|
6325
6602
|
if (sz !== null) {
|
|
6326
6603
|
img.width = sz.w;
|
|
6327
6604
|
img.height = sz.h;
|
|
6328
|
-
return;
|
|
6605
|
+
return 0;
|
|
6329
6606
|
}
|
|
6330
6607
|
console.error(`Error: No or improper image file="${img.src}"`);
|
|
6331
6608
|
img.width = 0;
|
|
6332
6609
|
img.height = 0;
|
|
6610
|
+
missingImages.add(img);
|
|
6611
|
+
return 1;
|
|
6333
6612
|
};
|
|
6334
6613
|
var sizeContentItem = (item, measurer, env) => {
|
|
6335
|
-
if (item.kind === "text") return sizeTextContent([item], measurer, env);
|
|
6614
|
+
if (item.kind === "text") return { ...sizeTextContent([item], measurer, env), rv: 0 };
|
|
6336
6615
|
if (item.kind === "table") {
|
|
6337
|
-
sizeTableInner(item, measurer, env);
|
|
6338
|
-
return item.dimen !== void 0 ? item.dimen : { w: 0, h: 0 };
|
|
6616
|
+
const rv = sizeTableInner(item, measurer, env);
|
|
6617
|
+
return { ...item.dimen !== void 0 ? item.dimen : { w: 0, h: 0 }, rv };
|
|
6339
6618
|
}
|
|
6340
6619
|
if (item.kind === "image") {
|
|
6341
|
-
sizeHtmlImg(item, env.imageSizer);
|
|
6342
|
-
return { w: item.width ?? 0, h: item.height ?? 0 };
|
|
6620
|
+
const rv = sizeHtmlImg(item, env.imageSizer);
|
|
6621
|
+
return { w: item.width ?? 0, h: item.height ?? 0, rv };
|
|
6343
6622
|
}
|
|
6344
|
-
return { w: 0, h: 0 };
|
|
6623
|
+
return { w: 0, h: 0, rv: 0 };
|
|
6345
6624
|
};
|
|
6346
6625
|
var cellPad = (cell2, tbl) => cell2.cellpadding !== void 0 ? cell2.cellpadding : tbl.cellpadding !== void 0 ? tbl.cellpadding : DEFAULT_CELLPADDING;
|
|
6347
6626
|
var cellBorder = (cell2, tbl) => {
|
|
@@ -6351,27 +6630,60 @@ var cellBorder = (cell2, tbl) => {
|
|
|
6351
6630
|
if (tbl.border !== void 0) return tbl.border;
|
|
6352
6631
|
return DEFAULT_BORDER;
|
|
6353
6632
|
};
|
|
6633
|
+
function inheritTablePenColor(tbl, parentColor) {
|
|
6634
|
+
if (tbl.color === void 0) tbl.color = parentColor;
|
|
6635
|
+
const tblColor = tbl.color;
|
|
6636
|
+
for (const row of tbl.rows) {
|
|
6637
|
+
for (const cell2 of row.cells) {
|
|
6638
|
+
if (cell2.color === void 0) cell2.color = tblColor;
|
|
6639
|
+
for (const item of cell2.content) {
|
|
6640
|
+
if (item.kind === "table") inheritTablePenColor(item, cell2.color);
|
|
6641
|
+
}
|
|
6642
|
+
}
|
|
6643
|
+
}
|
|
6644
|
+
}
|
|
6645
|
+
var WARN_CELL_TOO_SMALL = "Warning: cell size too small for content";
|
|
6646
|
+
var WARN_CELL_UNSPECIFIED = "Warning: fixed cell size with unspecified width or height";
|
|
6647
|
+
var WARN_TABLE_TOO_SMALL = "Warning: table size too small for content";
|
|
6648
|
+
var WARN_TABLE_UNSPECIFIED = "Warning: fixed table size with unspecified width or height";
|
|
6649
|
+
var sizeWarned = /* @__PURE__ */ new WeakSet();
|
|
6650
|
+
var fixedCellCheck = (cell2, sz, warn) => {
|
|
6651
|
+
if (!cell2.fixedsize) return { rv: 0, zero: false };
|
|
6652
|
+
if (cell2.width && cell2.height) {
|
|
6653
|
+
const small = (cell2.width < sz.w || cell2.height < sz.h) && cell2.content[0]?.kind !== "image";
|
|
6654
|
+
if (small && warn) console.warn(WARN_CELL_TOO_SMALL);
|
|
6655
|
+
return { rv: small ? 1 : 0, zero: true };
|
|
6656
|
+
}
|
|
6657
|
+
if (warn) console.warn(WARN_CELL_UNSPECIFIED);
|
|
6658
|
+
return { rv: 1, zero: false };
|
|
6659
|
+
};
|
|
6354
6660
|
var getCellSize = (cell2, tbl, measurer, env) => {
|
|
6355
6661
|
const margin = 2 * (cellPad(cell2, tbl) + cellBorder(cell2, tbl));
|
|
6356
|
-
let cw = 0, ch = 0;
|
|
6662
|
+
let cw = 0, ch = 0, rv = 0;
|
|
6357
6663
|
for (const item of cell2.content) {
|
|
6358
6664
|
const s = sizeContentItem(item, measurer, env);
|
|
6359
6665
|
cw = Math.max(cw, s.w);
|
|
6360
6666
|
ch += s.h;
|
|
6667
|
+
rv |= s.rv;
|
|
6361
6668
|
}
|
|
6362
6669
|
let szx = cw + margin;
|
|
6363
6670
|
let szy = ch + margin;
|
|
6364
|
-
|
|
6671
|
+
const warn = !sizeWarned.has(cell2);
|
|
6672
|
+
sizeWarned.add(cell2);
|
|
6673
|
+
const fixed = fixedCellCheck(cell2, { w: szx, h: szy }, warn);
|
|
6674
|
+
rv |= fixed.rv;
|
|
6675
|
+
if (fixed.zero) {
|
|
6365
6676
|
szx = 0;
|
|
6366
6677
|
szy = 0;
|
|
6367
6678
|
}
|
|
6368
6679
|
const bw = cell2.width !== void 0 ? cell2.width : 0;
|
|
6369
6680
|
const bh = cell2.height !== void 0 ? cell2.height : 0;
|
|
6370
|
-
return { w: Math.max(szx, bw), h: Math.max(szy, bh) };
|
|
6681
|
+
return { w: Math.max(szx, bw), h: Math.max(szy, bh), rv };
|
|
6371
6682
|
};
|
|
6372
6683
|
var buildLayouts = (tbl, measurer, env) => {
|
|
6373
6684
|
const entries = [];
|
|
6374
|
-
|
|
6685
|
+
let rv = 0;
|
|
6686
|
+
const ps = new PointSet();
|
|
6375
6687
|
let rowIdx = 0;
|
|
6376
6688
|
for (const row of tbl.rows) {
|
|
6377
6689
|
let col = 0;
|
|
@@ -6381,14 +6693,15 @@ var buildLayouts = (tbl, measurer, env) => {
|
|
|
6381
6693
|
}
|
|
6382
6694
|
const colspan = c.colspan !== void 0 ? c.colspan : 1;
|
|
6383
6695
|
const rowspan = c.rowspan !== void 0 ? c.rowspan : 1;
|
|
6384
|
-
const { w, h } = getCellSize(c, tbl, measurer, env);
|
|
6385
|
-
|
|
6696
|
+
const { w, h, rv: cellRv } = getCellSize(c, tbl, measurer, env);
|
|
6697
|
+
rv |= cellRv;
|
|
6698
|
+
col = findCol(ps, rowIdx, col, colspan, rowspan);
|
|
6386
6699
|
entries.push({ cell: c, row: rowIdx, col, colspan, rowspan, w, h });
|
|
6387
6700
|
col += colspan;
|
|
6388
6701
|
}
|
|
6389
6702
|
rowIdx++;
|
|
6390
6703
|
}
|
|
6391
|
-
return entries;
|
|
6704
|
+
return { entries, rv };
|
|
6392
6705
|
};
|
|
6393
6706
|
var setColWidths = (entries, ncols, spacing) => {
|
|
6394
6707
|
const widths = new Array(ncols + 1).fill(0);
|
|
@@ -6441,21 +6754,34 @@ var sumTableDims = (a) => {
|
|
|
6441
6754
|
var layoutHtmlTable = (tbl, measurer, env = DEFAULT_SIZE_ENV) => {
|
|
6442
6755
|
const spacing = getSpacing(tbl);
|
|
6443
6756
|
const border = getBorder(tbl);
|
|
6444
|
-
const entries = buildLayouts(tbl, measurer, env);
|
|
6757
|
+
const { entries, rv } = buildLayouts(tbl, measurer, env);
|
|
6445
6758
|
if (entries.length === 0) {
|
|
6446
|
-
return { entries, widths: [], heights: [], spacing, border };
|
|
6759
|
+
return { entries, widths: [], heights: [], spacing, border, rv };
|
|
6447
6760
|
}
|
|
6448
6761
|
const ncols = Math.max(...entries.map((e) => e.col + e.colspan));
|
|
6449
6762
|
const nrows = Math.max(...entries.map((e) => e.row + e.rowspan));
|
|
6450
6763
|
const widths = setColWidths(entries, ncols, spacing);
|
|
6451
6764
|
const heights = setRowHeights(entries, nrows, spacing);
|
|
6452
|
-
return { entries, widths, heights, spacing, border };
|
|
6765
|
+
return { entries, widths, heights, spacing, border, rv };
|
|
6766
|
+
};
|
|
6767
|
+
var warnFixedTable = (tbl, dims) => {
|
|
6768
|
+
const warn = !sizeWarned.has(tbl);
|
|
6769
|
+
sizeWarned.add(tbl);
|
|
6770
|
+
if (tbl.fixedsize !== true) return 0;
|
|
6771
|
+
if (tbl.width && tbl.height) {
|
|
6772
|
+
if (tbl.width >= dims.wd && tbl.height >= dims.ht) return 0;
|
|
6773
|
+
if (warn) console.warn(WARN_TABLE_TOO_SMALL);
|
|
6774
|
+
return 1;
|
|
6775
|
+
}
|
|
6776
|
+
if (warn) console.warn(WARN_TABLE_UNSPECIFIED);
|
|
6777
|
+
return 1;
|
|
6453
6778
|
};
|
|
6454
6779
|
var sizeTableInner = (tbl, measurer, env) => {
|
|
6455
|
-
const { entries, widths, heights, spacing, border } = layoutHtmlTable(tbl, measurer, env);
|
|
6780
|
+
const { entries, widths, heights, spacing, border, rv } = layoutHtmlTable(tbl, measurer, env);
|
|
6456
6781
|
if (entries.length === 0) {
|
|
6782
|
+
const fixed2 = warnFixedTable(tbl, sumTableDims({ widths, heights, ncols: 0, nrows: 0, spacing, border }));
|
|
6457
6783
|
tbl.dimen = { w: 0, h: 0 };
|
|
6458
|
-
return;
|
|
6784
|
+
return rv | fixed2;
|
|
6459
6785
|
}
|
|
6460
6786
|
const ncols = Math.max(...entries.map((e) => e.col + e.colspan));
|
|
6461
6787
|
const nrows = Math.max(...entries.map((e) => e.row + e.rowspan));
|
|
@@ -6463,19 +6789,22 @@ var sizeTableInner = (tbl, measurer, env) => {
|
|
|
6463
6789
|
const { wd, ht } = sumTableDims({ widths, heights, ncols, nrows, spacing, border });
|
|
6464
6790
|
const baseWd = tbl.width !== void 0 ? tbl.width : 0;
|
|
6465
6791
|
const baseHt = tbl.height !== void 0 ? tbl.height : 0;
|
|
6792
|
+
const fixed = warnFixedTable(tbl, { wd, ht });
|
|
6466
6793
|
const zeroContent = isTblFixed(tbl) && baseWd !== 0 && baseHt !== 0;
|
|
6467
6794
|
tbl.dimen = {
|
|
6468
6795
|
w: Math.max(zeroContent ? 0 : wd, baseWd),
|
|
6469
6796
|
h: Math.max(zeroContent ? 0 : ht, baseHt)
|
|
6470
6797
|
};
|
|
6798
|
+
return rv | fixed;
|
|
6471
6799
|
};
|
|
6472
6800
|
var sizeHtmlLabel = (label, measurer, env = DEFAULT_SIZE_ENV) => {
|
|
6473
6801
|
if (label.kind === "table") {
|
|
6474
|
-
sizeTableInner(label.table, measurer, env);
|
|
6802
|
+
const rv = sizeTableInner(label.table, measurer, env);
|
|
6475
6803
|
label.dimen = label.table.dimen;
|
|
6476
|
-
|
|
6477
|
-
label.dimen = sizeTextContent(label.texts, measurer, env);
|
|
6804
|
+
return rv;
|
|
6478
6805
|
}
|
|
6806
|
+
label.dimen = sizeTextContent(label.texts, measurer, env);
|
|
6807
|
+
return 0;
|
|
6479
6808
|
};
|
|
6480
6809
|
|
|
6481
6810
|
// src/common/splines-constants.ts
|
|
@@ -6918,28 +7247,18 @@ function posHtmlLabel(label, finfo, measurer) {
|
|
|
6918
7247
|
if (label.kind === "table") return posHtmlTable(label.table, finfo, measurer);
|
|
6919
7248
|
return posTextLabel(label, finfo, measurer);
|
|
6920
7249
|
}
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
const tblColor = tbl.color;
|
|
6924
|
-
for (const row of tbl.rows) {
|
|
6925
|
-
for (const cell2 of row.cells) {
|
|
6926
|
-
if (cell2.color === void 0) cell2.color = tblColor;
|
|
6927
|
-
for (const item of cell2.content) {
|
|
6928
|
-
if (item.kind === "table") inheritTablePenColor(item, cell2.color);
|
|
6929
|
-
}
|
|
6930
|
-
}
|
|
6931
|
-
}
|
|
6932
|
-
}
|
|
6933
|
-
function makeHtmlLabel(content, finfo, measurer) {
|
|
7250
|
+
var HTML_PARSE_FATAL = 3;
|
|
7251
|
+
function makeHtmlLabelRv(content, finfo, measurer) {
|
|
6934
7252
|
const { fontname, fontsize, fontcolor, imageSizer, pencolor } = finfo;
|
|
6935
7253
|
let lbl;
|
|
6936
7254
|
try {
|
|
6937
7255
|
lbl = parseHtmlLabel(content);
|
|
6938
|
-
} catch {
|
|
6939
|
-
|
|
7256
|
+
} catch (e) {
|
|
7257
|
+
if (e instanceof HtmlLexError) for (const line of e.diagnostics) console.error(line);
|
|
7258
|
+
return { label: makeLabel("", fontname, fontsize, fontcolor, measurer), rv: HTML_PARSE_FATAL };
|
|
6940
7259
|
}
|
|
6941
7260
|
if (lbl.kind === "table") inheritTablePenColor(lbl.table, pencolor);
|
|
6942
|
-
sizeHtmlLabel(lbl, measurer, {
|
|
7261
|
+
const rv = sizeHtmlLabel(lbl, measurer, {
|
|
6943
7262
|
fontsize,
|
|
6944
7263
|
fontname,
|
|
6945
7264
|
imageSizer
|
|
@@ -6947,7 +7266,7 @@ function makeHtmlLabel(content, finfo, measurer) {
|
|
|
6947
7266
|
const placed = posHtmlLabel(lbl, { fontname, fontsize, fontcolor }, measurer);
|
|
6948
7267
|
const dim = lbl.dimen ?? { w: 0, h: 0 };
|
|
6949
7268
|
const text = lbl.kind === "table" ? "<TABLE>" : content;
|
|
6950
|
-
return htmlTextLabel(text, { fontname, fontsize, fontcolor }, placed, dim);
|
|
7269
|
+
return { label: htmlTextLabel(text, { fontname, fontsize, fontcolor }, placed, dim), rv };
|
|
6951
7270
|
}
|
|
6952
7271
|
function htmlTextLabel(text, finfo, placed, dim) {
|
|
6953
7272
|
return {
|
|
@@ -7336,6 +7655,159 @@ function interpretCRNL(str) {
|
|
|
7336
7655
|
return out;
|
|
7337
7656
|
}
|
|
7338
7657
|
|
|
7658
|
+
// src/model/graphInfo.ts
|
|
7659
|
+
function makeGraphInfo() {
|
|
7660
|
+
return {
|
|
7661
|
+
bb: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } },
|
|
7662
|
+
rankdir: 0,
|
|
7663
|
+
flags: 0,
|
|
7664
|
+
charset: 0,
|
|
7665
|
+
gui_state: 0,
|
|
7666
|
+
has_labels: 0,
|
|
7667
|
+
has_images: false
|
|
7668
|
+
};
|
|
7669
|
+
}
|
|
7670
|
+
|
|
7671
|
+
// src/model/graph.ts
|
|
7672
|
+
var Graph = class {
|
|
7673
|
+
/** Graph name; agnameof equivalent. @see lib/cgraph/cgraph.h:agnameof */
|
|
7674
|
+
name;
|
|
7675
|
+
/**
|
|
7676
|
+
* True when the graph was declared with NO name (`digraph {`), as opposed to
|
|
7677
|
+
* an explicit empty name (`digraph "" {`). Both store `name === ''`, but
|
|
7678
|
+
* cgraph gives the truly-anonymous root the internal id `%1` (agnameof) while
|
|
7679
|
+
* the empty-named one keeps `""`. Only the imagemap `<map id/name>` reads this
|
|
7680
|
+
* (map.ts:mapGraphName); dot/xdot re-serialization keeps `name` so an
|
|
7681
|
+
* anonymous root round-trips as `digraph {`, not `digraph %1 {`.
|
|
7682
|
+
* @see lib/cgraph/id.c:idmap (anon → `%1`) ; lib/cgraph/agraph.c:agnameof
|
|
7683
|
+
*/
|
|
7684
|
+
anonymous;
|
|
7685
|
+
/**
|
|
7686
|
+
* Directed/strict classification; mirrors Agdesc_t.directed and
|
|
7687
|
+
* Agdesc_t.strict. @see lib/cgraph/cgraph.h:Agdesc_s
|
|
7688
|
+
*/
|
|
7689
|
+
kind;
|
|
7690
|
+
/**
|
|
7691
|
+
* Node set in insertion order, keyed by name.
|
|
7692
|
+
* Mirrors Agraph_t.n_seq (sequence dict) merged with n_id access.
|
|
7693
|
+
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
7694
|
+
*/
|
|
7695
|
+
nodes;
|
|
7696
|
+
/**
|
|
7697
|
+
* All edges owned by this graph (root graph only for ownership; subgraphs
|
|
7698
|
+
* reference a subset). Mirrors Agraph_t.e_seq.
|
|
7699
|
+
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
7700
|
+
*/
|
|
7701
|
+
edges;
|
|
7702
|
+
/**
|
|
7703
|
+
* Named subgraphs, keyed by name. Mirrors Agraph_t.g_seq/g_id.
|
|
7704
|
+
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
7705
|
+
*/
|
|
7706
|
+
subgraphs;
|
|
7707
|
+
/**
|
|
7708
|
+
* String attributes (agget/agset equivalents).
|
|
7709
|
+
* Replaces the Agattr_t / Agsym_t machinery for simple key-value access.
|
|
7710
|
+
* @see lib/cgraph/cgraph.h:Agattr_s
|
|
7711
|
+
*/
|
|
7712
|
+
attrs;
|
|
7713
|
+
/** Default attributes applied to all nodes in this graph scope. */
|
|
7714
|
+
nodeDefaults;
|
|
7715
|
+
/** Default attributes applied to all edges in this graph scope. */
|
|
7716
|
+
edgeDefaults;
|
|
7717
|
+
/**
|
|
7718
|
+
* Snapshot of the enclosing graphs' graph-attribute defaults (this graph ->
|
|
7719
|
+
* root, inner wins) captured when this subgraph was OPENED during parsing.
|
|
7720
|
+
* Graph attributes set on an ancestor AFTER this subgraph was created are not
|
|
7721
|
+
* included — mirroring cgraph's parse-time agsubg defval copy. Used for
|
|
7722
|
+
* order-correct label/font inheritance (e.g. a root `label=` declared after a
|
|
7723
|
+
* cluster must NOT apply to that cluster). Undefined on the root graph.
|
|
7724
|
+
* @see lib/cgraph/graph.c:agsubg (attr defval copy)
|
|
7725
|
+
*/
|
|
7726
|
+
graphDefaultsSnapshot;
|
|
7727
|
+
/**
|
|
7728
|
+
* Keys in `attrs` the BUILDER seeded from `graphDefaultsSnapshot` rather than
|
|
7729
|
+
* the input declaring them in this scope (see builder.ts GRAPH_LABEL_INHERIT_
|
|
7730
|
+
* KEYS). cgraph distinguishes these structurally — a seeded value is inherited
|
|
7731
|
+
* through the dict view and has no local symbol, while a local declaration
|
|
7732
|
+
* creates one even when its value equals the inherited value — so the
|
|
7733
|
+
* serializer needs the provenance to decide what write_dict would print.
|
|
7734
|
+
* Undefined on the root graph and on any scope that seeded nothing.
|
|
7735
|
+
* @see lib/cgraph/write.c:262 write_dict
|
|
7736
|
+
*/
|
|
7737
|
+
seededAttrs;
|
|
7738
|
+
/**
|
|
7739
|
+
* Graph-attribute keys whose declaration in THIS scope was the first anywhere
|
|
7740
|
+
* in the graph. cgraph's `setattr` splits on exactly this: a key with no
|
|
7741
|
+
* existing symbol takes the global-declaration branch, which ends up seeding
|
|
7742
|
+
* every direct subgraph that already exists with a local empty value (see
|
|
7743
|
+
* `eagerEmptyParts`); a key some earlier scope already declared takes the
|
|
7744
|
+
* "new local definition" branch and touches no subgraph at all. So an
|
|
7745
|
+
* identical `graph [fill=x]` statement makes a child print `fill=""` or print
|
|
7746
|
+
* nothing purely according to whether a SIBLING declared `fill` first.
|
|
7747
|
+
* Undefined on any scope that declared nothing new.
|
|
7748
|
+
* @see lib/cgraph/attr.c:257 setattr (lsym / psym / global branches)
|
|
7749
|
+
*/
|
|
7750
|
+
firstGraphDecl;
|
|
7751
|
+
/**
|
|
7752
|
+
* Layout-engine info; replaces GD_* macros via agbindrec (AD-1).
|
|
7753
|
+
* @see lib/cgraph/cgraph.h:agbindrec
|
|
7754
|
+
*/
|
|
7755
|
+
info;
|
|
7756
|
+
/**
|
|
7757
|
+
* Immediate parent graph. null for root graphs.
|
|
7758
|
+
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
7759
|
+
*/
|
|
7760
|
+
parent;
|
|
7761
|
+
/**
|
|
7762
|
+
* Root (main) graph. Self-referential for root graphs;
|
|
7763
|
+
* points up for subgraphs.
|
|
7764
|
+
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
7765
|
+
*/
|
|
7766
|
+
root;
|
|
7767
|
+
/**
|
|
7768
|
+
* Subgraph sequence number (AGSEQ). A global counter on the root, assigned
|
|
7769
|
+
* at creation in source order, counting anonymous subgraphs. The root keeps
|
|
7770
|
+
* the default 0 (par == NULL never calls agnextseq). Consumed by getObjId to
|
|
7771
|
+
* emit cluster ids `clust<seq>`.
|
|
7772
|
+
* @see lib/cgraph/cgraph.h:AGSEQ
|
|
7773
|
+
* @see lib/cgraph/graph.c:agopen (AGSEQ(g) = agnextseq(par, AGRAPH))
|
|
7774
|
+
*/
|
|
7775
|
+
seq = 0;
|
|
7776
|
+
/**
|
|
7777
|
+
* Root-only counter mirroring `clos->seq[AGRAPH]`: the running maximum AGSEQ
|
|
7778
|
+
* handed out to subgraphs. Meaningful only on the root graph; `assignSubgSeq`
|
|
7779
|
+
* pre-increments it. Other graphs leave it at 0.
|
|
7780
|
+
* @see lib/cgraph/graph.c:agnextseq (++clos->seq[AGRAPH])
|
|
7781
|
+
*/
|
|
7782
|
+
subgSeqCounter = 0;
|
|
7783
|
+
/**
|
|
7784
|
+
* Names of graph attributes (AGRAPH) declared anywhere in this hierarchy —
|
|
7785
|
+
* the port's stand-in for cgraph's `Agsym_t` symbol table. Populated on the
|
|
7786
|
+
* ROOT only, at parse time, whenever a graph attribute is assigned on any
|
|
7787
|
+
* (sub)graph: setting `ordering=out` on a subgraph declares "ordering"
|
|
7788
|
+
* graph-wide with an empty default, so `agGraphAttr(root, "ordering")` returns
|
|
7789
|
+
* `""` (not undefined) — mirroring `agfindgraphattr`/`late_string`. Read via
|
|
7790
|
+
* `agGraphAttr` (model/cgraph-ops.ts); empty on non-root graphs.
|
|
7791
|
+
* @see lib/cgraph/attr.c:agattr (graph-wide declaration, "" default)
|
|
7792
|
+
*/
|
|
7793
|
+
declaredGraphAttrs = /* @__PURE__ */ new Set();
|
|
7794
|
+
/** @see lib/cgraph/graph.c:agopen */
|
|
7795
|
+
constructor(name, kind, anonymous = false) {
|
|
7796
|
+
this.name = name;
|
|
7797
|
+
this.anonymous = anonymous;
|
|
7798
|
+
this.kind = kind;
|
|
7799
|
+
this.nodes = /* @__PURE__ */ new Map();
|
|
7800
|
+
this.edges = [];
|
|
7801
|
+
this.subgraphs = /* @__PURE__ */ new Map();
|
|
7802
|
+
this.attrs = /* @__PURE__ */ new Map();
|
|
7803
|
+
this.nodeDefaults = /* @__PURE__ */ new Map();
|
|
7804
|
+
this.edgeDefaults = /* @__PURE__ */ new Map();
|
|
7805
|
+
this.info = makeGraphInfo();
|
|
7806
|
+
this.parent = null;
|
|
7807
|
+
this.root = this;
|
|
7808
|
+
}
|
|
7809
|
+
};
|
|
7810
|
+
|
|
7339
7811
|
// src/common/make-label.ts
|
|
7340
7812
|
var DEFAULT_FONTSIZE2 = 14;
|
|
7341
7813
|
var DEFAULT_FONTNAME = "Times-Roman";
|
|
@@ -7351,6 +7823,14 @@ function getPenColor(obj) {
|
|
|
7351
7823
|
function rootOf(obj) {
|
|
7352
7824
|
return obj instanceof Edge ? obj.tail.root : obj.root;
|
|
7353
7825
|
}
|
|
7826
|
+
function inLabelOf(obj) {
|
|
7827
|
+
if (obj instanceof Edge) {
|
|
7828
|
+
const sep = obj.head.root.kind.endsWith("undirected") ? "--" : "->";
|
|
7829
|
+
return `in label of edge ${obj.tail.name} ${sep} ${obj.head.name}`;
|
|
7830
|
+
}
|
|
7831
|
+
if (obj instanceof Graph) return `in label of graph ${obj.name}`;
|
|
7832
|
+
return `in label of node ${obj.name}`;
|
|
7833
|
+
}
|
|
7354
7834
|
function buildSpan(text, font, measured) {
|
|
7355
7835
|
return {
|
|
7356
7836
|
str: text,
|
|
@@ -7418,7 +7898,9 @@ function makeLabel(text, fontname, fontsize, fontcolor, measurer) {
|
|
|
7418
7898
|
function makeAnyLabel(content, isHtml, font, measurer, obj) {
|
|
7419
7899
|
if (isHtml && content !== "") {
|
|
7420
7900
|
const imageSizer = obj !== void 0 ? rootOf(obj).info.gvc?.imageSizer : void 0;
|
|
7421
|
-
|
|
7901
|
+
const { label, rv } = makeHtmlLabelRv(content, { ...font, pencolor: getPenColor(obj), imageSizer }, measurer);
|
|
7902
|
+
if (rv !== 0 && obj !== void 0) console.error(inLabelOf(obj));
|
|
7903
|
+
return label;
|
|
7422
7904
|
}
|
|
7423
7905
|
const subst2 = obj !== void 0 ? substObj(content, obj, false) : content;
|
|
7424
7906
|
const text = htmlEntityUTF8(subst2);
|
|
@@ -8887,19 +9369,6 @@ var RenderJob = class {
|
|
|
8887
9369
|
}
|
|
8888
9370
|
};
|
|
8889
9371
|
|
|
8890
|
-
// src/model/graphInfo.ts
|
|
8891
|
-
function makeGraphInfo() {
|
|
8892
|
-
return {
|
|
8893
|
-
bb: { ll: { x: 0, y: 0 }, ur: { x: 0, y: 0 } },
|
|
8894
|
-
rankdir: 0,
|
|
8895
|
-
flags: 0,
|
|
8896
|
-
charset: 0,
|
|
8897
|
-
gui_state: 0,
|
|
8898
|
-
has_labels: 0,
|
|
8899
|
-
has_images: false
|
|
8900
|
-
};
|
|
8901
|
-
}
|
|
8902
|
-
|
|
8903
9372
|
// src/common/shapeData.ts
|
|
8904
9373
|
var DOGEAR = 1;
|
|
8905
9374
|
var TAB = 2;
|
|
@@ -15489,146 +15958,6 @@ function ncross(ctx) {
|
|
|
15489
15958
|
return total;
|
|
15490
15959
|
}
|
|
15491
15960
|
|
|
15492
|
-
// src/model/graph.ts
|
|
15493
|
-
var Graph = class {
|
|
15494
|
-
/** Graph name; agnameof equivalent. @see lib/cgraph/cgraph.h:agnameof */
|
|
15495
|
-
name;
|
|
15496
|
-
/**
|
|
15497
|
-
* True when the graph was declared with NO name (`digraph {`), as opposed to
|
|
15498
|
-
* an explicit empty name (`digraph "" {`). Both store `name === ''`, but
|
|
15499
|
-
* cgraph gives the truly-anonymous root the internal id `%1` (agnameof) while
|
|
15500
|
-
* the empty-named one keeps `""`. Only the imagemap `<map id/name>` reads this
|
|
15501
|
-
* (map.ts:mapGraphName); dot/xdot re-serialization keeps `name` so an
|
|
15502
|
-
* anonymous root round-trips as `digraph {`, not `digraph %1 {`.
|
|
15503
|
-
* @see lib/cgraph/id.c:idmap (anon → `%1`) ; lib/cgraph/agraph.c:agnameof
|
|
15504
|
-
*/
|
|
15505
|
-
anonymous;
|
|
15506
|
-
/**
|
|
15507
|
-
* Directed/strict classification; mirrors Agdesc_t.directed and
|
|
15508
|
-
* Agdesc_t.strict. @see lib/cgraph/cgraph.h:Agdesc_s
|
|
15509
|
-
*/
|
|
15510
|
-
kind;
|
|
15511
|
-
/**
|
|
15512
|
-
* Node set in insertion order, keyed by name.
|
|
15513
|
-
* Mirrors Agraph_t.n_seq (sequence dict) merged with n_id access.
|
|
15514
|
-
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
15515
|
-
*/
|
|
15516
|
-
nodes;
|
|
15517
|
-
/**
|
|
15518
|
-
* All edges owned by this graph (root graph only for ownership; subgraphs
|
|
15519
|
-
* reference a subset). Mirrors Agraph_t.e_seq.
|
|
15520
|
-
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
15521
|
-
*/
|
|
15522
|
-
edges;
|
|
15523
|
-
/**
|
|
15524
|
-
* Named subgraphs, keyed by name. Mirrors Agraph_t.g_seq/g_id.
|
|
15525
|
-
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
15526
|
-
*/
|
|
15527
|
-
subgraphs;
|
|
15528
|
-
/**
|
|
15529
|
-
* String attributes (agget/agset equivalents).
|
|
15530
|
-
* Replaces the Agattr_t / Agsym_t machinery for simple key-value access.
|
|
15531
|
-
* @see lib/cgraph/cgraph.h:Agattr_s
|
|
15532
|
-
*/
|
|
15533
|
-
attrs;
|
|
15534
|
-
/** Default attributes applied to all nodes in this graph scope. */
|
|
15535
|
-
nodeDefaults;
|
|
15536
|
-
/** Default attributes applied to all edges in this graph scope. */
|
|
15537
|
-
edgeDefaults;
|
|
15538
|
-
/**
|
|
15539
|
-
* Snapshot of the enclosing graphs' graph-attribute defaults (this graph ->
|
|
15540
|
-
* root, inner wins) captured when this subgraph was OPENED during parsing.
|
|
15541
|
-
* Graph attributes set on an ancestor AFTER this subgraph was created are not
|
|
15542
|
-
* included — mirroring cgraph's parse-time agsubg defval copy. Used for
|
|
15543
|
-
* order-correct label/font inheritance (e.g. a root `label=` declared after a
|
|
15544
|
-
* cluster must NOT apply to that cluster). Undefined on the root graph.
|
|
15545
|
-
* @see lib/cgraph/graph.c:agsubg (attr defval copy)
|
|
15546
|
-
*/
|
|
15547
|
-
graphDefaultsSnapshot;
|
|
15548
|
-
/**
|
|
15549
|
-
* Keys in `attrs` the BUILDER seeded from `graphDefaultsSnapshot` rather than
|
|
15550
|
-
* the input declaring them in this scope (see builder.ts GRAPH_LABEL_INHERIT_
|
|
15551
|
-
* KEYS). cgraph distinguishes these structurally — a seeded value is inherited
|
|
15552
|
-
* through the dict view and has no local symbol, while a local declaration
|
|
15553
|
-
* creates one even when its value equals the inherited value — so the
|
|
15554
|
-
* serializer needs the provenance to decide what write_dict would print.
|
|
15555
|
-
* Undefined on the root graph and on any scope that seeded nothing.
|
|
15556
|
-
* @see lib/cgraph/write.c:262 write_dict
|
|
15557
|
-
*/
|
|
15558
|
-
seededAttrs;
|
|
15559
|
-
/**
|
|
15560
|
-
* Graph-attribute keys whose declaration in THIS scope was the first anywhere
|
|
15561
|
-
* in the graph. cgraph's `setattr` splits on exactly this: a key with no
|
|
15562
|
-
* existing symbol takes the global-declaration branch, which ends up seeding
|
|
15563
|
-
* every direct subgraph that already exists with a local empty value (see
|
|
15564
|
-
* `eagerEmptyParts`); a key some earlier scope already declared takes the
|
|
15565
|
-
* "new local definition" branch and touches no subgraph at all. So an
|
|
15566
|
-
* identical `graph [fill=x]` statement makes a child print `fill=""` or print
|
|
15567
|
-
* nothing purely according to whether a SIBLING declared `fill` first.
|
|
15568
|
-
* Undefined on any scope that declared nothing new.
|
|
15569
|
-
* @see lib/cgraph/attr.c:257 setattr (lsym / psym / global branches)
|
|
15570
|
-
*/
|
|
15571
|
-
firstGraphDecl;
|
|
15572
|
-
/**
|
|
15573
|
-
* Layout-engine info; replaces GD_* macros via agbindrec (AD-1).
|
|
15574
|
-
* @see lib/cgraph/cgraph.h:agbindrec
|
|
15575
|
-
*/
|
|
15576
|
-
info;
|
|
15577
|
-
/**
|
|
15578
|
-
* Immediate parent graph. null for root graphs.
|
|
15579
|
-
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
15580
|
-
*/
|
|
15581
|
-
parent;
|
|
15582
|
-
/**
|
|
15583
|
-
* Root (main) graph. Self-referential for root graphs;
|
|
15584
|
-
* points up for subgraphs.
|
|
15585
|
-
* @see lib/cgraph/cgraph.h:Agraph_s
|
|
15586
|
-
*/
|
|
15587
|
-
root;
|
|
15588
|
-
/**
|
|
15589
|
-
* Subgraph sequence number (AGSEQ). A global counter on the root, assigned
|
|
15590
|
-
* at creation in source order, counting anonymous subgraphs. The root keeps
|
|
15591
|
-
* the default 0 (par == NULL never calls agnextseq). Consumed by getObjId to
|
|
15592
|
-
* emit cluster ids `clust<seq>`.
|
|
15593
|
-
* @see lib/cgraph/cgraph.h:AGSEQ
|
|
15594
|
-
* @see lib/cgraph/graph.c:agopen (AGSEQ(g) = agnextseq(par, AGRAPH))
|
|
15595
|
-
*/
|
|
15596
|
-
seq = 0;
|
|
15597
|
-
/**
|
|
15598
|
-
* Root-only counter mirroring `clos->seq[AGRAPH]`: the running maximum AGSEQ
|
|
15599
|
-
* handed out to subgraphs. Meaningful only on the root graph; `assignSubgSeq`
|
|
15600
|
-
* pre-increments it. Other graphs leave it at 0.
|
|
15601
|
-
* @see lib/cgraph/graph.c:agnextseq (++clos->seq[AGRAPH])
|
|
15602
|
-
*/
|
|
15603
|
-
subgSeqCounter = 0;
|
|
15604
|
-
/**
|
|
15605
|
-
* Names of graph attributes (AGRAPH) declared anywhere in this hierarchy —
|
|
15606
|
-
* the port's stand-in for cgraph's `Agsym_t` symbol table. Populated on the
|
|
15607
|
-
* ROOT only, at parse time, whenever a graph attribute is assigned on any
|
|
15608
|
-
* (sub)graph: setting `ordering=out` on a subgraph declares "ordering"
|
|
15609
|
-
* graph-wide with an empty default, so `agGraphAttr(root, "ordering")` returns
|
|
15610
|
-
* `""` (not undefined) — mirroring `agfindgraphattr`/`late_string`. Read via
|
|
15611
|
-
* `agGraphAttr` (model/cgraph-ops.ts); empty on non-root graphs.
|
|
15612
|
-
* @see lib/cgraph/attr.c:agattr (graph-wide declaration, "" default)
|
|
15613
|
-
*/
|
|
15614
|
-
declaredGraphAttrs = /* @__PURE__ */ new Set();
|
|
15615
|
-
/** @see lib/cgraph/graph.c:agopen */
|
|
15616
|
-
constructor(name, kind, anonymous = false) {
|
|
15617
|
-
this.name = name;
|
|
15618
|
-
this.anonymous = anonymous;
|
|
15619
|
-
this.kind = kind;
|
|
15620
|
-
this.nodes = /* @__PURE__ */ new Map();
|
|
15621
|
-
this.edges = [];
|
|
15622
|
-
this.subgraphs = /* @__PURE__ */ new Map();
|
|
15623
|
-
this.attrs = /* @__PURE__ */ new Map();
|
|
15624
|
-
this.nodeDefaults = /* @__PURE__ */ new Map();
|
|
15625
|
-
this.edgeDefaults = /* @__PURE__ */ new Map();
|
|
15626
|
-
this.info = makeGraphInfo();
|
|
15627
|
-
this.parent = null;
|
|
15628
|
-
this.root = this;
|
|
15629
|
-
}
|
|
15630
|
-
};
|
|
15631
|
-
|
|
15632
15961
|
// src/model/cgraph-ops.ts
|
|
15633
15962
|
var LOCALNAMEPREFIX = "%";
|
|
15634
15963
|
function freshNodeId(root) {
|
|
@@ -25057,18 +25386,22 @@ function dotSameports(g) {
|
|
|
25057
25386
|
function dist2(p, q) {
|
|
25058
25387
|
const dx = p.x - q.x;
|
|
25059
25388
|
const dy = p.y - q.y;
|
|
25060
|
-
return dx
|
|
25389
|
+
return fma(dx, dx, dy * dy);
|
|
25061
25390
|
}
|
|
25062
25391
|
function distPt(p, q) {
|
|
25063
25392
|
return Math.sqrt(dist2(p, q));
|
|
25064
25393
|
}
|
|
25065
|
-
function
|
|
25394
|
+
function bezier(v, t) {
|
|
25066
25395
|
const u = 1 - t;
|
|
25067
|
-
const [
|
|
25068
|
-
|
|
25069
|
-
|
|
25070
|
-
|
|
25071
|
-
|
|
25396
|
+
const x = [v[0].x, v[1].x, v[2].x, v[3].x];
|
|
25397
|
+
const y = [v[0].y, v[1].y, v[2].y, v[3].y];
|
|
25398
|
+
for (let i = 1; i <= 3; i++) {
|
|
25399
|
+
for (let j = 0; j <= 3 - i; j++) {
|
|
25400
|
+
x[j] = fma(x[j], u, t * x[j + 1]);
|
|
25401
|
+
y[j] = fma(y[j], u, t * y[j + 1]);
|
|
25402
|
+
}
|
|
25403
|
+
}
|
|
25404
|
+
return { x: x[0], y: y[0] };
|
|
25072
25405
|
}
|
|
25073
25406
|
function dotneatoClosest(spl, pt) {
|
|
25074
25407
|
let besti = 0;
|
|
@@ -25098,7 +25431,7 @@ function dotneatoClosest(spl, pt) {
|
|
|
25098
25431
|
let pt2;
|
|
25099
25432
|
for (; ; ) {
|
|
25100
25433
|
const t = (lo + hi) / 2;
|
|
25101
|
-
pt2 =
|
|
25434
|
+
pt2 = bezier(c, t);
|
|
25102
25435
|
if (Math.abs(dlo2 - dhi2) < 1 || Math.abs(hi - lo) < 1e-5) break;
|
|
25103
25436
|
if (dlo2 < dhi2) {
|
|
25104
25437
|
hi = t;
|
|
@@ -26010,9 +26343,19 @@ var ShortestHelper = class _ShortestHelper {
|
|
|
26010
26343
|
_ShortestHelper.connectAll(tris);
|
|
26011
26344
|
const ftrii = _ShortestHelper.findTri(tris, eps[0]);
|
|
26012
26345
|
const ltrii = _ShortestHelper.findTri(tris, eps[1]);
|
|
26013
|
-
if (ftrii === NO_TRI
|
|
26346
|
+
if (ftrii === NO_TRI) {
|
|
26347
|
+
console.warn("source point not in any triangle");
|
|
26348
|
+
return null;
|
|
26349
|
+
}
|
|
26350
|
+
if (ltrii === NO_TRI) {
|
|
26351
|
+
console.warn("destination point not in any triangle");
|
|
26352
|
+
return null;
|
|
26353
|
+
}
|
|
26014
26354
|
if (ftrii === ltrii) return [eps[0], eps[1]];
|
|
26015
|
-
if (!_ShortestHelper.markPath(tris, ftrii, ltrii))
|
|
26355
|
+
if (!_ShortestHelper.markPath(tris, ftrii, ltrii)) {
|
|
26356
|
+
console.warn("cannot find triangle path");
|
|
26357
|
+
return [eps[0], eps[1]];
|
|
26358
|
+
}
|
|
26016
26359
|
const epnls = [{ pp: eps[0], link: null }, { pp: eps[1], link: null }];
|
|
26017
26360
|
const dq = _ShortestHelper.initDeque(pnlps.length);
|
|
26018
26361
|
_ShortestHelper.add2dq(dq, DQ_FRONT, epnls[0]);
|
|
@@ -27994,7 +28337,7 @@ function nodeCover(n) {
|
|
|
27994
28337
|
for (let i = 0; i < NODECARD; i++) {
|
|
27995
28338
|
if (n.branch[i].child !== null) {
|
|
27996
28339
|
if (flag) {
|
|
27997
|
-
r = n.branch[i].rect;
|
|
28340
|
+
r = { boundary: [...n.branch[i].rect.boundary] };
|
|
27998
28341
|
flag = false;
|
|
27999
28342
|
} else {
|
|
28000
28343
|
r = combineRect(r, n.branch[i].rect);
|
|
@@ -29947,7 +30290,10 @@ function makeFlatLabeledEdge(g, e) {
|
|
|
29947
30290
|
info: { ...e.info, tail_port: e.info.head_port, head_port: e.info.tail_port }
|
|
29948
30291
|
};
|
|
29949
30292
|
const ps = routeFlatLabeledChannel(g, sample, ln, et);
|
|
29950
|
-
if (ps === null || ps.length === 0)
|
|
30293
|
+
if (ps === null || ps.length === 0) {
|
|
30294
|
+
e.info.lost = true;
|
|
30295
|
+
return true;
|
|
30296
|
+
}
|
|
29951
30297
|
if (!tailIsLeft) ps.reverse();
|
|
29952
30298
|
clipAndInstall(e, e.head, ps, ps.length, { ...buildDotSinfo(), ignoreSwap: true });
|
|
29953
30299
|
return true;
|
|
@@ -30260,8 +30606,8 @@ function nodeInsideFn2(box) {
|
|
|
30260
30606
|
const pw = box.penwidth ?? DEFAULT_NODEPENWIDTH;
|
|
30261
30607
|
return box.isEllipse ? makeEllipseInsideFn(halfW, halfH, pw) : makeBoxInsideFn(halfW, halfH, pw);
|
|
30262
30608
|
}
|
|
30263
|
-
function clipToNodes(
|
|
30264
|
-
const step1 = clip.tail ? bezierClipNode(
|
|
30609
|
+
function clipToNodes(bezier2, tailBox, headBox, penwidth = DEFAULT_NODEPENWIDTH, clip = CLIP_BOTH) {
|
|
30610
|
+
const step1 = clip.tail ? bezierClipNode(bezier2, tailBox.center.x, tailBox.center.y, nodeInsideFn2(tailBox), true) : bezier2;
|
|
30265
30611
|
const step2 = clip.head ? bezierClipNode(step1, headBox.center.x, headBox.center.y, nodeInsideFn2(headBox), false) : step1;
|
|
30266
30612
|
const arrowTip = step2[3];
|
|
30267
30613
|
const elen = normalArrowLen(penwidth);
|
|
@@ -30275,9 +30621,9 @@ function clipToNodes(bezier, tailBox, headBox, penwidth = DEFAULT_NODEPENWIDTH,
|
|
|
30275
30621
|
function routeWithRank(tailBox, headBox, rank3, penwidth = DEFAULT_NODEPENWIDTH, port) {
|
|
30276
30622
|
const corridor = port ? { tailP: port.tailP, headP: port.headP } : void 0;
|
|
30277
30623
|
const { startPt, endPt, boxes } = buildRankCorridor(tailBox, headBox, rank3, corridor);
|
|
30278
|
-
const
|
|
30624
|
+
const bezier2 = computeSpline(boxes, startPt, endPt);
|
|
30279
30625
|
const clip = port ? { tail: port.clipTail, head: port.clipHead } : CLIP_BOTH;
|
|
30280
|
-
const { clipped, arrowTip, arrowDir } = clipToNodes(
|
|
30626
|
+
const { clipped, arrowTip, arrowDir } = clipToNodes(bezier2, tailBox, headBox, penwidth, clip);
|
|
30281
30627
|
return { bezierPts: clipped, arrowTip, arrowDir };
|
|
30282
30628
|
}
|
|
30283
30629
|
function routeSimple(tailBox, headBox, routeBezierFn) {
|
|
@@ -32870,24 +33216,27 @@ function buildNodes(nodeArr) {
|
|
|
32870
33216
|
ysize: n.info.ht
|
|
32871
33217
|
}));
|
|
32872
33218
|
}
|
|
33219
|
+
function isConcentrateDup(ps, e) {
|
|
33220
|
+
const ti = e.tail.id;
|
|
33221
|
+
const hi = e.head.id;
|
|
33222
|
+
const lo = ti <= hi ? ti : hi;
|
|
33223
|
+
const up = ti <= hi ? hi : ti;
|
|
33224
|
+
if (ps.isInPS(lo, up)) return true;
|
|
33225
|
+
ps.addPS(lo, up);
|
|
33226
|
+
return false;
|
|
33227
|
+
}
|
|
32873
33228
|
function buildEdges(g, nodeArr, orthoNodes) {
|
|
32874
33229
|
const concentrate = dotRoot(g).info.concentrate ?? false;
|
|
32875
33230
|
const nodeIndex = /* @__PURE__ */ new Map();
|
|
32876
33231
|
nodeArr.forEach((n, i) => nodeIndex.set(n, i));
|
|
32877
33232
|
const outIndex = buildOutEdgeIndex(g);
|
|
32878
|
-
const
|
|
33233
|
+
const ps = concentrate ? new PointSet() : null;
|
|
32879
33234
|
const result = [];
|
|
32880
33235
|
for (const n of nodeArr) {
|
|
32881
33236
|
const oes = outIndex.get(n);
|
|
32882
33237
|
if (oes === void 0) continue;
|
|
32883
33238
|
for (const e of oes) {
|
|
32884
|
-
if (
|
|
32885
|
-
const ti = e.tail.id;
|
|
32886
|
-
const hi = e.head.id;
|
|
32887
|
-
const key = ti <= hi ? `${ti},${hi}` : `${hi},${ti}`;
|
|
32888
|
-
if (seen.has(key)) continue;
|
|
32889
|
-
seen.add(key);
|
|
32890
|
-
}
|
|
33239
|
+
if (ps !== null && isConcentrateDup(ps, e)) continue;
|
|
32891
33240
|
result.push({
|
|
32892
33241
|
tail: orthoNodes[nodeIndex.get(e.tail)],
|
|
32893
33242
|
head: orthoNodes[nodeIndex.get(e.head)],
|
|
@@ -33975,15 +34324,6 @@ function spiralSearch(info, ctx, wide) {
|
|
|
33975
34324
|
|
|
33976
34325
|
// src/layout/pack/poly-pack.ts
|
|
33977
34326
|
var C2 = 100;
|
|
33978
|
-
function psKey(x, y) {
|
|
33979
|
-
return `${cround(x)},${cround(y)}`;
|
|
33980
|
-
}
|
|
33981
|
-
function inPS(ps, p) {
|
|
33982
|
-
return ps.has(psKey(p.x, p.y));
|
|
33983
|
-
}
|
|
33984
|
-
function insertPS(ps, p) {
|
|
33985
|
-
ps.add(psKey(p.x, p.y));
|
|
33986
|
-
}
|
|
33987
34327
|
function computeStep(ng, bbs, margin) {
|
|
33988
34328
|
let b = 0;
|
|
33989
34329
|
let c = 0;
|
|
@@ -34030,14 +34370,14 @@ function genBox2(p) {
|
|
|
34030
34370
|
function hasCollision(cells, dx, dy, ps) {
|
|
34031
34371
|
for (let i = 0; i < cells.length; i++) {
|
|
34032
34372
|
const cell2 = cells[i];
|
|
34033
|
-
if (cell2 !== void 0 && inPS(
|
|
34373
|
+
if (cell2 !== void 0 && ps.inPS({ x: cell2.x + dx, y: cell2.y + dy })) return true;
|
|
34034
34374
|
}
|
|
34035
34375
|
return false;
|
|
34036
34376
|
}
|
|
34037
34377
|
function markCells(cells, dx, dy, ps) {
|
|
34038
34378
|
for (let i = 0; i < cells.length; i++) {
|
|
34039
34379
|
const cell2 = cells[i];
|
|
34040
|
-
if (cell2 !== void 0)
|
|
34380
|
+
if (cell2 !== void 0) ps.addPS(cell2.x + dx, cell2.y + dy);
|
|
34041
34381
|
}
|
|
34042
34382
|
}
|
|
34043
34383
|
function fits(x, y, info, ctx) {
|
|
@@ -34082,7 +34422,7 @@ function polyRects(ng, bbs, pinfo) {
|
|
|
34082
34422
|
infos.push(genBox2({ bb, ssize: step, margin: pinfo.margin, idx: i }));
|
|
34083
34423
|
}
|
|
34084
34424
|
const sorted = gvQsort([...infos], cmpByGPerimeter);
|
|
34085
|
-
const ctx = { ps:
|
|
34425
|
+
const ctx = { ps: new PointSet(), step, bbs };
|
|
34086
34426
|
const places = new Array(ng).fill({ x: 0, y: 0 });
|
|
34087
34427
|
for (let i = 0; i < sorted.length; i++) {
|
|
34088
34428
|
const info = sorted[i];
|
|
@@ -34092,57 +34432,6 @@ function polyRects(ng, bbs, pinfo) {
|
|
|
34092
34432
|
return places;
|
|
34093
34433
|
}
|
|
34094
34434
|
|
|
34095
|
-
// src/common/pointset.ts
|
|
34096
|
-
function cmpPair(a, b) {
|
|
34097
|
-
if (a.x > b.x) return 1;
|
|
34098
|
-
if (a.x < b.x) return -1;
|
|
34099
|
-
if (a.y > b.y) return 1;
|
|
34100
|
-
if (a.y < b.y) return -1;
|
|
34101
|
-
return 0;
|
|
34102
|
-
}
|
|
34103
|
-
var PointSet = class {
|
|
34104
|
-
byX = /* @__PURE__ */ new Map();
|
|
34105
|
-
n = 0;
|
|
34106
|
-
/**
|
|
34107
|
-
* Insert (x, y). A duplicate keeps the point inserted first, as `dtinsert`
|
|
34108
|
-
* returns the existing object and the new one is freed.
|
|
34109
|
-
* @see lib/common/pointset.c:addPS
|
|
34110
|
-
*/
|
|
34111
|
-
addPS(x, y) {
|
|
34112
|
-
let col = this.byX.get(x);
|
|
34113
|
-
if (col === void 0) {
|
|
34114
|
-
col = /* @__PURE__ */ new Map();
|
|
34115
|
-
this.byX.set(x, col);
|
|
34116
|
-
}
|
|
34117
|
-
if (col.has(y)) return;
|
|
34118
|
-
col.set(y, { x, y });
|
|
34119
|
-
this.n++;
|
|
34120
|
-
}
|
|
34121
|
-
/** @see lib/common/pointset.c:inPS */
|
|
34122
|
-
inPS(pt) {
|
|
34123
|
-
return this.byX.get(pt.x)?.has(pt.y) ?? false;
|
|
34124
|
-
}
|
|
34125
|
-
/** @see lib/common/pointset.c:isInPS */
|
|
34126
|
-
isInPS(x, y) {
|
|
34127
|
-
return this.byX.get(x)?.has(y) ?? false;
|
|
34128
|
-
}
|
|
34129
|
-
/** @see lib/common/pointset.c:sizeOf */
|
|
34130
|
-
sizeOf() {
|
|
34131
|
-
return this.n;
|
|
34132
|
-
}
|
|
34133
|
-
/**
|
|
34134
|
-
* The points in dictionary order (`dtflatten` walks the ordered set).
|
|
34135
|
-
* @see lib/common/pointset.c:pointsOf
|
|
34136
|
-
*/
|
|
34137
|
-
pointsOf() {
|
|
34138
|
-
const pts = [];
|
|
34139
|
-
for (const col of this.byX.values()) {
|
|
34140
|
-
for (const p of col.values()) pts.push({ x: p.x, y: p.y });
|
|
34141
|
-
}
|
|
34142
|
-
return pts.sort(cmpPair);
|
|
34143
|
-
}
|
|
34144
|
-
};
|
|
34145
|
-
|
|
34146
34435
|
// src/layout/pack/poly-place.ts
|
|
34147
34436
|
var C_AVG = 100;
|
|
34148
34437
|
function grid(x, s) {
|
|
@@ -37983,6 +38272,12 @@ function chainOf(e) {
|
|
|
37983
38272
|
}
|
|
37984
38273
|
return list;
|
|
37985
38274
|
}
|
|
38275
|
+
function warnNoControlPoints(e) {
|
|
38276
|
+
console.warn(
|
|
38277
|
+
`Warning: Could not create control points for multiple spline for edge (${e.tail.name},${e.head.name})`
|
|
38278
|
+
);
|
|
38279
|
+
return 1;
|
|
38280
|
+
}
|
|
37986
38281
|
function genroute(g, trip, t, e, doPolyline) {
|
|
37987
38282
|
const eps = [
|
|
37988
38283
|
{ x: trip.ps[0].x, y: trip.ps[0].y },
|
|
@@ -37992,7 +38287,7 @@ function genroute(g, trip, t, e, doPolyline) {
|
|
|
37992
38287
|
const mult = e.info.count ?? 1;
|
|
37993
38288
|
const head = e.head;
|
|
37994
38289
|
const pl = shortestPath({ ps: trip.ps }, eps);
|
|
37995
|
-
if (pl === null) return
|
|
38290
|
+
if (pl === null) return warnNoControlPoints(e);
|
|
37996
38291
|
if (pl.length === 2) {
|
|
37997
38292
|
const chain = chainOf(e);
|
|
37998
38293
|
makeStraightEdges(g, chain, chain.length, doPolyline ? 1 : 0, MSINFO);
|
|
@@ -38000,7 +38295,7 @@ function genroute(g, trip, t, e, doPolyline) {
|
|
|
38000
38295
|
}
|
|
38001
38296
|
if (mult === 1 || concentrate) {
|
|
38002
38297
|
const spl = routeMember(trip.ps, t, pl, doPolyline);
|
|
38003
|
-
if (spl === null) return
|
|
38298
|
+
if (spl === null) return warnNoControlPoints(e);
|
|
38004
38299
|
finishEdge(e, spl, e.head !== head);
|
|
38005
38300
|
return 0;
|
|
38006
38301
|
}
|
|
@@ -38008,7 +38303,7 @@ function genroute(g, trip, t, e, doPolyline) {
|
|
|
38008
38303
|
const cpts = [];
|
|
38009
38304
|
for (let i = 0; i + 2 < pl.length; i++) {
|
|
38010
38305
|
const cp = mkCtrlPts(t, mult + 1, pl[i], pl[i + 1], pl[i + 2], trip);
|
|
38011
|
-
if (cp === null) return
|
|
38306
|
+
if (cp === null) return warnNoControlPoints(e);
|
|
38012
38307
|
cpts.push(cp);
|
|
38013
38308
|
}
|
|
38014
38309
|
let cur = e;
|
|
@@ -38023,9 +38318,9 @@ function genroute(g, trip, t, e, doPolyline) {
|
|
|
38023
38318
|
poly[pn - j] = cpts[j - 1][i + 1];
|
|
38024
38319
|
}
|
|
38025
38320
|
const mmpl = shortestPath({ ps: poly }, eps);
|
|
38026
|
-
if (mmpl === null) return
|
|
38321
|
+
if (mmpl === null) return warnNoControlPoints(cur);
|
|
38027
38322
|
const spl = routeMember(poly, pl.length - 1, mmpl, doPolyline);
|
|
38028
|
-
if (spl === null) return
|
|
38323
|
+
if (spl === null) return warnNoControlPoints(cur);
|
|
38029
38324
|
finishEdge(cur, spl, cur.head !== head);
|
|
38030
38325
|
cur = cur.info.to_virt;
|
|
38031
38326
|
}
|
|
@@ -47249,22 +47544,22 @@ function freeBlocktree(bp) {
|
|
|
47249
47544
|
|
|
47250
47545
|
// src/layout/circo/position-helpers.ts
|
|
47251
47546
|
function rotatePoint(x, y, cosR, sinR) {
|
|
47252
|
-
return [x
|
|
47547
|
+
return [fma(x, cosR, -sinR * y), fma(x, sinR, cosR * y)];
|
|
47253
47548
|
}
|
|
47254
47549
|
function nodePsi(n) {
|
|
47255
47550
|
return n.info.alg?.psi ?? 0;
|
|
47256
47551
|
}
|
|
47257
47552
|
function rotFromParentPos(sn, theta) {
|
|
47258
|
-
let r = theta + Math.PI - sn.parentPos;
|
|
47553
|
+
let r = theta + (Math.PI - sn.parentPos);
|
|
47259
47554
|
if (r < 0) r += 2 * Math.PI;
|
|
47260
47555
|
return r;
|
|
47261
47556
|
}
|
|
47262
47557
|
function closestNode(sn, x, y, skip) {
|
|
47263
47558
|
let best = skip;
|
|
47264
|
-
let bestDist =
|
|
47559
|
+
let bestDist = libmHypot(skip.info.pos[0] + x, skip.info.pos[1] + y);
|
|
47265
47560
|
for (const dn of sn.subGraph.nodes) {
|
|
47266
47561
|
if (dn.orig === skip) continue;
|
|
47267
|
-
const d =
|
|
47562
|
+
const d = libmHypot(dn.orig.info.pos[0] + x, dn.orig.info.pos[1] + y);
|
|
47268
47563
|
if (d < bestDist) {
|
|
47269
47564
|
bestDist = d;
|
|
47270
47565
|
best = dn.orig;
|
|
@@ -47277,22 +47572,19 @@ function rotCoalesced(sn, x, y, nbr, theta) {
|
|
|
47277
47572
|
const r = sn.radius - rho;
|
|
47278
47573
|
const nx = nbr.info.pos[0];
|
|
47279
47574
|
const ny = nbr.info.pos[1];
|
|
47280
|
-
|
|
47281
|
-
const phi2 = Math.atan2(ny, nx);
|
|
47282
|
-
return theta + Math.PI - phi2 - nodePsi(nbr);
|
|
47283
|
-
}
|
|
47284
|
-
const R2 = Math.hypot(x, y);
|
|
47575
|
+
const R2 = libmHypot(x, y);
|
|
47285
47576
|
const phi = Math.atan2(ny, nx + r);
|
|
47286
47577
|
const l = r - rho / Math.cos(phi);
|
|
47287
|
-
return theta + Math.PI / 2 - phi - Math.asin(l / R2 * Math.cos(phi));
|
|
47578
|
+
return theta + (Math.PI / 2 - phi - Math.asin(l / R2 * Math.cos(phi)));
|
|
47288
47579
|
}
|
|
47289
47580
|
function rotGeneral(sn, x, y, nbr, theta) {
|
|
47290
47581
|
if (closestNode(sn, x, y, nbr) === nbr) return 0;
|
|
47291
|
-
|
|
47582
|
+
const r = sn.radius - sn.rad0;
|
|
47583
|
+
if (isCoalesced(sn) && -r < nbr.info.pos[0]) return rotCoalesced(sn, x, y, nbr, theta);
|
|
47292
47584
|
const phi = Math.atan2(nbr.info.pos[1], nbr.info.pos[0]);
|
|
47293
|
-
let
|
|
47294
|
-
if (
|
|
47295
|
-
return
|
|
47585
|
+
let t = theta + (Math.PI - phi - nodePsi(nbr));
|
|
47586
|
+
if (t > 2 * Math.PI) t -= 2 * Math.PI;
|
|
47587
|
+
return t;
|
|
47296
47588
|
}
|
|
47297
47589
|
function applyDelta(sn, x, y, rotate) {
|
|
47298
47590
|
const cosR = Math.cos(rotate);
|
|
@@ -47335,7 +47627,7 @@ function getInfo(pi, stp, minDist) {
|
|
|
47335
47627
|
}
|
|
47336
47628
|
function setInfo(p0, p1, delta2) {
|
|
47337
47629
|
const t = Math.max(
|
|
47338
|
-
(p0.diameter
|
|
47630
|
+
fma(p0.diameter, p1.minRadius, p1.diameter * p0.minRadius) / (2 * delta2 * p0.minRadius * p1.minRadius),
|
|
47339
47631
|
1
|
|
47340
47632
|
);
|
|
47341
47633
|
p0.scale = Math.max(p0.scale, t);
|
|
@@ -47345,7 +47637,13 @@ function placeChild(child, ca, ctx) {
|
|
|
47345
47637
|
const dx = ctx.childRadius * Math.cos(ca);
|
|
47346
47638
|
const dy = ctx.childRadius * Math.sin(ca);
|
|
47347
47639
|
applyDelta(child, dx, dy, getRotation(child, dx, dy, ca));
|
|
47348
|
-
return
|
|
47640
|
+
return nextChildAngle(ca, ctx.incAngle, ctx.mindistAngle, ctx.length);
|
|
47641
|
+
}
|
|
47642
|
+
function nextChildAngle(ca, inc2, mda, length) {
|
|
47643
|
+
return length === 1 ? ca + (inc2 + mda) : ca + (inc2 + mda / 2);
|
|
47644
|
+
}
|
|
47645
|
+
function leftoverArc(childRadius, diameter) {
|
|
47646
|
+
return fma(2 * Math.PI, childRadius, -diameter);
|
|
47349
47647
|
}
|
|
47350
47648
|
function advanceAngleL1(ca, inc2, total, cnt, stp) {
|
|
47351
47649
|
const next = cnt === 0 ? 0 : total === 2 ? Math.PI : ca + inc2;
|
|
@@ -47355,7 +47653,7 @@ function advanceAngleL1(ca, inc2, total, cnt, stp) {
|
|
|
47355
47653
|
}
|
|
47356
47654
|
function advanceAngleLN(ca, inc2, mda, total, theta) {
|
|
47357
47655
|
if (total === 1) return theta;
|
|
47358
|
-
return ca + inc2 + mda / 2;
|
|
47656
|
+
return ca + (inc2 + mda / 2);
|
|
47359
47657
|
}
|
|
47360
47658
|
function maybeWritePsi(n, stp, ca, isMid) {
|
|
47361
47659
|
if (isMid && n === stp.neighbor) {
|
|
@@ -47370,7 +47668,7 @@ function positionChildren(pi, stp, length, minDist) {
|
|
|
47370
47668
|
let md = minDist;
|
|
47371
47669
|
if (length === 1) {
|
|
47372
47670
|
cr = Math.max(cr, pi.diameter / (2 * Math.PI));
|
|
47373
|
-
const d =
|
|
47671
|
+
const d = leftoverArc(cr, pi.diameter);
|
|
47374
47672
|
if (d > 0) md += d / pi.childCount;
|
|
47375
47673
|
}
|
|
47376
47674
|
stp.subtreeR = Math.max(stp.subtreeR, cr + pi.maxRadius);
|
|
@@ -54399,11 +54697,11 @@ function lexToken(s, i) {
|
|
|
54399
54697
|
function scanNumberAmbiguities(src, stripped) {
|
|
54400
54698
|
const out = [];
|
|
54401
54699
|
let line = 1;
|
|
54402
|
-
let
|
|
54700
|
+
let lineAt2 = 0;
|
|
54403
54701
|
for (let i = 0; i < stripped.length; ) {
|
|
54404
54702
|
const { next, bad } = lexToken(stripped, i);
|
|
54405
54703
|
if (bad !== null) {
|
|
54406
|
-
for (;
|
|
54704
|
+
for (; lineAt2 < i; lineAt2++) if (src[lineAt2] === "\n") line++;
|
|
54407
54705
|
out.push({ text: bad, line, offset: i });
|
|
54408
54706
|
}
|
|
54409
54707
|
i = next;
|