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