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