@@ -958,11 +958,10 @@ class WidgetAnnotation extends Annotation {
958
958
if ( ! annotationStorage || isPassword ) {
959
959
return null ;
960
960
}
961
- let value = annotationStorage [ this . data . id ] || "" ;
961
+ const value = annotationStorage [ this . data . id ] || "" ;
962
962
if ( value === "" ) {
963
963
return null ;
964
964
}
965
- value = escapeString ( value ) ;
966
965
967
966
const defaultPadding = 2 ;
968
967
const hPadding = defaultPadding ;
@@ -982,13 +981,28 @@ class WidgetAnnotation extends Annotation {
982
981
983
982
const vPadding = defaultPadding + Math . abs ( descent ) * fontSize ;
984
983
const defaultAppearance = this . data . defaultAppearance ;
984
+
985
+ if ( this . data . multiLine ) {
986
+ return this . _getMultilineAppearance (
987
+ defaultAppearance ,
988
+ value ,
989
+ font ,
990
+ fontSize ,
991
+ totalWidth ,
992
+ totalHeight ,
993
+ alignment ,
994
+ hPadding ,
995
+ vPadding
996
+ ) ;
997
+ }
998
+
985
999
const alignment = this . data . textAlignment ;
986
1000
if ( alignment === 0 || alignment > 2 ) {
987
1001
// Left alignment: nothing to do
988
1002
return (
989
1003
"/Tx BMC q BT " +
990
1004
defaultAppearance +
991
- ` 1 0 0 1 ${ hPadding } ${ vPadding } Tm (${ value } ) Tj` +
1005
+ ` 1 0 0 1 ${ hPadding } ${ vPadding } Tm (${ escapeString ( value ) } ) Tj` +
992
1006
" ET Q EMC"
993
1007
) ;
994
1008
}
@@ -1076,7 +1090,7 @@ class WidgetAnnotation extends Annotation {
1076
1090
shift = shift . toFixed ( 2 ) ;
1077
1091
vPadding = vPadding . toFixed ( 2 ) ;
1078
1092
1079
- return `${ shift } ${ vPadding } Td (${ text } ) Tj` ;
1093
+ return `${ shift } ${ vPadding } Td (${ escapeString ( text ) } ) Tj` ;
1080
1094
}
1081
1095
}
1082
1096
@@ -1114,6 +1128,97 @@ class TextWidgetAnnotation extends WidgetAnnotation {
1114
1128
! this . hasFieldFlag ( AnnotationFieldFlag . FILESELECT ) &&
1115
1129
this . data . maxLen !== null ;
1116
1130
}
1131
+
1132
+ _getMultilineAppearance (
1133
+ defaultAppearance ,
1134
+ text ,
1135
+ font ,
1136
+ fontSize ,
1137
+ width ,
1138
+ height ,
1139
+ alignment ,
1140
+ hPadding ,
1141
+ vPadding
1142
+ ) {
1143
+ const lines = text . replace ( "\r\n" , "\n" ) . split ( "\n" ) ;
1144
+ const buf = [ ] ;
1145
+ const totalWidth = width - 2 * hPadding ;
1146
+ for ( const line of lines ) {
1147
+ const chunks = this . _splitLine ( line , font , fontSize , totalWidth ) ;
1148
+ for ( const chunk of chunks ) {
1149
+ const padding = buf . length === 0 ? hPadding : 0 ;
1150
+ buf . push (
1151
+ this . _renderText (
1152
+ chunk ,
1153
+ font ,
1154
+ fontSize ,
1155
+ width ,
1156
+ alignment ,
1157
+ padding ,
1158
+ - fontSize // <0 because a line is below the previous one
1159
+ )
1160
+ ) ;
1161
+ }
1162
+ }
1163
+
1164
+ const renderedText = buf . join ( "\n" ) ;
1165
+ return (
1166
+ "/Tx BMC q BT " +
1167
+ defaultAppearance +
1168
+ ` 1 0 0 1 0 ${ height } Tm ${ renderedText } ` +
1169
+ " ET Q EMC"
1170
+ ) ;
1171
+ }
1172
+
1173
+ _splitLine ( line , font , fontSize , width ) {
1174
+ const scale = fontSize / 1000 ;
1175
+ const whitespace = font . charsToGlyphs ( " " , true ) [ 0 ] . width * scale ;
1176
+ const chunks = [ ] ;
1177
+
1178
+ let lastSpacePos = - 1 ,
1179
+ startChunk = 0 ,
1180
+ currentWidth = 0 ;
1181
+
1182
+ for ( let i = 0 , ii = line . length ; i < ii ; i ++ ) {
1183
+ const character = line . charAt ( i ) ;
1184
+ if ( character === " " ) {
1185
+ if ( currentWidth + whitespace > width ) {
1186
+ // We can break here
1187
+ chunks . push ( line . substring ( startChunk , i ) ) ;
1188
+ startChunk = i ;
1189
+ currentWidth = whitespace ;
1190
+ lastSpacePos = - 1 ;
1191
+ } else {
1192
+ currentWidth += whitespace ;
1193
+ lastSpacePos = i ;
1194
+ }
1195
+ } else {
1196
+ const charWidth = font . charsToGlyphs ( character , false ) [ 0 ] . width * scale ;
1197
+ if ( currentWidth + charWidth > width ) {
1198
+ // We must break to the last white position (if available)
1199
+ if ( lastSpacePos !== - 1 ) {
1200
+ chunks . push ( line . substring ( startChunk , lastSpacePos + 1 ) ) ;
1201
+ startChunk = i = lastSpacePos + 1 ;
1202
+ lastSpacePos = - 1 ;
1203
+ currentWidth = 0 ;
1204
+ } else {
1205
+ // Just break in the middle of the word
1206
+ chunks . push ( line . substring ( startChunk , i ) ) ;
1207
+ startChunk = i ;
1208
+ currentWidth = charWidth ;
1209
+ }
1210
+ } else {
1211
+ currentWidth += charWidth ;
1212
+ }
1213
+ }
1214
+ }
1215
+
1216
+ if ( startChunk < line . length ) {
1217
+ chunks . push ( line . substring ( startChunk , line . length ) ) ;
1218
+ }
1219
+
1220
+ return chunks ;
1221
+ }
1117
1222
}
1118
1223
1119
1224
class ButtonWidgetAnnotation extends WidgetAnnotation {
0 commit comments