Skip to content

Commit 005391f

Browse files
committed
Support setFixedPosition on formfield elements.
DEVSIX-8179
1 parent 76f6a88 commit 005391f

21 files changed

+533
-49
lines changed

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

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -367,42 +367,6 @@ protected void writeAcroFormFieldLangAttribute(PdfDocument pdfDoc) {
367367
}
368368
}
369369

370-
/**
371-
* Deletes all margin properties. Used in {@code applyAcroField} to not apply margins twice as we already use area
372-
* with margins applied (margins shouldn't be an interactive part of the field, i.e. included into its occupied
373-
* area).
374-
*
375-
* @return the map of deleted margins.
376-
*/
377-
Map<Integer, Object> deleteMargins() {
378-
379-
final Map<Integer, Object> margins = new HashMap<>();
380-
margins.put(Property.MARGIN_TOP, this.modelElement.<UnitValue>getOwnProperty(Property.MARGIN_TOP));
381-
margins.put(Property.MARGIN_BOTTOM, this.modelElement.<UnitValue>getOwnProperty(Property.MARGIN_BOTTOM));
382-
margins.put(Property.MARGIN_LEFT, this.modelElement.<UnitValue>getOwnProperty(Property.MARGIN_LEFT));
383-
margins.put(Property.MARGIN_RIGHT, this.modelElement.<UnitValue>getOwnProperty(Property.MARGIN_RIGHT));
384-
385-
modelElement.deleteOwnProperty(Property.MARGIN_RIGHT);
386-
modelElement.deleteOwnProperty(Property.MARGIN_LEFT);
387-
modelElement.deleteOwnProperty(Property.MARGIN_TOP);
388-
modelElement.deleteOwnProperty(Property.MARGIN_BOTTOM);
389-
return margins;
390-
}
391-
392-
/**
393-
* Applies the properties to the model element.
394-
*
395-
* @param properties the properties to apply
396-
*/
397-
void applyProperties(Map<Integer, Object> properties) {
398-
for (Entry<Integer, Object> integerObjectEntry : properties.entrySet()) {
399-
if (integerObjectEntry.getValue() != null) {
400-
modelElement.setProperty(integerObjectEntry.getKey(), integerObjectEntry.getValue());
401-
} else {
402-
modelElement.deleteOwnProperty(integerObjectEntry.getKey());
403-
}
404-
}
405-
}
406370

407371
private void processLangAttribute() {
408372
IPropertyContainer propertyContainer = flatRenderer.getModelElement();

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ This file is part of the iText (R) project.
3030
import com.itextpdf.forms.form.FormProperty;
3131
import com.itextpdf.forms.form.element.Button;
3232
import com.itextpdf.forms.logs.FormsLogMessageConstants;
33+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3334
import com.itextpdf.io.logs.IoLogMessageConstant;
3435
import com.itextpdf.kernel.colors.Color;
3536
import com.itextpdf.kernel.geom.Rectangle;
@@ -251,7 +252,7 @@ protected void applyAcroField(DrawContext drawContext) {
251252
PdfDocument doc = drawContext.getDocument();
252253
Rectangle area = getOccupiedArea().getBBox().clone();
253254
applyMargins(area, false);
254-
final Map<Integer, Object> margins = deleteMargins();
255+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(modelElement);
255256
PdfPage page = doc.getPage(occupiedArea.getPageNumber());
256257

257258
Background background = this.<Background>getProperty(Property.BACKGROUND);
@@ -285,7 +286,7 @@ protected void applyAcroField(DrawContext drawContext) {
285286
// with the same names (and add all the widgets as kids to that merged field), so we can add it anyway.
286287
forms.addField(button, page);
287288

288-
applyProperties(margins);
289+
FormFieldRendererUtil.reapplyProperties(modelElement, properties);
289290
}
290291

291292
/**

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ This file is part of the iText (R) project.
3434
import com.itextpdf.forms.form.renderer.checkboximpl.PdfACheckBoxRenderingStrategy;
3535
import com.itextpdf.forms.form.renderer.checkboximpl.PdfCheckBoxRenderingStrategy;
3636
import com.itextpdf.forms.util.BorderStyleUtil;
37+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3738
import com.itextpdf.kernel.geom.Rectangle;
3839
import com.itextpdf.kernel.pdf.IConformanceLevel;
3940
import com.itextpdf.kernel.pdf.PdfAConformanceLevel;
@@ -192,6 +193,24 @@ protected void adjustFieldLayout(LayoutContext layoutContext) {
192193
// We don't need any layout adjustments
193194
}
194195

196+
/**
197+
* Applies given paddings to the given rectangle.
198+
*
199+
* Checkboxes don't support setting of paddings as they are always centered.
200+
* So that this method returns the rectangle as is.
201+
*
202+
* @param rect a rectangle paddings will be applied on.
203+
* @param paddings the paddings to be applied on the given rectangle
204+
* @param reverse indicates whether paddings will be applied
205+
* inside (in case of false) or outside (in case of true) the rectangle.
206+
*
207+
* @return The rectangle NOT modified by the paddings.
208+
*/
209+
@Override
210+
protected Rectangle applyPaddings(Rectangle rect, UnitValue[] paddings, boolean reverse) {
211+
return rect;
212+
}
213+
195214
/**
196215
* Creates a flat renderer for the checkbox.
197216
*
@@ -242,7 +261,7 @@ protected void applyAcroField(DrawContext drawContext) {
242261
final PdfDocument doc = drawContext.getDocument();
243262
final Rectangle area = flatRenderer.getOccupiedArea().getBBox().clone();
244263

245-
final Map<Integer, Object> margins = deleteMargins();
264+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
246265
final PdfPage page = doc.getPage(occupiedArea.getPageNumber());
247266
final CheckBoxFormFieldBuilder builder = new CheckBoxFormFieldBuilder(doc, name).setWidgetRectangle(area)
248267
.setGenericConformanceLevel(this.<IConformanceLevel>getProperty(FormProperty.FORM_CONFORMANCE_LEVEL));
@@ -267,7 +286,7 @@ protected void applyAcroField(DrawContext drawContext) {
267286
checkBox.enableFieldRegeneration();
268287

269288
PdfFormCreator.getAcroForm(doc, true).addField(checkBox, page);
270-
applyProperties(margins);
289+
FormFieldRendererUtil.reapplyProperties(modelElement, properties);
271290
}
272291

273292
/**

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This file is part of the iText (R) project.
2929
import com.itextpdf.forms.form.FormProperty;
3030
import com.itextpdf.forms.form.element.InputField;
3131
import com.itextpdf.forms.logs.FormsLogMessageConstants;
32+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3233
import com.itextpdf.io.logs.IoLogMessageConstant;
3334
import com.itextpdf.kernel.geom.Rectangle;
3435
import com.itextpdf.kernel.pdf.PdfDocument;
@@ -163,7 +164,7 @@ protected void applyAcroField(DrawContext drawContext) {
163164
final PdfDocument doc = drawContext.getDocument();
164165
final Rectangle area = this.getOccupiedArea().getBBox().clone();
165166
applyMargins(area, false);
166-
final Map<Integer, Object> margins = deleteMargins();
167+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
167168
final PdfPage page = doc.getPage(occupiedArea.getPageNumber());
168169
final float fontSizeValue = fontSize.getValue();
169170

@@ -197,7 +198,7 @@ protected void applyAcroField(DrawContext drawContext) {
197198
inputField.enableFieldRegeneration();
198199
PdfFormCreator.getAcroForm(doc, true).addField(inputField, page);
199200

200-
applyProperties(margins);
201+
FormFieldRendererUtil.reapplyProperties(modelElement, properties);
201202
}
202203

203204
/**

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This file is part of the iText (R) project.
3232
import com.itextpdf.forms.form.element.Radio;
3333
import com.itextpdf.forms.util.BorderStyleUtil;
3434
import com.itextpdf.forms.util.DrawingUtil;
35+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3536
import com.itextpdf.kernel.colors.Color;
3637
import com.itextpdf.kernel.colors.ColorConstants;
3738
import com.itextpdf.kernel.exceptions.PdfException;
@@ -173,7 +174,7 @@ protected void applyAcroField(DrawContext drawContext) {
173174
PdfDocument doc = drawContext.getDocument();
174175
PdfAcroForm form = PdfFormCreator.getAcroForm(doc, true);
175176
Rectangle area = flatRenderer.getOccupiedArea().getBBox().clone();
176-
final Map<Integer, Object> margins = deleteMargins();
177+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
177178

178179
PdfPage page = doc.getPage(occupiedArea.getPageNumber());
179180
String groupName = this.<String>getProperty(FormProperty.FORM_FIELD_RADIO_GROUP_NAME);
@@ -212,7 +213,7 @@ protected void applyAcroField(DrawContext drawContext) {
212213

213214
applyAccessibilityProperties(radioGroup, doc);
214215
form.addField(radioGroup, page);
215-
applyProperties(margins);
216+
FormFieldRendererUtil.reapplyProperties(this.modelElement, properties);
216217
}
217218

218219
/**

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ This file is part of the iText (R) project.
3131
import com.itextpdf.forms.form.element.ComboBoxField;
3232
import com.itextpdf.forms.form.element.SelectFieldItem;
3333
import com.itextpdf.forms.util.BorderStyleUtil;
34+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3435
import com.itextpdf.io.logs.IoLogMessageConstant;
3536
import com.itextpdf.kernel.font.PdfFont;
3637
import com.itextpdf.kernel.geom.Rectangle;
@@ -56,6 +57,7 @@ This file is part of the iText (R) project.
5657

5758
import java.util.ArrayList;
5859
import java.util.List;
60+
import java.util.Map;
5961
import org.slf4j.Logger;
6062
import org.slf4j.LoggerFactory;
6163

@@ -117,6 +119,9 @@ protected void applyAcroField(DrawContext drawContext) {
117119
.setFont(font)
118120
.setGenericConformanceLevel(getGenericConformanceLevel(doc));
119121

122+
applyMargins(area, false);
123+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
124+
120125
modelElement.setProperty(Property.FONT_PROVIDER, this.<FontProvider>getProperty(Property.FONT_PROVIDER));
121126
modelElement.setProperty(Property.RENDERING_MODE, this.<RenderingMode>getProperty(Property.RENDERING_MODE));
122127
setupBuilderValues(builder, comboBoxFieldModelElement);
@@ -154,6 +159,7 @@ protected void applyAcroField(DrawContext drawContext) {
154159
comboBoxField.enableFieldRegeneration();
155160

156161
PdfFormCreator.getAcroForm(doc, true).addField(comboBoxField, page);
162+
FormFieldRendererUtil.reapplyProperties(this.modelElement, properties);
157163
}
158164

159165

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ This file is part of the iText (R) project.
3030
import com.itextpdf.forms.form.element.AbstractSelectField;
3131
import com.itextpdf.forms.form.element.ListBoxField;
3232
import com.itextpdf.forms.util.BorderStyleUtil;
33+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3334
import com.itextpdf.io.logs.IoLogMessageConstant;
3435
import com.itextpdf.kernel.colors.ColorConstants;
3536
import com.itextpdf.kernel.colors.DeviceRgb;
@@ -57,6 +58,7 @@ This file is part of the iText (R) project.
5758

5859
import java.util.ArrayList;
5960
import java.util.List;
61+
import java.util.Map;
6062
import org.slf4j.Logger;
6163
import org.slf4j.LoggerFactory;
6264

@@ -193,6 +195,8 @@ protected void applyAcroField(DrawContext drawContext) {
193195
final Rectangle area = this.getOccupiedArea().getBBox().clone();
194196
final PdfPage page = doc.getPage(occupiedArea.getPageNumber());
195197

198+
applyMargins(area, false);
199+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
196200
// Some properties are set to the HtmlDocumentRenderer, which is root renderer for this ButtonRenderer, but
197201
// in forms logic root renderer is CanvasRenderer, and these properties will have default values. So
198202
// we get them from renderer and set these properties to model element, which will be passed to forms logic.
@@ -229,6 +233,7 @@ protected void applyAcroField(DrawContext drawContext) {
229233
choiceField.getFirstFormAnnotation().setFormFieldElement(lbModelElement);
230234
choiceField.enableFieldRegeneration();
231235
PdfFormCreator.getAcroForm(doc, true).addField(choiceField, page);
236+
FormFieldRendererUtil.reapplyProperties(this.modelElement, properties);
232237

233238
}
234239

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ This file is part of the iText (R) project.
2929
import com.itextpdf.forms.fields.PdfSignatureFormField;
3030
import com.itextpdf.forms.fields.SignatureFormFieldBuilder;
3131
import com.itextpdf.forms.form.element.SignatureFieldAppearance;
32+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3233
import com.itextpdf.io.logs.IoLogMessageConstant;
3334
import com.itextpdf.kernel.colors.Color;
3435
import com.itextpdf.kernel.geom.Rectangle;
@@ -53,6 +54,7 @@ This file is part of the iText (R) project.
5354
import com.itextpdf.layout.renderer.ParagraphRenderer;
5455

5556
import java.util.List;
57+
import java.util.Map;
5658
import org.slf4j.Logger;
5759
import org.slf4j.LoggerFactory;
5860

@@ -128,6 +130,8 @@ protected void adjustFieldLayout(LayoutContext layoutContext) {
128130
Rectangle bBox = getOccupiedArea().getBBox().clone();
129131
applyPaddings(bBox, false);
130132
applyBorderBox(bBox, false);
133+
applyMargins(bBox, false);
134+
131135
if (bBox.getY() < 0) {
132136
bBox.setHeight(bBox.getY() + bBox.getHeight());
133137
bBox.setY(0);
@@ -194,7 +198,6 @@ protected void adjustFieldLayout(LayoutContext layoutContext) {
194198
default:
195199
return;
196200
}
197-
198201
adjustChildrenLayout(renderingMode, signatureRect, descriptionRect, layoutContext.getArea().getPageNumber());
199202
}
200203

@@ -236,7 +239,7 @@ protected void applyAcroField(DrawContext drawContext) {
236239
PdfDocument doc = drawContext.getDocument();
237240
Rectangle area = getOccupiedArea().getBBox().clone();
238241
applyMargins(area, false);
239-
deleteMargins();
242+
Map<Integer,Object> properties = FormFieldRendererUtil.removeProperties(this.modelElement);
240243
PdfPage page = doc.getPage(occupiedArea.getPageNumber());
241244

242245
Background background = this.<Background>getProperty(Property.BACKGROUND);
@@ -266,6 +269,7 @@ protected void applyAcroField(DrawContext drawContext) {
266269
sigField.enableFieldRegeneration();
267270
PdfAcroForm forms = PdfFormCreator.getAcroForm(doc, true);
268271
forms.addField(sigField, page);
272+
FormFieldRendererUtil.reapplyProperties(modelElement, properties);
269273

270274
}
271275

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ This file is part of the iText (R) project.
3030
import com.itextpdf.forms.form.FormProperty;
3131
import com.itextpdf.forms.form.element.TextArea;
3232
import com.itextpdf.forms.logs.FormsLogMessageConstants;
33+
import com.itextpdf.forms.util.FormFieldRendererUtil;
3334
import com.itextpdf.io.logs.IoLogMessageConstant;
3435
import com.itextpdf.kernel.geom.Rectangle;
3536
import com.itextpdf.kernel.pdf.PdfDocument;
@@ -193,7 +194,7 @@ protected void applyAcroField(DrawContext drawContext) {
193194
PdfDocument doc = drawContext.getDocument();
194195
Rectangle area = getOccupiedArea().getBBox().clone();
195196
applyMargins(area, false);
196-
final Map<Integer, Object> margins = deleteMargins();
197+
final Map<Integer, Object> properties = FormFieldRendererUtil.removeProperties(modelElement);
197198
PdfPage page = doc.getPage(occupiedArea.getPageNumber());
198199
final float fontSizeValue = fontSize.getValue();
199200
final PdfString defaultValue = new PdfString(getDefaultValue());
@@ -215,7 +216,7 @@ protected void applyAcroField(DrawContext drawContext) {
215216
applyAccessibilityProperties(inputField, doc);
216217
PdfFormCreator.getAcroForm(doc, true).addField(inputField, page);
217218

218-
applyProperties(margins);
219+
FormFieldRendererUtil.reapplyProperties(modelElement, properties);
219220
}
220221

221222
/**
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.itextpdf.forms.util;
2+
3+
import com.itextpdf.layout.IPropertyContainer;
4+
import com.itextpdf.layout.properties.Property;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Map.Entry;
9+
10+
/**
11+
* Utility class for centralized logic related to form field rendering.
12+
*/
13+
public final class FormFieldRendererUtil {
14+
15+
//These properties are related to the outer box of the element.
16+
private static final int[] PROPERTIES_THAT_IMPACT_LAYOUT = new int[] {
17+
Property.MARGIN_TOP, Property.MARGIN_BOTTOM, Property.MARGIN_LEFT, Property.MARGIN_RIGHT,
18+
Property.WIDTH, Property.BOTTOM, Property.LEFT, Property.POSITION
19+
};
20+
21+
/**
22+
* Creates a new instance of {@link FormFieldRendererUtil}.
23+
*/
24+
private FormFieldRendererUtil() {
25+
// empty constructor
26+
}
27+
28+
/**
29+
* Removes properties that impact the lay outing of interactive form fields.
30+
*
31+
* @param modelElement The model element to remove the properties from.
32+
*
33+
* @return A map containing the removed properties.
34+
*/
35+
public static Map<Integer, Object> removeProperties(IPropertyContainer modelElement) {
36+
final Map<Integer, Object> properties = new HashMap<>(PROPERTIES_THAT_IMPACT_LAYOUT.length);
37+
for (int i : PROPERTIES_THAT_IMPACT_LAYOUT) {
38+
properties.put(i, modelElement.<Object>getOwnProperty(i));
39+
modelElement.deleteOwnProperty(i);
40+
}
41+
42+
return properties;
43+
}
44+
45+
/**
46+
* Reapplies the properties {@link IPropertyContainer}.
47+
*
48+
* @param modelElement The model element to reapply the properties to.
49+
* @param properties The properties to reapply.
50+
*/
51+
public static void reapplyProperties(IPropertyContainer modelElement, Map<Integer, Object> properties) {
52+
for (Entry<Integer, Object> integerObjectEntry : properties.entrySet()) {
53+
if (integerObjectEntry.getValue() != null) {
54+
modelElement.setProperty(integerObjectEntry.getKey(), integerObjectEntry.getValue());
55+
} else {
56+
modelElement.deleteOwnProperty(integerObjectEntry.getKey());
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)