@knowvah/dot-engine 2.6.11 → 2.7.0
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/README.md +1 -1
- package/dist/api.js +18 -4
- package/dist/api.js.map +3 -3
- package/dist/async/render-async.d.ts.map +1 -1
- package/dist/common/agerr.d.ts +37 -0
- package/dist/common/agerr.d.ts.map +1 -0
- package/dist/common/arrows-shapes-poly.d.ts.map +1 -1
- package/dist/common/color.d.ts.map +1 -1
- package/dist/common/crand.d.ts +0 -20
- package/dist/common/crand.d.ts.map +1 -1
- package/dist/common/emit-once.d.ts +6 -0
- package/dist/common/emit-once.d.ts.map +1 -0
- package/dist/common/graph-init.d.ts.map +1 -1
- package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
- package/dist/common/htmltable-emit-fill.d.ts +29 -2
- package/dist/common/htmltable-emit-fill.d.ts.map +1 -1
- package/dist/common/htmltable-emit-rules.d.ts.map +1 -1
- package/dist/common/htmltable-emit.d.ts.map +1 -1
- package/dist/common/htmltable-lex-expat.d.ts +1 -6
- package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
- package/dist/common/htmltable-pos-runs.d.ts +7 -4
- package/dist/common/htmltable-pos-runs.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +1 -7
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/libm-trig.d.ts +5 -0
- package/dist/common/libm-trig.d.ts.map +1 -0
- package/dist/common/multicolor.d.ts +21 -13
- package/dist/common/multicolor.d.ts.map +1 -1
- package/dist/common/poly-gencode.d.ts +1 -2
- package/dist/common/poly-gencode.d.ts.map +1 -1
- package/dist/common/poly-init.d.ts.map +1 -1
- package/dist/common/postproc.d.ts.map +1 -1
- package/dist/common/random.d.ts.map +1 -1
- package/dist/common/render-state.d.ts +8 -0
- package/dist/common/render-state.d.ts.map +1 -0
- package/dist/common/splines-clip.d.ts +7 -0
- package/dist/common/splines-clip.d.ts.map +1 -1
- package/dist/common/splines-geom.d.ts +8 -0
- package/dist/common/splines-geom.d.ts.map +1 -1
- package/dist/common/splines-routespl.d.ts.map +1 -1
- package/dist/common/textmeasure-lookup.d.ts.map +1 -1
- package/dist/common/textmeasure.d.ts.map +1 -1
- package/dist/gvc/anchor.d.ts.map +1 -1
- package/dist/gvc/context.d.ts +6 -0
- package/dist/gvc/context.d.ts.map +1 -1
- package/dist/gvc/device-cluster.d.ts +15 -0
- package/dist/gvc/device-cluster.d.ts.map +1 -1
- package/dist/gvc/device-labels.d.ts +14 -0
- package/dist/gvc/device-labels.d.ts.map +1 -1
- package/dist/gvc/device.d.ts.map +1 -1
- package/dist/gvc/first-layer.d.ts +9 -0
- package/dist/gvc/first-layer.d.ts.map +1 -0
- package/dist/gvc/gvrender-set-style.d.ts +28 -0
- package/dist/gvc/gvrender-set-style.d.ts.map +1 -0
- package/dist/gvc/usershape.d.ts +18 -0
- package/dist/gvc/usershape.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3169 -1296
- package/dist/index.js.map +4 -4
- package/dist/layout/dot/cluster.d.ts.map +1 -1
- package/dist/layout/dot/compound.d.ts.map +1 -1
- package/dist/layout/dot/conc.d.ts.map +1 -1
- package/dist/layout/dot/decomp.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-clip.d.ts +32 -14
- package/dist/layout/dot/edge-route-clip.d.ts.map +1 -1
- package/dist/layout/dot/edge-route-routing.d.ts.map +1 -1
- package/dist/layout/dot/mincross-build.d.ts.map +1 -1
- package/dist/layout/dot/mincross-cross.d.ts.map +1 -1
- package/dist/layout/dot/rank.d.ts.map +1 -1
- package/dist/layout/dot/splines.d.ts.map +1 -1
- package/dist/layout/fdp/index.d.ts.map +1 -1
- package/dist/layout/fdp/tlayout-parms.d.ts.map +1 -1
- package/dist/layout/fdp/xlayout.d.ts.map +1 -1
- package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts +11 -0
- package/dist/layout/neato/__fixtures__/dijkstra-f.d.ts.map +1 -0
- package/dist/layout/neato/__fixtures__/hier-imds.d.ts +36 -0
- package/dist/layout/neato/__fixtures__/hier-imds.d.ts.map +1 -0
- package/dist/layout/neato/__fixtures__/hier-majorization.d.ts +32 -0
- package/dist/layout/neato/__fixtures__/hier-majorization.d.ts.map +1 -0
- package/dist/layout/neato/cdt-surface.d.ts.map +1 -1
- package/dist/layout/neato/compute-hierarchy.d.ts +24 -0
- package/dist/layout/neato/compute-hierarchy.d.ts.map +1 -0
- package/dist/layout/neato/conjgrad-mkernel.d.ts +20 -0
- package/dist/layout/neato/conjgrad-mkernel.d.ts.map +1 -0
- package/dist/layout/neato/conjgrad.d.ts +19 -0
- package/dist/layout/neato/conjgrad.d.ts.map +1 -1
- package/dist/layout/neato/constrained-majorization.d.ts +26 -0
- package/dist/layout/neato/constrained-majorization.d.ts.map +1 -0
- package/dist/layout/neato/dijkstra.d.ts +33 -16
- package/dist/layout/neato/dijkstra.d.ts.map +1 -1
- package/dist/layout/neato/edge-len.d.ts.map +1 -1
- package/dist/layout/neato/fdp-adjust.d.ts.map +1 -1
- package/dist/layout/neato/gts-triangle.d.ts +14 -0
- package/dist/layout/neato/gts-triangle.d.ts.map +1 -0
- package/dist/layout/neato/init.d.ts +6 -22
- package/dist/layout/neato/init.d.ts.map +1 -1
- package/dist/layout/neato/kk.d.ts.map +1 -1
- package/dist/layout/neato/kkutils.d.ts +20 -0
- package/dist/layout/neato/kkutils.d.ts.map +1 -0
- package/dist/layout/neato/make-graph-data.d.ts +43 -0
- package/dist/layout/neato/make-graph-data.d.ts.map +1 -0
- package/dist/layout/neato/matrix-ops.d.ts +46 -0
- package/dist/layout/neato/matrix-ops.d.ts.map +1 -1
- package/dist/layout/neato/multispline-router.d.ts.map +1 -1
- package/dist/layout/neato/multispline.d.ts.map +1 -1
- package/dist/layout/neato/opt-arrangement.d.ts +20 -0
- package/dist/layout/neato/opt-arrangement.d.ts.map +1 -0
- package/dist/layout/neato/poly.d.ts.map +1 -1
- package/dist/layout/neato/quad-prog-solve.d.ts +44 -0
- package/dist/layout/neato/quad-prog-solve.d.ts.map +1 -0
- package/dist/layout/neato/sgd.d.ts.map +1 -1
- package/dist/layout/neato/smart-ini-x.d.ts +9 -0
- package/dist/layout/neato/smart-ini-x.d.ts.map +1 -0
- package/dist/layout/neato/splines.d.ts +1 -1
- package/dist/layout/neato/splines.d.ts.map +1 -1
- package/dist/layout/neato/start.d.ts +4 -1
- package/dist/layout/neato/start.d.ts.map +1 -1
- package/dist/layout/neato/stress.d.ts +8 -0
- package/dist/layout/neato/stress.d.ts.map +1 -1
- package/dist/model/edge.d.ts +1 -1
- package/dist/model/edge.d.ts.map +1 -1
- package/dist/model/lazy-attrs.d.ts +10 -0
- package/dist/model/lazy-attrs.d.ts.map +1 -0
- package/dist/model/node.d.ts +1 -1
- package/dist/model/node.d.ts.map +1 -1
- package/dist/ortho/index.d.ts.map +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/render/color-resolve.d.ts +49 -1
- package/dist/render/color-resolve.d.ts.map +1 -1
- package/dist/render/dot/edge-draw.d.ts +1 -1
- package/dist/render/dot/edge-draw.d.ts.map +1 -1
- package/dist/render/public.d.ts.map +1 -1
- package/dist/render/svg-edge-split.d.ts +2 -0
- package/dist/render/svg-edge-split.d.ts.map +1 -1
- package/dist/render/svg-multicolor.d.ts +2 -2
- package/dist/render/svg-multicolor.d.ts.map +1 -1
- package/dist/render/xdot-public.d.ts.map +1 -1
- package/dist/render.js +2799 -927
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/async/render-async.ts +6 -0
- package/src/common/agerr.ts +96 -0
- package/src/common/arrows-shapes-poly.ts +19 -5
- package/src/common/color.ts +38 -10
- package/src/common/crand.ts +8 -2
- package/src/common/emit-once.ts +27 -0
- package/src/common/graph-init.ts +2 -1
- package/src/common/htmltable-attr-warn.ts +3 -4
- package/src/common/htmltable-emit-fill.ts +104 -11
- package/src/common/htmltable-emit-rules.ts +2 -0
- package/src/common/htmltable-emit.ts +4 -3
- package/src/common/htmltable-lex-expat.ts +96 -23
- package/src/common/htmltable-pos-runs.ts +11 -6
- package/src/common/htmltable.ts +28 -117
- package/src/common/libm-trig.ts +43 -0
- package/src/common/multicolor.ts +88 -24
- package/src/common/poly-gencode.ts +30 -10
- package/src/common/poly-init.ts +20 -1
- package/src/common/postproc.ts +4 -1
- package/src/common/random.ts +11 -1
- package/src/common/render-state.ts +36 -0
- package/src/common/splines-clip.ts +15 -12
- package/src/common/splines-geom.ts +8 -4
- package/src/common/splines-routespl.ts +2 -1
- package/src/common/textmeasure-lookup.ts +9 -2
- package/src/common/textmeasure.ts +45 -2
- package/src/gvc/anchor.ts +1 -12
- package/src/gvc/context.ts +8 -0
- package/src/gvc/device-cluster.ts +93 -10
- package/src/gvc/device-labels.ts +27 -0
- package/src/gvc/device.ts +34 -8
- package/src/gvc/first-layer.ts +26 -0
- package/src/gvc/gvrender-set-style.ts +114 -0
- package/src/gvc/usershape.ts +26 -0
- package/src/index.ts +3 -0
- package/src/layout/dot/cluster.ts +2 -1
- package/src/layout/dot/compound.ts +3 -4
- package/src/layout/dot/conc.ts +6 -5
- package/src/layout/dot/decomp.ts +3 -0
- package/src/layout/dot/edge-route-clip.ts +46 -28
- package/src/layout/dot/edge-route-routing.ts +11 -3
- package/src/layout/dot/fastgr.ts +2 -2
- package/src/layout/dot/mincross-build.ts +2 -0
- package/src/layout/dot/mincross-cross.ts +2 -0
- package/src/layout/dot/rank.ts +2 -0
- package/src/layout/dot/splines.ts +2 -1
- package/src/layout/fdp/index.ts +2 -1
- package/src/layout/fdp/tlayout-parms.ts +9 -2
- package/src/layout/fdp/xlayout.ts +10 -2
- package/src/layout/neato/__fixtures__/dijkstra-f.ts +17 -0
- package/src/layout/neato/__fixtures__/hier/c1554.gv +33 -0
- package/src/layout/neato/__fixtures__/hier/c1554.plain +26 -0
- package/src/layout/neato/__fixtures__/hier/c1554.xdot +161 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/cycle.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.plain +11 -0
- package/src/layout/neato/__fixtures__/hier/cases/dirnone.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.plain +13 -0
- package/src/layout/neato/__fixtures__/hier/cases/epsilon.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.plain +8 -0
- package/src/layout/neato/__fixtures__/hier/cases/levelsgap.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/mds.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/multiedge.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.plain +8 -0
- package/src/layout/neato/__fixtures__/hier/cases/neglevelsgap.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/startrandom.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/startregular.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.plain +13 -0
- package/src/layout/neato/__fixtures__/hier/cases/tdist.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.plain +10 -0
- package/src/layout/neato/__fixtures__/hier/cases/undirected.stderr +0 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.gv +1 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.plain +16 -0
- package/src/layout/neato/__fixtures__/hier/hier-probe.xdot +62 -0
- package/src/layout/neato/__fixtures__/hier-imds.ts +151 -0
- package/src/layout/neato/__fixtures__/hier-majorization.ts +145 -0
- package/src/layout/neato/cdt-surface.ts +12 -22
- package/src/layout/neato/compute-hierarchy.ts +90 -0
- package/src/layout/neato/conjgrad-mkernel.ts +141 -0
- package/src/layout/neato/conjgrad.ts +208 -0
- package/src/layout/neato/constrained-majorization.ts +479 -0
- package/src/layout/neato/dijkstra.ts +218 -92
- package/src/layout/neato/edge-len.ts +2 -1
- package/src/layout/neato/fdp-adjust.ts +3 -2
- package/src/layout/neato/gts-triangle.ts +42 -0
- package/src/layout/neato/init.ts +68 -68
- package/src/layout/neato/kk.ts +2 -1
- package/src/layout/neato/kkutils.ts +96 -0
- package/src/layout/neato/make-graph-data.ts +166 -0
- package/src/layout/neato/matrix-ops.ts +138 -0
- package/src/layout/neato/multispline-router.ts +3 -3
- package/src/layout/neato/multispline.ts +3 -2
- package/src/layout/neato/opt-arrangement.ts +86 -0
- package/src/layout/neato/poly.ts +3 -2
- package/src/layout/neato/quad-prog-solve.ts +489 -0
- package/src/layout/neato/sgd.ts +5 -2
- package/src/layout/neato/smart-ini-x.ts +503 -0
- package/src/layout/neato/splines.ts +4 -4
- package/src/layout/neato/start.ts +19 -14
- package/src/layout/neato/stress.ts +28 -0
- package/src/model/edge.ts +3 -2
- package/src/model/lazy-attrs.ts +36 -0
- package/src/model/node.ts +3 -2
- package/src/ortho/index.ts +2 -1
- package/src/parser/dot.js +4 -1
- package/src/parser/dot.pegjs +5 -1
- package/src/parser/index.ts +4 -3
- package/src/render/color-resolve.ts +193 -4
- package/src/render/dot/edge-draw.ts +6 -3
- package/src/render/dot.ts +1 -1
- package/src/render/public.ts +2 -0
- package/src/render/svg-edge-split.ts +6 -4
- package/src/render/svg-multicolor.ts +4 -3
- package/src/render/svg-parallel-edge.ts +2 -2
- package/src/render/xdot-public.ts +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knowvah/dot-engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Faithful TypeScript port of Graphviz (dot, neato, fdp, sfdp, circo, twopi, osage, patchwork) — no C: no native binary, no WASM. Oracle-verified against the C implementation, runs in the browser.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphviz",
|
|
@@ -18,6 +18,7 @@ import type { EngineName } from '../gvc/context.js';
|
|
|
18
18
|
import { createDefaultContext } from '../gvc/default-context.js';
|
|
19
19
|
import { checkRenderArgs } from '../render/public.js';
|
|
20
20
|
import { render as deviceRender } from '../gvc/device.js';
|
|
21
|
+
import { resetRenderState } from '../common/render-state.js';
|
|
21
22
|
import type { ImageSizer } from '../common/htmltable-types.js';
|
|
22
23
|
import type { ImageResolver } from '../gvc/image-resolver.js';
|
|
23
24
|
import type { OutputFormat, RenderOptions } from '../render/public.js';
|
|
@@ -148,6 +149,11 @@ export async function renderAsync(
|
|
|
148
149
|
const engine: EngineName = opts?.engine ?? 'dot';
|
|
149
150
|
try {
|
|
150
151
|
const { fontIssues, sizes, bytes } = await prefetchAll(g, opts);
|
|
152
|
+
// AD-4: reset after the last await, so the synchronous layout + render
|
|
153
|
+
// below starts from C's initial process state even when other renders ran
|
|
154
|
+
// while the prefetch was pending. renderSvgAsync and renderSvgInto reach
|
|
155
|
+
// this through renderAsync.
|
|
156
|
+
resetRenderState();
|
|
151
157
|
// Created after fonts settle so the measurer sees the loaded faces.
|
|
152
158
|
const ctx = createDefaultContext();
|
|
153
159
|
if (opts?.imageSizer !== undefined) {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The one stderr writer for messages C prints through cgraph's agerr family
|
|
5
|
+
* (`agerr`, `agerrorf`, `agwarningf`, `AGPREV` continuations). Sites whose C
|
|
6
|
+
* counterpart is `fprintf(stderr)`/`fputs`/`printf` do not use it.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { registerRenderState } from './render-state.js';
|
|
10
|
+
|
|
11
|
+
/** `agerrlevel_t` as the port uses it: AGERR, AGWARN, AGPREV. */
|
|
12
|
+
export type AgerrLevel = 'error' | 'warning' | 'prev';
|
|
13
|
+
|
|
14
|
+
/** The console channel a line goes to. */
|
|
15
|
+
export type AgerrChannel = 'warn' | 'error';
|
|
16
|
+
|
|
17
|
+
const PREFIX_ERROR = 'Error';
|
|
18
|
+
const PREFIX_WARNING = 'Warning';
|
|
19
|
+
const PREFIX_SEP = ': ';
|
|
20
|
+
const DEL = 0x7f;
|
|
21
|
+
const LAST_CNTRL = 0x1f;
|
|
22
|
+
const WHITESPACE = new Set([0x09, 0x0a, 0x0b, 0x0c, 0x0d]);
|
|
23
|
+
const OCTAL_WIDTH = 3;
|
|
24
|
+
const OCTAL_RADIX = 8;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The level of the last non-AGPREV message, which AGPREV continues: C's
|
|
28
|
+
* `agerrno`, zero-initialised, i.e. AGWARN. Reset per render (AD-4).
|
|
29
|
+
* @see lib/cgraph/agerror.c:agerrno
|
|
30
|
+
*/
|
|
31
|
+
let lastLevel: 'error' | 'warning' = 'warning';
|
|
32
|
+
|
|
33
|
+
registerRenderState(() => {
|
|
34
|
+
lastLevel = 'warning';
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `default_usererrf`: every character that `gv_iscntrl(c) && !gv_isspace(c)`
|
|
39
|
+
* (0x00-0x1F except `\t\n\v\f\r`, and 0x7F) is written as `\ooo`.
|
|
40
|
+
* @see lib/cgraph/agerror.c:default_usererrf
|
|
41
|
+
*/
|
|
42
|
+
export function escapeControl(message: string): string {
|
|
43
|
+
let out = '';
|
|
44
|
+
for (const ch of message) {
|
|
45
|
+
const c = ch.codePointAt(0)!;
|
|
46
|
+
if ((c <= LAST_CNTRL || c === DEL) && !WHITESPACE.has(c)) {
|
|
47
|
+
out += `\\${c.toString(OCTAL_RADIX).padStart(OCTAL_WIDTH, '0')}`;
|
|
48
|
+
} else out += ch;
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Write one already-assembled stderr line (prefix included) on a console
|
|
55
|
+
* channel, escaped as `default_usererrf` would.
|
|
56
|
+
*/
|
|
57
|
+
export function agerrLineOn(channel: AgerrChannel, line: string): void {
|
|
58
|
+
if (channel === 'warn') console.warn(escapeControl(line));
|
|
59
|
+
else console.error(escapeControl(line));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The part of C's `agerr(level, ...)` that is not formatting: the `Error: `/
|
|
64
|
+
* `Warning: ` prefix (none for AGPREV), escaping, and the console channel
|
|
65
|
+
* (`console.warn` for warnings, `console.error` otherwise; AGPREV continues
|
|
66
|
+
* the previous level's channel).
|
|
67
|
+
* @see lib/cgraph/agerror.c:out
|
|
68
|
+
*/
|
|
69
|
+
export function agerr(level: AgerrLevel, msg: string, channel?: AgerrChannel): void {
|
|
70
|
+
if (level === 'prev') {
|
|
71
|
+
agerrLineOn(channel ?? (lastLevel === 'warning' ? 'warn' : 'error'), msg);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
lastLevel = level;
|
|
75
|
+
const prefix = level === 'error' ? PREFIX_ERROR : PREFIX_WARNING;
|
|
76
|
+
agerrLineOn(channel ?? (level === 'warning' ? 'warn' : 'error'), `${prefix}${PREFIX_SEP}${msg}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @see lib/cgraph/agerror.c:agerrorf */
|
|
80
|
+
export const agerrorf = (msg: string, channel?: AgerrChannel): void => agerr('error', msg, channel);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @see lib/cgraph/agerror.c:agwarningf
|
|
84
|
+
* `channel` overrides the console channel for sites that have always written
|
|
85
|
+
* their warning on `console.error`.
|
|
86
|
+
*/
|
|
87
|
+
export const agwarningf = (msg: string, channel?: AgerrChannel): void =>
|
|
88
|
+
agerr('warning', msg, channel);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* A finished line whose prefix is already part of the text. The channel
|
|
92
|
+
* follows the prefix (`Warning` -> `console.warn`) unless `channel` is given.
|
|
93
|
+
*/
|
|
94
|
+
export function agerrFinished(line: string, channel?: AgerrChannel): void {
|
|
95
|
+
agerrLineOn(channel ?? (line.startsWith(PREFIX_WARNING) ? 'warn' : 'error'), line);
|
|
96
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import type { Point } from '../model/geom.js';
|
|
12
12
|
import { ccwrotatepf, cwrotatepf } from '../model/geom.js';
|
|
13
13
|
import { bezier } from './bezier.js';
|
|
14
|
+
import { fma } from './fma.js';
|
|
14
15
|
import type { GenResult } from './arrows-shapes-util.js';
|
|
15
16
|
import {
|
|
16
17
|
vsub, vadd, miterShape, negUnit, backwardDelta, axialProjection,
|
|
@@ -206,14 +207,27 @@ function cubicHalf(c: Point[], rightHalf: boolean): Point[] {
|
|
|
206
207
|
return half;
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* Build the four Bézier control points for the curve arms.
|
|
212
|
+
*
|
|
213
|
+
* The oracle (libgvc 16.1 `_arrow_type_curve`) contracts only the
|
|
214
|
+
* `p.x +/- 0.95 * v.x` term into `fmadd(v.x, +/-0.95, p.x)`; every other add
|
|
215
|
+
* is a plain fadd, and `w.x * 4.0 / 3.0` is `(w.x * 4) / 3` (fmul, fdiv).
|
|
216
|
+
* Only the x arms carry the 0.95 term, so AF[1].y / AF[2].y stay unfused.
|
|
217
|
+
* @see lib/common/arrows.c:arrow_type_curve
|
|
218
|
+
*/
|
|
210
219
|
function curveControlPoints(p: Point, v: Point, w: Point, flag: number): Point[] {
|
|
211
220
|
const AF0: Point = { x: p.x + v.x + w.x, y: p.y + v.y + w.y };
|
|
212
221
|
const AF3: Point = { x: p.x - v.x + w.x, y: p.y - v.y + w.y };
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
222
|
+
const bulgeX = (w.x * 4.0) / 3.0;
|
|
223
|
+
const bulgeY = (w.y * 4.0) / 3.0;
|
|
224
|
+
const x1 = fma(v.x, 0.95, p.x) + w.x;
|
|
225
|
+
const x2 = fma(v.x, -0.95, p.x) + w.x;
|
|
226
|
+
if (flag & ARR_MOD_INV) { /* ----(-| */
|
|
227
|
+
return [AF0, { x: x1 + bulgeX, y: AF0.y + bulgeY }, { x: x2 + bulgeX, y: AF3.y + bulgeY }, AF3];
|
|
228
|
+
}
|
|
229
|
+
/* ----)-| */
|
|
230
|
+
return [AF0, { x: x1 - bulgeX, y: AF0.y - bulgeY }, { x: x2 - bulgeX, y: AF3.y - bulgeY }, AF3];
|
|
217
231
|
}
|
|
218
232
|
|
|
219
233
|
/** @see lib/common/arrows.c:arrow_type_curve */
|
package/src/common/color.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { isExactlyEqual } from '../util/math.js';
|
|
9
9
|
import { COLOR_LIB } from './colorData.js';
|
|
10
|
+
import { registerRenderState } from './render-state.js';
|
|
10
11
|
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Public types
|
|
@@ -37,6 +38,7 @@ interface HsvaTuple { H: number; S: number; V: number; A: number }
|
|
|
37
38
|
// ---------------------------------------------------------------------------
|
|
38
39
|
|
|
39
40
|
let colorScheme: string = '';
|
|
41
|
+
registerRenderState(() => { colorScheme = ''; });
|
|
40
42
|
|
|
41
43
|
/** @see lib/common/colxlate.c:setColorScheme */
|
|
42
44
|
export function setColorScheme(scheme: string): void {
|
|
@@ -256,17 +258,43 @@ function setBlackOpaque(color: GVColor, targetType: ColorType): void {
|
|
|
256
258
|
// Hex and HSV string parsers
|
|
257
259
|
// ---------------------------------------------------------------------------
|
|
258
260
|
|
|
259
|
-
/**
|
|
261
|
+
/** C isspace in the "C" locale. */
|
|
262
|
+
const SSCANF_SPACE = new Set([' ', '\t', '\n', '\v', '\f', '\r']);
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* `sscanf(p, "#" + "%<width>x" * max)`: the values converted before the first
|
|
266
|
+
* failure. Each `%x` skips leading white space then takes up to `width` hex
|
|
267
|
+
* digits, so a short or odd-length run still converts ("#12345" gives 0x12,
|
|
268
|
+
* 0x34, 0x5). Sign and `0x` prefixes are not modelled.
|
|
269
|
+
* @see lib/common/colxlate.c:colorxlate
|
|
270
|
+
*/
|
|
271
|
+
function scanHexGroups(p: string, width: number, max: number): number[] {
|
|
272
|
+
const out: number[] = [];
|
|
273
|
+
if (p.charAt(0) !== '#') return out;
|
|
274
|
+
let i = 1;
|
|
275
|
+
while (out.length < max) {
|
|
276
|
+
while (SSCANF_SPACE.has(p.charAt(i))) i++;
|
|
277
|
+
let j = i;
|
|
278
|
+
while (j < p.length && j - i < width && /[0-9a-fA-F]/.test(p.charAt(j))) j++;
|
|
279
|
+
if (j === i) break;
|
|
280
|
+
out.push(parseInt(p.slice(i, j), 16));
|
|
281
|
+
i = j;
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Parse "#rrggbb", "#rrggbbaa" (any run of at least three two-digit groups),
|
|
288
|
+
* or the 4-character "#rgb" form, as colorxlate's sscanf calls do. Returns
|
|
289
|
+
* null on failure.
|
|
290
|
+
*/
|
|
260
291
|
function parseHexColor(p: string): RgbaTuple | null {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (!m3) return null;
|
|
268
|
-
const r = parseInt(m3[1], 16); const g = parseInt(m3[2], 16); const b = parseInt(m3[3], 16);
|
|
269
|
-
return { r: r | (r << 4), g: g | (g << 4), b: b | (b << 4), a: 255 };
|
|
292
|
+
const g = scanHexGroups(p, 2, 4);
|
|
293
|
+
if (g.length >= 3) return { r: g[0]!, g: g[1]!, b: g[2]!, a: g[3] ?? 255 };
|
|
294
|
+
const short = p.length === 4 ? scanHexGroups(p, 1, 3) : [];
|
|
295
|
+
if (short.length !== 3) return null;
|
|
296
|
+
const [r, gg, b] = short as [number, number, number];
|
|
297
|
+
return { r: r | (r << 4), g: gg | (gg << 4), b: b | (b << 4), a: 255 };
|
|
270
298
|
}
|
|
271
299
|
|
|
272
300
|
/** Clamp a number to [0, 1]. */
|
package/src/common/crand.ts
CHANGED
|
@@ -21,11 +21,17 @@
|
|
|
21
21
|
* @see lib/util/random.c:gv_random / gv_permutation (15.0.0)
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
+
import { registerRenderState } from './render-state.js';
|
|
25
|
+
|
|
24
26
|
/** RAND_MAX on the reference platform. */
|
|
25
27
|
export const C_RAND_MAX = 2147483647;
|
|
26
28
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
+
/** Unseeded C rand() behaves as srand(1). */
|
|
30
|
+
const UNSEEDED_STATE = 1;
|
|
31
|
+
|
|
32
|
+
/** Current stream state. */
|
|
33
|
+
let state = UNSEEDED_STATE;
|
|
34
|
+
registerRenderState(() => { state = UNSEEDED_STATE; });
|
|
29
35
|
|
|
30
36
|
/** srand(3). */
|
|
31
37
|
export function csrand(seed: number): void {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EPL-2.0
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Once-per-process message gate. C keeps the seen strings in a file static
|
|
5
|
+
* dictionary that is cleared only by `emit_once_reset` in `gvFreeContext`; one
|
|
6
|
+
* native run is one process, so the port clears it per render (AD-4).
|
|
7
|
+
*
|
|
8
|
+
* @see lib/common/emit.c:emit_once
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { registerRenderState } from './render-state.js';
|
|
12
|
+
|
|
13
|
+
const seen = new Set<string>();
|
|
14
|
+
|
|
15
|
+
registerRenderState(() => {
|
|
16
|
+
seen.clear();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* True the first time `str` is offered since the last reset, false after.
|
|
21
|
+
* @see lib/common/emit.c:emit_once
|
|
22
|
+
*/
|
|
23
|
+
export function emitOnce(str: string): boolean {
|
|
24
|
+
if (seen.has(str)) return false;
|
|
25
|
+
seen.add(str);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
package/src/common/graph-init.ts
CHANGED
|
@@ -29,6 +29,7 @@ import type { RatioKind } from '../model/layoutParams.js';
|
|
|
29
29
|
import { doGraphLabel } from '../layout/dot/graph-label.js';
|
|
30
30
|
import { mapbool, setClType, LOCAL, GLOBAL, NOCLUST } from '../layout/dot/rank.js';
|
|
31
31
|
import { cround } from './arith.js';
|
|
32
|
+
import { agwarningf } from './agerr.js';
|
|
32
33
|
|
|
33
34
|
// ---------------------------------------------------------------------------
|
|
34
35
|
// Constants — @see lib/common/const.h
|
|
@@ -88,7 +89,7 @@ export function findCharset(g: Graph): number {
|
|
|
88
89
|
}
|
|
89
90
|
if (p === 'big-5' || p === 'big5') return CHAR_BIG5;
|
|
90
91
|
if (p === 'utf-8' || p === 'utf8') return CHAR_UTF8;
|
|
91
|
-
|
|
92
|
+
agwarningf(`Unsupported charset "${raw}" - assuming utf-8`);
|
|
92
93
|
return CHAR_UTF8;
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* @see lib/common/htmllex.c:doAttrs
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import { agerrFinished } from './agerr.js';
|
|
15
|
+
|
|
14
16
|
/** An attribute as startElement gets it: name in source case, value decoded by expat. */
|
|
15
17
|
export type AttrEntry = readonly [name: string, value: string];
|
|
16
18
|
|
|
@@ -272,10 +274,7 @@ export class StderrLines {
|
|
|
272
274
|
}
|
|
273
275
|
|
|
274
276
|
/** A finished stderr line on the console channel the port uses for it. */
|
|
275
|
-
export const consoleLine = (line: string): void =>
|
|
276
|
-
if (line.startsWith('Warning')) console.warn(line);
|
|
277
|
-
else console.error(line);
|
|
278
|
-
};
|
|
277
|
+
export const consoleLine = (line: string): void => agerrFinished(line);
|
|
279
278
|
|
|
280
279
|
/** One label's stderr: what make_html_label and make_label print, in order. */
|
|
281
280
|
export const labelStderr = (): StderrLines => new StderrLines(consoleLine);
|
|
@@ -16,9 +16,11 @@ import { ObjType, EmitState, MapShape } from '../gvc/job.js';
|
|
|
16
16
|
import type { RendererPlugin } from '../gvc/context.js';
|
|
17
17
|
import { FillType, PenType } from '../gvc/context.js';
|
|
18
18
|
import { transformPoint } from '../gvc/device.js';
|
|
19
|
-
import { resolveRenderColor } from '../render/color-resolve.js';
|
|
19
|
+
import { firstColor, resolveRenderColor } from '../render/color-resolve.js';
|
|
20
20
|
import { emitRoundedBezier } from './poly-shapes.js';
|
|
21
|
+
import type { PlacedHtml, PlacedCell } from './htmltable-pos.js';
|
|
21
22
|
import { htmlStyle } from './htmltable-style.js';
|
|
23
|
+
import { gvrenderSetStyle } from '../gvc/gvrender-set-style.js';
|
|
22
24
|
import {
|
|
23
25
|
BORDER_LEFT,
|
|
24
26
|
BORDER_TOP,
|
|
@@ -26,24 +28,54 @@ import {
|
|
|
26
28
|
BORDER_BOTTOM,
|
|
27
29
|
BORDER_MASK,
|
|
28
30
|
} from './htmltable-types.js';
|
|
31
|
+
import { parseSegs, parseSegsSilent } from './multicolor.js';
|
|
32
|
+
import { agwarningf } from './agerr.js';
|
|
33
|
+
import { registerRenderState } from './render-state.js';
|
|
29
34
|
|
|
30
35
|
// ---------------------------------------------------------------------------
|
|
31
36
|
// Gradient spec parser
|
|
32
37
|
// ---------------------------------------------------------------------------
|
|
33
38
|
|
|
39
|
+
/** The colours and fraction findStopColor yields; `stop` null → DEFAULT_COLOR. */
|
|
40
|
+
export interface HtmlStopColor {
|
|
41
|
+
fill: string;
|
|
42
|
+
stop: string | null;
|
|
43
|
+
frac: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @see lib/common/emit.c:findStopColor */
|
|
47
|
+
const MSG_MANY_COLORS = 'More than 2 colors specified for a gradient - ignoring remaining';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Port of C's findStopColor over parseSegs: null when parseSegs returns
|
|
51
|
+
* non-zero (including the rv 3 over-full warning), has < 2 segments or has no
|
|
52
|
+
* first colour. `silent` skips every diagnostic (port-internal pre-passes);
|
|
53
|
+
* otherwise parseSegs' once-per-render messages and the more-than-2-colours
|
|
54
|
+
* warning print as C does (no AGPREV context).
|
|
55
|
+
*
|
|
56
|
+
* @see lib/common/emit.c:findStopColor
|
|
57
|
+
*/
|
|
58
|
+
export function findHtmlStopColor(color: string, silent = false): HtmlStopColor | null {
|
|
59
|
+
const { segs, error } = silent ? parseSegsSilent(color) : parseSegs(color);
|
|
60
|
+
const first = segs[0];
|
|
61
|
+
const second = segs[1];
|
|
62
|
+
if (error !== 0 || first === undefined || second === undefined || first.color === null) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (segs.length > 2 && !silent) agwarningf(MSG_MANY_COLORS);
|
|
66
|
+
const frac = first.hasFraction ? first.t : second.hasFraction ? 1 - second.t : 0;
|
|
67
|
+
return { fill: first.color, stop: second.color, frac };
|
|
68
|
+
}
|
|
69
|
+
|
|
34
70
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
71
|
+
* [fill, stop] of a colour-list gradient spec, or null for a solid colour.
|
|
72
|
+
* Silent {@link findHtmlStopColor} for call sites that only need the colours.
|
|
37
73
|
*
|
|
38
74
|
* @see lib/common/emit.c:findStopColor
|
|
39
75
|
*/
|
|
40
76
|
export function parseGradientSpec(color: string): [string, string] | null {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const c0 = color.slice(0, idx).trim();
|
|
44
|
-
const c1 = color.slice(idx + 1).trim();
|
|
45
|
-
if (c0.length === 0) return null;
|
|
46
|
-
return [c0, c1.length > 0 ? c1 : 'black'];
|
|
77
|
+
const spec = findHtmlStopColor(color, true);
|
|
78
|
+
return spec === null ? null : [spec.fill, spec.stop ?? 'black'];
|
|
47
79
|
}
|
|
48
80
|
|
|
49
81
|
// ---------------------------------------------------------------------------
|
|
@@ -102,6 +134,8 @@ export interface HtmlPaint {
|
|
|
102
134
|
* C setFill's findStopColor hit. @see lib/common/htmltable.c:setFill
|
|
103
135
|
*/
|
|
104
136
|
stop?: string;
|
|
137
|
+
/** findStopColor's fraction; defaults to 0. Ignored without `stop`. */
|
|
138
|
+
gradientFrac?: number;
|
|
105
139
|
/** Gradient angle in degrees; defaults to 0. Ignored without `stop`. */
|
|
106
140
|
gradientAngle?: number;
|
|
107
141
|
/** True → radial gradient (RGRADIENT); else linear. Ignored without `stop`. */
|
|
@@ -136,8 +170,19 @@ export function htmlFillPenWidth(): number {
|
|
|
136
170
|
export function resetHtmlFillPenWidth(): void {
|
|
137
171
|
htmlFillPen = 1.0;
|
|
138
172
|
}
|
|
173
|
+
registerRenderState(resetHtmlFillPenWidth);
|
|
139
174
|
|
|
140
175
|
/** Map an HTML STYLE to the C pen type: dashed wins over dotted. @see lib/common/htmltable.c:doBorder */
|
|
176
|
+
/** gvc->defaultlinestyle. @see lib/common/emit.c:105 */
|
|
177
|
+
const DEFAULT_LINE_STYLE: readonly string[] = ['solid', 'setlinewidth(1)'];
|
|
178
|
+
|
|
179
|
+
/** The style list doBorder hands to gvrender_set_style for a pen type. */
|
|
180
|
+
function htmlBorderStyle(pen: PenType): readonly string[] {
|
|
181
|
+
if (pen === PenType.Dashed) return ['dashed'];
|
|
182
|
+
if (pen === PenType.Dotted) return ['dotted'];
|
|
183
|
+
return DEFAULT_LINE_STYLE;
|
|
184
|
+
}
|
|
185
|
+
|
|
141
186
|
function penTypeOf(style: string | undefined): PenType {
|
|
142
187
|
const st = htmlStyle(style);
|
|
143
188
|
if (st.dashed) return PenType.Dashed;
|
|
@@ -153,7 +198,7 @@ function penTypeOf(style: string | undefined): PenType {
|
|
|
153
198
|
*/
|
|
154
199
|
export function withHtmlPaint(paint: HtmlPaint, job: RenderJob, drawFn: () => void): void {
|
|
155
200
|
paintObj.fillColor = paint.fill !== undefined
|
|
156
|
-
? resolveRenderColor(paint.fill) : { type: 'none' };
|
|
201
|
+
? resolveRenderColor(firstColor(paint.fill)) : { type: 'none' };
|
|
157
202
|
paintObj.penColor = paint.pen !== undefined
|
|
158
203
|
? resolveRenderColor(paint.pen) : { type: 'string', s: 'transparent' };
|
|
159
204
|
applyHtmlFill(paint);
|
|
@@ -163,6 +208,9 @@ export function withHtmlPaint(paint: HtmlPaint, job: RenderJob, drawFn: () => vo
|
|
|
163
208
|
// so xdot emits `S 5 -solid` per border/fill. rawStyle carries it (SVG's
|
|
164
209
|
// style emit treats "solid" as the default → no visible change).
|
|
165
210
|
paintObj.rawStyle = paintObj.pen === PenType.Solid ? ['solid'] : [];
|
|
211
|
+
// emit_html_tbl/cell border: dashed or dotted by name, else defaultlinestyle.
|
|
212
|
+
// @see lib/common/htmltable.c:267 doBorder
|
|
213
|
+
gvrenderSetStyle(htmlBorderStyle(paintObj.pen));
|
|
166
214
|
// Inherit the enclosing object's emit-state (the label state during an HTML
|
|
167
215
|
// label emit) so the fill/border ops route to the same xbuf as the label
|
|
168
216
|
// (_ldraw_), not the shape draw buffer. SVG ignores emit_state, so unchanged.
|
|
@@ -183,7 +231,7 @@ function applyHtmlFill(paint: HtmlPaint): void {
|
|
|
183
231
|
paintObj.fill = paint.radial === true ? FillType.Radial : FillType.Linear;
|
|
184
232
|
paintObj.stopColor = resolveRenderColor(paint.stop);
|
|
185
233
|
paintObj.gradientAngle = paint.gradientAngle ?? 0;
|
|
186
|
-
paintObj.gradientFrac = 0;
|
|
234
|
+
paintObj.gradientFrac = paint.gradientFrac ?? 0;
|
|
187
235
|
return;
|
|
188
236
|
}
|
|
189
237
|
paintObj.fill = paint.fill !== undefined ? FillType.Solid : FillType.None;
|
|
@@ -366,3 +414,48 @@ function emitSidedPolylines(
|
|
|
366
414
|
renderer.polyline(seq.map((i) => corners[i]!), job);
|
|
367
415
|
}
|
|
368
416
|
}
|
|
417
|
+
|
|
418
|
+
// ---------------------------------------------------------------------------
|
|
419
|
+
// htmlLabelColors — the colour names C resolves while emitting an HTML label
|
|
420
|
+
// ---------------------------------------------------------------------------
|
|
421
|
+
|
|
422
|
+
/** @see lib/common/const.h DEFAULT_COLOR */
|
|
423
|
+
const HTML_DEFAULT_COLOR = 'black';
|
|
424
|
+
|
|
425
|
+
/** setFill's names: the fill (and a gradient's stop). @see htmltable.c:setFill */
|
|
426
|
+
function bgNames(bgcolor: string): string[] {
|
|
427
|
+
const spec = parseGradientSpec(bgcolor);
|
|
428
|
+
return spec === null ? [bgcolor] : [spec[0], spec[1]];
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** One cell in emit_html_cell order: fill, border, then the child. */
|
|
432
|
+
function cellNames(cell: PlacedCell): string[] {
|
|
433
|
+
if (htmlStyle(cell.style).invisible) return [];
|
|
434
|
+
const out = cell.bgcolor !== undefined ? bgNames(cell.bgcolor) : [];
|
|
435
|
+
if (cell.border > 0) out.push(cell.color ?? HTML_DEFAULT_COLOR);
|
|
436
|
+
if (cell.nested !== undefined) out.push(...tableNames(cell.nested));
|
|
437
|
+
else for (const line of cell.lines) if (line.fontColor !== null) out.push(line.fontColor);
|
|
438
|
+
return out;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** One table in emit_html_tbl order: fill, rules, border, cells. */
|
|
442
|
+
function tableNames(tbl: PlacedHtml): string[] {
|
|
443
|
+
if (htmlStyle(tbl.style).invisible) return [];
|
|
444
|
+
const out = tbl.bgcolor !== undefined ? bgNames(tbl.bgcolor) : [];
|
|
445
|
+
const color = tbl.color ?? HTML_DEFAULT_COLOR;
|
|
446
|
+
if (tbl.cells.some((c) => c.vruled === true || c.hruled === true)) out.push(color);
|
|
447
|
+
if (tbl.border > 0) out.push(color);
|
|
448
|
+
for (const cell of tbl.cells) out.push(...cellNames(cell));
|
|
449
|
+
return out;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* The names an HTML label hands to gvrender_resolve_color, in C's order: the
|
|
454
|
+
* root table's pen first (emit_html_label), then emit_html_tbl's walk.
|
|
455
|
+
* @see lib/common/htmltable.c:emit_html_label
|
|
456
|
+
* @see lib/common/htmltable.c:emit_html_tbl
|
|
457
|
+
* @see lib/common/htmltable.c:emit_html_cell
|
|
458
|
+
*/
|
|
459
|
+
export function htmlLabelColors(label: PlacedHtml): string[] {
|
|
460
|
+
return [label.color ?? HTML_DEFAULT_COLOR, ...tableNames(label)];
|
|
461
|
+
}
|
|
@@ -14,6 +14,7 @@ import type { RenderJob } from '../gvc/job.js';
|
|
|
14
14
|
import type { RendererPlugin } from '../gvc/context.js';
|
|
15
15
|
import type { PlacedCell, PlacedHtml } from './htmltable-pos.js';
|
|
16
16
|
import { doSide, withHtmlPaint } from './htmltable-emit-fill.js';
|
|
17
|
+
import { registerRenderState } from './render-state.js';
|
|
17
18
|
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
19
20
|
// Rule context
|
|
@@ -217,6 +218,7 @@ export function resetHtmlAnchorIds(): void {
|
|
|
217
218
|
anchorEnv.objLabel = null;
|
|
218
219
|
anchorEnv.imgscale = 'false';
|
|
219
220
|
}
|
|
221
|
+
registerRenderState(resetHtmlAnchorIds);
|
|
220
222
|
|
|
221
223
|
/**
|
|
222
224
|
* Open an anchor when the data carries href/title/target.
|
|
@@ -31,7 +31,7 @@ import type { PlacedHtml, PlacedCell, PlacedLine, PlacedImage } from './htmltabl
|
|
|
31
31
|
import { transformPoint } from '../gvc/device.js';
|
|
32
32
|
import { gvrenderTextspan } from '../gvc/textspan-emit.js';
|
|
33
33
|
import {
|
|
34
|
-
withHtmlPaint,
|
|
34
|
+
withHtmlPaint, findHtmlStopColor, doBorder, mkPts,
|
|
35
35
|
htmlFillPenWidth, resetHtmlFillPenWidth, type HtmlPaint,
|
|
36
36
|
} from './htmltable-emit-fill.js';
|
|
37
37
|
import { emitRoundedBezier } from './poly-shapes.js';
|
|
@@ -121,10 +121,11 @@ function bgFillPaint(ctx: BgFillCtx): HtmlPaint {
|
|
|
121
121
|
// penWidth = the leaked gvrender pen width (prior doBorder); a bordered cell's
|
|
122
122
|
// fill carries it as stroke-width even with stroke="none". @see htmltable.c:setFill
|
|
123
123
|
const penWidth = htmlFillPenWidth();
|
|
124
|
-
const spec =
|
|
124
|
+
const spec = findHtmlStopColor(ctx.bgcolor);
|
|
125
125
|
if (spec === null) return { fill: ctx.bgcolor, penWidth };
|
|
126
126
|
return {
|
|
127
|
-
fill: spec
|
|
127
|
+
fill: spec.fill, stop: spec.stop ?? 'black', gradientFrac: spec.frac,
|
|
128
|
+
gradientAngle: ctx.gradientangle ?? 0,
|
|
128
129
|
radial: htmlStyle(ctx.style).radial, penWidth,
|
|
129
130
|
};
|
|
130
131
|
}
|