@knowvah/dot-engine 2.6.7 → 2.6.8
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-attr-warn.d.ts +10 -4
- package/dist/common/htmltable-attr-warn.d.ts.map +1 -1
- package/dist/common/htmltable-label.d.ts +37 -0
- package/dist/common/htmltable-label.d.ts.map +1 -0
- package/dist/common/htmltable-lex-attvalue.d.ts +59 -0
- package/dist/common/htmltable-lex-attvalue.d.ts.map +1 -0
- package/dist/common/htmltable-lex-expat.d.ts +15 -4
- package/dist/common/htmltable-lex-expat.d.ts.map +1 -1
- package/dist/common/htmltable-lex.d.ts.map +1 -1
- package/dist/common/htmltable-parse-attrs.d.ts +3 -1
- package/dist/common/htmltable-parse-attrs.d.ts.map +1 -1
- package/dist/common/htmltable-parse.d.ts +6 -5
- package/dist/common/htmltable-parse.d.ts.map +1 -1
- package/dist/common/htmltable-pos.d.ts +3 -26
- package/dist/common/htmltable-pos.d.ts.map +1 -1
- package/dist/common/htmltable-types.d.ts +3 -1
- package/dist/common/htmltable-types.d.ts.map +1 -1
- package/dist/common/htmltable.d.ts +3 -2
- package/dist/common/htmltable.d.ts.map +1 -1
- package/dist/common/make-label.d.ts.map +1 -1
- package/dist/index.js +174 -84
- package/dist/index.js.map +4 -4
- package/dist/render.js +174 -84
- package/dist/render.js.map +4 -4
- package/package.json +1 -1
- package/src/common/htmltable-attr-warn.ts +24 -7
- package/src/common/htmltable-label.ts +109 -0
- package/src/common/htmltable-lex-attvalue.ts +141 -0
- package/src/common/htmltable-lex-expat.ts +59 -27
- package/src/common/htmltable-lex.ts +9 -10
- package/src/common/htmltable-parse-attrs.ts +10 -13
- package/src/common/htmltable-parse.ts +16 -29
- package/src/common/htmltable-pos.ts +5 -88
- package/src/common/htmltable-types.ts +4 -1
- package/src/common/htmltable.ts +16 -16
- package/src/common/make-label.ts +8 -3
|
@@ -219,13 +219,11 @@ const rejectTableAfterTag = (s: ParseState, start: number): void => {
|
|
|
219
219
|
// Cell content helpers — mirrors htmlparse.y cell rule
|
|
220
220
|
// ---------------------------------------------------------------------------
|
|
221
221
|
|
|
222
|
-
const parseImgContent = (
|
|
223
|
-
s: ParseState, t: OpenToken, cellAttrs: Record<string, string>,
|
|
224
|
-
): HtmlImage => {
|
|
222
|
+
const parseImgContent = (s: ParseState, t: OpenToken): HtmlImage => {
|
|
225
223
|
consume(s);
|
|
226
224
|
const img: HtmlImage = {
|
|
227
225
|
kind: 'image',
|
|
228
|
-
src:
|
|
226
|
+
src: t.attrs['src'] ?? '',
|
|
229
227
|
scale: t.attrs['scale'],
|
|
230
228
|
};
|
|
231
229
|
consumeClose(s, 'IMG');
|
|
@@ -272,17 +270,15 @@ const scanAfterTable = (s: ParseState, t: Token, st: CellScan): HtmlCellContent[
|
|
|
272
270
|
};
|
|
273
271
|
|
|
274
272
|
/** `image` as the cell's only child. */
|
|
275
|
-
const scanCellImage = (
|
|
276
|
-
s: ParseState, t: OpenToken, cellAttrs: Record<string, string>, st: CellScan,
|
|
277
|
-
): HtmlCellContent[] => {
|
|
273
|
+
const scanCellImage = (s: ParseState, t: OpenToken, st: CellScan): HtmlCellContent[] => {
|
|
278
274
|
if (st.kind !== 'none') throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
279
275
|
st.kind = 'image';
|
|
280
|
-
return [parseImgContent(s, t
|
|
276
|
+
return [parseImgContent(s, t)];
|
|
281
277
|
};
|
|
282
278
|
|
|
283
279
|
/** One step of `cell: T_cell (fonttable | fonttext | image) T_end_cell`. */
|
|
284
280
|
const scanCellItem = (
|
|
285
|
-
s: ParseState, t: Token,
|
|
281
|
+
s: ParseState, t: Token, fontStack: FontState[], st: CellScan,
|
|
286
282
|
): HtmlCellContent[] => {
|
|
287
283
|
if (st.kind === 'fonttable') throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
288
284
|
if (st.kind === 'table') return scanAfterTable(s, t, st);
|
|
@@ -292,7 +288,7 @@ const scanCellItem = (
|
|
|
292
288
|
return [parseFontTable(s, wrapper, fontStack)];
|
|
293
289
|
}
|
|
294
290
|
if (t.type === 'open' && t.tag === 'TABLE') return scanCellTable(s, t, fontStack, st);
|
|
295
|
-
if (t.type === 'open' && t.tag === 'IMG') return scanCellImage(s, t,
|
|
291
|
+
if (t.type === 'open' && t.tag === 'IMG') return scanCellImage(s, t, st);
|
|
296
292
|
if (st.kind === 'image') throw parseError(s, t, MSG_SYNTAX_ERROR);
|
|
297
293
|
return scanCellText(s, t, fontStack, st);
|
|
298
294
|
};
|
|
@@ -305,14 +301,12 @@ const endsCell = (s: ParseState, t: Token, st: CellScan): boolean => {
|
|
|
305
301
|
throw parseError(s, t, afterText ? MSG_TEXT_AFTER_TABLE : MSG_SYNTAX_ERROR);
|
|
306
302
|
};
|
|
307
303
|
|
|
308
|
-
const parseCellContent = (
|
|
309
|
-
s: ParseState, cellAttrs: Record<string, string>, fontStack: FontState[],
|
|
310
|
-
): HtmlCellContent[] => {
|
|
304
|
+
const parseCellContent = (s: ParseState, fontStack: FontState[]): HtmlCellContent[] => {
|
|
311
305
|
const content: HtmlCellContent[] = [];
|
|
312
306
|
const st: CellScan = { kind: 'none', textNonSpace: false, afterNonSpace: false };
|
|
313
307
|
for (let t = peek(s); t !== undefined; t = peek(s)) {
|
|
314
308
|
if (endsCell(s, t, st)) break;
|
|
315
|
-
content.push(...scanCellItem(s, t,
|
|
309
|
+
content.push(...scanCellItem(s, t, fontStack, st));
|
|
316
310
|
}
|
|
317
311
|
const nxt = peek(s);
|
|
318
312
|
if (nxt?.type === 'close' && nxt.tag === 'TD') consume(s);
|
|
@@ -327,7 +321,7 @@ const parseCellContent = (
|
|
|
327
321
|
/** @see lib/common/htmlparse.y:cell rule / lib/common/htmllex.c:mkCell */
|
|
328
322
|
const parseCell = (
|
|
329
323
|
s: ParseState, attrs: Record<string, string>, fontStack: FontState[],
|
|
330
|
-
): HtmlCell => buildCell(parseCellContent(s,
|
|
324
|
+
): HtmlCell => buildCell(parseCellContent(s, fontStack), attrs);
|
|
331
325
|
|
|
332
326
|
// ---------------------------------------------------------------------------
|
|
333
327
|
// parseRow — parses <TR>...</TR>
|
|
@@ -560,21 +554,16 @@ export interface ParsedHtmlLabel {
|
|
|
560
554
|
}
|
|
561
555
|
|
|
562
556
|
/**
|
|
563
|
-
* Parse an HTML-like label string,
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
* (already stripped).
|
|
557
|
+
* Parse an HTML-like label string, writing the lexer's warnings to `stderr` as
|
|
558
|
+
* the parser reaches their tokens. The caller owns `stderr` and flushes it: a
|
|
559
|
+
* warning without a newline continues into the caller's next write. Input is
|
|
560
|
+
* the content between the outer `<` `>` delimiters (already stripped).
|
|
567
561
|
*
|
|
568
562
|
* @see lib/common/htmlparse.y:parseHTML
|
|
569
563
|
*/
|
|
570
|
-
export const parseHtmlLabelRv = (
|
|
571
|
-
src: string,
|
|
572
|
-
writeLine: (line: string) => void = (line) => console.warn(line),
|
|
573
|
-
): ParsedHtmlLabel => {
|
|
564
|
+
export const parseHtmlLabelRv = (src: string, stderr: StderrLines): ParsedHtmlLabel => {
|
|
574
565
|
const { tokens, error, eof } = tokenizeDeferred(`<HTML>${src}</HTML>`, { start: 6, end: 6 + src.length });
|
|
575
|
-
const s: ParseState = {
|
|
576
|
-
tokens, pos: 0, pending: error, stderr: new StderrLines(writeLine), emitted: new WeakSet(), warn: false, eof,
|
|
577
|
-
};
|
|
566
|
+
const s: ParseState = { tokens, pos: 0, pending: error, stderr, emitted: new WeakSet(), warn: false, eof };
|
|
578
567
|
try {
|
|
579
568
|
const label = parseTokens(s);
|
|
580
569
|
if (error !== undefined) throw error;
|
|
@@ -583,8 +572,6 @@ export const parseHtmlLabelRv = (
|
|
|
583
572
|
// Running off the truncated stream means C's lexer would have hit the error.
|
|
584
573
|
if (error !== undefined && s.pos >= tokens.length) { emitEof(s); throw error; }
|
|
585
574
|
throw e;
|
|
586
|
-
} finally {
|
|
587
|
-
s.stderr?.flush();
|
|
588
575
|
}
|
|
589
576
|
};
|
|
590
577
|
|
|
@@ -594,4 +581,4 @@ export const parseHtmlLabelRv = (
|
|
|
594
581
|
* the sync pass prints.
|
|
595
582
|
*/
|
|
596
583
|
export const parseHtmlLabel = (src: string): HtmlLabel =>
|
|
597
|
-
parseHtmlLabelRv(src, () => undefined).label;
|
|
584
|
+
parseHtmlLabelRv(src, new StderrLines(() => undefined)).label;
|
|
@@ -16,14 +16,11 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { Box } from '../model/geom.js';
|
|
19
|
-
import type { TextlabelT } from './types.js';
|
|
20
19
|
import type { TextMeasurer } from './textmeasure.js';
|
|
21
|
-
import type { HtmlCell, HtmlImage, HtmlLabel, HtmlTable, HtmlText
|
|
20
|
+
import type { HtmlCell, HtmlImage, HtmlLabel, HtmlTable, HtmlText } from './htmltable-types.js';
|
|
22
21
|
import {
|
|
23
|
-
layoutHtmlTable, cellPad, cellBorder,
|
|
22
|
+
layoutHtmlTable, cellPad, cellBorder, withTableFont,
|
|
24
23
|
} from './htmltable.js';
|
|
25
|
-
import { makeLabel } from './make-label.js';
|
|
26
|
-
import { HtmlLexError } from './htmltable-lex.js';
|
|
27
24
|
import { TOP, BOTTOM, LEFT, RIGHT } from './splines-constants.js';
|
|
28
25
|
import type { PlacedLine, HtmlFontInfo } from './htmltable-pos-runs.js';
|
|
29
26
|
import {
|
|
@@ -171,15 +168,14 @@ export interface PlacedHtml {
|
|
|
171
168
|
* of pos_html_cell: LEFT flushes the box right edge in (`ur.x -= delx`), RIGHT
|
|
172
169
|
* flushes the left edge in, default splits (center); VALIGN BOTTOM/TOP flush,
|
|
173
170
|
* default centers on BOTH axes. Parallels the existing `alignImageBox`, but
|
|
174
|
-
* text default-centers vertically where an image does not.
|
|
175
|
-
*
|
|
176
|
-
* exactly what C does for every non-TEXT cell.)
|
|
171
|
+
* text default-centers vertically where an image does not. ALIGN="TEXT" keeps
|
|
172
|
+
* the box's width: lines then align across the whole cell.
|
|
177
173
|
* @see lib/common/htmltable.c:pos_html_cell (text branch, :1487-1526)
|
|
178
174
|
*/
|
|
179
175
|
export function alignContentBox(box: Box, cell: HtmlCell, w: number, h: number): Box {
|
|
180
176
|
const out: Box = { ll: { ...box.ll }, ur: { ...box.ur } };
|
|
181
177
|
const delx = out.ur.x - out.ll.x - w;
|
|
182
|
-
if (delx > 0) {
|
|
178
|
+
if (delx > 0 && cell.align !== 'text') {
|
|
183
179
|
if (cell.align === 'left') out.ur.x -= delx;
|
|
184
180
|
else if (cell.align === 'right') out.ll.x += delx;
|
|
185
181
|
else { out.ll.x += delx / 2; out.ur.x -= delx / 2; }
|
|
@@ -520,82 +516,3 @@ export function posHtmlLabel(
|
|
|
520
516
|
if (label.kind === 'table') return withTableFont(env, label.table.font, 'emit', () => posHtmlTable(label.table, env, measurer));
|
|
521
517
|
return posTextLabel(label, finfo, measurer);
|
|
522
518
|
}
|
|
523
|
-
|
|
524
|
-
/** parseHTML's rv for a label that failed to parse (`ctx->error`). */
|
|
525
|
-
const HTML_PARSE_FATAL = 3;
|
|
526
|
-
|
|
527
|
-
/** A built HTML label plus make_html_label's "problem" return value. */
|
|
528
|
-
export interface HtmlLabelResult {
|
|
529
|
-
label: TextlabelT;
|
|
530
|
-
rv: number;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/**
|
|
534
|
-
* make_html_label: parse, size and position an HTML-like label. Returns C's
|
|
535
|
-
* rv too (nonzero: the caller appends `in label of ...`, labels.c:make_label).
|
|
536
|
-
* Parse diagnostics print here, once per label, as parseHTML does. The
|
|
537
|
-
* optional `imageSizer` resolves `<IMG SRC>`; absent means C's missing image.
|
|
538
|
-
* @see lib/common/htmltable.c:make_html_label
|
|
539
|
-
*/
|
|
540
|
-
export function makeHtmlLabelRv(
|
|
541
|
-
content: string,
|
|
542
|
-
finfo: HtmlFontInfo & { imageSizer?: ImageSizer; pencolor?: string },
|
|
543
|
-
measurer: TextMeasurer,
|
|
544
|
-
): HtmlLabelResult {
|
|
545
|
-
const { fontname, fontsize, fontcolor, imageSizer, pencolor } = finfo;
|
|
546
|
-
let lbl: HtmlLabel, lexWarn: boolean; // lexWarn: htmllex.c's ctx->warn, rv bit 1
|
|
547
|
-
try {
|
|
548
|
-
({ label: lbl, warn: lexWarn } = parseHtmlLabelRv(content));
|
|
549
|
-
} catch (e) {
|
|
550
|
-
// C aborts the HTML parse on a syntax error (YYABORT): parseHTML returns
|
|
551
|
-
// rv 3 (ctx->error) with no label, and make_html_label returns it with
|
|
552
|
-
// lp->html cleared and no spans, so the label renders empty.
|
|
553
|
-
// @see lib/common/htmltable.c:1880 (rv == 3), htmlparse.y (YYABORT)
|
|
554
|
-
if (e instanceof HtmlLexError) for (const line of e.diagnostics) console.error(line);
|
|
555
|
-
return { label: makeLabel('', fontname, fontsize, fontcolor, measurer), rv: HTML_PARSE_FATAL };
|
|
556
|
-
}
|
|
557
|
-
// A top-level table with no explicit COLOR inherits the object's pen color,
|
|
558
|
-
// which then flows table->cell->nested-table.
|
|
559
|
-
// @see lib/common/htmltable.c:1911 (getPenColor), :1406/:1556 (inheritance)
|
|
560
|
-
if (lbl.kind === 'table') inheritTablePenColor(lbl.table, pencolor);
|
|
561
|
-
const rv = Number(lexWarn) | sizeHtmlLabel(lbl, measurer, {
|
|
562
|
-
fontsize, fontname, imageSizer,
|
|
563
|
-
});
|
|
564
|
-
const placed = posHtmlLabel(lbl, { fontname, fontsize, fontcolor }, measurer);
|
|
565
|
-
const dim = lbl.dimen ?? { w: 0, h: 0 };
|
|
566
|
-
// C replaces table-label text: "this may be used for the title and
|
|
567
|
-
// alt fields in image maps" — anchors inherit it as default tooltip.
|
|
568
|
-
// @see lib/common/htmltable.c:make_html_label (line 1935)
|
|
569
|
-
const text = lbl.kind === 'table' ? '<TABLE>' : content;
|
|
570
|
-
return { label: htmlTextLabel(text, { fontname, fontsize, fontcolor }, placed, dim), rv };
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
/** {@link makeHtmlLabelRv} without the problem flag. */
|
|
574
|
-
export function makeHtmlLabel(
|
|
575
|
-
content: string,
|
|
576
|
-
finfo: HtmlFontInfo & { imageSizer?: ImageSizer; pencolor?: string },
|
|
577
|
-
measurer: TextMeasurer,
|
|
578
|
-
): TextlabelT {
|
|
579
|
-
return makeHtmlLabelRv(content, finfo, measurer).label;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
/** Build the TextlabelT wrapper around a positioned HTML label. */
|
|
583
|
-
function htmlTextLabel(
|
|
584
|
-
text: string,
|
|
585
|
-
finfo: HtmlFontInfo,
|
|
586
|
-
placed: PlacedHtml,
|
|
587
|
-
dim: { w: number; h: number },
|
|
588
|
-
): TextlabelT {
|
|
589
|
-
return {
|
|
590
|
-
text,
|
|
591
|
-
fontname: finfo.fontname, fontcolor: finfo.fontcolor, charset: 0,
|
|
592
|
-
fontsize: finfo.fontsize,
|
|
593
|
-
dimen: { x: dim.w, y: dim.h },
|
|
594
|
-
space: { x: dim.w, y: dim.h },
|
|
595
|
-
pos: { x: 0, y: 0 },
|
|
596
|
-
u: { kind: 'html', html: placed },
|
|
597
|
-
valign: 'c'.charCodeAt(0),
|
|
598
|
-
set: false,
|
|
599
|
-
html: true,
|
|
600
|
-
};
|
|
601
|
-
}
|
|
@@ -40,6 +40,9 @@ export class HtmlParseError extends DotEngineError {
|
|
|
40
40
|
/** @see lib/common/htmltable.h HALIGN_* flags */
|
|
41
41
|
export type HtmlAlign = 'left' | 'center' | 'right';
|
|
42
42
|
|
|
43
|
+
/** A cell's ALIGN: TEXT (HALIGN_TEXT) leaves the text block the cell's width. @see lib/common/htmllex.c:cell_halignfn */
|
|
44
|
+
export type HtmlCellAlign = HtmlAlign | 'text';
|
|
45
|
+
|
|
43
46
|
/** @see lib/common/htmltable.h VALIGN_* flags */
|
|
44
47
|
export type HtmlVAlign = 'top' | 'middle' | 'bottom';
|
|
45
48
|
|
|
@@ -132,7 +135,7 @@ export interface HtmlCell {
|
|
|
132
135
|
*/
|
|
133
136
|
vruled?: boolean;
|
|
134
137
|
port?: string;
|
|
135
|
-
align?:
|
|
138
|
+
align?: HtmlCellAlign;
|
|
136
139
|
valign?: HtmlVAlign;
|
|
137
140
|
balign?: HtmlAlign;
|
|
138
141
|
bgcolor?: string;
|
package/src/common/htmltable.ts
CHANGED
|
@@ -20,13 +20,13 @@ export type { TextMeasurer } from './textmeasure.js';
|
|
|
20
20
|
|
|
21
21
|
import type {
|
|
22
22
|
HtmlCell, HtmlCellContent, HtmlImage, HtmlLabel, HtmlTable, HtmlText,
|
|
23
|
-
HtmlTextItem,
|
|
23
|
+
HtmlTextItem, ImageSizer,
|
|
24
24
|
} from './htmltable-types.js';
|
|
25
|
-
import type { ImageSizer } from './htmltable-types.js';
|
|
26
25
|
import { findImageSize } from '../gvc/usershape.js';
|
|
27
26
|
import { PointSet } from './pointset.js';
|
|
28
27
|
import type { TextMeasurer } from './textmeasure.js';
|
|
29
28
|
import { withTableFont } from './htmltable-fontinfo.js';
|
|
29
|
+
import { agerrLine, type StderrLines } from './htmltable-attr-warn.js';
|
|
30
30
|
|
|
31
31
|
export { withTableFont } from './htmltable-fontinfo.js';
|
|
32
32
|
|
|
@@ -85,6 +85,7 @@ export interface HtmlSizeEnv {
|
|
|
85
85
|
fontsize: number;
|
|
86
86
|
fontname: string;
|
|
87
87
|
imageSizer?: ImageSizer;
|
|
88
|
+
stderr?: StderrLines; // the label's stderr; none: straight to the console
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
const defaultSizeEnv = (): HtmlSizeEnv => ({ fontsize: DEFAULT_FONTSIZE, fontname: '' });
|
|
@@ -230,21 +231,20 @@ const sizeTextContent = (
|
|
|
230
231
|
/** Images whose sizing failed: size_html_img's rv = 1 on every later call. */
|
|
231
232
|
const missingImages = new WeakSet<HtmlImage>();
|
|
232
233
|
|
|
233
|
-
const sizeHtmlImg = (img: HtmlImage, imageSizer
|
|
234
|
+
const sizeHtmlImg = (img: HtmlImage, { imageSizer, stderr }: HtmlSizeEnv): number => {
|
|
234
235
|
// C sizes each image once (processTbl); the port's size and pos passes
|
|
235
236
|
// share layoutHtmlTable, so guard against re-sizing (and re-warning). The
|
|
236
237
|
// returned rv still follows C on every call.
|
|
237
238
|
if (img.width !== undefined && img.height !== undefined) return missingImages.has(img) ? 1 : 0;
|
|
238
239
|
const sz = imageSizer !== undefined ? imageSizer(img.src) : findImageSize(img.src);
|
|
239
240
|
if (sz !== null) {
|
|
240
|
-
img.width = sz.w;
|
|
241
|
-
img.height = sz.h;
|
|
241
|
+
img.width = sz.w; img.height = sz.h;
|
|
242
242
|
return 0;
|
|
243
243
|
}
|
|
244
244
|
// Missing-image: zero size + warning.
|
|
245
245
|
// C: agerrorf("No or improper image file=\"%s\"\n", img->src) — agerr
|
|
246
246
|
// prefixes "Error: " on stderr.
|
|
247
|
-
|
|
247
|
+
agerrLine(stderr, `Error: No or improper image file="${img.src}"`);
|
|
248
248
|
img.width = 0;
|
|
249
249
|
img.height = 0;
|
|
250
250
|
missingImages.add(img);
|
|
@@ -262,7 +262,7 @@ const sizeContentItem = (
|
|
|
262
262
|
return { ...(item.dimen !== undefined ? item.dimen : { w: 0, h: 0 }), rv };
|
|
263
263
|
}
|
|
264
264
|
if (item.kind === 'image') {
|
|
265
|
-
const rv = sizeHtmlImg(item, env
|
|
265
|
+
const rv = sizeHtmlImg(item, env);
|
|
266
266
|
return { w: item.width ?? 0, h: item.height ?? 0, rv };
|
|
267
267
|
}
|
|
268
268
|
return { w: 0, h: 0, rv: 0 };
|
|
@@ -327,15 +327,15 @@ const sizeWarned = new WeakSet<object>();
|
|
|
327
327
|
* @see lib/common/htmltable.c:1141 (size_html_cell FIXED_FLAG)
|
|
328
328
|
*/
|
|
329
329
|
const fixedCellCheck = (
|
|
330
|
-
cell: HtmlCell, sz: { w: number; h: number }, warn: boolean,
|
|
330
|
+
cell: HtmlCell, sz: { w: number; h: number }, warn: boolean, out: StderrLines | undefined,
|
|
331
331
|
): { rv: number; zero: boolean } => {
|
|
332
332
|
if (!cell.fixedsize) return { rv: 0, zero: false };
|
|
333
333
|
if (cell.width && cell.height) {
|
|
334
334
|
const small = (cell.width < sz.w || cell.height < sz.h) && cell.content[0]?.kind !== 'image';
|
|
335
|
-
if (small && warn)
|
|
335
|
+
if (small && warn) agerrLine(out, WARN_CELL_TOO_SMALL);
|
|
336
336
|
return { rv: small ? 1 : 0, zero: true };
|
|
337
337
|
}
|
|
338
|
-
if (warn)
|
|
338
|
+
if (warn) agerrLine(out, WARN_CELL_UNSPECIFIED);
|
|
339
339
|
return { rv: 1, zero: false };
|
|
340
340
|
};
|
|
341
341
|
|
|
@@ -360,7 +360,7 @@ const getCellSize = (
|
|
|
360
360
|
let szy = ch + margin;
|
|
361
361
|
const warn = !sizeWarned.has(cell);
|
|
362
362
|
sizeWarned.add(cell);
|
|
363
|
-
const fixed = fixedCellCheck(cell, { w: szx, h: szy }, warn);
|
|
363
|
+
const fixed = fixedCellCheck(cell, { w: szx, h: szy }, warn, env.stderr);
|
|
364
364
|
rv |= fixed.rv;
|
|
365
365
|
if (fixed.zero) { szx = 0; szy = 0; }
|
|
366
366
|
const bw = cell.width !== undefined ? cell.width : 0;
|
|
@@ -504,16 +504,16 @@ export const layoutHtmlTable = (
|
|
|
504
504
|
* table, the returned `rv = 1` follows C on every call.
|
|
505
505
|
* @see lib/common/htmltable.c:size_html_tbl (:1683, :1689)
|
|
506
506
|
*/
|
|
507
|
-
const warnFixedTable = (tbl: HtmlTable, dims: { wd: number; ht: number }): number => {
|
|
507
|
+
const warnFixedTable = (tbl: HtmlTable, dims: { wd: number; ht: number }, out: StderrLines | undefined): number => {
|
|
508
508
|
const warn = !sizeWarned.has(tbl);
|
|
509
509
|
sizeWarned.add(tbl);
|
|
510
510
|
if (tbl.fixedsize !== true) return 0;
|
|
511
511
|
if (tbl.width && tbl.height) {
|
|
512
512
|
if (tbl.width >= dims.wd && tbl.height >= dims.ht) return 0;
|
|
513
|
-
if (warn)
|
|
513
|
+
if (warn) agerrLine(out, WARN_TABLE_TOO_SMALL);
|
|
514
514
|
return 1;
|
|
515
515
|
}
|
|
516
|
-
if (warn)
|
|
516
|
+
if (warn) agerrLine(out, WARN_TABLE_UNSPECIFIED);
|
|
517
517
|
return 1;
|
|
518
518
|
};
|
|
519
519
|
|
|
@@ -525,7 +525,7 @@ const sizeTableBody = (
|
|
|
525
525
|
): number => {
|
|
526
526
|
const { entries, widths, heights, spacing, border, rv } = layoutHtmlTable(tbl, measurer, env);
|
|
527
527
|
if (entries.length === 0) {
|
|
528
|
-
const fixed = warnFixedTable(tbl, sumTableDims({ widths, heights, ncols: 0, nrows: 0, spacing, border }));
|
|
528
|
+
const fixed = warnFixedTable(tbl, sumTableDims({ widths, heights, ncols: 0, nrows: 0, spacing, border }), env.stderr);
|
|
529
529
|
tbl.dimen = { w: 0, h: 0 };
|
|
530
530
|
return rv | fixed;
|
|
531
531
|
}
|
|
@@ -535,7 +535,7 @@ const sizeTableBody = (
|
|
|
535
535
|
const { wd, ht } = sumTableDims({ widths, heights, ncols, nrows, spacing, border });
|
|
536
536
|
const baseWd = tbl.width !== undefined ? tbl.width : 0;
|
|
537
537
|
const baseHt = tbl.height !== undefined ? tbl.height : 0;
|
|
538
|
-
const fixed = warnFixedTable(tbl, { wd, ht });
|
|
538
|
+
const fixed = warnFixedTable(tbl, { wd, ht }, env.stderr);
|
|
539
539
|
// C zeroes only the CONTENT-derived term for a FIXEDSIZE table that has BOTH
|
|
540
540
|
// width and height, so the box becomes fmax(0, width)=width / fmax(0,height)=
|
|
541
541
|
// height (the explicit size). A fixed table missing a dimension warns and
|
package/src/common/make-label.ts
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
import type { TextlabelT } from './types.js';
|
|
13
13
|
import type { TextMeasurer, TextSize } from './textmeasure.js';
|
|
14
14
|
import type { TextSpan } from './emit-types.js';
|
|
15
|
-
import {
|
|
15
|
+
import { makeHtmlLabelTo } from './htmltable-label.js';
|
|
16
|
+
import { labelStderr } from './htmltable-attr-warn.js';
|
|
16
17
|
import { substObj, type GraphObj } from './subst.js';
|
|
17
18
|
import { Edge } from '../model/edge.js';
|
|
18
19
|
import { Graph } from '../model/graph.js';
|
|
@@ -205,8 +206,12 @@ export function makeAnyLabel(
|
|
|
205
206
|
// it (htmltable.c:1911 getPenColor). @see getPenColor
|
|
206
207
|
// ADR-2: a per-context sizer (when set) wins over the global one.
|
|
207
208
|
const imageSizer = obj !== undefined ? rootOf(obj).info.gvc?.imageSizer : undefined;
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
// One stderr for the label: doInt's unterminated warning runs into the
|
|
210
|
+
// next write, `in label of ...` included (agerr AGPREV).
|
|
211
|
+
const stderr = labelStderr();
|
|
212
|
+
const { label, rv } = makeHtmlLabelTo(content, { ...font, pencolor: getPenColor(obj), imageSizer }, measurer, stderr);
|
|
213
|
+
if (rv !== 0 && obj !== undefined) stderr.write(`${inLabelOf(obj)}\n`);
|
|
214
|
+
stderr.flush();
|
|
210
215
|
return label;
|
|
211
216
|
}
|
|
212
217
|
// Plain path: resolve \G \N \E \T \H \L against the owning object
|