Skip to content

Commit 8ca40bb

Browse files
author
Eugene Bochilo
committed
Finalize multiline text form field drawing
DEVSIX-7441
1 parent 690d344 commit 8ca40bb

File tree

40 files changed

+138
-100
lines changed

40 files changed

+138
-100
lines changed

forms/src/main/java/com/itextpdf/forms/form/element/TextArea.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class TextArea extends FormField<TextArea> implements IPlaceholderable {
4141
/**
4242
* Default padding X offset.
4343
*/
44-
private static final float X_OFFSET = 1;
44+
private static final float X_OFFSET = 3;
4545

4646
/**
4747
* The placeholder paragraph.
@@ -124,8 +124,5 @@ private void setProperties() {
124124
setProperty(Property.BOX_SIZING, BoxSizingPropertyValue.BORDER_BOX);
125125

126126
setProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, 1));
127-
128-
setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT);
129-
setProperty(Property.OVERFLOW_Y, OverflowPropertyValue.HIDDEN);
130127
}
131128
}

forms/src/main/java/com/itextpdf/forms/form/renderer/AbstractFormFieldRenderer.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ public abstract class AbstractFormFieldRenderer extends BlockRenderer {
7171
* @return true, if fields need to be flattened
7272
*/
7373
public boolean isFlatten() {
74-
Boolean flatten;
7574
if (parent != null) {
7675
// First check parent. This is a workaround for the case when some fields are inside other fields
7776
// either directly or via other elements (input text field inside div inside input button field). In this
@@ -84,7 +83,7 @@ public boolean isFlatten() {
8483
nextParent = nextParent.getParent();
8584
}
8685
}
87-
flatten = getPropertyAsBoolean(FormProperty.FORM_FIELD_FLATTEN);
86+
Boolean flatten = getPropertyAsBoolean(FormProperty.FORM_FIELD_FLATTEN);
8887
return flatten == null ?
8988
(boolean) modelElement.<Boolean>getDefaultProperty(FormProperty.FORM_FIELD_FLATTEN) : (boolean) flatten;
9089
}
@@ -112,8 +111,12 @@ public LayoutResult layout(LayoutContext layoutContext) {
112111
float parentHeight = layoutContext.getArea().getBBox().getHeight();
113112

114113
IRenderer renderer = createFlatRenderer();
115-
renderer.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.VISIBLE);
116-
renderer.setProperty(Property.OVERFLOW_Y, OverflowPropertyValue.VISIBLE);
114+
if (renderer.<OverflowPropertyValue>getOwnProperty(Property.OVERFLOW_X) == null) {
115+
renderer.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.VISIBLE);
116+
}
117+
if (renderer.<OverflowPropertyValue>getOwnProperty(Property.OVERFLOW_Y) == null) {
118+
renderer.setProperty(Property.OVERFLOW_Y, OverflowPropertyValue.VISIBLE);
119+
}
117120
addChild(renderer);
118121

119122
Rectangle bBox = layoutContext.getArea().getBBox().clone().moveDown(INF - parentHeight).setHeight(INF);

forms/src/main/java/com/itextpdf/forms/form/renderer/AbstractTextFieldRenderer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public abstract class AbstractTextFieldRenderer extends AbstractFormFieldRendere
6969
*/
7070
IRenderer createParagraphRenderer(String defaultValue) {
7171
if (defaultValue.trim().isEmpty()) {
72-
defaultValue = "\u00A0";
72+
defaultValue = "\u00a0";
7373
}
7474
Paragraph paragraph = new Paragraph(defaultValue).setMargin(0);
7575
return paragraph.createRendererSubTree();
@@ -170,8 +170,10 @@ void adjustNumberOfContentLines(List<LineRenderer> lines, Rectangle bBox, int ro
170170
*/
171171
void adjustNumberOfContentLines(List<LineRenderer> lines, Rectangle bBox, float height) {
172172
float averageLineHeight = bBox.getHeight() / lines.size();
173-
int visibleLinesNumber = (int) Math.ceil(height / averageLineHeight);
174-
adjustNumberOfContentLines(lines, bBox, visibleLinesNumber, height);
173+
if (averageLineHeight > EPS) {
174+
int visibleLinesNumber = (int) Math.ceil(height / averageLineHeight);
175+
adjustNumberOfContentLines(lines, bBox, visibleLinesNumber, height);
176+
}
175177
}
176178

177179
private static void adjustNumberOfContentLines(List<LineRenderer> lines, Rectangle bBox,

forms/src/main/java/com/itextpdf/forms/form/renderer/InputFieldRenderer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ IRenderer createParagraphRenderer(String defaultValue) {
9999
return ((InputField) modelElement).getPlaceholder().createRendererSubTree();
100100
}
101101
if (defaultValue.isEmpty()) {
102-
defaultValue = "\u00A0";
102+
defaultValue = "\u00a0";
103103
}
104104

105105
Text text = new Text(defaultValue);

forms/src/main/java/com/itextpdf/forms/form/renderer/TextAreaRenderer.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ This file is part of the iText (R) project.
3434
import com.itextpdf.kernel.pdf.PdfDocument;
3535
import com.itextpdf.kernel.pdf.PdfPage;
3636
import com.itextpdf.kernel.pdf.PdfString;
37+
import com.itextpdf.layout.element.Paragraph;
38+
import com.itextpdf.layout.element.Text;
39+
import com.itextpdf.layout.layout.LayoutArea;
3740
import com.itextpdf.layout.layout.LayoutContext;
3841
import com.itextpdf.layout.layout.LayoutResult;
3942
import com.itextpdf.layout.minmaxwidth.MinMaxWidth;
43+
import com.itextpdf.layout.properties.OverflowPropertyValue;
4044
import com.itextpdf.layout.properties.Property;
4145
import com.itextpdf.layout.properties.UnitValue;
4246
import com.itextpdf.layout.renderer.DrawContext;
@@ -167,7 +171,17 @@ IRenderer createParagraphRenderer(String defaultValue) {
167171
.getPlaceholder().isEmpty()) {
168172
return ((TextArea) modelElement).getPlaceholder().createRendererSubTree();
169173
}
170-
return super.createParagraphRenderer(defaultValue);
174+
if (defaultValue.isEmpty()) {
175+
defaultValue = "\u00a0";
176+
}
177+
178+
Text text = new Text(defaultValue);
179+
FormFieldValueNonTrimmingTextRenderer nextRenderer = new FormFieldValueNonTrimmingTextRenderer(text);
180+
text.setNextRenderer(nextRenderer);
181+
182+
IRenderer flatRenderer = new Paragraph(text).setMargin(0).createRendererSubTree();
183+
flatRenderer.setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT);
184+
return flatRenderer;
171185
}
172186

173187
/* (non-Javadoc)
@@ -211,9 +225,13 @@ public <T1> T1 getProperty(int key) {
211225
logger.error(MessageFormatUtil.format(IoLogMessageConstant.PROPERTY_IN_PERCENTS_NOT_SUPPORTED,
212226
Property.FONT_SIZE));
213227
}
228+
float fontSizeValue = fontSize.getValue();
229+
if (fontSizeValue < EPS) {
230+
fontSizeValue = DEFAULT_FONT_SIZE;
231+
}
214232
int cols = getCols();
215233
return (T1) (Object) UnitValue.createPointValue(
216-
updateHtmlColsSizeBasedWidth(fontSize.getValue() * (cols * 0.5f + 2) + 2));
234+
updateHtmlColsSizeBasedWidth(fontSizeValue * (cols * 0.5f + 2) + 2));
217235
}
218236
return width;
219237
}
@@ -262,14 +280,22 @@ private void approximateFontSizeToFitMultiLine(LayoutContext layoutContext) {
262280
float lFontSize = MIN_FONT_SIZE;
263281
float rFontSize = DEFAULT_FONT_SIZE;
264282
flatRenderer.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(DEFAULT_FONT_SIZE));
265-
if (flatRenderer.layout(layoutContext).getStatus() == LayoutResult.FULL) {
283+
Float areaWidth = retrieveWidth(layoutContext.getArea().getBBox().getWidth());
284+
Float areaHeight = retrieveHeight();
285+
LayoutContext newLayoutContext;
286+
if (areaWidth == null || areaHeight == null) {
287+
modelElement.setFontSize(DEFAULT_FONT_SIZE);
288+
return;
289+
}
290+
newLayoutContext = new LayoutContext(new LayoutArea(1, new Rectangle((float) areaWidth, (float) areaHeight)));
291+
if (flatRenderer.layout(newLayoutContext).getStatus() == LayoutResult.FULL) {
266292
lFontSize = DEFAULT_FONT_SIZE;
267293
} else {
268294
final int numberOfIterations = 6;
269295
for (int i = 0; i < numberOfIterations; i++) {
270296
float mFontSize = (lFontSize + rFontSize) / 2;
271297
flatRenderer.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(mFontSize));
272-
LayoutResult result = flatRenderer.layout(layoutContext);
298+
LayoutResult result = flatRenderer.layout(newLayoutContext);
273299
if (result.getStatus() == LayoutResult.FULL) {
274300
lFontSize = mFontSize;
275301
} else {

forms/src/test/java/com/itextpdf/forms/FormFieldFlatteningTest.java

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -107,24 +107,17 @@ public void formFlatteningChoiceFieldTest01() throws IOException, InterruptedExc
107107

108108
@Test
109109
public void multiLineFormFieldClippingTest() throws IOException, InterruptedException {
110-
// TODO: DEVSIX-7441 - remove flag
111-
final boolean experimentalRenderingPreviousValue = ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING;
112-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = false;
113-
try {
114-
String src = sourceFolder + "multiLineFormFieldClippingTest.pdf";
115-
String dest = destinationFolder + "multiLineFormFieldClippingTest_flattened.pdf";
116-
String cmp = sourceFolder + "cmp_multiLineFormFieldClippingTest_flattened.pdf";
117-
118-
PdfDocument doc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
119-
PdfAcroForm form = PdfAcroForm.getAcroForm(doc, true);
120-
form.getField("Text1").setValue("Tall letters: T I J L R E F");
121-
form.flattenFields();
122-
doc.close();
123-
124-
Assert.assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder, "diff_"));
125-
} finally {
126-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = experimentalRenderingPreviousValue;
127-
}
110+
String src = sourceFolder + "multiLineFormFieldClippingTest.pdf";
111+
String dest = destinationFolder + "multiLineFormFieldClippingTest_flattened.pdf";
112+
String cmp = sourceFolder + "cmp_multiLineFormFieldClippingTest_flattened.pdf";
113+
114+
PdfDocument doc = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
115+
PdfAcroForm form = PdfAcroForm.getAcroForm(doc, true);
116+
form.getField("Text1").setValue("Tall letters: T I J L R E F");
117+
form.flattenFields();
118+
doc.close();
119+
120+
Assert.assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder, "diff_"));
128121
}
129122

130123
@Test
@@ -188,29 +181,15 @@ private static void flattenFieldsAndCompare(String srcFile, String outFile)
188181

189182
@Test
190183
public void fieldsJustificationTest01() throws IOException, InterruptedException {
191-
// TODO: DEVSIX-7441 - remove flag
192-
final boolean experimentalRenderingPreviousValue = ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING;
193-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = false;
194-
try {
195-
fillTextFieldsThenFlattenThenCompare("fieldsJustificationTest01");
196-
} finally {
197-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = experimentalRenderingPreviousValue;
198-
}
184+
fillTextFieldsThenFlattenThenCompare("fieldsJustificationTest01");
199185
}
200186

201187
@Test
202188
@LogMessages(messages = {
203189
@LogMessage(messageTemplate = FormsLogMessageConstants.ANNOTATION_IN_ACROFORM_DICTIONARY, count = 2)
204190
})
205191
public void fieldsJustificationTest02() throws IOException, InterruptedException {
206-
// TODO: DEVSIX-7441 - remove flag
207-
final boolean experimentalRenderingPreviousValue = ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING;
208-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = false;
209-
try {
210-
fillTextFieldsThenFlattenThenCompare("fieldsJustificationTest02");
211-
} finally {
212-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = experimentalRenderingPreviousValue;
213-
}
192+
fillTextFieldsThenFlattenThenCompare("fieldsJustificationTest02");
214193
}
215194

216195
private static void fillTextFieldsThenFlattenThenCompare(String testName) throws IOException, InterruptedException {

forms/src/test/java/com/itextpdf/forms/PdfFormFieldMultilineTextTest.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ This file is part of the iText (R) project.
2222
*/
2323
package com.itextpdf.forms;
2424

25-
import com.itextpdf.commons.utils.ExperimentalFeatures;
2625
import com.itextpdf.forms.fields.PdfFormField;
2726
import com.itextpdf.forms.fields.PdfTextFormField;
2827
import com.itextpdf.forms.fields.TextFormFieldBuilder;
@@ -54,20 +53,13 @@ public class PdfFormFieldMultilineTextTest extends ExtendedITextTest {
5453
public static final String destinationFolder = "./target/test/com/itextpdf/forms/PdfFormFieldMultilineTextTest/";
5554
public static final String sourceFolder = "./src/test/resources/com/itextpdf/forms/PdfFormFieldMultilineTextTest/";
5655

57-
private static boolean experimentalRenderingPreviousValue;
58-
5956
@BeforeClass
6057
public static void beforeClass() {
61-
// TODO: DEVSIX-7441 - remove flag
62-
experimentalRenderingPreviousValue = ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING;
63-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = false;
64-
6558
createDestinationFolder(destinationFolder);
6659
}
6760

6861
@AfterClass
6962
public static void afterClass() {
70-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = experimentalRenderingPreviousValue;
7163
}
7264

7365

forms/src/test/java/com/itextpdf/forms/PdfFormFieldTest.java

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,46 +1260,39 @@ public void pdfWithDifferentFieldsTest() throws IOException, InterruptedExceptio
12601260

12611261
@Test
12621262
public void textFieldWithWideUnicodeRange() throws IOException, InterruptedException {
1263-
// TODO: DEVSIX-7441 - remove flag
1264-
final boolean experimentalRenderingPreviousValue = ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING;
1265-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = false;
1266-
try {
1267-
String filename = "textFieldWithWideUnicodeRange.pdf";
1268-
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(destinationFolder + filename));
1269-
pdfDoc.addNewPage();
1270-
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
1271-
1272-
form.addField(new TextFormFieldBuilder(pdfDoc, "text_helvetica").setWidgetRectangle(
1273-
new Rectangle(36, 400, 100, 40))
1274-
.createText().setValue("Helvetica"));
1275-
1276-
PdfFont noto = PdfFontFactory.createFont(sourceFolder + "NotoSans-Regular.ttf", PdfEncodings.IDENTITY_H);
1277-
noto.setSubset(false);
1278-
String value = "aAáÁàÀăĂắẮằẰẵẴẳẲâÂấẤầẦẫẪǎǍåÅǻǺäÄǟǞãÃą" +
1279-
"ĄāĀảẢạẠặẶẬæÆǽǼbBḃḂcCćĆčČċĊçÇdDd̂D̂ďĎḋḊḑḐđĐðÐeE" +
1280-
"éÉèÈĕĔêÊếẾềỀễỄěĚëËẽẼėĖęĘēĒẻẺẹẸệỆəƏfFḟḞgGǵǴğĞ" +
1281-
"ǧǦġĠģĢḡḠǥǤhHȟȞḧḦħĦḥḤiIíÍìÌĭĬîÎǐǏïÏĩĨİįĮīĪỉỈị" +
1282-
"ỊıjJĵĴǰJ̌kKḱḰǩǨķĶlLĺĹl̂L̂ľĽļĻłŁŀĿmMm̂M̂ṁṀnNńŃn̂N̂ňŇ" +
1283-
"ñÑṅṄņŅŋŊoOóÓòÒŏŎôÔốỐồỒỗỖǒǑöÖȫȪőŐõÕȯȮȱȰøØǿǾǫǪ" +
1284-
"ǭǬōŌỏỎơƠớỚờỜọỌộỘœŒpPṗṖqQĸrRŕŔřŘŗŖsSśŚšŠṡṠşŞṣ" +
1285-
"ṢșȘßẞtTťŤṫṪţŢțȚŧŦuUúÚùÙûÛǔǓůŮüÜűŰũŨųŲūŪủỦưƯứ" +
1286-
"ỨừỪữỮửỬựỰụỤvVwWẃẂẁẀŵŴẅẄxXẍẌyYýÝỳỲŷŶÿŸỹỸẏẎȳȲỷỶ" +
1287-
"ỵỴzZźŹẑẐžŽżŻẓẒʒƷǯǮþÞʼn";
1288-
PdfFormField textField = new TextFormFieldBuilder(pdfDoc, "text").setWidgetRectangle(
1289-
new Rectangle(36, 500, 400, 300))
1290-
.createMultilineText().setValue(value);
1291-
textField.setFont(noto).setFontSize(12);
1292-
1293-
form.addField(textField);
1294-
1295-
pdfDoc.close();
1296-
1297-
Assert.assertNull(
1298-
new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename,
1299-
destinationFolder, "diff_"));
1300-
} finally {
1301-
ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING = experimentalRenderingPreviousValue;
1302-
}
1263+
String filename = "textFieldWithWideUnicodeRange.pdf";
1264+
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(destinationFolder + filename));
1265+
pdfDoc.addNewPage();
1266+
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
1267+
1268+
form.addField(new TextFormFieldBuilder(pdfDoc, "text_helvetica").setWidgetRectangle(
1269+
new Rectangle(36, 400, 100, 40))
1270+
.createText().setValue("Helvetica"));
1271+
1272+
PdfFont noto = PdfFontFactory.createFont(sourceFolder + "NotoSans-Regular.ttf", PdfEncodings.IDENTITY_H);
1273+
noto.setSubset(false);
1274+
String value = "aAáÁàÀăĂắẮằẰẵẴẳẲâÂấẤầẦẫẪǎǍåÅǻǺäÄǟǞãÃą" +
1275+
"ĄāĀảẢạẠặẶẬæÆǽǼbBḃḂcCćĆčČċĊçÇdDd̂D̂ďĎḋḊḑḐđĐðÐeE" +
1276+
"éÉèÈĕĔêÊếẾềỀễỄěĚëËẽẼėĖęĘēĒẻẺẹẸệỆəƏfFḟḞgGǵǴğĞ" +
1277+
"ǧǦġĠģĢḡḠǥǤhHȟȞḧḦħĦḥḤiIíÍìÌĭĬîÎǐǏïÏĩĨİįĮīĪỉỈị" +
1278+
"ỊıjJĵĴǰJ̌kKḱḰǩǨķĶlLĺĹl̂L̂ľĽļĻłŁŀĿmMm̂M̂ṁṀnNńŃn̂N̂ňŇ" +
1279+
"ñÑṅṄņŅŋŊoOóÓòÒŏŎôÔốỐồỒỗỖǒǑöÖȫȪőŐõÕȯȮȱȰøØǿǾǫǪ" +
1280+
"ǭǬōŌỏỎơƠớỚờỜọỌộỘœŒpPṗṖqQĸrRŕŔřŘŗŖsSśŚšŠṡṠşŞṣ" +
1281+
"ṢșȘßẞtTťŤṫṪţŢțȚŧŦuUúÚùÙûÛǔǓůŮüÜűŰũŨųŲūŪủỦưƯứ" +
1282+
"ỨừỪữỮửỬựỰụỤvVwWẃẂẁẀŵŴẅẄxXẍẌyYýÝỳỲŷŶÿŸỹỸẏẎȳȲỷỶ" +
1283+
"ỵỴzZźŹẑẐžŽżŻẓẒʒƷǯǮþÞʼn";
1284+
PdfFormField textField = new TextFormFieldBuilder(pdfDoc, "text").setWidgetRectangle(
1285+
new Rectangle(36, 500, 400, 300))
1286+
.createMultilineText().setValue(value);
1287+
textField.setFont(noto).setFontSize(12);
1288+
1289+
form.addField(textField);
1290+
1291+
pdfDoc.close();
1292+
1293+
Assert.assertNull(
1294+
new CompareTool().compareByContent(destinationFolder + filename, sourceFolder + "cmp_" + filename,
1295+
destinationFolder, "diff_"));
13031296
}
13041297

13051298
@Test

0 commit comments

Comments
 (0)