• 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/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