Skip to content

Commit 5d251a3

Browse files
authored
Merge pull request #13566 from calixteman/layout4
XFA - Fix layout issues
2 parents 3264d40 + df08b15 commit 5d251a3

File tree

7 files changed

+334
-229
lines changed

7 files changed

+334
-229
lines changed

src/core/xfa/html_utils.js

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,24 +102,12 @@ const converters = {
102102
style.width = measureToString(width);
103103
} else {
104104
style.width = "auto";
105-
if (node.maxW > 0) {
106-
style.maxWidth = measureToString(node.maxW);
107-
}
108-
if (parent.layout === "position") {
109-
style.minWidth = measureToString(node.minW);
110-
}
111105
}
112106

113107
if (height !== "") {
114108
style.height = measureToString(height);
115109
} else {
116110
style.height = "auto";
117-
if (node.maxH > 0) {
118-
style.maxHeight = measureToString(node.maxH);
119-
}
120-
if (parent.layout === "position") {
121-
style.minHeight = measureToString(node.minH);
122-
}
123111
}
124112
},
125113
position(node, style) {
@@ -188,6 +176,20 @@ const converters = {
188176
},
189177
};
190178

179+
function setMinMaxDimensions(node, style) {
180+
const parent = node[$getParent]();
181+
if (parent.layout === "position") {
182+
style.minWidth = measureToString(node.minW);
183+
if (node.maxW) {
184+
style.maxWidth = measureToString(node.maxW);
185+
}
186+
style.minHeight = measureToString(node.minH);
187+
if (node.maxH) {
188+
style.maxHeight = measureToString(node.maxH);
189+
}
190+
}
191+
}
192+
191193
function layoutText(text, xfaFont, fonts, width) {
192194
const measure = new TextMeasure(xfaFont, fonts);
193195
if (typeof text === "string") {
@@ -283,16 +285,9 @@ function fixDimensions(node) {
283285
}
284286
}
285287

286-
if (node.layout === "position") {
287-
// Acrobat doesn't take into account min, max values
288-
// for containers with positioned layout (which makes sense).
289-
node.minW = node.minH = 0;
290-
node.maxW = node.maxH = Infinity;
291-
} else {
292-
if (node.layout === "table") {
293-
if (node.w === "" && Array.isArray(node.columnWidths)) {
294-
node.w = node.columnWidths.reduce((a, x) => a + x, 0);
295-
}
288+
if (node.layout === "table") {
289+
if (node.w === "" && Array.isArray(node.columnWidths)) {
290+
node.w = node.columnWidths.reduce((a, x) => a + x, 0);
296291
}
297292
}
298293
}
@@ -471,5 +466,6 @@ export {
471466
layoutClass,
472467
layoutText,
473468
measureToString,
469+
setMinMaxDimensions,
474470
toStyle,
475471
};

src/core/xfa/layout.js

Lines changed: 167 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
* limitations under the License.
1414
*/
1515

16-
import { $extra, $flushHTML } from "./xfa_object.js";
16+
import {
17+
$extra,
18+
$flushHTML,
19+
$getParent,
20+
$getTemplateRoot,
21+
$isSplittable,
22+
} from "./xfa_object.js";
1723
import { measureToString } from "./html_utils.js";
1824

1925
// Subform and ExclGroup have a layout so they share these functions.
@@ -146,59 +152,181 @@ function addHTML(node, html, bbox) {
146152

147153
function getAvailableSpace(node) {
148154
const availableSpace = node[$extra].availableSpace;
149-
const marginH = node.margin
155+
const marginV = node.margin
150156
? node.margin.topInset + node.margin.bottomInset
151157
: 0;
158+
const marginH = node.margin
159+
? node.margin.leftInset + node.margin.rightInset
160+
: 0;
152161

153162
switch (node.layout) {
154163
case "lr-tb":
155164
case "rl-tb":
156-
switch (node[$extra].attempt) {
157-
case 0:
158-
return {
159-
width: availableSpace.width - node[$extra].currentWidth,
160-
height: availableSpace.height - marginH - node[$extra].prevHeight,
161-
};
162-
case 1:
163-
return {
164-
width: availableSpace.width,
165-
height: availableSpace.height - marginH - node[$extra].height,
166-
};
167-
default:
168-
// Overflow must stay in the container.
169-
return {
170-
width: Infinity,
171-
height: Infinity,
172-
};
165+
if (node[$extra].attempt === 0) {
166+
return {
167+
width: availableSpace.width - marginH - node[$extra].currentWidth,
168+
height: availableSpace.height - marginV - node[$extra].prevHeight,
169+
};
173170
}
171+
return {
172+
width: availableSpace.width - marginH,
173+
height: availableSpace.height - marginV - node[$extra].height,
174+
};
174175
case "rl-row":
175176
case "row":
176-
if (node[$extra].attempt === 0) {
177-
const width = node[$extra].columnWidths
178-
.slice(node[$extra].currentColumn)
179-
.reduce((a, x) => a + x);
180-
return { width, height: availableSpace.height - marginH };
177+
const width = node[$extra].columnWidths
178+
.slice(node[$extra].currentColumn)
179+
.reduce((a, x) => a + x);
180+
return { width, height: availableSpace.height - marginH };
181+
case "table":
182+
case "tb":
183+
return {
184+
width: availableSpace.width - marginH,
185+
height: availableSpace.height - marginV - node[$extra].height,
186+
};
187+
case "position":
188+
default:
189+
return availableSpace;
190+
}
191+
}
192+
193+
function getTransformedBBox(node) {
194+
// Take into account rotation and anchor the get the
195+
// real bounding box.
196+
let w = node.w === "" ? NaN : node.w;
197+
let h = node.h === "" ? NaN : node.h;
198+
let [centerX, centerY] = [0, 0];
199+
switch (node.anchorType || "") {
200+
case "bottomCenter":
201+
[centerX, centerY] = [w / 2, h];
202+
break;
203+
case "bottomLeft":
204+
[centerX, centerY] = [0, h];
205+
break;
206+
case "bottomRight":
207+
[centerX, centerY] = [w, h];
208+
break;
209+
case "middleCenter":
210+
[centerX, centerY] = [w / 2, h / 2];
211+
break;
212+
case "middleLeft":
213+
[centerX, centerY] = [0, h / 2];
214+
break;
215+
case "middleRight":
216+
[centerX, centerY] = [w, h / 2];
217+
break;
218+
case "topCenter":
219+
[centerX, centerY] = [w / 2, 0];
220+
break;
221+
case "topRight":
222+
[centerX, centerY] = [w, 0];
223+
break;
224+
}
225+
226+
let x;
227+
let y;
228+
switch (node.rotate || 0) {
229+
case 0:
230+
[x, y] = [-centerX, -centerY];
231+
break;
232+
case 90:
233+
[x, y] = [-centerY, centerX];
234+
[w, h] = [h, -w];
235+
break;
236+
case 180:
237+
[x, y] = [centerX, centerY];
238+
[w, h] = [-w, -h];
239+
break;
240+
case 270:
241+
[x, y] = [centerY, -centerX];
242+
[w, h] = [-h, w];
243+
break;
244+
}
245+
246+
return [
247+
node.x + x + Math.min(0, w),
248+
node.y + y + Math.min(0, h),
249+
Math.abs(w),
250+
Math.abs(h),
251+
];
252+
}
253+
254+
/**
255+
* Returning true means that the node will be layed out
256+
* else the layout will go to its next step (changing of line
257+
* in case of lr-tb or changing content area...).
258+
*/
259+
function checkDimensions(node, space) {
260+
if (node.w === 0 || node.h === 0) {
261+
return true;
262+
}
263+
264+
if (space.width <= 0 || space.height <= 0) {
265+
return false;
266+
}
267+
268+
const parent = node[$getParent]();
269+
const attempt = (node[$extra] && node[$extra].attempt) || 0;
270+
switch (parent.layout) {
271+
case "lr-tb":
272+
case "rl-tb":
273+
switch (attempt) {
274+
case 0: {
275+
let w, h;
276+
if (node.w !== "" || node.h !== "") {
277+
[, , w, h] = getTransformedBBox(node);
278+
}
279+
if (node.h !== "" && Math.round(h - space.height) > 1) {
280+
return false;
281+
}
282+
if (node.w !== "") {
283+
return Math.round(w - space.width) <= 1;
284+
}
285+
286+
return node.minW <= space.width;
287+
}
288+
case 1: {
289+
if (node.h !== "" && !node[$isSplittable]()) {
290+
const [, , , h] = getTransformedBBox(node);
291+
if (Math.round(h - space.height) > 1) {
292+
return false;
293+
}
294+
}
295+
return true;
296+
}
297+
default:
298+
return true;
181299
}
182-
// Overflow must stay in the container.
183-
return { width: Infinity, height: Infinity };
184300
case "table":
185301
case "tb":
186-
if (node[$extra].attempt === 0) {
187-
return {
188-
width: availableSpace.width,
189-
height: availableSpace.height - marginH - node[$extra].height,
190-
};
302+
if (attempt !== 1 && node.h !== "" && !node[$isSplittable]()) {
303+
const [, , , h] = getTransformedBBox(node);
304+
if (Math.round(h - space.height) > 1) {
305+
return false;
306+
}
191307
}
192-
// Overflow must stay in the container.
193-
return { width: Infinity, height: Infinity };
308+
return true;
194309
case "position":
195-
default:
196-
if (node[$extra].attempt === 0) {
197-
return availableSpace;
310+
const [x, y, w, h] = getTransformedBBox(node);
311+
const isWidthOk = node.w === "" || Math.round(w + x - space.width) <= 1;
312+
const isHeightOk = node.h === "" || Math.round(h + y - space.height) <= 1;
313+
314+
if (isWidthOk && isHeightOk) {
315+
return true;
198316
}
199-
// Overflow must stay in the container.
200-
return { width: Infinity, height: Infinity };
317+
318+
const area = node[$getTemplateRoot]()[$extra].currentContentArea;
319+
if (isWidthOk) {
320+
return h + y > area.h;
321+
}
322+
323+
return w + x > area.w;
324+
case "rl-row":
325+
case "row":
326+
default:
327+
// No layout, so accept everything.
328+
return true;
201329
}
202330
}
203331

204-
export { addHTML, flushHTML, getAvailableSpace };
332+
export { addHTML, checkDimensions, flushHTML, getAvailableSpace };

0 commit comments

Comments
 (0)