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