1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fpdfsdk/cpdfsdk_appstream.h"
8
9 #include <utility>
10
11 #include "constants/form_flags.h"
12 #include "core/fpdfapi/font/cpdf_font.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_document.h"
15 #include "core/fpdfapi/parser/cpdf_name.h"
16 #include "core/fpdfapi/parser/cpdf_number.h"
17 #include "core/fpdfapi/parser/cpdf_reference.h"
18 #include "core/fpdfapi/parser/cpdf_stream.h"
19 #include "core/fpdfapi/parser/cpdf_string.h"
20 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
21 #include "core/fpdfdoc/cba_fontmap.h"
22 #include "core/fpdfdoc/cpdf_formcontrol.h"
23 #include "core/fpdfdoc/cpdf_icon.h"
24 #include "core/fpdfdoc/cpvt_word.h"
25 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
26 #include "fpdfsdk/cpdfsdk_interactiveform.h"
27 #include "fpdfsdk/cpdfsdk_pageview.h"
28 #include "fpdfsdk/cpdfsdk_widget.h"
29 #include "fpdfsdk/pwl/cpwl_edit.h"
30 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
31 #include "fpdfsdk/pwl/cpwl_icon.h"
32 #include "fpdfsdk/pwl/cpwl_wnd.h"
33 #include "third_party/base/ptr_util.h"
34
35 namespace {
36
37 // Checkbox & radiobutton styles.
38 enum class CheckStyle { kCheck = 0, kCircle, kCross, kDiamond, kSquare, kStar };
39
40 // Pushbutton layout styles.
41 enum class ButtonStyle {
42 kLabel = 0,
43 kIcon,
44 kIconTopLabelBottom,
45 kIconBottomLabelTop,
46 kIconLeftLabelRight,
47 kIconRightLabelLeft,
48 kLabelOverIcon
49 };
50
51 const char kAppendRectOperator[] = "re";
52 const char kConcatMatrixOperator[] = "cm";
53 const char kCurveToOperator[] = "c";
54 const char kEndPathNoFillOrStrokeOperator[] = "n";
55 const char kFillOperator[] = "f";
56 const char kFillEvenOddOperator[] = "f*";
57 const char kInvokeNamedXObjectOperator[] = "Do";
58 const char kLineToOperator[] = "l";
59 const char kMarkedSequenceBeginOperator[] = "BMC";
60 const char kMarkedSequenceEndOperator[] = "EMC";
61 const char kMoveTextPositionOperator[] = "Td";
62 const char kMoveToOperator[] = "m";
63 const char kSetCharacterSpacingOperator[] = "Tc";
64 const char kSetCMYKOperator[] = "k";
65 const char kSetCMKYStrokedOperator[] = "K";
66 const char kSetDashOperator[] = "d";
67 const char kSetGrayOperator[] = "g";
68 const char kSetGrayStrokedOperator[] = "G";
69 const char kSetLineCapStyleOperator[] = "J";
70 const char kSetLineJoinStyleOperator[] = "j";
71 const char kSetLineWidthOperator[] = "w";
72 const char kSetNonZeroWindingClipOperator[] = "W";
73 const char kSetRGBOperator[] = "rg";
74 const char kSetRGBStrokedOperator[] = "RG";
75 const char kSetTextFontAndSizeOperator[] = "Tf";
76 const char kShowTextOperator[] = "Tj";
77 const char kStateRestoreOperator[] = "Q";
78 const char kStateSaveOperator[] = "q";
79 const char kStrokeOperator[] = "S";
80 const char kTextBeginOperator[] = "BT";
81 const char kTextEndOperator[] = "ET";
82
83 class AutoClosedCommand {
84 public:
AutoClosedCommand(std::ostringstream * stream,ByteString open,ByteString close)85 AutoClosedCommand(std::ostringstream* stream,
86 ByteString open,
87 ByteString close)
88 : stream_(stream), close_(close) {
89 *stream_ << open << "\n";
90 }
91
~AutoClosedCommand()92 virtual ~AutoClosedCommand() { *stream_ << close_ << "\n"; }
93
94 private:
95 std::ostringstream* stream_;
96 ByteString close_;
97 };
98
99 class AutoClosedQCommand final : public AutoClosedCommand {
100 public:
AutoClosedQCommand(std::ostringstream * stream)101 explicit AutoClosedQCommand(std::ostringstream* stream)
102 : AutoClosedCommand(stream, kStateSaveOperator, kStateRestoreOperator) {}
~AutoClosedQCommand()103 ~AutoClosedQCommand() override {}
104 };
105
GetColorAppStream(const CFX_Color & color,const bool & bFillOrStroke)106 ByteString GetColorAppStream(const CFX_Color& color,
107 const bool& bFillOrStroke) {
108 std::ostringstream sColorStream;
109
110 switch (color.nColorType) {
111 case CFX_Color::kRGB:
112 sColorStream << color.fColor1 << " " << color.fColor2 << " "
113 << color.fColor3 << " "
114 << (bFillOrStroke ? kSetRGBOperator : kSetRGBStrokedOperator)
115 << "\n";
116 break;
117 case CFX_Color::kGray:
118 sColorStream << color.fColor1 << " "
119 << (bFillOrStroke ? kSetGrayOperator
120 : kSetGrayStrokedOperator)
121 << "\n";
122 break;
123 case CFX_Color::kCMYK:
124 sColorStream << color.fColor1 << " " << color.fColor2 << " "
125 << color.fColor3 << " " << color.fColor4 << " "
126 << (bFillOrStroke ? kSetCMYKOperator
127 : kSetCMKYStrokedOperator)
128 << "\n";
129 break;
130 }
131
132 return ByteString(sColorStream);
133 }
134
GetAP_Check(const CFX_FloatRect & crBBox)135 ByteString GetAP_Check(const CFX_FloatRect& crBBox) {
136 const float fWidth = crBBox.Width();
137 const float fHeight = crBBox.Height();
138
139 CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f),
140 CFX_PointF(0.29f, 0.40f)},
141 {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f),
142 CFX_PointF(0.31f, 0.28f)},
143 {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f),
144 CFX_PointF(0.77f, 0.67f)},
145 {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f),
146 CFX_PointF(0.76f, 0.75f)},
147 {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f),
148 CFX_PointF(0.68f, 0.75f)},
149 {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f),
150 CFX_PointF(0.44f, 0.47f)},
151 {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f),
152 CFX_PointF(0.41f, 0.58f)},
153 {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f),
154 CFX_PointF(0.30f, 0.56f)}};
155
156 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
157 for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) {
158 pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
159 pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
160 }
161 }
162
163 std::ostringstream csAP;
164 csAP << pts[0][0].x << " " << pts[0][0].y << " " << kMoveToOperator << "\n";
165
166 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
167 size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
168
169 float px1 = pts[i][1].x - pts[i][0].x;
170 float py1 = pts[i][1].y - pts[i][0].y;
171 float px2 = pts[i][2].x - pts[nNext][0].x;
172 float py2 = pts[i][2].y - pts[nNext][0].y;
173
174 csAP << pts[i][0].x + px1 * FX_BEZIER << " "
175 << pts[i][0].y + py1 * FX_BEZIER << " "
176 << pts[nNext][0].x + px2 * FX_BEZIER << " "
177 << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
178 << pts[nNext][0].y << " " << kCurveToOperator << "\n";
179 }
180
181 return ByteString(csAP);
182 }
183
GetAP_Circle(const CFX_FloatRect & crBBox)184 ByteString GetAP_Circle(const CFX_FloatRect& crBBox) {
185 std::ostringstream csAP;
186
187 float fWidth = crBBox.Width();
188 float fHeight = crBBox.Height();
189
190 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
191 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
192 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
193 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
194
195 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
196
197 float px = pt2.x - pt1.x;
198 float py = pt2.y - pt1.y;
199
200 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
201 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
202 << " " << kCurveToOperator << "\n";
203
204 px = pt3.x - pt2.x;
205 py = pt2.y - pt3.y;
206
207 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
208 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
209 << kCurveToOperator << "\n";
210
211 px = pt3.x - pt4.x;
212 py = pt3.y - pt4.y;
213
214 csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
215 << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
216 << " " << kCurveToOperator << "\n";
217
218 px = pt4.x - pt1.x;
219 py = pt1.y - pt4.y;
220
221 csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
222 << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " "
223 << kCurveToOperator << "\n";
224
225 return ByteString(csAP);
226 }
227
GetAP_Cross(const CFX_FloatRect & crBBox)228 ByteString GetAP_Cross(const CFX_FloatRect& crBBox) {
229 std::ostringstream csAP;
230
231 csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
232 csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
233 << "\n";
234 csAP << crBBox.left << " " << crBBox.bottom << " " << kMoveToOperator << "\n";
235 csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
236
237 return ByteString(csAP);
238 }
239
GetAP_Diamond(const CFX_FloatRect & crBBox)240 ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) {
241 std::ostringstream csAP;
242
243 float fWidth = crBBox.Width();
244 float fHeight = crBBox.Height();
245
246 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
247 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
248 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
249 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
250
251 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
252 csAP << pt2.x << " " << pt2.y << " " << kLineToOperator << "\n";
253 csAP << pt3.x << " " << pt3.y << " " << kLineToOperator << "\n";
254 csAP << pt4.x << " " << pt4.y << " " << kLineToOperator << "\n";
255 csAP << pt1.x << " " << pt1.y << " " << kLineToOperator << "\n";
256
257 return ByteString(csAP);
258 }
259
GetAP_Square(const CFX_FloatRect & crBBox)260 ByteString GetAP_Square(const CFX_FloatRect& crBBox) {
261 std::ostringstream csAP;
262
263 csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
264 csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
265 csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
266 << "\n";
267 csAP << crBBox.left << " " << crBBox.bottom << " " << kLineToOperator << "\n";
268 csAP << crBBox.left << " " << crBBox.top << " " << kLineToOperator << "\n";
269
270 return ByteString(csAP);
271 }
272
GetAP_Star(const CFX_FloatRect & crBBox)273 ByteString GetAP_Star(const CFX_FloatRect& crBBox) {
274 std::ostringstream csAP;
275
276 float fRadius = (crBBox.top - crBBox.bottom) / (1 + (float)cos(FX_PI / 5.0f));
277 CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
278 (crBBox.top + crBBox.bottom) / 2.0f);
279
280 float px[5];
281 float py[5];
282 float fAngel = FX_PI / 10.0f;
283 for (int32_t i = 0; i < 5; i++) {
284 px[i] = ptCenter.x + fRadius * (float)cos(fAngel);
285 py[i] = ptCenter.y + fRadius * (float)sin(fAngel);
286 fAngel += FX_PI * 2 / 5.0f;
287 }
288
289 csAP << px[0] << " " << py[0] << " " << kMoveToOperator << "\n";
290
291 int32_t nNext = 0;
292 for (int32_t j = 0; j < 5; j++) {
293 nNext += 2;
294 if (nNext >= 5)
295 nNext -= 5;
296 csAP << px[nNext] << " " << py[nNext] << " " << kLineToOperator << "\n";
297 }
298
299 return ByteString(csAP);
300 }
301
GetAP_HalfCircle(const CFX_FloatRect & crBBox,float fRotate)302 ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) {
303 std::ostringstream csAP;
304
305 float fWidth = crBBox.Width();
306 float fHeight = crBBox.Height();
307
308 CFX_PointF pt1(-fWidth / 2, 0);
309 CFX_PointF pt2(0, fHeight / 2);
310 CFX_PointF pt3(fWidth / 2, 0);
311
312 float px;
313 float py;
314
315 csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
316 << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
317 << crBBox.bottom + fHeight / 2 << " " << kConcatMatrixOperator << "\n";
318
319 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
320
321 px = pt2.x - pt1.x;
322 py = pt2.y - pt1.y;
323
324 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
325 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
326 << " " << kCurveToOperator << "\n";
327
328 px = pt3.x - pt2.x;
329 py = pt2.y - pt3.y;
330
331 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
332 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
333 << kCurveToOperator << "\n";
334
335 return ByteString(csAP);
336 }
337
GetAppStream_Check(const CFX_FloatRect & rcBBox,const CFX_Color & crText)338 ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
339 const CFX_Color& crText) {
340 std::ostringstream sAP;
341 {
342 AutoClosedQCommand q(&sAP);
343 sAP << GetColorAppStream(crText, true) << GetAP_Check(rcBBox)
344 << kFillOperator << "\n";
345 }
346 return ByteString(sAP);
347 }
348
GetAppStream_Circle(const CFX_FloatRect & rcBBox,const CFX_Color & crText)349 ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
350 const CFX_Color& crText) {
351 std::ostringstream sAP;
352 {
353 AutoClosedQCommand q(&sAP);
354 sAP << GetColorAppStream(crText, true) << GetAP_Circle(rcBBox)
355 << kFillOperator << "\n";
356 }
357 return ByteString(sAP);
358 }
359
GetAppStream_Cross(const CFX_FloatRect & rcBBox,const CFX_Color & crText)360 ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
361 const CFX_Color& crText) {
362 std::ostringstream sAP;
363 {
364 AutoClosedQCommand q(&sAP);
365 sAP << GetColorAppStream(crText, false) << GetAP_Cross(rcBBox)
366 << kStrokeOperator << "\n";
367 }
368 return ByteString(sAP);
369 }
370
GetAppStream_Diamond(const CFX_FloatRect & rcBBox,const CFX_Color & crText)371 ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
372 const CFX_Color& crText) {
373 std::ostringstream sAP;
374 {
375 AutoClosedQCommand q(&sAP);
376 sAP << "1 " << kSetLineWidthOperator << "\n"
377 << GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox)
378 << kFillOperator << "\n";
379 }
380 return ByteString(sAP);
381 }
382
GetAppStream_Square(const CFX_FloatRect & rcBBox,const CFX_Color & crText)383 ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
384 const CFX_Color& crText) {
385 std::ostringstream sAP;
386 {
387 AutoClosedQCommand q(&sAP);
388 sAP << GetColorAppStream(crText, true) << GetAP_Square(rcBBox)
389 << kFillOperator << "\n";
390 }
391 return ByteString(sAP);
392 }
393
GetAppStream_Star(const CFX_FloatRect & rcBBox,const CFX_Color & crText)394 ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
395 const CFX_Color& crText) {
396 std::ostringstream sAP;
397 {
398 AutoClosedQCommand q(&sAP);
399 sAP << GetColorAppStream(crText, true) << GetAP_Star(rcBBox)
400 << kFillOperator << "\n";
401 }
402 return ByteString(sAP);
403 }
404
GetCircleFillAppStream(const CFX_FloatRect & rect,const CFX_Color & color)405 ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
406 const CFX_Color& color) {
407 std::ostringstream sAppStream;
408 ByteString sColor = GetColorAppStream(color, true);
409 if (sColor.GetLength() > 0) {
410 AutoClosedQCommand q(&sAppStream);
411 sAppStream << sColor << GetAP_Circle(rect) << kFillOperator << "\n";
412 }
413 return ByteString(sAppStream);
414 }
415
GetCircleBorderAppStream(const CFX_FloatRect & rect,float fWidth,const CFX_Color & color,const CFX_Color & crLeftTop,const CFX_Color & crRightBottom,BorderStyle nStyle,const CPWL_Dash & dash)416 ByteString GetCircleBorderAppStream(const CFX_FloatRect& rect,
417 float fWidth,
418 const CFX_Color& color,
419 const CFX_Color& crLeftTop,
420 const CFX_Color& crRightBottom,
421 BorderStyle nStyle,
422 const CPWL_Dash& dash) {
423 std::ostringstream sAppStream;
424 ByteString sColor;
425
426 if (fWidth > 0.0f) {
427 AutoClosedQCommand q(&sAppStream);
428
429 float fHalfWidth = fWidth / 2.0f;
430 CFX_FloatRect rect_by_2 = rect.GetDeflated(fHalfWidth, fHalfWidth);
431
432 float div = fHalfWidth * 0.75f;
433 CFX_FloatRect rect_by_75 = rect.GetDeflated(div, div);
434 switch (nStyle) {
435 default:
436 case BorderStyle::SOLID:
437 case BorderStyle::UNDERLINE: {
438 sColor = GetColorAppStream(color, false);
439 if (sColor.GetLength() > 0) {
440 AutoClosedQCommand q2(&sAppStream);
441 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
442 << sColor << GetAP_Circle(rect_by_2) << " "
443 << kStrokeOperator << "\n";
444 }
445 } break;
446 case BorderStyle::DASH: {
447 sColor = GetColorAppStream(color, false);
448 if (sColor.GetLength() > 0) {
449 AutoClosedQCommand q2(&sAppStream);
450 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
451 << "[" << dash.nDash << " " << dash.nGap << "] "
452 << dash.nPhase << " " << kSetDashOperator << "\n"
453 << sColor << GetAP_Circle(rect_by_2) << " "
454 << kStrokeOperator << "\n";
455 }
456 } break;
457 case BorderStyle::BEVELED: {
458 sColor = GetColorAppStream(color, false);
459 if (sColor.GetLength() > 0) {
460 AutoClosedQCommand q2(&sAppStream);
461 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
462 << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
463 << "\n";
464 }
465
466 sColor = GetColorAppStream(crLeftTop, false);
467 if (sColor.GetLength() > 0) {
468 AutoClosedQCommand q2(&sAppStream);
469 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
470 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
471 << " " << kStrokeOperator << "\n";
472 }
473
474 sColor = GetColorAppStream(crRightBottom, false);
475 if (sColor.GetLength() > 0) {
476 AutoClosedQCommand q2(&sAppStream);
477 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
478 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
479 << " " << kStrokeOperator << "\n";
480 }
481 } break;
482 case BorderStyle::INSET: {
483 sColor = GetColorAppStream(color, false);
484 if (sColor.GetLength() > 0) {
485 AutoClosedQCommand q2(&sAppStream);
486 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
487 << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
488 << "\n";
489 }
490
491 sColor = GetColorAppStream(crLeftTop, false);
492 if (sColor.GetLength() > 0) {
493 AutoClosedQCommand q2(&sAppStream);
494 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
495 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
496 << " " << kStrokeOperator << "\n";
497 }
498
499 sColor = GetColorAppStream(crRightBottom, false);
500 if (sColor.GetLength() > 0) {
501 AutoClosedQCommand q2(&sAppStream);
502 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
503 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
504 << " " << kStrokeOperator << "\n";
505 }
506 } break;
507 }
508 }
509 return ByteString(sAppStream);
510 }
511
GetCheckBoxAppStream(const CFX_FloatRect & rcBBox,CheckStyle nStyle,const CFX_Color & crText)512 ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
513 CheckStyle nStyle,
514 const CFX_Color& crText) {
515 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
516 switch (nStyle) {
517 default:
518 case CheckStyle::kCheck:
519 return GetAppStream_Check(rcCenter, crText);
520 case CheckStyle::kCircle:
521 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
522 return GetAppStream_Circle(rcCenter, crText);
523 case CheckStyle::kCross:
524 return GetAppStream_Cross(rcCenter, crText);
525 case CheckStyle::kDiamond:
526 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
527 return GetAppStream_Diamond(rcCenter, crText);
528 case CheckStyle::kSquare:
529 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
530 return GetAppStream_Square(rcCenter, crText);
531 case CheckStyle::kStar:
532 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
533 return GetAppStream_Star(rcCenter, crText);
534 }
535 }
536
GetRadioButtonAppStream(const CFX_FloatRect & rcBBox,CheckStyle nStyle,const CFX_Color & crText)537 ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
538 CheckStyle nStyle,
539 const CFX_Color& crText) {
540 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
541 switch (nStyle) {
542 default:
543 case CheckStyle::kCheck:
544 return GetAppStream_Check(rcCenter, crText);
545 case CheckStyle::kCircle:
546 rcCenter.ScaleFromCenterPoint(1.0f / 2.0f);
547 return GetAppStream_Circle(rcCenter, crText);
548 case CheckStyle::kCross:
549 return GetAppStream_Cross(rcCenter, crText);
550 case CheckStyle::kDiamond:
551 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
552 return GetAppStream_Diamond(rcCenter, crText);
553 case CheckStyle::kSquare:
554 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
555 return GetAppStream_Square(rcCenter, crText);
556 case CheckStyle::kStar:
557 rcCenter.ScaleFromCenterPoint(2.0f / 3.0f);
558 return GetAppStream_Star(rcCenter, crText);
559 }
560 }
561
GetFontSetString(IPVT_FontMap * pFontMap,int32_t nFontIndex,float fFontSize)562 ByteString GetFontSetString(IPVT_FontMap* pFontMap,
563 int32_t nFontIndex,
564 float fFontSize) {
565 if (!pFontMap)
566 return ByteString();
567
568 ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
569 if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
570 return ByteString();
571
572 std::ostringstream sRet;
573 sRet << "/" << sFontAlias << " " << fFontSize << " "
574 << kSetTextFontAndSizeOperator << "\n";
575 return ByteString(sRet);
576 }
577
GetWordRenderString(const ByteString & strWords)578 ByteString GetWordRenderString(const ByteString& strWords) {
579 if (strWords.GetLength() > 0) {
580 return PDF_EncodeString(strWords, false) + " " + kShowTextOperator + "\n";
581 }
582 return ByteString();
583 }
584
GetEditAppStream(CPWL_EditImpl * pEdit,const CFX_PointF & ptOffset,bool bContinuous,uint16_t SubWord)585 ByteString GetEditAppStream(CPWL_EditImpl* pEdit,
586 const CFX_PointF& ptOffset,
587 bool bContinuous,
588 uint16_t SubWord) {
589 CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
590 pIterator->SetAt(0);
591
592 std::ostringstream sEditStream;
593 std::ostringstream sWords;
594 int32_t nCurFontIndex = -1;
595 CFX_PointF ptOld;
596 CFX_PointF ptNew;
597 CPVT_WordPlace oldplace;
598
599 while (pIterator->NextWord()) {
600 CPVT_WordPlace place = pIterator->GetAt();
601 if (bContinuous) {
602 if (place.LineCmp(oldplace) != 0) {
603 if (sWords.tellp() > 0) {
604 sEditStream << GetWordRenderString(ByteString(sWords));
605 sWords.str("");
606 }
607
608 CPVT_Word word;
609 if (pIterator->GetWord(word)) {
610 ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
611 word.ptWord.y + ptOffset.y);
612 } else {
613 CPVT_Line line;
614 pIterator->GetLine(line);
615 ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
616 line.ptLine.y + ptOffset.y);
617 }
618
619 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
620 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
621 << kMoveTextPositionOperator << "\n";
622
623 ptOld = ptNew;
624 }
625 }
626
627 CPVT_Word word;
628 if (pIterator->GetWord(word)) {
629 if (word.nFontIndex != nCurFontIndex) {
630 if (sWords.tellp() > 0) {
631 sEditStream << GetWordRenderString(ByteString(sWords));
632 sWords.str("");
633 }
634 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
635 word.fFontSize);
636 nCurFontIndex = word.nFontIndex;
637 }
638
639 sWords << pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord);
640 }
641
642 oldplace = place;
643 } else {
644 CPVT_Word word;
645 if (pIterator->GetWord(word)) {
646 ptNew =
647 CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
648
649 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
650 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
651 << kMoveTextPositionOperator << "\n";
652 ptOld = ptNew;
653 }
654
655 if (word.nFontIndex != nCurFontIndex) {
656 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
657 word.fFontSize);
658 nCurFontIndex = word.nFontIndex;
659 }
660
661 sEditStream << GetWordRenderString(
662 pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord));
663 }
664 }
665 }
666
667 if (sWords.tellp() > 0) {
668 sEditStream << GetWordRenderString(ByteString(sWords));
669 sWords.str("");
670 }
671
672 std::ostringstream sAppStream;
673 if (sEditStream.tellp() > 0) {
674 float fCharSpace = pEdit->GetCharSpace();
675 if (!IsFloatZero(fCharSpace))
676 sAppStream << fCharSpace << " " << kSetCharacterSpacingOperator << "\n";
677
678 sAppStream << sEditStream.str();
679 }
680
681 return ByteString(sAppStream);
682 }
683
GenerateIconAppStream(CPDF_IconFit & fit,CPDF_Stream * pIconStream,const CFX_FloatRect & rcIcon)684 ByteString GenerateIconAppStream(CPDF_IconFit& fit,
685 CPDF_Stream* pIconStream,
686 const CFX_FloatRect& rcIcon) {
687 if (rcIcon.IsEmpty() || !pIconStream)
688 return ByteString();
689
690 CPWL_Wnd::CreateParams cp;
691 cp.dwFlags = PWS_VISIBLE;
692
693 CPWL_Icon icon(cp, pdfium::MakeUnique<CPDF_Icon>(pIconStream), &fit);
694 icon.Realize();
695 if (!icon.Move(rcIcon, false, false))
696 return ByteString();
697
698 ByteString sAlias = icon.GetImageAlias();
699 if (sAlias.GetLength() <= 0)
700 return ByteString();
701
702 CFX_FloatRect rcPlate = icon.GetClientRect();
703 CFX_Matrix mt = icon.GetImageMatrix().GetInverse();
704
705 float fHScale;
706 float fVScale;
707 std::tie(fHScale, fVScale) = icon.GetScale();
708
709 float fx;
710 float fy;
711 std::tie(fx, fy) = icon.GetImageOffset();
712
713 std::ostringstream str;
714 {
715 AutoClosedQCommand q(&str);
716 str << rcPlate.left << " " << rcPlate.bottom << " "
717 << rcPlate.right - rcPlate.left << " " << rcPlate.top - rcPlate.bottom
718 << " " << kAppendRectOperator << " " << kSetNonZeroWindingClipOperator
719 << " " << kEndPathNoFillOrStrokeOperator << "\n";
720
721 str << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx << " "
722 << rcPlate.bottom + fy << " " << kConcatMatrixOperator << "\n";
723 str << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " " << mt.e
724 << " " << mt.f << " " << kConcatMatrixOperator << "\n";
725
726 str << "0 " << kSetGrayOperator << " 0 " << kSetGrayStrokedOperator << " 1 "
727 << kSetLineWidthOperator << " /" << sAlias << " "
728 << kInvokeNamedXObjectOperator << "\n";
729 }
730 icon.Destroy();
731
732 return ByteString(str);
733 }
734
GetPushButtonAppStream(const CFX_FloatRect & rcBBox,IPVT_FontMap * pFontMap,CPDF_Stream * pIconStream,CPDF_IconFit & IconFit,const WideString & sLabel,const CFX_Color & crText,float fFontSize,ButtonStyle nLayOut)735 ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
736 IPVT_FontMap* pFontMap,
737 CPDF_Stream* pIconStream,
738 CPDF_IconFit& IconFit,
739 const WideString& sLabel,
740 const CFX_Color& crText,
741 float fFontSize,
742 ButtonStyle nLayOut) {
743 const float fAutoFontScale = 1.0f / 3.0f;
744
745 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
746 pEdit->SetFontMap(pFontMap);
747 pEdit->SetAlignmentH(1, true);
748 pEdit->SetAlignmentV(1, true);
749 pEdit->SetMultiLine(false, true);
750 pEdit->SetAutoReturn(false, true);
751 if (IsFloatZero(fFontSize))
752 pEdit->SetAutoFontSize(true, true);
753 else
754 pEdit->SetFontSize(fFontSize);
755
756 pEdit->Initialize();
757 pEdit->SetText(sLabel);
758
759 CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
760 CFX_FloatRect rcLabel;
761 CFX_FloatRect rcIcon;
762 float fWidth = 0.0f;
763 float fHeight = 0.0f;
764
765 switch (nLayOut) {
766 case ButtonStyle::kLabel:
767 rcLabel = rcBBox;
768 break;
769 case ButtonStyle::kIcon:
770 rcIcon = rcBBox;
771 break;
772 case ButtonStyle::kIconTopLabelBottom:
773 if (pIconStream) {
774 if (IsFloatZero(fFontSize)) {
775 fHeight = rcBBox.Height();
776 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
777 rcBBox.bottom + fHeight * fAutoFontScale);
778 rcIcon =
779 CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
780 } else {
781 fHeight = rcLabelContent.Height();
782
783 if (rcBBox.bottom + fHeight > rcBBox.top) {
784 rcLabel = rcBBox;
785 } else {
786 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
787 rcBBox.bottom + fHeight);
788 rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
789 rcBBox.top);
790 }
791 }
792 } else {
793 rcLabel = rcBBox;
794 }
795 break;
796 case ButtonStyle::kIconBottomLabelTop:
797 if (pIconStream) {
798 if (IsFloatZero(fFontSize)) {
799 fHeight = rcBBox.Height();
800 rcLabel =
801 CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
802 rcBBox.right, rcBBox.top);
803 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
804 rcLabel.bottom);
805 } else {
806 fHeight = rcLabelContent.Height();
807
808 if (rcBBox.bottom + fHeight > rcBBox.top) {
809 rcLabel = rcBBox;
810 } else {
811 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
812 rcBBox.right, rcBBox.top);
813 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
814 rcLabel.bottom);
815 }
816 }
817 } else {
818 rcLabel = rcBBox;
819 }
820 break;
821 case ButtonStyle::kIconLeftLabelRight:
822 if (pIconStream) {
823 if (IsFloatZero(fFontSize)) {
824 fWidth = rcBBox.right - rcBBox.left;
825 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
826 rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
827 rcBBox.bottom, rcBBox.right, rcBBox.top);
828 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
829 rcBBox.top);
830 } else {
831 if (rcLabelContent.Width() < fWidth) {
832 rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
833 rcBBox.bottom, rcBBox.right, rcBBox.top);
834 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
835 rcBBox.top);
836 } else {
837 rcLabel = rcBBox;
838 }
839 }
840 } else {
841 fWidth = rcLabelContent.Width();
842 if (rcBBox.left + fWidth > rcBBox.right) {
843 rcLabel = rcBBox;
844 } else {
845 rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
846 rcBBox.right, rcBBox.top);
847 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
848 rcBBox.top);
849 }
850 }
851 } else {
852 rcLabel = rcBBox;
853 }
854 break;
855 case ButtonStyle::kIconRightLabelLeft:
856 if (pIconStream) {
857 if (IsFloatZero(fFontSize)) {
858 fWidth = rcBBox.right - rcBBox.left;
859 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
860 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
861 rcBBox.left + fWidth * fAutoFontScale,
862 rcBBox.top);
863 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
864 rcBBox.top);
865 } else {
866 if (rcLabelContent.Width() < fWidth) {
867 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
868 rcBBox.left + rcLabelContent.Width(),
869 rcBBox.top);
870 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
871 rcBBox.top);
872 } else {
873 rcLabel = rcBBox;
874 }
875 }
876 } else {
877 fWidth = rcLabelContent.Width();
878 if (rcBBox.left + fWidth > rcBBox.right) {
879 rcLabel = rcBBox;
880 } else {
881 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
882 rcBBox.left + fWidth, rcBBox.top);
883 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
884 rcBBox.top);
885 }
886 }
887 } else {
888 rcLabel = rcBBox;
889 }
890 break;
891 case ButtonStyle::kLabelOverIcon:
892 rcLabel = rcBBox;
893 rcIcon = rcBBox;
894 break;
895 }
896
897 std::ostringstream sTemp;
898 sTemp << GenerateIconAppStream(IconFit, pIconStream, rcIcon);
899
900 if (!rcLabel.IsEmpty()) {
901 pEdit->SetPlateRect(rcLabel);
902 ByteString sEdit =
903 GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f), true, 0);
904 if (sEdit.GetLength() > 0) {
905 AutoClosedCommand bt(&sTemp, kTextBeginOperator, kTextEndOperator);
906 sTemp << GetColorAppStream(crText, true) << sEdit;
907 }
908 }
909
910 if (sTemp.tellp() <= 0)
911 return ByteString();
912
913 std::ostringstream sAppStream;
914 {
915 AutoClosedQCommand q(&sAppStream);
916 sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
917 << rcBBox.right - rcBBox.left << " "
918 << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
919 << " " << kSetNonZeroWindingClipOperator << " "
920 << kEndPathNoFillOrStrokeOperator << "\n";
921 sAppStream << sTemp.str().c_str();
922 }
923 return ByteString(sAppStream);
924 }
925
GetBorderAppStreamInternal(const CFX_FloatRect & rect,float fWidth,const CFX_Color & color,const CFX_Color & crLeftTop,const CFX_Color & crRightBottom,BorderStyle nStyle,const CPWL_Dash & dash)926 ByteString GetBorderAppStreamInternal(const CFX_FloatRect& rect,
927 float fWidth,
928 const CFX_Color& color,
929 const CFX_Color& crLeftTop,
930 const CFX_Color& crRightBottom,
931 BorderStyle nStyle,
932 const CPWL_Dash& dash) {
933 std::ostringstream sAppStream;
934 ByteString sColor;
935
936 float fLeft = rect.left;
937 float fRight = rect.right;
938 float fTop = rect.top;
939 float fBottom = rect.bottom;
940
941 if (fWidth > 0.0f) {
942 float fHalfWidth = fWidth / 2.0f;
943 AutoClosedQCommand q(&sAppStream);
944
945 switch (nStyle) {
946 default:
947 case BorderStyle::SOLID:
948 sColor = GetColorAppStream(color, true);
949 if (sColor.GetLength() > 0) {
950 sAppStream << sColor;
951 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
952 << fTop - fBottom << " " << kAppendRectOperator << "\n";
953 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
954 << fRight - fLeft - fWidth * 2 << " "
955 << fTop - fBottom - fWidth * 2 << " "
956 << kAppendRectOperator << "\n";
957 sAppStream << kFillEvenOddOperator << "\n";
958 }
959 break;
960 case BorderStyle::DASH:
961 sColor = GetColorAppStream(color, false);
962 if (sColor.GetLength() > 0) {
963 sAppStream << sColor;
964 sAppStream << fWidth << " " << kSetLineWidthOperator << " ["
965 << dash.nDash << " " << dash.nGap << "] " << dash.nPhase
966 << " " << kSetDashOperator << "\n";
967 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
968 << kMoveToOperator << "\n";
969 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " "
970 << kLineToOperator << "\n";
971 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " "
972 << kLineToOperator << "\n";
973 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
974 << " " << kLineToOperator << "\n";
975 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
976 << kLineToOperator << " " << kStrokeOperator << "\n";
977 }
978 break;
979 case BorderStyle::BEVELED:
980 case BorderStyle::INSET:
981 sColor = GetColorAppStream(crLeftTop, true);
982 if (sColor.GetLength() > 0) {
983 sAppStream << sColor;
984 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
985 << kMoveToOperator << "\n";
986 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " "
987 << kLineToOperator << "\n";
988 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
989 << kLineToOperator << "\n";
990 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
991 << " " << kLineToOperator << "\n";
992 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
993 << " " << kLineToOperator << "\n";
994 sAppStream << fLeft + fHalfWidth * 2 << " "
995 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
996 << " " << kFillOperator << "\n";
997 }
998
999 sColor = GetColorAppStream(crRightBottom, true);
1000 if (sColor.GetLength() > 0) {
1001 sAppStream << sColor;
1002 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
1003 << kMoveToOperator << "\n";
1004 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
1005 << " " << kLineToOperator << "\n";
1006 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1007 << kLineToOperator << "\n";
1008 sAppStream << fLeft + fHalfWidth * 2 << " "
1009 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
1010 << "\n";
1011 sAppStream << fRight - fHalfWidth * 2 << " "
1012 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
1013 << "\n";
1014 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
1015 << " " << kLineToOperator << " " << kFillOperator << "\n";
1016 }
1017
1018 sColor = GetColorAppStream(color, true);
1019 if (sColor.GetLength() > 0) {
1020 sAppStream << sColor;
1021 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
1022 << fTop - fBottom << " " << kAppendRectOperator << "\n";
1023 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1024 << fRight - fLeft - fHalfWidth * 2 << " "
1025 << fTop - fBottom - fHalfWidth * 2 << " "
1026 << kAppendRectOperator << " " << kFillEvenOddOperator
1027 << "\n";
1028 }
1029 break;
1030 case BorderStyle::UNDERLINE:
1031 sColor = GetColorAppStream(color, false);
1032 if (sColor.GetLength() > 0) {
1033 sAppStream << sColor;
1034 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n";
1035 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " "
1036 << kMoveToOperator << "\n";
1037 sAppStream << fRight << " " << fBottom + fWidth / 2 << " "
1038 << kLineToOperator << " " << kStrokeOperator << "\n";
1039 }
1040 break;
1041 }
1042 }
1043
1044 return ByteString(sAppStream);
1045 }
1046
GetDropButtonAppStream(const CFX_FloatRect & rcBBox)1047 ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
1048 if (rcBBox.IsEmpty())
1049 return ByteString();
1050
1051 std::ostringstream sAppStream;
1052 {
1053 AutoClosedQCommand q(&sAppStream);
1054 sAppStream << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 220.0f / 255.0f,
1055 220.0f / 255.0f, 220.0f / 255.0f),
1056 true)
1057 << rcBBox.left << " " << rcBBox.bottom << " "
1058 << rcBBox.right - rcBBox.left << " "
1059 << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
1060 << " " << kFillOperator << "\n";
1061 }
1062
1063 {
1064 AutoClosedQCommand q(&sAppStream);
1065 sAppStream << GetBorderAppStreamInternal(
1066 rcBBox, 2, CFX_Color(CFX_Color::kGray, 0),
1067 CFX_Color(CFX_Color::kGray, 1), CFX_Color(CFX_Color::kGray, 0.5),
1068 BorderStyle::BEVELED, CPWL_Dash(3, 0, 0));
1069 }
1070
1071 CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2,
1072 (rcBBox.top + rcBBox.bottom) / 2);
1073 if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) &&
1074 IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) {
1075 AutoClosedQCommand q(&sAppStream);
1076 sAppStream << " 0 " << kSetGrayOperator << "\n"
1077 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
1078 << kMoveToOperator << "\n"
1079 << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " "
1080 << kLineToOperator << "\n"
1081 << ptCenter.x << " " << ptCenter.y - 1.5f << " "
1082 << kLineToOperator << "\n"
1083 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
1084 << kLineToOperator << " " << kFillOperator << "\n";
1085 }
1086
1087 return ByteString(sAppStream);
1088 }
1089
GetRectFillAppStream(const CFX_FloatRect & rect,const CFX_Color & color)1090 ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
1091 const CFX_Color& color) {
1092 std::ostringstream sAppStream;
1093 ByteString sColor = GetColorAppStream(color, true);
1094 if (sColor.GetLength() > 0) {
1095 AutoClosedQCommand q(&sAppStream);
1096 sAppStream << sColor << rect.left << " " << rect.bottom << " "
1097 << rect.right - rect.left << " " << rect.top - rect.bottom << " "
1098 << kAppendRectOperator << " " << kFillOperator << "\n";
1099 }
1100
1101 return ByteString(sAppStream);
1102 }
1103
SetDefaultIconName(CPDF_Stream * pIcon,const char * name)1104 void SetDefaultIconName(CPDF_Stream* pIcon, const char* name) {
1105 if (!pIcon)
1106 return;
1107
1108 CPDF_Dictionary* pImageDict = pIcon->GetDict();
1109 if (!pImageDict)
1110 return;
1111
1112 if (pImageDict->KeyExist("Name"))
1113 return;
1114
1115 pImageDict->SetNewFor<CPDF_String>("Name", name, false);
1116 }
1117
1118 } // namespace
1119
CPDFSDK_AppStream(CPDFSDK_Widget * widget,CPDF_Dictionary * dict)1120 CPDFSDK_AppStream::CPDFSDK_AppStream(CPDFSDK_Widget* widget,
1121 CPDF_Dictionary* dict)
1122 : widget_(widget), dict_(dict) {}
1123
~CPDFSDK_AppStream()1124 CPDFSDK_AppStream::~CPDFSDK_AppStream() {}
1125
SetAsPushButton()1126 void CPDFSDK_AppStream::SetAsPushButton() {
1127 CPDF_FormControl* pControl = widget_->GetFormControl();
1128 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1129 ButtonStyle nLayout = ButtonStyle::kLabel;
1130 switch (pControl->GetTextPosition()) {
1131 case TEXTPOS_ICON:
1132 nLayout = ButtonStyle::kIcon;
1133 break;
1134 case TEXTPOS_BELOW:
1135 nLayout = ButtonStyle::kIconTopLabelBottom;
1136 break;
1137 case TEXTPOS_ABOVE:
1138 nLayout = ButtonStyle::kIconBottomLabelTop;
1139 break;
1140 case TEXTPOS_RIGHT:
1141 nLayout = ButtonStyle::kIconLeftLabelRight;
1142 break;
1143 case TEXTPOS_LEFT:
1144 nLayout = ButtonStyle::kIconRightLabelLeft;
1145 break;
1146 case TEXTPOS_OVERLAID:
1147 nLayout = ButtonStyle::kLabelOverIcon;
1148 break;
1149 default:
1150 nLayout = ButtonStyle::kLabel;
1151 break;
1152 }
1153
1154 CFX_Color crBackground;
1155 CFX_Color crBorder;
1156 int iColorType;
1157 float fc[4];
1158 pControl->GetOriginalBackgroundColor(iColorType, fc);
1159 if (iColorType > 0)
1160 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1161
1162 pControl->GetOriginalBorderColor(iColorType, fc);
1163 if (iColorType > 0)
1164 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1165
1166 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1167 CPWL_Dash dsBorder(3, 0, 0);
1168 CFX_Color crLeftTop;
1169 CFX_Color crRightBottom;
1170
1171 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1172 switch (nBorderStyle) {
1173 case BorderStyle::DASH:
1174 dsBorder = CPWL_Dash(3, 3, 0);
1175 break;
1176 case BorderStyle::BEVELED:
1177 fBorderWidth *= 2;
1178 crLeftTop = CFX_Color(CFX_Color::kGray, 1);
1179 crRightBottom = crBackground / 2.0f;
1180 break;
1181 case BorderStyle::INSET:
1182 fBorderWidth *= 2;
1183 crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
1184 crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
1185 break;
1186 default:
1187 break;
1188 }
1189
1190 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1191 CFX_Color crText(CFX_Color::kGray, 0);
1192 ByteString csNameTag;
1193 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1194 Optional<CFX_Color::Type> color = da.GetColor(fc);
1195 if (color) {
1196 iColorType = *color;
1197 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1198 }
1199
1200 float fFontSize;
1201 Optional<ByteString> font = da.GetFont(&fFontSize);
1202 if (font)
1203 csNameTag = *font;
1204 else
1205 fFontSize = 12.0f;
1206
1207 WideString csWCaption;
1208 WideString csNormalCaption;
1209 WideString csRolloverCaption;
1210 WideString csDownCaption;
1211 if (pControl->HasMKEntry("CA"))
1212 csNormalCaption = pControl->GetNormalCaption();
1213
1214 if (pControl->HasMKEntry("RC"))
1215 csRolloverCaption = pControl->GetRolloverCaption();
1216
1217 if (pControl->HasMKEntry("AC"))
1218 csDownCaption = pControl->GetDownCaption();
1219
1220 CPDF_Stream* pNormalIcon = nullptr;
1221 CPDF_Stream* pRolloverIcon = nullptr;
1222 CPDF_Stream* pDownIcon = nullptr;
1223 if (pControl->HasMKEntry("I"))
1224 pNormalIcon = pControl->GetNormalIcon();
1225
1226 if (pControl->HasMKEntry("RI"))
1227 pRolloverIcon = pControl->GetRolloverIcon();
1228
1229 if (pControl->HasMKEntry("IX"))
1230 pDownIcon = pControl->GetDownIcon();
1231
1232 SetDefaultIconName(pNormalIcon, "ImgA");
1233 SetDefaultIconName(pRolloverIcon, "ImgB");
1234 SetDefaultIconName(pDownIcon, "ImgC");
1235
1236 CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
1237 widget_->GetPDFAnnot()->GetAnnotDict());
1238 font_map.SetAPType("N");
1239
1240 CPDF_IconFit iconFit = pControl->GetIconFit();
1241 ByteString csAP =
1242 GetRectFillAppStream(rcWindow, crBackground) +
1243 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1244 crRightBottom, nBorderStyle, dsBorder) +
1245 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1246 &font_map, pNormalIcon, iconFit, csNormalCaption,
1247 crText, fFontSize, nLayout);
1248
1249 Write("N", csAP, ByteString());
1250 if (pNormalIcon)
1251 AddImage("N", pNormalIcon);
1252
1253 CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
1254 if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
1255 if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
1256 csRolloverCaption = csNormalCaption;
1257 pRolloverIcon = pNormalIcon;
1258 }
1259
1260 font_map.SetAPType("R");
1261
1262 csAP =
1263 GetRectFillAppStream(rcWindow, crBackground) +
1264 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1265 crRightBottom, nBorderStyle, dsBorder) +
1266 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1267 &font_map, pRolloverIcon, iconFit,
1268 csRolloverCaption, crText, fFontSize, nLayout);
1269
1270 Write("R", csAP, ByteString());
1271 if (pRolloverIcon)
1272 AddImage("R", pRolloverIcon);
1273
1274 if (csDownCaption.IsEmpty() && !pDownIcon) {
1275 csDownCaption = csNormalCaption;
1276 pDownIcon = pNormalIcon;
1277 }
1278
1279 switch (nBorderStyle) {
1280 case BorderStyle::BEVELED: {
1281 CFX_Color crTemp = crLeftTop;
1282 crLeftTop = crRightBottom;
1283 crRightBottom = crTemp;
1284 break;
1285 }
1286 case BorderStyle::INSET: {
1287 crLeftTop = CFX_Color(CFX_Color::kGray, 0);
1288 crRightBottom = CFX_Color(CFX_Color::kGray, 1);
1289 break;
1290 }
1291 default:
1292 break;
1293 }
1294
1295 font_map.SetAPType("D");
1296
1297 csAP =
1298 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1299 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1300 crRightBottom, nBorderStyle, dsBorder) +
1301 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1302 &font_map, pDownIcon, iconFit, csDownCaption,
1303 crText, fFontSize, nLayout);
1304
1305 Write("D", csAP, ByteString());
1306 if (pDownIcon)
1307 AddImage("D", pDownIcon);
1308 } else {
1309 Remove("D");
1310 Remove("R");
1311 }
1312 }
1313
SetAsCheckBox()1314 void CPDFSDK_AppStream::SetAsCheckBox() {
1315 CPDF_FormControl* pControl = widget_->GetFormControl();
1316 CFX_Color crBackground, crBorder, crText;
1317 int iColorType;
1318 float fc[4];
1319
1320 pControl->GetOriginalBackgroundColor(iColorType, fc);
1321 if (iColorType > 0)
1322 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1323
1324 pControl->GetOriginalBorderColor(iColorType, fc);
1325 if (iColorType > 0)
1326 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1327
1328 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1329 CPWL_Dash dsBorder(3, 0, 0);
1330 CFX_Color crLeftTop, crRightBottom;
1331
1332 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1333 switch (nBorderStyle) {
1334 case BorderStyle::DASH:
1335 dsBorder = CPWL_Dash(3, 3, 0);
1336 break;
1337 case BorderStyle::BEVELED:
1338 fBorderWidth *= 2;
1339 crLeftTop = CFX_Color(CFX_Color::kGray, 1);
1340 crRightBottom = crBackground / 2.0f;
1341 break;
1342 case BorderStyle::INSET:
1343 fBorderWidth *= 2;
1344 crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
1345 crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
1346 break;
1347 default:
1348 break;
1349 }
1350
1351 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1352 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1353 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1354 Optional<CFX_Color::Type> color = da.GetColor(fc);
1355 if (color) {
1356 iColorType = *color;
1357 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1358 }
1359
1360 CheckStyle nStyle = CheckStyle::kCheck;
1361 WideString csWCaption = pControl->GetNormalCaption();
1362 if (csWCaption.GetLength() > 0) {
1363 switch (csWCaption[0]) {
1364 case L'l':
1365 nStyle = CheckStyle::kCircle;
1366 break;
1367 case L'8':
1368 nStyle = CheckStyle::kCross;
1369 break;
1370 case L'u':
1371 nStyle = CheckStyle::kDiamond;
1372 break;
1373 case L'n':
1374 nStyle = CheckStyle::kSquare;
1375 break;
1376 case L'H':
1377 nStyle = CheckStyle::kStar;
1378 break;
1379 case L'4':
1380 default:
1381 nStyle = CheckStyle::kCheck;
1382 }
1383 }
1384
1385 ByteString csAP_N_ON =
1386 GetRectFillAppStream(rcWindow, crBackground) +
1387 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1388 crRightBottom, nBorderStyle, dsBorder);
1389
1390 ByteString csAP_N_OFF = csAP_N_ON;
1391
1392 switch (nBorderStyle) {
1393 case BorderStyle::BEVELED: {
1394 CFX_Color crTemp = crLeftTop;
1395 crLeftTop = crRightBottom;
1396 crRightBottom = crTemp;
1397 break;
1398 }
1399 case BorderStyle::INSET: {
1400 crLeftTop = CFX_Color(CFX_Color::kGray, 0);
1401 crRightBottom = CFX_Color(CFX_Color::kGray, 1);
1402 break;
1403 }
1404 default:
1405 break;
1406 }
1407
1408 ByteString csAP_D_ON =
1409 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1410 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1411 crRightBottom, nBorderStyle, dsBorder);
1412
1413 ByteString csAP_D_OFF = csAP_D_ON;
1414
1415 csAP_N_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1416 csAP_D_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1417
1418 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1419 Write("N", csAP_N_OFF, "Off");
1420
1421 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1422 Write("D", csAP_D_OFF, "Off");
1423
1424 ByteString csAS = widget_->GetAppState();
1425 if (csAS.IsEmpty())
1426 widget_->SetAppState("Off");
1427 }
1428
SetAsRadioButton()1429 void CPDFSDK_AppStream::SetAsRadioButton() {
1430 CPDF_FormControl* pControl = widget_->GetFormControl();
1431 CFX_Color crBackground;
1432 CFX_Color crBorder;
1433 CFX_Color crText;
1434 int iColorType;
1435 float fc[4];
1436
1437 pControl->GetOriginalBackgroundColor(iColorType, fc);
1438 if (iColorType > 0)
1439 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1440
1441 pControl->GetOriginalBorderColor(iColorType, fc);
1442 if (iColorType > 0)
1443 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1444
1445 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1446 CPWL_Dash dsBorder(3, 0, 0);
1447 CFX_Color crLeftTop;
1448 CFX_Color crRightBottom;
1449 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1450 switch (nBorderStyle) {
1451 case BorderStyle::DASH:
1452 dsBorder = CPWL_Dash(3, 3, 0);
1453 break;
1454 case BorderStyle::BEVELED:
1455 fBorderWidth *= 2;
1456 crLeftTop = CFX_Color(CFX_Color::kGray, 1);
1457 crRightBottom = crBackground / 2.0f;
1458 break;
1459 case BorderStyle::INSET:
1460 fBorderWidth *= 2;
1461 crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
1462 crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
1463 break;
1464 default:
1465 break;
1466 }
1467
1468 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1469 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1470 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1471 Optional<CFX_Color::Type> color = da.GetColor(fc);
1472 if (color) {
1473 iColorType = *color;
1474 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1475 }
1476
1477 CheckStyle nStyle = CheckStyle::kCircle;
1478 WideString csWCaption = pControl->GetNormalCaption();
1479 if (csWCaption.GetLength() > 0) {
1480 switch (csWCaption[0]) {
1481 case L'8':
1482 nStyle = CheckStyle::kCross;
1483 break;
1484 case L'u':
1485 nStyle = CheckStyle::kDiamond;
1486 break;
1487 case L'n':
1488 nStyle = CheckStyle::kSquare;
1489 break;
1490 case L'H':
1491 nStyle = CheckStyle::kStar;
1492 break;
1493 case L'4':
1494 nStyle = CheckStyle::kCheck;
1495 break;
1496 case L'l':
1497 default:
1498 nStyle = CheckStyle::kCircle;
1499 }
1500 }
1501
1502 ByteString csAP_N_ON;
1503 CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f);
1504 if (nStyle == CheckStyle::kCircle) {
1505 if (nBorderStyle == BorderStyle::BEVELED) {
1506 crLeftTop = CFX_Color(CFX_Color::kGray, 1);
1507 crRightBottom = crBackground - 0.25f;
1508 } else if (nBorderStyle == BorderStyle::INSET) {
1509 crLeftTop = CFX_Color(CFX_Color::kGray, 0.5f);
1510 crRightBottom = CFX_Color(CFX_Color::kGray, 0.75f);
1511 }
1512
1513 csAP_N_ON =
1514 GetCircleFillAppStream(rcCenter, crBackground) +
1515 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1516 crRightBottom, nBorderStyle, dsBorder);
1517 } else {
1518 csAP_N_ON =
1519 GetRectFillAppStream(rcWindow, crBackground) +
1520 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1521 crRightBottom, nBorderStyle, dsBorder);
1522 }
1523
1524 ByteString csAP_N_OFF = csAP_N_ON;
1525
1526 switch (nBorderStyle) {
1527 case BorderStyle::BEVELED: {
1528 CFX_Color crTemp = crLeftTop;
1529 crLeftTop = crRightBottom;
1530 crRightBottom = crTemp;
1531 break;
1532 }
1533 case BorderStyle::INSET: {
1534 crLeftTop = CFX_Color(CFX_Color::kGray, 0);
1535 crRightBottom = CFX_Color(CFX_Color::kGray, 1);
1536 break;
1537 }
1538 default:
1539 break;
1540 }
1541
1542 ByteString csAP_D_ON;
1543
1544 if (nStyle == CheckStyle::kCircle) {
1545 CFX_Color crBK = crBackground - 0.25f;
1546 if (nBorderStyle == BorderStyle::BEVELED) {
1547 crLeftTop = crBackground - 0.25f;
1548 crRightBottom = CFX_Color(CFX_Color::kGray, 1);
1549 crBK = crBackground;
1550 } else if (nBorderStyle == BorderStyle::INSET) {
1551 crLeftTop = CFX_Color(CFX_Color::kGray, 0);
1552 crRightBottom = CFX_Color(CFX_Color::kGray, 1);
1553 }
1554
1555 csAP_D_ON =
1556 GetCircleFillAppStream(rcCenter, crBK) +
1557 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1558 crRightBottom, nBorderStyle, dsBorder);
1559 } else {
1560 csAP_D_ON =
1561 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1562 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1563 crRightBottom, nBorderStyle, dsBorder);
1564 }
1565
1566 ByteString csAP_D_OFF = csAP_D_ON;
1567
1568 csAP_N_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1569 csAP_D_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1570
1571 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1572 Write("N", csAP_N_OFF, "Off");
1573
1574 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1575 Write("D", csAP_D_OFF, "Off");
1576
1577 ByteString csAS = widget_->GetAppState();
1578 if (csAS.IsEmpty())
1579 widget_->SetAppState("Off");
1580 }
1581
SetAsComboBox(Optional<WideString> sValue)1582 void CPDFSDK_AppStream::SetAsComboBox(Optional<WideString> sValue) {
1583 CPDF_FormControl* pControl = widget_->GetFormControl();
1584 CPDF_FormField* pField = pControl->GetField();
1585 std::ostringstream sBody;
1586
1587 CFX_FloatRect rcClient = widget_->GetClientRect();
1588 CFX_FloatRect rcButton = rcClient;
1589 rcButton.left = rcButton.right - 13;
1590 rcButton.Normalize();
1591
1592 // Font map must outlive |pEdit|.
1593 CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
1594 widget_->GetPDFAnnot()->GetAnnotDict());
1595
1596 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
1597 pEdit->EnableRefresh(false);
1598 pEdit->SetFontMap(&font_map);
1599
1600 CFX_FloatRect rcEdit = rcClient;
1601 rcEdit.right = rcButton.left;
1602 rcEdit.Normalize();
1603
1604 pEdit->SetPlateRect(rcEdit);
1605 pEdit->SetAlignmentV(1, true);
1606
1607 float fFontSize = widget_->GetFontSize();
1608 if (IsFloatZero(fFontSize))
1609 pEdit->SetAutoFontSize(true, true);
1610 else
1611 pEdit->SetFontSize(fFontSize);
1612
1613 pEdit->Initialize();
1614
1615 if (sValue.has_value()) {
1616 pEdit->SetText(sValue.value());
1617 } else {
1618 int32_t nCurSel = pField->GetSelectedIndex(0);
1619 if (nCurSel < 0)
1620 pEdit->SetText(pField->GetValue());
1621 else
1622 pEdit->SetText(pField->GetOptionLabel(nCurSel));
1623 }
1624
1625 CFX_FloatRect rcContent = pEdit->GetContentRect();
1626 ByteString sEdit = GetEditAppStream(pEdit.get(), CFX_PointF(), true, 0);
1627 if (sEdit.GetLength() > 0) {
1628 sBody << "/Tx ";
1629 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1630 kMarkedSequenceEndOperator);
1631 AutoClosedQCommand q(&sBody);
1632
1633 if (rcContent.Width() > rcEdit.Width() ||
1634 rcContent.Height() > rcEdit.Height()) {
1635 sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
1636 << " " << rcEdit.Height() << " " << kAppendRectOperator << "\n"
1637 << kSetNonZeroWindingClipOperator << "\n"
1638 << kEndPathNoFillOrStrokeOperator << "\n";
1639 }
1640
1641 CFX_Color crText = widget_->GetTextPWLColor();
1642 AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
1643 sBody << GetColorAppStream(crText, true) << sEdit;
1644 }
1645
1646 sBody << GetDropButtonAppStream(rcButton);
1647 Write("N",
1648 GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
1649 ByteString());
1650 }
1651
SetAsListBox()1652 void CPDFSDK_AppStream::SetAsListBox() {
1653 CPDF_FormControl* pControl = widget_->GetFormControl();
1654 CPDF_FormField* pField = pControl->GetField();
1655 CFX_FloatRect rcClient = widget_->GetClientRect();
1656 std::ostringstream sBody;
1657
1658 // Font map must outlive |pEdit|.
1659 CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
1660 widget_->GetPDFAnnot()->GetAnnotDict());
1661
1662 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
1663 pEdit->EnableRefresh(false);
1664 pEdit->SetFontMap(&font_map);
1665 pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f));
1666
1667 float fFontSize = widget_->GetFontSize();
1668 pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
1669 pEdit->Initialize();
1670
1671 std::ostringstream sList;
1672 float fy = rcClient.top;
1673
1674 int32_t nTop = pField->GetTopVisibleIndex();
1675 int32_t nCount = pField->CountOptions();
1676 int32_t nSelCount = pField->CountSelectedItems();
1677
1678 for (int32_t i = nTop; i < nCount; ++i) {
1679 bool bSelected = false;
1680 for (int32_t j = 0; j < nSelCount; ++j) {
1681 if (pField->GetSelectedIndex(j) == i) {
1682 bSelected = true;
1683 break;
1684 }
1685 }
1686
1687 pEdit->SetText(pField->GetOptionLabel(i));
1688
1689 CFX_FloatRect rcContent = pEdit->GetContentRect();
1690 float fItemHeight = rcContent.Height();
1691
1692 if (bSelected) {
1693 CFX_FloatRect rcItem =
1694 CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
1695 {
1696 AutoClosedQCommand q(&sList);
1697 sList << GetColorAppStream(CFX_Color(CFX_Color::kRGB, 0, 51.0f / 255.0f,
1698 113.0f / 255.0f),
1699 true)
1700 << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
1701 << " " << rcItem.Height() << " " << kAppendRectOperator << " "
1702 << kFillOperator << "\n";
1703 }
1704
1705 AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
1706 sList << GetColorAppStream(CFX_Color(CFX_Color::kGray, 1), true)
1707 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
1708 } else {
1709 CFX_Color crText = widget_->GetTextPWLColor();
1710
1711 AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
1712 sList << GetColorAppStream(crText, true)
1713 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
1714 }
1715
1716 fy -= fItemHeight;
1717 }
1718
1719 if (sList.tellp() > 0) {
1720 sBody << "/Tx ";
1721 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1722 kMarkedSequenceEndOperator);
1723 AutoClosedQCommand q(&sBody);
1724
1725 sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
1726 << " " << rcClient.Height() << " " << kAppendRectOperator << "\n"
1727 << kSetNonZeroWindingClipOperator << "\n"
1728 << kEndPathNoFillOrStrokeOperator << "\n"
1729 << sList.str();
1730 }
1731 Write("N",
1732 GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sBody),
1733 ByteString());
1734 }
1735
SetAsTextField(Optional<WideString> sValue)1736 void CPDFSDK_AppStream::SetAsTextField(Optional<WideString> sValue) {
1737 CPDF_FormControl* pControl = widget_->GetFormControl();
1738 CPDF_FormField* pField = pControl->GetField();
1739 std::ostringstream sBody;
1740 std::ostringstream sLines;
1741
1742 // Font map must outlive |pEdit|.
1743 CBA_FontMap font_map(widget_->GetPDFPage()->GetDocument(),
1744 widget_->GetPDFAnnot()->GetAnnotDict());
1745
1746 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
1747 pEdit->EnableRefresh(false);
1748 pEdit->SetFontMap(&font_map);
1749
1750 CFX_FloatRect rcClient = widget_->GetClientRect();
1751 pEdit->SetPlateRect(rcClient);
1752 pEdit->SetAlignmentH(pControl->GetControlAlignment(), true);
1753
1754 uint32_t dwFieldFlags = pField->GetFieldFlags();
1755 bool bMultiLine = dwFieldFlags & pdfium::form_flags::kTextMultiline;
1756 if (bMultiLine) {
1757 pEdit->SetMultiLine(true, true);
1758 pEdit->SetAutoReturn(true, true);
1759 } else {
1760 pEdit->SetAlignmentV(1, true);
1761 }
1762
1763 uint16_t subWord = 0;
1764 if (dwFieldFlags & pdfium::form_flags::kTextPassword) {
1765 subWord = '*';
1766 pEdit->SetPasswordChar(subWord, true);
1767 }
1768
1769 int nMaxLen = pField->GetMaxLen();
1770 bool bCharArray = dwFieldFlags & pdfium::form_flags::kTextComb;
1771 float fFontSize = widget_->GetFontSize();
1772
1773 #ifdef PDF_ENABLE_XFA
1774 if (!sValue.has_value() && widget_->GetMixXFAWidget())
1775 sValue = widget_->GetValue();
1776 #endif // PDF_ENABLE_XFA
1777
1778 if (nMaxLen > 0) {
1779 if (bCharArray) {
1780 pEdit->SetCharArray(nMaxLen);
1781 if (IsFloatZero(fFontSize)) {
1782 fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(
1783 font_map.GetPDFFont(0).Get(), rcClient, nMaxLen);
1784 }
1785 } else {
1786 if (sValue.has_value())
1787 nMaxLen = sValue.value().GetLength();
1788 pEdit->SetLimitChar(nMaxLen);
1789 }
1790 }
1791
1792 if (IsFloatZero(fFontSize))
1793 pEdit->SetAutoFontSize(true, true);
1794 else
1795 pEdit->SetFontSize(fFontSize);
1796
1797 pEdit->Initialize();
1798 pEdit->SetText(sValue.value_or(pField->GetValue()));
1799
1800 CFX_FloatRect rcContent = pEdit->GetContentRect();
1801 ByteString sEdit =
1802 GetEditAppStream(pEdit.get(), CFX_PointF(), !bCharArray, subWord);
1803
1804 if (sEdit.GetLength() > 0) {
1805 sBody << "/Tx ";
1806 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1807 kMarkedSequenceEndOperator);
1808 AutoClosedQCommand q(&sBody);
1809
1810 if (rcContent.Width() > rcClient.Width() ||
1811 rcContent.Height() > rcClient.Height()) {
1812 sBody << rcClient.left << " " << rcClient.bottom << " "
1813 << rcClient.Width() << " " << rcClient.Height() << " "
1814 << kAppendRectOperator << "\n"
1815 << kSetNonZeroWindingClipOperator << "\n"
1816 << kEndPathNoFillOrStrokeOperator << "\n";
1817 }
1818 CFX_Color crText = widget_->GetTextPWLColor();
1819
1820 AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
1821 sBody << GetColorAppStream(crText, true) << sEdit;
1822 }
1823
1824 if (bCharArray) {
1825 switch (widget_->GetBorderStyle()) {
1826 case BorderStyle::SOLID: {
1827 ByteString sColor =
1828 GetColorAppStream(widget_->GetBorderPWLColor(), false);
1829 if (sColor.GetLength() > 0) {
1830 AutoClosedQCommand q(&sLines);
1831 sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
1832 << "\n"
1833 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
1834 << " 2 " << kSetLineCapStyleOperator << " 0 "
1835 << kSetLineJoinStyleOperator << "\n";
1836
1837 for (int32_t i = 1; i < nMaxLen; ++i) {
1838 sLines << rcClient.left +
1839 ((rcClient.right - rcClient.left) / nMaxLen) * i
1840 << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
1841 << rcClient.left +
1842 ((rcClient.right - rcClient.left) / nMaxLen) * i
1843 << " " << rcClient.top << " " << kLineToOperator << " "
1844 << kStrokeOperator << "\n";
1845 }
1846 }
1847 break;
1848 }
1849 case BorderStyle::DASH: {
1850 ByteString sColor =
1851 GetColorAppStream(widget_->GetBorderPWLColor(), false);
1852 if (sColor.GetLength() > 0) {
1853 CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
1854 AutoClosedQCommand q(&sLines);
1855 sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
1856 << "\n"
1857 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
1858 << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
1859 << dsBorder.nPhase << " " << kSetDashOperator << "\n";
1860
1861 for (int32_t i = 1; i < nMaxLen; ++i) {
1862 sLines << rcClient.left +
1863 ((rcClient.right - rcClient.left) / nMaxLen) * i
1864 << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
1865 << rcClient.left +
1866 ((rcClient.right - rcClient.left) / nMaxLen) * i
1867 << " " << rcClient.top << " " << kLineToOperator << " "
1868 << kStrokeOperator << "\n";
1869 }
1870 }
1871 break;
1872 }
1873 default:
1874 break;
1875 }
1876 }
1877
1878 Write("N",
1879 GetBackgroundAppStream() + GetBorderAppStream() + ByteString(sLines) +
1880 ByteString(sBody),
1881 ByteString());
1882 }
1883
AddImage(const ByteString & sAPType,CPDF_Stream * pImage)1884 void CPDFSDK_AppStream::AddImage(const ByteString& sAPType,
1885 CPDF_Stream* pImage) {
1886 CPDF_Stream* pStream = dict_->GetStreamFor(sAPType);
1887 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1888 ByteString sImageAlias = "IMG";
1889
1890 if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
1891 sImageAlias = pImageDict->GetStringFor("Name");
1892 if (sImageAlias.IsEmpty())
1893 sImageAlias = "IMG";
1894 }
1895
1896 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
1897 if (!pStreamResList)
1898 pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources");
1899
1900 CPDF_Dictionary* pXObject =
1901 pStreamResList->SetNewFor<CPDF_Dictionary>("XObject");
1902 pXObject->SetNewFor<CPDF_Reference>(sImageAlias,
1903 widget_->GetPageView()->GetPDFDocument(),
1904 pImage->GetObjNum());
1905 }
1906
Write(const ByteString & sAPType,const ByteString & sContents,const ByteString & sAPState)1907 void CPDFSDK_AppStream::Write(const ByteString& sAPType,
1908 const ByteString& sContents,
1909 const ByteString& sAPState) {
1910 CPDF_Stream* pStream = nullptr;
1911 CPDF_Dictionary* pParentDict = nullptr;
1912 if (sAPState.IsEmpty()) {
1913 pParentDict = dict_.Get();
1914 pStream = dict_->GetStreamFor(sAPType);
1915 } else {
1916 CPDF_Dictionary* pAPTypeDict = dict_->GetDictFor(sAPType);
1917 if (!pAPTypeDict)
1918 pAPTypeDict = dict_->SetNewFor<CPDF_Dictionary>(sAPType);
1919
1920 pParentDict = pAPTypeDict;
1921 pStream = pAPTypeDict->GetStreamFor(sAPState);
1922 }
1923
1924 if (!pStream) {
1925 CPDF_Document* doc = widget_->GetPageView()->GetPDFDocument();
1926 pStream = doc->NewIndirect<CPDF_Stream>();
1927 pParentDict->SetNewFor<CPDF_Reference>(sAPType, doc, pStream->GetObjNum());
1928 }
1929
1930 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1931 if (!pStreamDict) {
1932 auto pNewDict =
1933 widget_->GetPDFAnnot()->GetDocument()->New<CPDF_Dictionary>();
1934 pStreamDict = pNewDict.Get();
1935 pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
1936 pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
1937 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
1938 pStream->InitStream({}, std::move(pNewDict));
1939 }
1940 pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
1941 pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
1942 pStream->SetDataAndRemoveFilter(sContents.raw_span());
1943 }
1944
Remove(const ByteString & sAPType)1945 void CPDFSDK_AppStream::Remove(const ByteString& sAPType) {
1946 dict_->RemoveFor(sAPType);
1947 }
1948
GetBackgroundAppStream() const1949 ByteString CPDFSDK_AppStream::GetBackgroundAppStream() const {
1950 CFX_Color crBackground = widget_->GetFillPWLColor();
1951 if (crBackground.nColorType != CFX_Color::kTransparent)
1952 return GetRectFillAppStream(widget_->GetRotatedRect(), crBackground);
1953
1954 return ByteString();
1955 }
1956
GetBorderAppStream() const1957 ByteString CPDFSDK_AppStream::GetBorderAppStream() const {
1958 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1959 CFX_Color crBorder = widget_->GetBorderPWLColor();
1960 CFX_Color crBackground = widget_->GetFillPWLColor();
1961 CFX_Color crLeftTop;
1962 CFX_Color crRightBottom;
1963
1964 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1965 CPWL_Dash dsBorder(3, 0, 0);
1966
1967 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1968 switch (nBorderStyle) {
1969 case BorderStyle::DASH:
1970 dsBorder = CPWL_Dash(3, 3, 0);
1971 break;
1972 case BorderStyle::BEVELED:
1973 fBorderWidth *= 2;
1974 crLeftTop = CFX_Color(CFX_Color::kGray, 1);
1975 crRightBottom = crBackground / 2.0f;
1976 break;
1977 case BorderStyle::INSET:
1978 fBorderWidth *= 2;
1979 crLeftTop = CFX_Color(CFX_Color::kGray, 0.5);
1980 crRightBottom = CFX_Color(CFX_Color::kGray, 0.75);
1981 break;
1982 default:
1983 break;
1984 }
1985
1986 return GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1987 crRightBottom, nBorderStyle, dsBorder);
1988 }
1989