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