@@ -68,7 +68,6 @@ This file is part of the iText (R) project.
6868import com .itextpdf .layout .Style ;
6969import com .itextpdf .layout .borders .Border ;
7070import com .itextpdf .layout .borders .SolidBorder ;
71- import com .itextpdf .layout .element .Div ;
7271import com .itextpdf .layout .element .Image ;
7372import com .itextpdf .layout .element .Paragraph ;
7473import com .itextpdf .layout .element .Text ;
@@ -84,7 +83,6 @@ This file is part of the iText (R) project.
8483import com .itextpdf .layout .renderer .MetaInfoContainer ;
8584
8685import java .util .LinkedHashSet ;
87- import java .util .List ;
8886import java .util .Set ;
8987import org .slf4j .Logger ;
9088import 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