gutterpress 0.11.23-alpha.7 → 0.11.23-beta.2
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 +3 -1
- package/dist/{README-syg2hn83.md → README-8rct3axy.md} +2 -2
- package/dist/api/index.d.ts +3 -3
- package/dist/api/index.js +8 -6
- package/dist/{build-w572wq10.js → build-3e18wnqj.js} +9 -8
- package/dist/{cli-mmgtqnmr.js → cli-0ep11b0q.js} +1 -1
- package/dist/cli-65gy8ask.js +82 -0
- package/dist/{cli-6pv84kf3.js → cli-88arpdke.js} +6 -84
- package/dist/{cli-eatdqx3z.js → cli-9n9kg58f.js} +1 -1
- package/dist/{cli-58fsk6d7.js → cli-pd2cje5b.js} +187 -44
- package/dist/{cli-3cvq3n1c.js → cli-pnrararp.js} +189 -85
- package/dist/{cli-wyg7qstd.js → cli-tgnyvra3.js} +15 -5
- package/dist/{cli-31anr0r9.js → cli-v0evdpdf.js} +68 -28
- package/dist/{cli-5ba6bm6z.js → cli-x7gcdg6w.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-2f3zqmza.js → doctor-2f4s9dyn.js} +3 -3
- package/dist/engine/compiler/postprocess.d.ts +3 -0
- package/dist/engine/shared/page-vars.d.ts +32 -0
- package/dist/engine/shared/pdf-inspect.d.ts +33 -0
- package/dist/{engine-4rabsgwq.js → engine-c4pxz79g.js} +2 -1
- package/dist/{engine-wm4fggac.js → engine-cs5g2ez0.js} +3 -3
- package/dist/{ext-0cgky8n3.js → ext-70gv86v5.js} +9 -8
- package/dist/{extension-restore-vghc58vx.js → extension-restore-chj5nx3t.js} +3 -3
- package/dist/{extension-restore-e7je32pr.js → extension-restore-pd87p8r2.js} +5 -4
- package/dist/{gutterpress-agent-d29ry3ak.js → gutterpress-agent-wyryqehx.js} +13 -4
- package/dist/{gutterpress-viewer-mafsby5k.js → gutterpress-viewer-ywkf49q5.js} +90 -166
- package/dist/{index-nfysshcc.js → index-0k43evt0.js} +309 -155
- package/dist/{index-wm4x7xbf.js → index-2t1gdma7.js} +178 -35
- package/dist/{index-cw03e9p4.js → index-7j3hkwya.js} +68 -28
- package/dist/{index-fp7xwvpr.js → index-80vg3ed6.js} +15 -5
- package/dist/{index-2vxzxyyj.js → index-swfdgn2n.js} +10 -10
- package/dist/index-tayzfr9c.js +99 -0
- package/dist/{index-hphcn7th.js → index-ytjkvwy5.js} +5 -85
- package/dist/index.d.ts +2 -0
- package/dist/index.js +234 -7
- package/dist/lib/book-css.d.ts +56 -0
- package/dist/lib/markdown/assemble.d.ts +58 -0
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/publish/google-drive.d.ts +12 -4
- package/dist/lib/publish/manifest-publish.d.ts +6 -0
- package/dist/lib/publish/providers/gdrive-folder.d.ts +30 -0
- package/dist/lib/publish/run-publish.d.ts +6 -1
- package/dist/lib/publish/types.d.ts +52 -5
- package/dist/lib/remote-auth/converge-merge.d.ts +3 -3
- package/dist/lib/remote-auth/sync-messages.d.ts +2 -2
- package/dist/lib/root-tokens.d.ts +76 -0
- package/dist/lib/source-provider.d.ts +27 -0
- package/dist/lib/version-changes.d.ts +26 -16
- package/dist/{manifest-79zsgkpn.yaml → manifest-0vwaskj2.yaml} +1 -1
- package/dist/{manifest-2kc56wvw.yaml → manifest-aya31jwt.yaml} +1 -1
- package/dist/{manifest-41ddzm13.yaml → manifest-mffah3hr.yaml} +1 -1
- package/dist/{manifest-sqzm4681.yaml → manifest-wbcv8cbp.yaml} +2 -2
- package/dist/{manifest.schema-93sd7zje.json → manifest.schema-0jgj0jt1.json} +1 -1
- package/dist/{new-88rkrv71.js → new-d61n5cn0.js} +9 -8
- package/dist/{page-rules-ytj9p04v.css → page-rules-vnja6grt.css} +2 -2
- package/dist/{plugins-3aj0wc5h.js → plugins-0hhw6s17.js} +1 -1
- package/dist/{plugins-sprxsz5d.js → plugins-e0n46s6m.js} +3 -3
- package/dist/{preflight-11dg1qkk.js → preflight-fjayhjr5.js} +9 -8
- package/dist/{preview-nftp782j.js → preview-h815jrfb.js} +9 -8
- package/dist/{publish-6tgxfck9.js → publish-ft39zgma.js} +25 -9
- package/dist/render.js +77 -26
- package/dist/schema/manifest.types.d.ts +2 -1
- package/dist/{source-provider-n7vehh6t.js → source-provider-j1w7byeq.js} +5 -1
- package/dist/{source-provider-tgzet3j5.js → source-provider-tjaf303m.js} +5 -1
- package/dist/test-helpers/vocabulary.d.ts +12 -0
- package/dist/{tokens-n82t4k9h.css → tokens-a7grv940.css} +4 -5
- package/dist/{validate-pktqrye5.js → validate-b201dbrb.js} +9 -8
- package/package.json +1 -1
- package/dist/index-46ycxe6r.js +0 -18
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launchChromium
|
|
3
3
|
} from "./cli-eyyggect.js";
|
|
4
|
+
import {
|
|
5
|
+
round3
|
|
6
|
+
} from "./cli-65gy8ask.js";
|
|
4
7
|
|
|
5
8
|
// src/engine/compiler/build.ts
|
|
6
9
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
@@ -630,6 +633,33 @@ function marginBoxesOnEdges(edges) {
|
|
|
630
633
|
return Object.entries(owners).filter(([, own]) => own.some((e) => edges.includes(e))).map(([name]) => name);
|
|
631
634
|
}
|
|
632
635
|
|
|
636
|
+
// src/engine/shared/page-vars.ts
|
|
637
|
+
var decls = (pairs) => pairs.map(([name, n]) => `--gp-page-${name}: ${round3(n)}pt;`).join(" ");
|
|
638
|
+
function pageDecls(model, name) {
|
|
639
|
+
const { width, height, margin } = resolvePage(model, { name, pseudos: ["right"] }).geometry;
|
|
640
|
+
return decls([
|
|
641
|
+
["width", width],
|
|
642
|
+
["height", height],
|
|
643
|
+
["margin-top", margin.top],
|
|
644
|
+
["margin-bottom", margin.bottom],
|
|
645
|
+
["margin-inside", margin.left],
|
|
646
|
+
["margin-outside", margin.right]
|
|
647
|
+
]);
|
|
648
|
+
}
|
|
649
|
+
function pageGeometryVarsCss(model, area) {
|
|
650
|
+
const bookWide = decls([
|
|
651
|
+
["bleed", area?.bleed ?? 0],
|
|
652
|
+
["safe", area?.safe ?? 0],
|
|
653
|
+
["gutter", area?.gutter ?? 0],
|
|
654
|
+
["art-safe", area?.artSafe ?? 0]
|
|
655
|
+
]);
|
|
656
|
+
return [
|
|
657
|
+
`:root { ${pageDecls(model)} ${bookWide} }`,
|
|
658
|
+
...model.pageAssignments.map((a) => `${a.selector} { ${pageDecls(model, a.page)} }`)
|
|
659
|
+
].join(`
|
|
660
|
+
`);
|
|
661
|
+
}
|
|
662
|
+
|
|
633
663
|
// src/engine/shared/margin-box-support.ts
|
|
634
664
|
var MARGIN_BOX_IGNORED_PROPERTIES = new Set([
|
|
635
665
|
"transform",
|
|
@@ -1002,12 +1032,14 @@ function needsMeasurement(value) {
|
|
|
1002
1032
|
|
|
1003
1033
|
// src/engine/shared/pdf-inspect.ts
|
|
1004
1034
|
import {
|
|
1035
|
+
decodePDFRawStream,
|
|
1005
1036
|
PDFArray,
|
|
1006
1037
|
PDFDict,
|
|
1007
1038
|
PDFDocument,
|
|
1008
1039
|
PDFHexString,
|
|
1009
1040
|
PDFName,
|
|
1010
1041
|
PDFNumber,
|
|
1042
|
+
PDFRawStream,
|
|
1011
1043
|
PDFRef,
|
|
1012
1044
|
PDFString
|
|
1013
1045
|
} from "pdf-lib";
|
|
@@ -1128,6 +1160,52 @@ async function inspectPdf(bytes) {
|
|
|
1128
1160
|
walkOutline(outlines);
|
|
1129
1161
|
return { pageCount: pages.length, boxes, linkTargets, namedDests, outline };
|
|
1130
1162
|
}
|
|
1163
|
+
var PROLOGUE = /^\s*(\d*\.?\d+) 0 0 -\d*\.?\d+ -?\d*\.?\d+ -?\d*\.?\d+ cm/;
|
|
1164
|
+
var CLIP = /(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+) re\s+W\*? n\b/g;
|
|
1165
|
+
var UNIFORM = /\bq\s+(\d*\.?\d+) 0 0 \1 (-?\d*\.?\d+) -?\d*\.?\d+ cm/g;
|
|
1166
|
+
var UNSCALED_EPSILON = 0.000001;
|
|
1167
|
+
function printScale(doc) {
|
|
1168
|
+
const readings = new Map;
|
|
1169
|
+
for (const page of doc.getPages()) {
|
|
1170
|
+
const contents = page.node.Contents();
|
|
1171
|
+
const streams = contents instanceof PDFArray ? contents.asArray().map((ref) => doc.context.lookup(ref)) : [contents];
|
|
1172
|
+
let text = "";
|
|
1173
|
+
for (const stream of streams) {
|
|
1174
|
+
if (!(stream instanceof PDFRawStream))
|
|
1175
|
+
continue;
|
|
1176
|
+
try {
|
|
1177
|
+
text += Buffer.from(decodePDFRawStream(stream).decode()).toString("latin1") + `
|
|
1178
|
+
`;
|
|
1179
|
+
} catch {}
|
|
1180
|
+
}
|
|
1181
|
+
const prologue = PROLOGUE.exec(text);
|
|
1182
|
+
if (!prologue)
|
|
1183
|
+
continue;
|
|
1184
|
+
let area;
|
|
1185
|
+
for (const m of text.matchAll(CLIP)) {
|
|
1186
|
+
const size = Number(m[3]) * Number(m[4]);
|
|
1187
|
+
if (!area || size > area.size)
|
|
1188
|
+
area = { x: Number(m[1]), size, end: m.index + m[0].length };
|
|
1189
|
+
}
|
|
1190
|
+
if (!area)
|
|
1191
|
+
continue;
|
|
1192
|
+
UNIFORM.lastIndex = area.end;
|
|
1193
|
+
for (let m;m = UNIFORM.exec(text); ) {
|
|
1194
|
+
if (Math.abs(Number(m[2]) - area.x) > 0.5)
|
|
1195
|
+
continue;
|
|
1196
|
+
const scale = Number(m[1]) * Number(prologue[1]) * 96 / 72;
|
|
1197
|
+
readings.set(scale, (readings.get(scale) ?? 0) + 1);
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
if ([...readings.values()].some((n) => n >= 3))
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
let best = null;
|
|
1204
|
+
for (const [scale, n] of readings)
|
|
1205
|
+
if (best === null || n > readings.get(best))
|
|
1206
|
+
best = scale;
|
|
1207
|
+
return best === null ? null : Math.abs(1 - best) < UNSCALED_EPSILON ? 1 : best;
|
|
1208
|
+
}
|
|
1131
1209
|
|
|
1132
1210
|
// src/lib/embedded-assets.ts
|
|
1133
1211
|
import { existsSync } from "node:fs";
|
|
@@ -1140,7 +1218,7 @@ import { fileURLToPath } from "node:url";
|
|
|
1140
1218
|
var favicon_default = "./favicon-272ga6y0.ico";
|
|
1141
1219
|
|
|
1142
1220
|
// src/assets/manifest.schema.json
|
|
1143
|
-
var manifest_schema_default = "./manifest.schema-
|
|
1221
|
+
var manifest_schema_default = "./manifest.schema-0jgj0jt1.json";
|
|
1144
1222
|
|
|
1145
1223
|
// src/assets/preview/scripts/preview-interface.js
|
|
1146
1224
|
var preview_interface_default = "./preview-interface-0xdh0r5b.js";
|
|
@@ -1155,31 +1233,31 @@ var preview_shell_default = "./preview-shell-wk9k3gcd.js";
|
|
|
1155
1233
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
1156
1234
|
|
|
1157
1235
|
// src/assets/engine/gutterpress-viewer.js
|
|
1158
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
1236
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-ywkf49q5.js";
|
|
1159
1237
|
|
|
1160
1238
|
// src/assets/engine/gutterpress-agent.js
|
|
1161
|
-
var gutterpress_agent_default = "./gutterpress-agent-
|
|
1239
|
+
var gutterpress_agent_default = "./gutterpress-agent-wyryqehx.js";
|
|
1162
1240
|
|
|
1163
1241
|
// src/assets/templates/book/manifest.yaml
|
|
1164
|
-
var manifest_default = "./manifest-
|
|
1242
|
+
var manifest_default = "./manifest-mffah3hr.yaml";
|
|
1165
1243
|
|
|
1166
1244
|
// src/assets/templates/book/chapter-01.md
|
|
1167
1245
|
var chapter_01_default = "./chapter-01-gsbjt584.md";
|
|
1168
1246
|
|
|
1169
1247
|
// src/assets/templates/zine/manifest.yaml
|
|
1170
|
-
var manifest_default2 = "./manifest-
|
|
1248
|
+
var manifest_default2 = "./manifest-wbcv8cbp.yaml";
|
|
1171
1249
|
|
|
1172
1250
|
// src/assets/templates/zine/chapter-01.md
|
|
1173
1251
|
var chapter_01_default2 = "./chapter-01-wgjfz4w6.md";
|
|
1174
1252
|
|
|
1175
1253
|
// src/assets/templates/technical/manifest.yaml
|
|
1176
|
-
var manifest_default3 = "./manifest-
|
|
1254
|
+
var manifest_default3 = "./manifest-aya31jwt.yaml";
|
|
1177
1255
|
|
|
1178
1256
|
// src/assets/templates/technical/chapter-01.md
|
|
1179
1257
|
var chapter_01_default3 = "./chapter-01-6fn9pvd0.md";
|
|
1180
1258
|
|
|
1181
1259
|
// src/assets/templates/paper/manifest.yaml
|
|
1182
|
-
var manifest_default4 = "./manifest-
|
|
1260
|
+
var manifest_default4 = "./manifest-0vwaskj2.yaml";
|
|
1183
1261
|
|
|
1184
1262
|
// src/assets/templates/paper/chapter-01.md
|
|
1185
1263
|
var chapter_01_default4 = "./chapter-01-s71xrf5q.md";
|
|
@@ -1212,7 +1290,7 @@ var plugin_test_js_default = "./plugin.test.js-gxzqqfdh.tpl";
|
|
|
1212
1290
|
var package_default2 = "./package-awwkt7sa.json";
|
|
1213
1291
|
|
|
1214
1292
|
// src/assets/extension-templates/look/README.md
|
|
1215
|
-
var README_default2 = "./README-
|
|
1293
|
+
var README_default2 = "./README-8rct3axy.md";
|
|
1216
1294
|
|
|
1217
1295
|
// src/assets/extension-templates/look/components.yaml
|
|
1218
1296
|
var components_default = "./components-zzqdpt3m.yaml";
|
|
@@ -1221,7 +1299,7 @@ var components_default = "./components-zzqdpt3m.yaml";
|
|
|
1221
1299
|
var callout_default = "./callout-hv56m16h.md";
|
|
1222
1300
|
|
|
1223
1301
|
// src/assets/extension-templates/look/styles/tokens.css
|
|
1224
|
-
var tokens_default = "./tokens-
|
|
1302
|
+
var tokens_default = "./tokens-a7grv940.css";
|
|
1225
1303
|
|
|
1226
1304
|
// src/assets/extension-templates/look/styles/base.css
|
|
1227
1305
|
var base_default = "./base-ypqh9n7f.css";
|
|
@@ -1233,7 +1311,7 @@ var components_default2 = "./components-aam0fe2z.css";
|
|
|
1233
1311
|
var page_templates_default = "./page-templates-tx9ryt19.css";
|
|
1234
1312
|
|
|
1235
1313
|
// src/assets/extension-templates/look/styles/page-rules.css
|
|
1236
|
-
var page_rules_default = "./page-rules-
|
|
1314
|
+
var page_rules_default = "./page-rules-vnja6grt.css";
|
|
1237
1315
|
|
|
1238
1316
|
// src/assets/extension-templates/look/styles/book.css
|
|
1239
1317
|
var book_default = "./book-ted3tzrp.css";
|
|
@@ -1341,9 +1419,9 @@ function pseudoVariants(model) {
|
|
|
1341
1419
|
function consumedStrings(model) {
|
|
1342
1420
|
const names = new Set;
|
|
1343
1421
|
for (const rule of model.pageRules)
|
|
1344
|
-
for (const
|
|
1345
|
-
if (
|
|
1346
|
-
for (const part of parseContent(
|
|
1422
|
+
for (const decls2 of Object.values(rule.marginBoxes))
|
|
1423
|
+
if (decls2.content) {
|
|
1424
|
+
for (const part of parseContent(decls2.content))
|
|
1347
1425
|
if (part.type === "string")
|
|
1348
1426
|
names.add(part.name);
|
|
1349
1427
|
}
|
|
@@ -1453,6 +1531,7 @@ function round(n) {
|
|
|
1453
1531
|
import { PDFDocument as PDFDocument2, PDFName as PDFName2, PDFNumber as PDFNumber2, rgb } from "pdf-lib";
|
|
1454
1532
|
async function postprocess(input, opts) {
|
|
1455
1533
|
const doc = await PDFDocument2.load(input, { updateMetadata: false });
|
|
1534
|
+
const scale = printScale(doc);
|
|
1456
1535
|
const g = opts.geometry;
|
|
1457
1536
|
const inset = g.bleed + g.slug;
|
|
1458
1537
|
const media = [0, 0, g.media.width, g.media.height];
|
|
@@ -1499,7 +1578,8 @@ async function postprocess(input, opts) {
|
|
|
1499
1578
|
bytes,
|
|
1500
1579
|
pageCount: doc.getPageCount(),
|
|
1501
1580
|
padded,
|
|
1502
|
-
boxes: { media, bleed: bleedBox, trim: trimBox }
|
|
1581
|
+
boxes: { media, bleed: bleedBox, trim: trimBox },
|
|
1582
|
+
scale
|
|
1503
1583
|
};
|
|
1504
1584
|
}
|
|
1505
1585
|
function drawCropMarks(page, g) {
|
|
@@ -1674,7 +1754,8 @@ async function build(opts) {
|
|
|
1674
1754
|
key: root.key
|
|
1675
1755
|
});
|
|
1676
1756
|
}
|
|
1677
|
-
const printArea =
|
|
1757
|
+
const printArea = await page.evaluate(`window.__gp.printArea()`);
|
|
1758
|
+
const geometryVarsCss = pageGeometryVarsCss(model, printArea);
|
|
1678
1759
|
const pinStyle = (group, pseudos) => pinRootStyle(resolvePage(model, { name: group.authorPage, pseudos }).geometry.margin, printArea, pseudos.includes("left") ? "verso" : "recto", group.edges, group.padding);
|
|
1679
1760
|
if (pinGroups.size) {
|
|
1680
1761
|
const lines = [];
|
|
@@ -1694,11 +1775,11 @@ async function build(opts) {
|
|
|
1694
1775
|
const body = [];
|
|
1695
1776
|
for (const [prop, value] of Object.entries(rule.decls))
|
|
1696
1777
|
body.push(` ${prop}: ${value};`);
|
|
1697
|
-
for (const [box,
|
|
1778
|
+
for (const [box, decls2] of Object.entries(rule.marginBoxes)) {
|
|
1698
1779
|
if (relocated.has(box.slice(1)))
|
|
1699
1780
|
continue;
|
|
1700
1781
|
body.push(` ${box} {`);
|
|
1701
|
-
for (const [prop, value] of Object.entries(
|
|
1782
|
+
for (const [prop, value] of Object.entries(decls2))
|
|
1702
1783
|
body.push(` ${prop}: ${value};`);
|
|
1703
1784
|
body.push(` }`);
|
|
1704
1785
|
}
|
|
@@ -1741,11 +1822,12 @@ ${pinCss}`);
|
|
|
1741
1822
|
const minContentHeightPx = Math.min(contentHeightPt(), ...model.pageNames.map((name) => contentHeightPt(name))) * 96 / 72;
|
|
1742
1823
|
const pageVarsCss = [
|
|
1743
1824
|
`:root { --gp-content-h: ${contentHeightPx}px; }`,
|
|
1744
|
-
...model.pageAssignments.map((a) => `${a.selector} { --gp-content-h: ${namedContentHeightsPx[a.page] ?? contentHeightPx}px; }`)
|
|
1825
|
+
...model.pageAssignments.map((a) => `${a.selector} { --gp-content-h: ${namedContentHeightsPx[a.page] ?? contentHeightPx}px; }`),
|
|
1826
|
+
geometryVarsCss
|
|
1745
1827
|
].join(`
|
|
1746
1828
|
`);
|
|
1747
1829
|
await page.evaluate(`window.__gp.addCss("gp-page-vars", ${JSON.stringify(pageVarsCss)})`);
|
|
1748
|
-
log(`page geometry published (--gp-content-h: ${Math.round(contentHeightPx)}px)`);
|
|
1830
|
+
log(`page geometry published (--gp-content-h: ${Math.round(contentHeightPx)}px, --gp-page-*)`);
|
|
1749
1831
|
const relocationBoxes = (group, pseudos) => {
|
|
1750
1832
|
const ctx = resolvePage(model, { name: group.authorPage, pseudos });
|
|
1751
1833
|
return marginBoxesOnEdges(group.edges).map((name) => [name, ctx.marginBoxes[`@${name}`]]).filter((pair) => {
|
|
@@ -1788,8 +1870,6 @@ ${pinCss}`);
|
|
|
1788
1870
|
const msg = `${headline}:
|
|
1789
1871
|
${describe(widthOffenders.boxes)}`;
|
|
1790
1872
|
if (opts.allowShrink) {
|
|
1791
|
-
if (scale !== null)
|
|
1792
|
-
diagnose("engine.width.overflow", `${headline}.`);
|
|
1793
1873
|
for (const o of widthOffenders.boxes)
|
|
1794
1874
|
diagnose("engine.width.overflow", `${o.desc} is ${Math.round(o.px)}px wide, past the ${Math.round(widthOffenders.limitPx)}px page content box. ${o.left < -1 ? "Keep it inside the page content box." : "Give it an explicit width that fits."}`);
|
|
1795
1875
|
log(`WARNING: ${msg}`);
|
|
@@ -1805,6 +1885,54 @@ ${describe(widthOffenders.intrinsics)}`;
|
|
|
1805
1885
|
diagnose("engine.width.intrinsic", `${o.desc} has no width set and is naturally wider than the page — if the printed output comes out smaller than your CSS says, give it an explicit width (e.g. width: 100%).`);
|
|
1806
1886
|
log(`WARNING: ${msg}`);
|
|
1807
1887
|
}
|
|
1888
|
+
let unclipped = null;
|
|
1889
|
+
if (!widthOffenders.boxes.length) {
|
|
1890
|
+
const g = tier2.geometry;
|
|
1891
|
+
const ext = g.bleed + g.slug;
|
|
1892
|
+
const contentPx = (name, pseudos) => {
|
|
1893
|
+
const { width, margin } = resolvePage(model, { name: name || undefined, pseudos }).geometry;
|
|
1894
|
+
return (width + 2 * ext - bleedMargin(margin.left, g) - bleedMargin(margin.right, g)) * 96 / 72;
|
|
1895
|
+
};
|
|
1896
|
+
const pages = await page.evaluate(`(() => {
|
|
1897
|
+
const body = document.body;
|
|
1898
|
+
const named = (el) => { const p = getComputedStyle(el).page; return p && p !== "auto" ? p : ""; };
|
|
1899
|
+
if (!body) return { first: "", used: [], reason: "there is no body" };
|
|
1900
|
+
const bs = getComputedStyle(body);
|
|
1901
|
+
const r = body.getBoundingClientRect();
|
|
1902
|
+
if (
|
|
1903
|
+
Math.abs(r.left + parseFloat(bs.borderLeftWidth)) > 0.01 ||
|
|
1904
|
+
Math.abs(r.right - parseFloat(bs.borderRightWidth) - window.innerWidth) > 0.01
|
|
1905
|
+
) return { first: "", used: [], reason: "the body does not span the page content box" };
|
|
1906
|
+
// The first page's name: the root's, overridden down the chain of
|
|
1907
|
+
// first in-flow children (CSS Paged Media's start page value).
|
|
1908
|
+
let first = named(document.documentElement) || named(body);
|
|
1909
|
+
for (let el = body; el; ) {
|
|
1910
|
+
el = [...el.children].find((c) => {
|
|
1911
|
+
const cs = getComputedStyle(c);
|
|
1912
|
+
return cs.display !== "none" && cs.position !== "absolute" && cs.position !== "fixed";
|
|
1913
|
+
});
|
|
1914
|
+
if (el && named(el)) first = named(el);
|
|
1915
|
+
}
|
|
1916
|
+
const used = new Set([""]);
|
|
1917
|
+
for (const el of document.querySelectorAll("*")) used.add(named(el));
|
|
1918
|
+
return { first, used: [...used], reason: "" };
|
|
1919
|
+
})()`);
|
|
1920
|
+
const firstPx = contentPx(pages.first, ["first", "right", "recto"]);
|
|
1921
|
+
const wider = pages.used.find((name) => pseudoContexts.some((pseudos) => contentPx(name, pseudos) > firstPx + 0.01));
|
|
1922
|
+
unclipped = pages.reason || (wider !== undefined ? `${wider ? `the page "${wider}"` : "the unnamed page"} is wider than the first page` : await page.evaluate(`(() => {
|
|
1923
|
+
const hs = getComputedStyle(document.documentElement);
|
|
1924
|
+
const bs = getComputedStyle(document.body);
|
|
1925
|
+
let css;
|
|
1926
|
+
if (hs.overflowX === "visible" && hs.overflowY === "visible")
|
|
1927
|
+
css = "html { overflow-x: clip !important; } " +
|
|
1928
|
+
"body { overflow-x: clip !important; overflow-y: visible !important; }";
|
|
1929
|
+
else if (bs.overflowX === "visible") css = "body { overflow-x: clip !important; }";
|
|
1930
|
+
else return "the body clips its own overflow";
|
|
1931
|
+
window.__gp.addCss("gp-root-clip", css);
|
|
1932
|
+
return "";
|
|
1933
|
+
})()`)) || null;
|
|
1934
|
+
log(`body overflow ${unclipped ? `left as authored: ${unclipped}` : "held to the page content box"}`);
|
|
1935
|
+
}
|
|
1808
1936
|
const rectoDecls = model.breaks.filter(isRectoVersoBreak);
|
|
1809
1937
|
const needsMeasure = tier3Reasons.length > 0 || consumedStrings(model).size > 0 || rectoDecls.length > 0 || model.counterResets.length > 0 || furnitureRoots.length > 0 || sideRoots.length > 0;
|
|
1810
1938
|
let tier = tier2.geometry.bleed > 0 || tier2.geometry.slug > 0 ? 2 : 1;
|
|
@@ -1949,8 +2077,8 @@ ${mapCss}`;
|
|
|
1949
2077
|
const g = ctx.geometry;
|
|
1950
2078
|
const eff = flushMargins(g.margin, group.edges);
|
|
1951
2079
|
const boxes = [];
|
|
1952
|
-
for (const [name,
|
|
1953
|
-
const text = evaluate(
|
|
2080
|
+
for (const [name, decls2] of relocationBoxes(group, pseudos)) {
|
|
2081
|
+
const text = evaluate(decls2.content, {
|
|
1954
2082
|
page: toFolioPage(physical, pageValues),
|
|
1955
2083
|
pages: pageCount,
|
|
1956
2084
|
strings: (n, w) => stringValueAt(byName.get(n) ?? [], physical, parseWhich(w)),
|
|
@@ -1962,13 +2090,13 @@ ${mapCss}`;
|
|
|
1962
2090
|
if (!text) {
|
|
1963
2091
|
if (!relocationDiagnosed.has(name)) {
|
|
1964
2092
|
relocationDiagnosed.add(name);
|
|
1965
|
-
diagnose("engine.pin.margin-box", `@${name} sits on an edge a pinned image frees, and its content could not be ` + `re-homed into the page (unsupported content value: ${
|
|
2093
|
+
diagnose("engine.pin.margin-box", `@${name} sits on an edge a pinned image frees, and its content could not be ` + `re-homed into the page (unsupported content value: ${decls2.content}). It will ` + `not print on that page — simplify the box's content, or pin the image to another edge.`);
|
|
1966
2094
|
}
|
|
1967
2095
|
continue;
|
|
1968
2096
|
}
|
|
1969
2097
|
const r = marginBoxRectPt(name, g);
|
|
1970
2098
|
const outDecls = {};
|
|
1971
|
-
for (const [prop, value] of Object.entries(
|
|
2099
|
+
for (const [prop, value] of Object.entries(decls2)) {
|
|
1972
2100
|
if (prop.toLowerCase() === "content" || isIgnoredMarginBoxProperty(prop))
|
|
1973
2101
|
continue;
|
|
1974
2102
|
outDecls[prop] = value;
|
|
@@ -2326,6 +2454,20 @@ ${mapCss}`;
|
|
|
2326
2454
|
author: opts.author
|
|
2327
2455
|
});
|
|
2328
2456
|
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.lastPage ? `; last page: ${opts.lastPage}` : ""})` : ""));
|
|
2457
|
+
{
|
|
2458
|
+
const scale = post.scale;
|
|
2459
|
+
if (scale !== null && scale < 1) {
|
|
2460
|
+
const pct = (scale * 100).toPrecision(6);
|
|
2461
|
+
const overPx = widthOffenders.defaultLimitPx * (1 / scale - 1);
|
|
2462
|
+
diagnose("engine.width.overflow", `This book printed at ${pct}% of its declared size: content reaches about ` + `${overPx < 0.1 ? overPx.toFixed(3) : overPx.toFixed(2)}px past the ` + `${Math.round(widthOffenders.defaultLimitPx)}px page content box, and Chromium shrinks ` + `the WHOLE print to fit it. The preview is not shrunk, so its lines and page ` + `breaks can differ from the PDF's.` + (unclipped ? ` Gutterpress could not hold it at the page content box: ${unclipped}.` : ""));
|
|
2463
|
+
if (!widthOffenders.boxes.length) {
|
|
2464
|
+
const named = await findWidthOffenders(page, model, 2 * (tier2.geometry.bleed + tier2.geometry.slug), sheetViewport, 0);
|
|
2465
|
+
for (const o of named.boxes)
|
|
2466
|
+
diagnose("engine.width.overflow", `${o.desc} reaches ${Math.max(o.px + Math.min(0, o.left) - (o.limit ?? named.limitPx), -o.left).toFixed(2)}px ` + `past the ${Math.round(o.limit ?? named.limitPx)}px page content box. Keep it ` + `inside the page content box.`);
|
|
2467
|
+
}
|
|
2468
|
+
log(`audit: printed at ${pct}% (shrink-to-fit)`);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2329
2471
|
return {
|
|
2330
2472
|
bytes: post.bytes,
|
|
2331
2473
|
tier,
|
|
@@ -2360,7 +2502,7 @@ function shrinkScale(boxes, limitPx) {
|
|
|
2360
2502
|
return null;
|
|
2361
2503
|
return Math.max(1 / MAX_SHRINK, limitPx / maxRight);
|
|
2362
2504
|
}
|
|
2363
|
-
async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreViewport) {
|
|
2505
|
+
async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreViewport, tolerancePx = 1) {
|
|
2364
2506
|
const contexts = [
|
|
2365
2507
|
resolvePage(model),
|
|
2366
2508
|
...model.pageNames.filter((n) => !n.startsWith("gp-") || n.startsWith("gp--pin-")).map((n) => resolvePage(model, { name: n }))
|
|
@@ -2386,7 +2528,8 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2386
2528
|
mobile: false
|
|
2387
2529
|
});
|
|
2388
2530
|
boxes.push(...JSON.parse(await page.evaluate(`(() => {
|
|
2389
|
-
const
|
|
2531
|
+
const TOL = ${tolerancePx};
|
|
2532
|
+
const LIMIT = Math.max(${widthPx} + TOL, ${Math.ceil(widthPx)});
|
|
2390
2533
|
const NAMED = ${JSON.stringify(namedLimits)};
|
|
2391
2534
|
const DEFAULT_LIMIT = ${defaultLimitPx};
|
|
2392
2535
|
// The page an element lands on: the nearest ancestor with a non-auto
|
|
@@ -2426,10 +2569,10 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2426
2569
|
// pulls) AND left-edge protrusion (negative left with an ordinary
|
|
2427
2570
|
// width) — both trigger the same whole-document shrink-to-fit,
|
|
2428
2571
|
// measured: a left bleed alone cost 16%.
|
|
2429
|
-
if (right <= LIMIT && r.width <= LIMIT && r.left >= -
|
|
2572
|
+
if (right <= LIMIT && r.width <= LIMIT && r.left >= -TOL) continue;
|
|
2430
2573
|
// ...but only where it actually escapes its clipping ancestors.
|
|
2431
2574
|
const clip = clipEdges(el).edges;
|
|
2432
|
-
if (Math.min(right, clip.right) <= LIMIT && Math.max(r.left, clip.left) >= -
|
|
2575
|
+
if (Math.min(right, clip.right) <= LIMIT && Math.max(r.left, clip.left) >= -TOL) continue;
|
|
2433
2576
|
let deepest = true;
|
|
2434
2577
|
for (const c of el.children) {
|
|
2435
2578
|
if (c.getBoundingClientRect().width >= r.width - 1) { deepest = false; break; }
|
|
@@ -2466,7 +2609,7 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2466
2609
|
const over = el.scrollWidth - el.clientWidth;
|
|
2467
2610
|
// clientWidth is 0 on inline/replaced boxes, where scrollWidth
|
|
2468
2611
|
// carries no overflow information -- skip rather than guess.
|
|
2469
|
-
if (el.clientWidth <= 0 || over <=
|
|
2612
|
+
if (el.clientWidth <= 0 || over <= TOL) continue;
|
|
2470
2613
|
// A descendant assigned to a DIFFERENT page is not overflowing this
|
|
2471
2614
|
// element's page -- it is laid out against its own, wider one. The
|
|
2472
2615
|
// full-bleed art plate is the standard case: it is legitimately
|
|
@@ -2520,7 +2663,7 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2520
2663
|
}
|
|
2521
2664
|
return JSON.stringify(out);
|
|
2522
2665
|
})()`));
|
|
2523
|
-
return { limitPx, boxes, intrinsics: replaced };
|
|
2666
|
+
return { limitPx, defaultLimitPx, boxes, intrinsics: replaced };
|
|
2524
2667
|
} finally {
|
|
2525
2668
|
await page.send("Emulation.setDeviceMetricsOverride", restoreViewport);
|
|
2526
2669
|
}
|
|
@@ -2603,10 +2746,10 @@ function counterStyleCss(model, sources, pageMap, pageCount, resetSites = [], ha
|
|
|
2603
2746
|
return "";
|
|
2604
2747
|
const pairs = new Map;
|
|
2605
2748
|
for (const rule of model.pageRules) {
|
|
2606
|
-
for (const
|
|
2607
|
-
if (!
|
|
2749
|
+
for (const decls2 of Object.values(rule.marginBoxes)) {
|
|
2750
|
+
if (!decls2.content)
|
|
2608
2751
|
continue;
|
|
2609
|
-
for (const part of parseContent(
|
|
2752
|
+
for (const part of parseContent(decls2.content)) {
|
|
2610
2753
|
if (part.type !== "string" || !byName.has(part.name))
|
|
2611
2754
|
continue;
|
|
2612
2755
|
const which = parseWhich(part.which);
|
|
@@ -2645,13 +2788,13 @@ function counterStyleCss(model, sources, pageMap, pageCount, resetSites = [], ha
|
|
|
2645
2788
|
for (const pseudos of variants) {
|
|
2646
2789
|
const resolved = resolvePage(model, { name, pseudos });
|
|
2647
2790
|
const lines = [];
|
|
2648
|
-
for (const [box,
|
|
2649
|
-
if (!
|
|
2791
|
+
for (const [box, decls2] of Object.entries(resolved.marginBoxes)) {
|
|
2792
|
+
if (!decls2.content)
|
|
2650
2793
|
continue;
|
|
2651
|
-
const hasString = /\bstring\s*\(/.test(
|
|
2652
|
-
const hasPageCounter = pageValues && /\bcounter\(\s*page\b(?!s)/.test(
|
|
2794
|
+
const hasString = /\bstring\s*\(/.test(decls2.content);
|
|
2795
|
+
const hasPageCounter = pageValues && /\bcounter\(\s*page\b(?!s)/.test(decls2.content);
|
|
2653
2796
|
const needsRewrite = hasString || hasPageCounter;
|
|
2654
|
-
lines.push(` ${box} { content: ${needsRewrite ? rewrite(
|
|
2797
|
+
lines.push(` ${box} { content: ${needsRewrite ? rewrite(decls2.content) : decls2.content}; }`);
|
|
2655
2798
|
}
|
|
2656
2799
|
if (!lines.length)
|
|
2657
2800
|
continue;
|
|
@@ -2665,13 +2808,13 @@ ${lines.join(`
|
|
|
2665
2808
|
if (hasBlank) {
|
|
2666
2809
|
const blank = resolvePage(model, { pseudos: ["blank"] });
|
|
2667
2810
|
const lines = [];
|
|
2668
|
-
for (const [box,
|
|
2669
|
-
if (!
|
|
2811
|
+
for (const [box, decls2] of Object.entries(blank.marginBoxes)) {
|
|
2812
|
+
if (!decls2.content)
|
|
2670
2813
|
continue;
|
|
2671
|
-
const hasString = /\bstring\s*\(/.test(
|
|
2672
|
-
const hasPageCounter = pageValues && /\bcounter\(\s*page\b(?!s)/.test(
|
|
2814
|
+
const hasString = /\bstring\s*\(/.test(decls2.content);
|
|
2815
|
+
const hasPageCounter = pageValues && /\bcounter\(\s*page\b(?!s)/.test(decls2.content);
|
|
2673
2816
|
const needsRewrite = hasString || hasPageCounter;
|
|
2674
|
-
lines.push(` ${box} { content: ${needsRewrite ? rewrite(
|
|
2817
|
+
lines.push(` ${box} { content: ${needsRewrite ? rewrite(decls2.content) : decls2.content}; }`);
|
|
2675
2818
|
}
|
|
2676
2819
|
out.push(`@page ${BLANK_PAGE} {
|
|
2677
2820
|
${lines.length ? lines.join(`
|