Skip to content

Commit d1345ff

Browse files
author
Eugene Bochilo
committed
Move legacy drawing logic for choices and comb text fields to separate class
DEVSIX-7442
1 parent 0d27ad3 commit d1345ff

File tree

4 files changed

+458
-146
lines changed

4 files changed

+458
-146
lines changed

forms/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
<artifactId>forms</artifactId>
1010
<name>iText - forms</name>
1111
<url>https://itextpdf.com/</url>
12+
13+
<properties>
14+
<sonar.coverage.exclusions>**/forms/fields/TextAndChoiceLegacyDrawer.java</sonar.coverage.exclusions>
15+
<sonar.cpd.exclusions>**/forms/fields/TextAndChoiceLegacyDrawer.java</sonar.cpd.exclusions>
16+
</properties>
17+
1218
<dependencies>
1319
<dependency>
1420
<groupId>com.itextpdf</groupId>

forms/src/main/java/com/itextpdf/forms/fields/ChoiceFormFieldBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,8 @@ private PdfChoiceFormField createChoice(int flags) {
147147
if (annotation != null) {
148148
PdfFormXObject xObject = new PdfFormXObject(
149149
new Rectangle(0, 0, getWidgetRectangle().getWidth(), getWidgetRectangle().getHeight()));
150-
field.getFirstFormAnnotation().drawChoiceAppearance(getWidgetRectangle(), field.fontSize,
151-
optionsArrayString, xObject, 0);
150+
TextAndChoiceLegacyDrawer.drawChoiceAppearance(field.getFirstFormAnnotation(), getWidgetRectangle(),
151+
field.fontSize, optionsArrayString, xObject, 0);
152152
annotation.setNormalAppearance(xObject.getPdfObject());
153153
setPageToField(field);
154154
}

forms/src/main/java/com/itextpdf/forms/fields/PdfFormAnnotation.java

Lines changed: 42 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ This file is part of the iText (R) project.
6868
import com.itextpdf.layout.Style;
6969
import com.itextpdf.layout.borders.Border;
7070
import com.itextpdf.layout.borders.SolidBorder;
71-
import com.itextpdf.layout.element.Div;
7271
import com.itextpdf.layout.element.Image;
7372
import com.itextpdf.layout.element.Paragraph;
7473
import com.itextpdf.layout.element.Text;
@@ -84,7 +83,6 @@ This file is part of the iText (R) project.
8483
import com.itextpdf.layout.renderer.MetaInfoContainer;
8584

8685
import java.util.LinkedHashSet;
87-
import java.util.List;
8886
import java.util.Set;
8987
import org.slf4j.Logger;
9088
import org.slf4j.LoggerFactory;
@@ -117,6 +115,8 @@ public class PdfFormAnnotation extends AbstractPdfFormField {
117115
* Default padding X offset.
118116
*/
119117
static final float X_OFFSET = 2;
118+
119+
private static final Logger LOGGER = LoggerFactory.getLogger(PdfFormAnnotation.class);
120120

121121
protected float borderWidth = 1;
122122
protected Color backgroundColor;
@@ -554,40 +554,10 @@ protected void drawTextAppearance(Rectangle rect, PdfFont font, float fontSize,
554554
Style paragraphStyle = new Style().setFont(font).setFontSize(fontSize);
555555
paragraphStyle.setProperty(Property.LEADING, new Leading(Leading.MULTIPLIED, 1));
556556
paragraphStyle.setFontColor(getColor());
557-
558-
int maxLen = new PdfTextFormField(parent.getPdfObject()).getMaxLen();
559-
// check if /Comb has been set
560-
if (parent.getFieldFlag(PdfTextFormField.FF_COMB) && 0 != maxLen) {
561-
float widthPerCharacter = width / maxLen;
562-
int numberOfCharacters = Math.min(maxLen, value.length());
563-
564-
int start;
565-
switch (textAlignment) {
566-
case RIGHT:
567-
start = (maxLen - numberOfCharacters);
568-
break;
569-
case CENTER:
570-
start = (maxLen - numberOfCharacters) / 2;
571-
break;
572-
default:
573-
start = 0;
574-
}
575-
float startOffset = widthPerCharacter * (start + 0.5f);
576-
for (int i = 0; i < numberOfCharacters; i++) {
577-
modelCanvas.showTextAligned(new Paragraph(value.substring(i, i + 1)).addStyle(paragraphStyle),
578-
startOffset + widthPerCharacter * i, rect.getHeight() / 2, TextAlignment.CENTER,
579-
VerticalAlignment.MIDDLE);
580-
}
581-
} else {
582-
if (parent.getFieldFlag(PdfTextFormField.FF_COMB)) {
583-
Logger logger = LoggerFactory.getLogger(PdfFormAnnotation.class);
584-
logger.error(MessageFormatUtil.format(
585-
IoLogMessageConstant.COMB_FLAG_MAY_BE_SET_ONLY_IF_MAXLEN_IS_PRESENT));
586-
}
587-
modelCanvas.showTextAligned(createParagraphForTextFieldValue(value).addStyle(paragraphStyle)
588-
.setPaddings(0, X_OFFSET, 0, X_OFFSET), x, rect.getHeight() / 2, textAlignment,
589-
VerticalAlignment.MIDDLE);
590-
}
557+
558+
modelCanvas.showTextAligned(createParagraphForTextFieldValue(value).addStyle(paragraphStyle)
559+
.setPaddings(0, X_OFFSET, 0, X_OFFSET), x, rect.getHeight() / 2, textAlignment,
560+
VerticalAlignment.MIDDLE);
591561
canvas.
592562
restoreState().
593563
endVariableText();
@@ -1006,81 +976,6 @@ void retrieveStyles() {
1006976
}
1007977
}
1008978

1009-
/**
1010-
* Draws the visual appearance of Choice box in a form field.
1011-
*
1012-
* @param rect The location on the page for the list field
1013-
* @param value The initial value
1014-
* @param appearance The appearance
1015-
*/
1016-
void drawChoiceAppearance(Rectangle rect, float fontSize, String value, PdfFormXObject appearance, int topIndex) {
1017-
PdfStream stream = (PdfStream) new PdfStream().makeIndirect(getDocument());
1018-
PdfResources resources = appearance.getResources();
1019-
PdfCanvas canvas = new PdfCanvas(stream, resources, getDocument());
1020-
1021-
float width = rect.getWidth();
1022-
float height = rect.getHeight();
1023-
float widthBorder = 6.0f;
1024-
float heightBorder = 2.0f;
1025-
1026-
drawBorder(canvas, appearance, width, height);
1027-
canvas.
1028-
beginVariableText().
1029-
saveState().
1030-
rectangle(3, 3, width - widthBorder, height - heightBorder).
1031-
clip().
1032-
endPath();
1033-
1034-
Canvas modelCanvas = new Canvas(canvas, new Rectangle(3, 0, Math.max(0, width - widthBorder),
1035-
Math.max(0, height - heightBorder)));
1036-
modelCanvas.setProperty(Property.APPEARANCE_STREAM_LAYOUT, Boolean.TRUE);
1037-
1038-
setMetaInfoToCanvas(modelCanvas);
1039-
1040-
Div div = new Div();
1041-
if (parent.getFieldFlag(PdfChoiceFormField.FF_COMBO)) {
1042-
div.setVerticalAlignment(VerticalAlignment.MIDDLE);
1043-
}
1044-
div.setHeight(Math.max(0, height - heightBorder));
1045-
List<String> strings = getFont().splitString(value, fontSize, width - widthBorder);
1046-
for (int index = 0; index < strings.size(); index++) {
1047-
Boolean isFull = modelCanvas.getRenderer().getPropertyAsBoolean(Property.FULL);
1048-
if (Boolean.TRUE.equals(isFull)) {
1049-
break;
1050-
}
1051-
1052-
Paragraph paragraph = new Paragraph(strings.get(index)).setFont(getFont())
1053-
.setFontSize(fontSize).setMargins(0, 0, 0, 0).setMultipliedLeading(1);
1054-
paragraph.setProperty(Property.FORCED_PLACEMENT, Boolean.TRUE);
1055-
paragraph.setTextAlignment(parent.getJustification());
1056-
1057-
if (getColor() != null) {
1058-
paragraph.setFontColor(getColor());
1059-
}
1060-
if (!parent.getFieldFlag(PdfChoiceFormField.FF_COMBO)) {
1061-
PdfArray indices = getParent().getAsArray(PdfName.I);
1062-
if (indices != null && indices.size() > 0) {
1063-
for (PdfObject ind : indices) {
1064-
if (!ind.isNumber()) {
1065-
continue;
1066-
}
1067-
if (((PdfNumber) ind).getValue() == index + topIndex) {
1068-
paragraph.setBackgroundColor(new DeviceRgb(10, 36, 106));
1069-
paragraph.setFontColor(ColorConstants.LIGHT_GRAY);
1070-
}
1071-
}
1072-
}
1073-
}
1074-
div.add(paragraph);
1075-
}
1076-
modelCanvas.add(div);
1077-
canvas.
1078-
restoreState().
1079-
endVariableText();
1080-
1081-
appearance.getPdfObject().setData(stream.getBytes());
1082-
}
1083-
1084979
static void setMetaInfoToCanvas(Canvas canvas) {
1085980
MetaInfoContainer metaInfo = FormsMetaInfoStaticContainer.getMetaInfoForLayout();
1086981
if (metaInfo != null) {
@@ -1162,8 +1057,7 @@ boolean regenerateTextAndChoiceField() {
11621057
bBox = new PdfArray(rect);
11631058
} else {
11641059
//Avoid NPE when handling corrupt pdfs
1165-
Logger logger = LoggerFactory.getLogger(PdfFormAnnotation.class);
1166-
logger.error(FormsLogMessageConstants.INCORRECT_PAGE_ROTATION);
1060+
LOGGER.error(FormsLogMessageConstants.INCORRECT_PAGE_ROTATION);
11671061
matrix = new PdfArray(new double[] {1, 0, 0, 1, 0, 0});
11681062
}
11691063
//Apply field rotation
@@ -1229,19 +1123,6 @@ boolean regenerateTextAndChoiceField() {
12291123
} else {
12301124
drawTextAppearance(bboxRectangle, getFont(), getFontSize(bBox, value), value, appearance);
12311125
}
1232-
} else {
1233-
int topIndex = 0;
1234-
if (!parent.getFieldFlag(PdfChoiceFormField.FF_COMBO)) {
1235-
PdfNumber topIndexNum = this.getParent().getAsNumber(PdfName.TI);
1236-
PdfArray options = parent.getOptions();
1237-
if (null != options) {
1238-
topIndex = null != topIndexNum ? topIndexNum.intValue() : 0;
1239-
PdfArray visibleOptions = topIndex > 0
1240-
? new PdfArray(options.subList(topIndex, options.size())) : (PdfArray) options.clone();
1241-
value = PdfFormField.optionsArrayToString(visibleOptions);
1242-
}
1243-
}
1244-
drawChoiceAppearance(bboxRectangle, getFontSize(bBox, value), value, appearance, topIndex);
12451126
}
12461127
PdfDictionary ap = new PdfDictionary();
12471128
ap.put(PdfName.N, appearance.getPdfObject());
@@ -1257,11 +1138,15 @@ boolean regenerateWidget() {
12571138
}
12581139
final PdfName type = parent.getFormType();
12591140

1260-
if (PdfName.Tx.equals(type) && ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING) {
1261-
drawTextFormFieldAndSaveAppearance();
1262-
return true;
1263-
} else if (PdfName.Ch.equals(type) || PdfName.Tx.equals(type)) {
1264-
return regenerateTextAndChoiceField();
1141+
if (PdfName.Ch.equals(type) || this.isCombTextFormField()) {
1142+
return TextAndChoiceLegacyDrawer.regenerateTextAndChoiceField(this);
1143+
} else if (PdfName.Tx.equals(type)) {
1144+
if (ExperimentalFeatures.ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING) {
1145+
drawTextFormFieldAndSaveAppearance();
1146+
return true;
1147+
} else {
1148+
return regenerateTextAndChoiceField();
1149+
}
12651150
} else if (PdfName.Btn.equals(type)) {
12661151
if (parent.getFieldFlag(PdfButtonFormField.FF_PUSH_BUTTON)) {
12671152
drawPushButtonFieldAndSaveAppearance();
@@ -1350,6 +1235,18 @@ Radio createRadio() {
13501235
return radio;
13511236
}
13521237

1238+
float getFontSize(PdfArray bBox, String value) {
1239+
if (getFontSize() == 0) {
1240+
if (bBox == null || value == null || value.isEmpty()) {
1241+
return DEFAULT_FONT_SIZE;
1242+
} else {
1243+
return FontSizeUtil.approximateFontSizeToFitSingleLine(getFont(), bBox.toRectangle(), value,
1244+
MIN_FONT_SIZE, borderWidth);
1245+
}
1246+
}
1247+
return getFontSize();
1248+
}
1249+
13531250
private static double degreeToRadians(double angle) {
13541251
return Math.PI * angle / 180.0;
13551252
}
@@ -1360,6 +1257,20 @@ private static Paragraph createParagraphForTextFieldValue(String value) {
13601257
return new Paragraph(text);
13611258
}
13621259

1260+
private boolean isCombTextFormField() {
1261+
final PdfName type = parent.getFormType();
1262+
if (PdfName.Tx.equals(type) && parent.getFieldFlag(PdfTextFormField.FF_COMB)) {
1263+
int maxLen = new PdfTextFormField(parent.getPdfObject()).getMaxLen();
1264+
if (maxLen == 0 || parent.isMultiline()) {
1265+
LOGGER.error(
1266+
MessageFormatUtil.format(IoLogMessageConstant.COMB_FLAG_MAY_BE_SET_ONLY_IF_MAXLEN_IS_PRESENT));
1267+
return false;
1268+
}
1269+
return true;
1270+
}
1271+
return false;
1272+
}
1273+
13631274
private String getRadioButtonValue() {
13641275
for (String state : getAppearanceStates()) {
13651276
if (!OFF_STATE_VALUE.equals(state)) {
@@ -1369,19 +1280,6 @@ private String getRadioButtonValue() {
13691280
return null;
13701281
}
13711282

1372-
private float getFontSize(PdfArray bBox, String value) {
1373-
if (getFontSize() == 0) {
1374-
if (bBox == null || value == null || value.isEmpty()) {
1375-
return DEFAULT_FONT_SIZE;
1376-
} else {
1377-
return FontSizeUtil.approximateFontSizeToFitSingleLine(getFont(), bBox.toRectangle(), value,
1378-
MIN_FONT_SIZE, borderWidth);
1379-
}
1380-
}
1381-
return getFontSize();
1382-
}
1383-
1384-
13851283
/**
13861284
* Calculate the necessary height offset after applying field rotation
13871285
* so that the origin of the bounding box is the lower left corner with respect to the field text.

0 commit comments

Comments
 (0)