Skip to content

Commit f2b9f0d

Browse files
authored
Merge pull request #13495 from calixteman/draws
XFA - Display rectangle, line and arc
2 parents b4c96f3 + 1f6345b commit f2b9f0d

File tree

5 files changed

+201
-9
lines changed

5 files changed

+201
-9
lines changed

src/core/xfa/template.js

+176-8
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import { stringToBytes, Util, warn } from "../../shared/util.js";
8080
import { searchNode } from "./som.js";
8181

8282
const TEMPLATE_NS_ID = NamespaceIds.template.id;
83+
const SVG_NS = "http://www.w3.org/2000/svg";
8384

8485
// In case of lr-tb (and rl-tb) layouts, we try:
8586
// - to put the container at the end of a line
@@ -171,6 +172,10 @@ const NOSPACE = 1;
171172
const VALID = 2;
172173
function checkDimensions(node, space) {
173174
const [x, y, w, h] = getTransformedBBox(node);
175+
if (node.w === 0 || node.h === 0) {
176+
return VALID;
177+
}
178+
174179
if (node.w !== "" && Math.round(x + w - space.width) > 1) {
175180
const area = getRoot(node)[$extra].currentContentArea;
176181
if (x + w > area.w) {
@@ -227,6 +232,73 @@ class Arc extends XFAObject {
227232
this.edge = null;
228233
this.fill = null;
229234
}
235+
236+
[$toHTML]() {
237+
const edge = this.edge ? this.edge : new Edge({});
238+
const edgeStyle = edge[$toStyle]();
239+
const style = Object.create(null);
240+
if (this.fill) {
241+
Object.assign(style, this.fill[$toStyle]());
242+
} else {
243+
style.fill = "transparent";
244+
}
245+
style.strokeWidth = measureToString(Math.round(edge.thickness));
246+
style.stroke = edgeStyle.color;
247+
let arc;
248+
const attributes = {
249+
xmlns: SVG_NS,
250+
style: {
251+
position: "absolute",
252+
width: "100%",
253+
height: "100%",
254+
},
255+
};
256+
257+
if (this.startAngle === 0 && this.sweepAngle === 360) {
258+
arc = {
259+
name: "ellipse",
260+
attributes: {
261+
xmlns: SVG_NS,
262+
cx: "50%",
263+
cy: "50%",
264+
rx: "50%",
265+
ry: "50%",
266+
style,
267+
},
268+
};
269+
} else {
270+
const startAngle = (this.startAngle * Math.PI) / 180;
271+
const sweepAngle = (this.sweepAngle * Math.PI) / 180;
272+
const largeArc = this.sweepAngle - this.startAngle > 180 ? 1 : 0;
273+
const [x1, y1, x2, y2] = [
274+
50 * (1 + Math.cos(startAngle)),
275+
50 * (1 - Math.sin(startAngle)),
276+
50 * (1 + Math.cos(sweepAngle)),
277+
50 * (1 - Math.sin(sweepAngle)),
278+
];
279+
280+
arc = {
281+
name: "path",
282+
attributes: {
283+
xmlns: SVG_NS,
284+
d: `M ${x1} ${y1} A 50 50 0 ${largeArc} 0 ${x2} ${y2}`,
285+
vectorEffect: "non-scaling-stroke",
286+
style,
287+
},
288+
};
289+
290+
Object.assign(attributes, {
291+
viewBox: "0 0 100 100",
292+
preserveAspectRatio: "none",
293+
});
294+
}
295+
296+
return HTMLResult.success({
297+
name: "svg",
298+
children: [arc],
299+
attributes,
300+
});
301+
}
230302
}
231303

232304
class Area extends XFAObject {
@@ -1170,7 +1242,7 @@ class Corner extends XFAObject {
11701242
// Maybe it's possible to implement them using svg and border-image...
11711243
// TODO: implement all the missing properties.
11721244
const style = toStyle(this, "visibility");
1173-
style.radius = measureToString(this.radius);
1245+
style.radius = measureToString(this.join === "square" ? 0 : this.radius);
11741246
return style;
11751247
}
11761248
}
@@ -1412,12 +1484,7 @@ class Draw extends XFAObject {
14121484
}
14131485

14141486
[$toHTML](availableSpace) {
1415-
if (
1416-
this.presence === "hidden" ||
1417-
this.presence === "inactive" ||
1418-
this.h === 0 ||
1419-
this.w === 0
1420-
) {
1487+
if (this.presence === "hidden" || this.presence === "inactive") {
14211488
return HTMLResult.EMPTY;
14221489
}
14231490

@@ -1485,7 +1552,7 @@ class Draw extends XFAObject {
14851552
}
14861553

14871554
html.children.push(value);
1488-
if (value.attributes.class.includes("xfaRich")) {
1555+
if (value.attributes.class && value.attributes.class.includes("xfaRich")) {
14891556
if (this.h === "") {
14901557
style.height = "auto";
14911558
}
@@ -2379,6 +2446,9 @@ class Fill extends XFAObject {
23792446
if (parent instanceof Border) {
23802447
propName = "background";
23812448
}
2449+
if (parent instanceof Rectangle) {
2450+
propName = "fill";
2451+
}
23822452
const style = Object.create(null);
23832453
for (const name of Object.getOwnPropertyNames(this)) {
23842454
if (name === "extras" || name === "color") {
@@ -2853,6 +2923,57 @@ class Line extends XFAObject {
28532923
this.usehref = attributes.usehref || "";
28542924
this.edge = null;
28552925
}
2926+
2927+
[$toHTML]() {
2928+
const parent = this[$getParent]()[$getParent]();
2929+
const edge = this.edge ? this.edge : new Edge({});
2930+
const edgeStyle = edge[$toStyle]();
2931+
const style = Object.create(null);
2932+
style.strokeWidth = measureToString(Math.round(edge.thickness));
2933+
style.stroke = edgeStyle.color;
2934+
let x1, y1, x2, y2;
2935+
let width = "100%";
2936+
let height = "100%";
2937+
2938+
if (parent.w <= edge.thickness) {
2939+
[x1, y1, x2, y2] = ["50%", 0, "50%", "100%"];
2940+
width = style.strokeWidth;
2941+
} else if (parent.h <= edge.thickness) {
2942+
[x1, y1, x2, y2] = [0, "50%", "100%", "50%"];
2943+
height = style.strokeWidth;
2944+
} else {
2945+
if (this.slope === "\\") {
2946+
[x1, y1, x2, y2] = [0, 0, "100%", "100%"];
2947+
} else {
2948+
[x1, y1, x2, y2] = [0, "100%", "100%", 0];
2949+
}
2950+
}
2951+
2952+
const line = {
2953+
name: "line",
2954+
attributes: {
2955+
xmlns: SVG_NS,
2956+
x1,
2957+
y1,
2958+
x2,
2959+
y2,
2960+
style,
2961+
},
2962+
};
2963+
2964+
return HTMLResult.success({
2965+
name: "svg",
2966+
children: [line],
2967+
attributes: {
2968+
xmlns: SVG_NS,
2969+
width,
2970+
height,
2971+
style: {
2972+
position: "absolute",
2973+
},
2974+
},
2975+
});
2976+
}
28562977
}
28572978

28582979
class Linear extends XFAObject {
@@ -3631,6 +3752,53 @@ class Rectangle extends XFAObject {
36313752
this.edge = new XFAObjectArray(4);
36323753
this.fill = null;
36333754
}
3755+
3756+
[$toHTML]() {
3757+
const edge = this.edge.children.length
3758+
? this.edge.children[0]
3759+
: new Edge({});
3760+
const edgeStyle = edge[$toStyle]();
3761+
const style = Object.create(null);
3762+
if (this.fill) {
3763+
Object.assign(style, this.fill[$toStyle]());
3764+
} else {
3765+
style.fill = "transparent";
3766+
}
3767+
style.strokeWidth = measureToString(2 * edge.thickness);
3768+
style.stroke = edgeStyle.color;
3769+
3770+
const corner = this.corner.children.length
3771+
? this.corner.children[0]
3772+
: new Corner({});
3773+
const cornerStyle = corner[$toStyle]();
3774+
3775+
const rect = {
3776+
name: "rect",
3777+
attributes: {
3778+
xmlns: SVG_NS,
3779+
width: "100%",
3780+
height: "100%",
3781+
x: 0,
3782+
y: 0,
3783+
rx: cornerStyle.radius,
3784+
ry: cornerStyle.radius,
3785+
style,
3786+
},
3787+
};
3788+
3789+
return HTMLResult.success({
3790+
name: "svg",
3791+
children: [rect],
3792+
attributes: {
3793+
xmlns: SVG_NS,
3794+
style: {
3795+
position: "absolute",
3796+
},
3797+
width: "100%",
3798+
height: "100%",
3799+
},
3800+
});
3801+
}
36343802
}
36353803

36363804
class RefElement extends StringObject {

src/display/xfa_layer.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,13 @@ class XfaLayer {
163163
continue;
164164
}
165165

166-
const childHtml = document.createElement(name);
166+
let childHtml;
167+
if (child?.attributes?.xmlns) {
168+
childHtml = document.createElementNS(child.attributes.xmlns, name);
169+
} else {
170+
childHtml = document.createElement(name);
171+
}
172+
167173
html.appendChild(childHtml);
168174
if (child.attributes) {
169175
this.setAttributes(childHtml, child, storage, intent);

test/pdfs/xfa_fish_licence.pdf.link

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://web.archive.org/web/20210609130056/https://inspection.canada.ca/DAM/DAM-food-aliments/STAGING/text-texte/c5704_re_1357758804123_eng.pdf

test/pdfs/xfa_imm1295e.pdf.link

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://web.archive.org/web/20210506174920/https://www.canada.ca/content/dam/ircc/migration/ircc/english/pdf/kits/forms/imm1295e.pdf

test/test_manifest.json

+16
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,14 @@
930930
"link": true,
931931
"type": "load"
932932
},
933+
{ "id": "xfa_fish_licence",
934+
"file": "pdfs/xfa_fish_licence.pdf",
935+
"md5": "9b993128bbd7f4217098fd44116ebec2",
936+
"link": true,
937+
"rounds": 1,
938+
"enableXfa": true,
939+
"type": "eq"
940+
},
933941
{ "id": "issue10272",
934942
"file": "pdfs/issue10272.pdf",
935943
"md5": "bf3b2f74c6878d38a70dc0825f1b9a02",
@@ -4201,6 +4209,14 @@
42014209
"type": "eq",
42024210
"about": "A CIDFontType0 font with a CFF font that isn't actually CID."
42034211
},
4212+
{ "id": "xfa_imm1295e",
4213+
"file": "pdfs/xfa_imm1295e.pdf",
4214+
"md5": "b995232fda9bb7fa57856ff7f4cda046",
4215+
"rounds": 1,
4216+
"link": true,
4217+
"enableXfa": true,
4218+
"type": "eq"
4219+
},
42044220
{ "id": "scorecard_reduced",
42054221
"file": "pdfs/scorecard_reduced.pdf",
42064222
"md5": "aa8ed0827092c963eea64adb718a3806",

0 commit comments

Comments
 (0)