@@ -28,7 +28,11 @@ This file is part of the iText (R) project.
2828import com .itextpdf .forms .fields .properties .CheckBoxType ;
2929import com .itextpdf .forms .form .FormProperty ;
3030import com .itextpdf .forms .form .element .CheckBox ;
31+ import com .itextpdf .forms .form .element .FormField ;
32+ import com .itextpdf .forms .form .element .IFormField ;
33+ import com .itextpdf .forms .form .element .InputField ;
3134import com .itextpdf .forms .form .element .Radio ;
35+ import com .itextpdf .forms .form .element .TextArea ;
3236import com .itextpdf .forms .logs .FormsLogMessageConstants ;
3337import com .itextpdf .forms .util .DrawingUtil ;
3438import com .itextpdf .forms .util .FontSizeUtil ;
@@ -66,6 +70,7 @@ This file is part of the iText (R) project.
6670import com .itextpdf .layout .element .Div ;
6771import com .itextpdf .layout .element .Paragraph ;
6872import com .itextpdf .layout .element .Text ;
73+ import com .itextpdf .layout .properties .Background ;
6974import com .itextpdf .layout .properties .BoxSizingPropertyValue ;
7075import com .itextpdf .layout .properties .Leading ;
7176import com .itextpdf .layout .properties .OverflowPropertyValue ;
@@ -114,7 +119,6 @@ public class PdfFormAnnotation extends AbstractPdfFormField {
114119 protected float borderWidth = 1 ;
115120 protected Color backgroundColor ;
116121 protected Color borderColor ;
117- protected int rotation = 0 ;
118122
119123 /**
120124 * Creates a form field annotation as a wrapper of a {@link PdfWidgetAnnotation}.
@@ -205,20 +209,22 @@ public PdfFormAnnotation setRotation(int degRotation) {
205209 if (degRotation < 0 ) {
206210 degRotation += 360 ;
207211 }
208-
209- this .rotation = degRotation ;
210212 }
211213 PdfDictionary mk = getWidget ().getAppearanceCharacteristics ();
212214 if (mk == null ) {
213215 mk = new PdfDictionary ();
214216 this .put (PdfName .MK , mk );
215217 }
216218 mk .put (PdfName .R , new PdfNumber (degRotation ));
217-
218- this .rotation = degRotation ;
219+
219220 regenerateField ();
220221 return this ;
221222 }
223+
224+ public int getRotation () {
225+ PdfDictionary mk = getWidget ().getAppearanceCharacteristics ();
226+ return mk == null || mk .getAsInt (PdfName .R ) == null ? 0 : (int ) mk .getAsInt (PdfName .R );
227+ }
222228
223229 /**
224230 * Sets the action on {@link PdfWidgetAnnotation widget} of this annotation form field.
@@ -291,6 +297,21 @@ public float getBorderWidth() {
291297 return borderWidth ;
292298 }
293299
300+ /**
301+ * Get border object specified in the widget annotation dictionary.
302+ *
303+ * @return {@link Border} specified in the widget annotation dictionary
304+ */
305+ public Border getBorder () {
306+ float borderWidth = getBorderWidth ();
307+ Border border = FormBorderFactory .getBorder (
308+ this .getWidget ().getBorderStyle (), borderWidth , borderColor , backgroundColor );
309+ if (border == null && borderWidth > 0 && borderColor != null ) {
310+ border = new SolidBorder (borderColor , Math .max (1 , borderWidth ));
311+ }
312+ return border ;
313+ }
314+
294315 /**
295316 * Sets the border width for the field.
296317 *
@@ -299,13 +320,15 @@ public float getBorderWidth() {
299320 * @return The edited {@link PdfFormAnnotation}.
300321 */
301322 public PdfFormAnnotation setBorderWidth (float borderWidth ) {
323+ // Acrobat doesn't support float border width therefore we round it.
324+ int roundedBorderWidth = (int ) Math .round (borderWidth );
302325 PdfDictionary bs = getWidget ().getBorderStyle ();
303326 if (bs == null ) {
304327 bs = new PdfDictionary ();
305328 put (PdfName .BS , bs );
306329 }
307- bs .put (PdfName .W , new PdfNumber (borderWidth ));
308- this .borderWidth = borderWidth ;
330+ bs .put (PdfName .W , new PdfNumber (roundedBorderWidth ));
331+ this .borderWidth = roundedBorderWidth ;
309332
310333 regenerateField ();
311334 return this ;
@@ -497,7 +520,8 @@ protected void drawTextAppearance(Rectangle rect, PdfFont font, float fontSize,
497520 saveState ().
498521 endPath ();
499522
500- TextAlignment textAlignment = parent .convertJustificationToTextAlignment ();
523+ TextAlignment textAlignment =
524+ parent .getJustification () == null ? TextAlignment .LEFT : parent .getJustification ();
501525 float x = 0 ;
502526 if (textAlignment == TextAlignment .RIGHT ) {
503527 x = rect .getWidth ();
@@ -584,7 +608,7 @@ protected void drawMultiLineTextAppearance(Rectangle rect, PdfFont font, String
584608 paragraph .setFontSize (getFontSize ());
585609 }
586610 paragraph .setProperty (Property .FORCED_PLACEMENT , Boolean .TRUE );
587- paragraph .setTextAlignment (parent .convertJustificationToTextAlignment ());
611+ paragraph .setTextAlignment (parent .getJustification ());
588612
589613 if (getColor () != null ) {
590614 paragraph .setFontColor (getColor ());
@@ -891,6 +915,54 @@ protected void drawRadioButtonAndSaveAppearance(String value) {
891915 getWidget ().setNormalAppearance (normalAppearance );
892916 }
893917
918+ /**
919+ * Draws the appearance of a text form field with and saves it into an appearance stream.
920+ */
921+ protected void drawTextFormFieldAndSaveAppearance () {
922+ Rectangle rectangle = getRect (this .getPdfObject ());
923+ if (rectangle == null ) {
924+ return ;
925+ }
926+
927+ IFormField textFormField ;
928+ if (parent .isMultiline ()) {
929+ textFormField = new TextArea (getParentField ().getPartialFieldName ().toUnicodeString ());
930+ textFormField .setProperty (Property .FONT_SIZE , UnitValue .createPointValue (getFontSize ()));
931+ } else {
932+ textFormField = new InputField (getParentField ().getPartialFieldName ().toUnicodeString ());
933+ textFormField .setProperty (Property .FONT_SIZE ,
934+ UnitValue .createPointValue (getFontSize (new PdfArray (rectangle ), parent .getValueAsString ())));
935+ }
936+ textFormField .setProperty (FormProperty .FORM_FIELD_VALUE , parent .getDisplayValue ());
937+ textFormField .setProperty (Property .FONT , getFont ());
938+ textFormField .setProperty (Property .TEXT_ALIGNMENT , parent .getJustification ());
939+ textFormField .setProperty (FormProperty .FORM_FIELD_PASSWORD_FLAG , getParentField ().isPassword ());
940+ textFormField .setProperty (Property .ADD_MARKED_CONTENT_TEXT , true );
941+ if (getColor () != null ) {
942+ textFormField .setProperty (Property .FONT_COLOR , new TransparentColor (getColor ()));
943+ }
944+
945+ textFormField .setProperty (Property .BORDER , getBorder ());
946+
947+ if (backgroundColor != null ) {
948+ textFormField .setProperty (Property .BACKGROUND , new Background (backgroundColor , 1f , 0 , 0 , 0 , 0 ));
949+ }
950+
951+ textFormField .setProperty (Property .WIDTH , UnitValue .createPointValue (rectangle .getWidth ()));
952+ textFormField .setProperty (Property .HEIGHT , UnitValue .createPointValue (rectangle .getHeight ()));
953+ // Always flatten
954+ textFormField .setProperty (FormProperty .FORM_FIELD_FLATTEN , true );
955+
956+ PdfFormXObject xObject = new PdfFormXObject (
957+ new Rectangle (0 , 0 , rectangle .getWidth (), rectangle .getHeight ()));
958+ applyRotation (xObject , rectangle .getWidth (), rectangle .getHeight ());
959+ Canvas canvas = new Canvas (xObject , this .getDocument ());
960+ canvas .setProperty (Property .APPEARANCE_STREAM_LAYOUT , Boolean .TRUE );
961+ canvas .add (textFormField );
962+
963+ getWidget ().setNormalAppearance (xObject .getPdfObject ());
964+ }
965+
894966 @ Override
895967 void retrieveStyles () {
896968 super .retrieveStyles ();
@@ -951,7 +1023,7 @@ void drawChoiceAppearance(Rectangle rect, float fontSize, String value, PdfFormX
9511023 Paragraph paragraph = new Paragraph (strings .get (index )).setFont (getFont ())
9521024 .setFontSize (fontSize ).setMargins (0 , 0 , 0 , 0 ).setMultipliedLeading (1 );
9531025 paragraph .setProperty (Property .FORCED_PLACEMENT , Boolean .TRUE );
954- paragraph .setTextAlignment (parent .convertJustificationToTextAlignment ());
1026+ paragraph .setTextAlignment (parent .getJustification ());
9551027
9561028 if (getColor () != null ) {
9571029 paragraph .setFontColor (getColor ());
@@ -1190,7 +1262,10 @@ boolean regenerateWidget() {
11901262 }
11911263 final PdfName type = parent .getFormType ();
11921264
1193- if (PdfName .Tx .equals (type ) || PdfName .Ch .equals (type )) {
1265+ if (PdfName .Tx .equals (type ) && ExperimentalFeatures .ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING ) {
1266+ drawTextFormFieldAndSaveAppearance ();
1267+ return true ;
1268+ } else if (PdfName .Ch .equals (type ) || PdfName .Tx .equals (type )) {
11941269 return regenerateTextAndChoiceField ();
11951270 } else if (PdfName .Btn .equals (type )) {
11961271 if (parent .getFieldFlag (PdfButtonFormField .FF_PUSH_BUTTON )) {
@@ -1391,7 +1466,7 @@ private static String obfuscatePassword(String text) {
13911466 }
13921467
13931468 private void applyRotation (PdfFormXObject xObject , float height , float width ) {
1394- switch (rotation ) {
1469+ switch (getRotation () ) {
13951470 case 90 :
13961471 xObject .put (PdfName .Matrix , new PdfArray (new float [] {0 , 1 , -1 , 0 , height , 0 }));
13971472 break ;
0 commit comments