blob: 405a20550725aa52c3f8038f80f5c86bc220ff69 [file] [log] [blame]
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001// Copyright 2017 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
Dan Sinclairc411eb92017-07-25 09:39:30 -04007#include "fpdfsdk/pwl/cpwl_appstream.h"
Dan Sinclaircb2ea422017-07-19 15:24:49 -04008
9#include <utility>
10
11#include "core/fpdfapi/parser/cpdf_dictionary.h"
12#include "core/fpdfapi/parser/cpdf_document.h"
13#include "core/fpdfapi/parser/cpdf_name.h"
14#include "core/fpdfapi/parser/cpdf_number.h"
15#include "core/fpdfapi/parser/cpdf_reference.h"
16#include "core/fpdfapi/parser/cpdf_stream.h"
17#include "core/fpdfapi/parser/cpdf_string.h"
Dan Sinclair14ddd422017-07-20 11:07:00 -040018#include "core/fpdfapi/parser/fpdf_parser_decode.h"
19#include "core/fpdfdoc/cpvt_word.h"
Dan Sinclaircb2ea422017-07-19 15:24:49 -040020#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
21#include "fpdfsdk/cpdfsdk_interform.h"
22#include "fpdfsdk/cpdfsdk_pageview.h"
23#include "fpdfsdk/cpdfsdk_widget.h"
24#include "fpdfsdk/formfiller/cba_fontmap.h"
Dan Sinclairc411eb92017-07-25 09:39:30 -040025#include "fpdfsdk/pwl/cpwl_edit.h"
26#include "fpdfsdk/pwl/cpwl_edit_impl.h"
27#include "fpdfsdk/pwl/cpwl_icon.h"
28#include "fpdfsdk/pwl/cpwl_wnd.h"
Dan Sinclaircb2ea422017-07-19 15:24:49 -040029
30namespace {
31
Dan Sinclair14ddd422017-07-20 11:07:00 -040032// Checkbox & radiobutton styles.
33enum class CheckStyle { kCheck = 0, kCircle, kCross, kDiamond, kSquare, kStar };
34
35// Pushbutton layout styles.
36enum class ButtonStyle {
37 kLabel = 0,
38 kIcon,
39 kIconTopLabelBottom,
40 kIconBottomLabelTop,
41 kIconLeftLabelRight,
42 kIconRightLabelLeft,
43 kLabelOverIcon
44};
45
Dan Sinclairbeef5e42017-07-24 10:32:05 -040046const char kAppendRectOperator[] = "re";
47const char kConcatMatrixOperator[] = "cm";
48const char kCurveToOperator[] = "c";
49const char kEndPathNoFillOrStrokeOperator[] = "n";
50const char kFillOperator[] = "f";
51const char kFillEvenOddOperator[] = "f*";
52const char kInvokeNamedXObjectOperator[] = "Do";
53const char kLineToOperator[] = "l";
54const char kMarkedSequenceBeginOperator[] = "BMC";
55const char kMarkedSequenceEndOperator[] = "EMC";
56const char kMoveTextPositionOperator[] = "Td";
57const char kMoveToOperator[] = "m";
58const char kSetCharacterSpacingOperator[] = "Tc";
59const char kSetCMYKOperator[] = "k";
60const char kSetCMKYStrokedOperator[] = "K";
61const char kSetDashOperator[] = "d";
62const char kSetGrayOperator[] = "g";
63const char kSetGrayStrokedOperator[] = "G";
64const char kSetLineCapStyleOperator[] = "J";
65const char kSetLineJoinStyleOperator[] = "j";
66const char kSetLineWidthOperator[] = "w";
67const char kSetNonZeroWindingClipOperator[] = "W";
68const char kSetRGBOperator[] = "rg";
69const char kSetRGBStrokedOperator[] = "RG";
70const char kSetTextFontAndSizeOperator[] = "Tf";
71const char kSetTextScaleHorizontalOperator[] = "Tz";
72const char kShowTextOperator[] = "Tj";
73const char kStateRestoreOperator[] = "Q";
74const char kStateSaveOperator[] = "q";
75const char kStrokeOperator[] = "S";
76const char kTextBeginOperator[] = "BT";
77const char kTextEndOperator[] = "ET";
78
Dan Sinclaire03f8b12017-07-20 11:08:21 -040079class AutoClosedCommand {
80 public:
81 AutoClosedCommand(std::ostringstream* stream,
82 CFX_ByteString open,
83 CFX_ByteString close)
84 : stream_(stream), close_(close) {
85 *stream_ << open << "\n";
86 }
87
88 virtual ~AutoClosedCommand() { *stream_ << close_ << "\n"; }
89
90 private:
91 std::ostringstream* stream_;
92 CFX_ByteString close_;
93};
94
95class AutoClosedQCommand : public AutoClosedCommand {
96 public:
97 explicit AutoClosedQCommand(std::ostringstream* stream)
Dan Sinclairbeef5e42017-07-24 10:32:05 -040098 : AutoClosedCommand(stream, kStateSaveOperator, kStateRestoreOperator) {}
Dan Sinclaire03f8b12017-07-20 11:08:21 -040099 ~AutoClosedQCommand() override {}
100};
101
Dan Sinclair14ddd422017-07-20 11:07:00 -0400102CFX_ByteString GetColorAppStream(const CFX_Color& color,
103 const bool& bFillOrStroke) {
104 std::ostringstream sColorStream;
105
106 switch (color.nColorType) {
107 case COLORTYPE_RGB:
108 sColorStream << color.fColor1 << " " << color.fColor2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400109 << color.fColor3 << " "
110 << (bFillOrStroke ? kSetRGBOperator : kSetRGBStrokedOperator)
Dan Sinclair14ddd422017-07-20 11:07:00 -0400111 << "\n";
112 break;
113 case COLORTYPE_GRAY:
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400114 sColorStream << color.fColor1 << " "
115 << (bFillOrStroke ? kSetGrayOperator
116 : kSetGrayStrokedOperator)
Dan Sinclair14ddd422017-07-20 11:07:00 -0400117 << "\n";
118 break;
119 case COLORTYPE_CMYK:
120 sColorStream << color.fColor1 << " " << color.fColor2 << " "
121 << color.fColor3 << " " << color.fColor4 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400122 << (bFillOrStroke ? kSetCMYKOperator
123 : kSetCMKYStrokedOperator)
124 << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400125 break;
126 }
127
128 return CFX_ByteString(sColorStream);
129}
130
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400131CFX_ByteString GetAP_Check(const CFX_FloatRect& crBBox) {
132 const float fWidth = crBBox.right - crBBox.left;
133 const float fHeight = crBBox.top - crBBox.bottom;
134
135 CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f),
136 CFX_PointF(0.29f, 0.40f)},
137 {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f),
138 CFX_PointF(0.31f, 0.28f)},
139 {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f),
140 CFX_PointF(0.77f, 0.67f)},
141 {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f),
142 CFX_PointF(0.76f, 0.75f)},
143 {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f),
144 CFX_PointF(0.68f, 0.75f)},
145 {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f),
146 CFX_PointF(0.44f, 0.47f)},
147 {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f),
148 CFX_PointF(0.41f, 0.58f)},
149 {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f),
150 CFX_PointF(0.30f, 0.56f)}};
151
152 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
153 for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) {
154 pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
155 pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
156 }
157 }
158
159 std::ostringstream csAP;
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400160 csAP << pts[0][0].x << " " << pts[0][0].y << " " << kMoveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400161
162 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
163 size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
164
165 float px1 = pts[i][1].x - pts[i][0].x;
166 float py1 = pts[i][1].y - pts[i][0].y;
167 float px2 = pts[i][2].x - pts[nNext][0].x;
168 float py2 = pts[i][2].y - pts[nNext][0].y;
169
170 csAP << pts[i][0].x + px1 * FX_BEZIER << " "
171 << pts[i][0].y + py1 * FX_BEZIER << " "
172 << pts[nNext][0].x + px2 * FX_BEZIER << " "
173 << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400174 << pts[nNext][0].y << " " << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400175 }
176
177 return CFX_ByteString(csAP);
178}
179
180CFX_ByteString GetAP_Circle(const CFX_FloatRect& crBBox) {
181 std::ostringstream csAP;
182
183 float fWidth = crBBox.right - crBBox.left;
184 float fHeight = crBBox.top - crBBox.bottom;
185
186 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
187 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
188 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
189 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
190
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400191 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400192
193 float px = pt2.x - pt1.x;
194 float py = pt2.y - pt1.y;
195
196 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
197 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400198 << " " << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400199
200 px = pt3.x - pt2.x;
201 py = pt2.y - pt3.y;
202
203 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400204 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
205 << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400206
207 px = pt3.x - pt4.x;
208 py = pt3.y - pt4.y;
209
210 csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
211 << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400212 << " " << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400213
214 px = pt4.x - pt1.x;
215 py = pt1.y - pt4.y;
216
217 csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400218 << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " "
219 << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400220
221 return CFX_ByteString(csAP);
222}
223
224CFX_ByteString GetAP_Cross(const CFX_FloatRect& crBBox) {
225 std::ostringstream csAP;
226
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400227 csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
228 csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
229 << "\n";
230 csAP << crBBox.left << " " << crBBox.bottom << " " << kMoveToOperator << "\n";
231 csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400232
233 return CFX_ByteString(csAP);
234}
235
236CFX_ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) {
237 std::ostringstream csAP;
238
239 float fWidth = crBBox.right - crBBox.left;
240 float fHeight = crBBox.top - crBBox.bottom;
241
242 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
243 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
244 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
245 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
246
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400247 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
248 csAP << pt2.x << " " << pt2.y << " " << kLineToOperator << "\n";
249 csAP << pt3.x << " " << pt3.y << " " << kLineToOperator << "\n";
250 csAP << pt4.x << " " << pt4.y << " " << kLineToOperator << "\n";
251 csAP << pt1.x << " " << pt1.y << " " << kLineToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400252
253 return CFX_ByteString(csAP);
254}
255
256CFX_ByteString GetAP_Square(const CFX_FloatRect& crBBox) {
257 std::ostringstream csAP;
258
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400259 csAP << crBBox.left << " " << crBBox.top << " " << kMoveToOperator << "\n";
260 csAP << crBBox.right << " " << crBBox.top << " " << kLineToOperator << "\n";
261 csAP << crBBox.right << " " << crBBox.bottom << " " << kLineToOperator
262 << "\n";
263 csAP << crBBox.left << " " << crBBox.bottom << " " << kLineToOperator << "\n";
264 csAP << crBBox.left << " " << crBBox.top << " " << kLineToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400265
266 return CFX_ByteString(csAP);
267}
268
269CFX_ByteString GetAP_Star(const CFX_FloatRect& crBBox) {
270 std::ostringstream csAP;
271
272 float fRadius = (crBBox.top - crBBox.bottom) / (1 + (float)cos(FX_PI / 5.0f));
273 CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
274 (crBBox.top + crBBox.bottom) / 2.0f);
275
276 float px[5];
277 float py[5];
278 float fAngel = FX_PI / 10.0f;
279 for (int32_t i = 0; i < 5; i++) {
280 px[i] = ptCenter.x + fRadius * (float)cos(fAngel);
281 py[i] = ptCenter.y + fRadius * (float)sin(fAngel);
282 fAngel += FX_PI * 2 / 5.0f;
283 }
284
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400285 csAP << px[0] << " " << py[0] << " " << kMoveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400286
287 int32_t nNext = 0;
288 for (int32_t j = 0; j < 5; j++) {
289 nNext += 2;
290 if (nNext >= 5)
291 nNext -= 5;
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400292 csAP << px[nNext] << " " << py[nNext] << " " << kLineToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400293 }
294
295 return CFX_ByteString(csAP);
296}
297
298CFX_ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) {
299 std::ostringstream csAP;
300
301 float fWidth = crBBox.right - crBBox.left;
302 float fHeight = crBBox.top - crBBox.bottom;
303
304 CFX_PointF pt1(-fWidth / 2, 0);
305 CFX_PointF pt2(0, fHeight / 2);
306 CFX_PointF pt3(fWidth / 2, 0);
307
308 float px;
309 float py;
310
311 csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
312 << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400313 << crBBox.bottom + fHeight / 2 << " " << kConcatMatrixOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400314
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400315 csAP << pt1.x << " " << pt1.y << " " << kMoveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400316
317 px = pt2.x - pt1.x;
318 py = pt2.y - pt1.y;
319
320 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
321 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400322 << " " << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400323
324 px = pt3.x - pt2.x;
325 py = pt2.y - pt3.y;
326
327 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400328 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " "
329 << kCurveToOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400330
331 return CFX_ByteString(csAP);
332}
333
334CFX_ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
335 const CFX_Color& crText) {
336 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400337 {
338 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400339 sAP << GetColorAppStream(crText, true) << GetAP_Check(rcBBox)
340 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400341 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400342 return CFX_ByteString(sAP);
343}
344
345CFX_ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
346 const CFX_Color& crText) {
347 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400348 {
349 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400350 sAP << GetColorAppStream(crText, true) << GetAP_Circle(rcBBox)
351 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400352 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400353 return CFX_ByteString(sAP);
354}
355
356CFX_ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
357 const CFX_Color& crText) {
358 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400359 {
360 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400361 sAP << GetColorAppStream(crText, false) << GetAP_Cross(rcBBox)
362 << kStrokeOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400363 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400364 return CFX_ByteString(sAP);
365}
366
367CFX_ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
368 const CFX_Color& crText) {
369 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400370 {
371 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400372 sAP << "1 " << kSetLineWidthOperator << "\n"
373 << GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox)
374 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400375 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400376 return CFX_ByteString(sAP);
377}
378
379CFX_ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
380 const CFX_Color& crText) {
381 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400382 {
383 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400384 sAP << GetColorAppStream(crText, true) << GetAP_Square(rcBBox)
385 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400386 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400387 return CFX_ByteString(sAP);
388}
389
390CFX_ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
391 const CFX_Color& crText) {
392 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400393 {
394 AutoClosedQCommand q(&sAP);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400395 sAP << GetColorAppStream(crText, true) << GetAP_Star(rcBBox)
396 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400397 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400398 return CFX_ByteString(sAP);
399}
400
401CFX_ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
402 const CFX_Color& color) {
403 std::ostringstream sAppStream;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400404 CFX_ByteString sColor = GetColorAppStream(color, true);
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400405 if (sColor.GetLength() > 0) {
406 AutoClosedQCommand q(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400407 sAppStream << sColor << GetAP_Circle(rect) << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400408 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400409 return CFX_ByteString(sAppStream);
410}
411
412CFX_ByteString GetCircleBorderAppStream(const CFX_FloatRect& rect,
413 float fWidth,
414 const CFX_Color& color,
415 const CFX_Color& crLeftTop,
416 const CFX_Color& crRightBottom,
417 BorderStyle nStyle,
418 const CPWL_Dash& dash) {
419 std::ostringstream sAppStream;
420 CFX_ByteString sColor;
421
422 if (fWidth > 0.0f) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400423 AutoClosedQCommand q(&sAppStream);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400424
425 float fHalfWidth = fWidth / 2.0f;
426 CFX_FloatRect rect_by_2 = rect.GetDeflated(fHalfWidth, fHalfWidth);
427
428 float div = fHalfWidth * 0.75f;
429 CFX_FloatRect rect_by_75 = rect.GetDeflated(div, div);
430 switch (nStyle) {
431 default:
432 case BorderStyle::SOLID:
433 case BorderStyle::UNDERLINE: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400434 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400435 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400436 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400437 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
438 << sColor << GetAP_Circle(rect_by_2) << " "
439 << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400440 }
441 } break;
442 case BorderStyle::DASH: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400443 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400444 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400445 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400446 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400447 << "[" << dash.nDash << " " << dash.nGap << "] "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400448 << dash.nPhase << " " << kSetDashOperator << "\n"
449 << sColor << GetAP_Circle(rect_by_2) << " "
450 << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400451 }
452 } break;
453 case BorderStyle::BEVELED: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400454 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400455 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400456 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400457 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
458 << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
459 << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400460 }
461
Dan Sinclair14ddd422017-07-20 11:07:00 -0400462 sColor = GetColorAppStream(crLeftTop, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400463 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400464 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400465 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400466 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400467 << " " << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400468 }
469
Dan Sinclair14ddd422017-07-20 11:07:00 -0400470 sColor = GetColorAppStream(crRightBottom, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400471 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400472 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400473 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400474 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400475 << " " << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400476 }
477 } break;
478 case BorderStyle::INSET: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400479 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400480 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400481 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400482 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
483 << sColor << GetAP_Circle(rect) << " " << kStrokeOperator
484 << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400485 }
486
Dan Sinclair14ddd422017-07-20 11:07:00 -0400487 sColor = GetColorAppStream(crLeftTop, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400488 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400489 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400490 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400491 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400492 << " " << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400493 }
494
Dan Sinclair14ddd422017-07-20 11:07:00 -0400495 sColor = GetColorAppStream(crRightBottom, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400496 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400497 AutoClosedQCommand q2(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400498 sAppStream << fHalfWidth << " " << kSetLineWidthOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400499 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400500 << " " << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400501 }
502 } break;
503 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400504 }
505 return CFX_ByteString(sAppStream);
506}
507
508CFX_ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400509 CheckStyle nStyle,
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400510 const CFX_Color& crText) {
511 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
512 switch (nStyle) {
513 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -0400514 case CheckStyle::kCheck:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400515 return GetAppStream_Check(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400516 case CheckStyle::kCircle:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400517 rcCenter.Scale(2.0f / 3.0f);
518 return GetAppStream_Circle(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400519 case CheckStyle::kCross:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400520 return GetAppStream_Cross(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400521 case CheckStyle::kDiamond:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400522 rcCenter.Scale(2.0f / 3.0f);
523 return GetAppStream_Diamond(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400524 case CheckStyle::kSquare:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400525 rcCenter.Scale(2.0f / 3.0f);
526 return GetAppStream_Square(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400527 case CheckStyle::kStar:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400528 rcCenter.Scale(2.0f / 3.0f);
529 return GetAppStream_Star(rcCenter, crText);
530 }
531}
532
533CFX_ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400534 CheckStyle nStyle,
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400535 const CFX_Color& crText) {
536 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
537 switch (nStyle) {
538 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -0400539 case CheckStyle::kCheck:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400540 return GetAppStream_Check(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400541 case CheckStyle::kCircle:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400542 rcCenter.Scale(1.0f / 2.0f);
543 return GetAppStream_Circle(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400544 case CheckStyle::kCross:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400545 return GetAppStream_Cross(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400546 case CheckStyle::kDiamond:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400547 rcCenter.Scale(2.0f / 3.0f);
548 return GetAppStream_Diamond(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400549 case CheckStyle::kSquare:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400550 rcCenter.Scale(2.0f / 3.0f);
551 return GetAppStream_Square(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400552 case CheckStyle::kStar:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400553 rcCenter.Scale(2.0f / 3.0f);
554 return GetAppStream_Star(rcCenter, crText);
555 }
556}
557
Dan Sinclair14ddd422017-07-20 11:07:00 -0400558CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
559 int32_t nFontIndex,
560 float fFontSize) {
561 if (!pFontMap)
562 return CFX_ByteString();
563
564 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
565 if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
566 return CFX_ByteString();
567
568 std::ostringstream sRet;
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400569 sRet << "/" << sFontAlias << " " << fFontSize << " "
570 << kSetTextFontAndSizeOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400571 return CFX_ByteString(sRet);
572}
573
574CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400575 if (strWords.GetLength() > 0) {
576 return PDF_EncodeString(strWords, false) + " " + kShowTextOperator + "\n";
577 }
Dan Sinclair14ddd422017-07-20 11:07:00 -0400578 return CFX_ByteString();
579}
580
Dan Sinclair6b0158f2017-07-24 09:42:55 -0400581CFX_ByteString GetEditAppStream(CPWL_EditImpl* pEdit,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400582 const CFX_PointF& ptOffset,
583 bool bContinuous,
584 uint16_t SubWord) {
Dan Sinclair6b0158f2017-07-24 09:42:55 -0400585 CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
Dan Sinclair14ddd422017-07-20 11:07:00 -0400586 pIterator->SetAt(0);
587
588 std::ostringstream sEditStream;
589 std::ostringstream sWords;
590 int32_t nCurFontIndex = -1;
591 CFX_PointF ptOld;
592 CFX_PointF ptNew;
593 CPVT_WordPlace oldplace;
594
595 while (pIterator->NextWord()) {
596 CPVT_WordPlace place = pIterator->GetAt();
597 if (bContinuous) {
598 if (place.LineCmp(oldplace) != 0) {
599 if (sWords.tellp() > 0) {
600 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
601 sWords.str("");
602 }
603
604 CPVT_Word word;
605 if (pIterator->GetWord(word)) {
606 ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
607 word.ptWord.y + ptOffset.y);
608 } else {
609 CPVT_Line line;
610 pIterator->GetLine(line);
611 ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
612 line.ptLine.y + ptOffset.y);
613 }
614
615 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400616 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
617 << kMoveTextPositionOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400618
619 ptOld = ptNew;
620 }
621 }
622
623 CPVT_Word word;
624 if (pIterator->GetWord(word)) {
625 if (word.nFontIndex != nCurFontIndex) {
626 if (sWords.tellp() > 0) {
627 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
628 sWords.str("");
629 }
630 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
631 word.fFontSize);
632 nCurFontIndex = word.nFontIndex;
633 }
634
Dan Sinclairc08dc392017-07-24 08:57:35 -0400635 sWords << pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400636 }
637
638 oldplace = place;
639 } else {
640 CPVT_Word word;
641 if (pIterator->GetWord(word)) {
642 ptNew =
643 CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
644
645 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400646 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y << " "
647 << kMoveTextPositionOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400648 ptOld = ptNew;
649 }
650
651 if (word.nFontIndex != nCurFontIndex) {
652 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
653 word.fFontSize);
654 nCurFontIndex = word.nFontIndex;
655 }
656
Dan Sinclairc08dc392017-07-24 08:57:35 -0400657 sEditStream << GetWordRenderString(
658 pEdit->GetPDFWordString(nCurFontIndex, word.Word, SubWord));
Dan Sinclair14ddd422017-07-20 11:07:00 -0400659 }
660 }
661 }
662
663 if (sWords.tellp() > 0) {
664 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
665 sWords.str("");
666 }
667
668 std::ostringstream sAppStream;
669 if (sEditStream.tellp() > 0) {
670 int32_t nHorzScale = pEdit->GetHorzScale();
671 if (nHorzScale != 100) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400672 sAppStream << nHorzScale << " " << kSetTextScaleHorizontalOperator
673 << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400674 }
675
676 float fCharSpace = pEdit->GetCharSpace();
677 if (!IsFloatZero(fCharSpace)) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400678 sAppStream << fCharSpace << " " << kSetCharacterSpacingOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400679 }
680
681 sAppStream << sEditStream.str();
682 }
683
684 return CFX_ByteString(sAppStream);
685}
686
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400687CFX_ByteString GenerateIconAppStream(CPDF_IconFit& fit,
688 CPDF_Stream* pIconStream,
689 const CFX_FloatRect& rcIcon) {
690 if (rcIcon.IsEmpty() || !pIconStream)
691 return CFX_ByteString();
692
693 CPWL_Icon icon;
694 PWL_CREATEPARAM cp;
695 cp.dwFlags = PWS_VISIBLE;
696 icon.Create(cp);
697 icon.SetIconFit(&fit);
698 icon.SetPDFStream(pIconStream);
699 icon.Move(rcIcon, false, false);
700
701 CFX_ByteString sAlias = icon.GetImageAlias();
702 if (sAlias.GetLength() <= 0)
703 return CFX_ByteString();
704
705 CFX_FloatRect rcPlate = icon.GetClientRect();
706 CFX_Matrix mt = icon.GetImageMatrix().GetInverse();
707
708 float fHScale;
709 float fVScale;
710 std::tie(fHScale, fVScale) = icon.GetScale();
711
712 float fx;
713 float fy;
714 std::tie(fx, fy) = icon.GetImageOffset();
715
716 std::ostringstream str;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400717 {
718 AutoClosedQCommand q(&str);
719 str << rcPlate.left << " " << rcPlate.bottom << " "
720 << rcPlate.right - rcPlate.left << " " << rcPlate.top - rcPlate.bottom
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400721 << " " << kAppendRectOperator << " " << kSetNonZeroWindingClipOperator
722 << " " << kEndPathNoFillOrStrokeOperator << "\n";
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400723
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400724 str << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400725 << rcPlate.bottom + fy << " " << kConcatMatrixOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400726 str << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " " << mt.e
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400727 << " " << mt.f << " " << kConcatMatrixOperator << "\n";
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400728
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400729 str << "0 " << kSetGrayOperator << " 0 " << kSetGrayStrokedOperator << " 1 "
730 << kSetLineWidthOperator << " /" << sAlias << " "
731 << kInvokeNamedXObjectOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400732 }
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400733 icon.Destroy();
734
735 return CFX_ByteString(str);
736}
737
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400738CFX_ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
739 IPVT_FontMap* pFontMap,
740 CPDF_Stream* pIconStream,
741 CPDF_IconFit& IconFit,
742 const CFX_WideString& sLabel,
743 const CFX_Color& crText,
744 float fFontSize,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400745 ButtonStyle nLayOut) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400746 const float fAutoFontScale = 1.0f / 3.0f;
747
Dan Sinclair6b0158f2017-07-24 09:42:55 -0400748 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400749 pEdit->SetFontMap(pFontMap);
750 pEdit->SetAlignmentH(1, true);
751 pEdit->SetAlignmentV(1, true);
752 pEdit->SetMultiLine(false, true);
753 pEdit->SetAutoReturn(false, true);
754 if (IsFloatZero(fFontSize))
755 pEdit->SetAutoFontSize(true, true);
756 else
757 pEdit->SetFontSize(fFontSize);
758
759 pEdit->Initialize();
760 pEdit->SetText(sLabel);
761
762 CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400763 CFX_FloatRect rcLabel;
764 CFX_FloatRect rcIcon;
765 float fWidth = 0.0f;
766 float fHeight = 0.0f;
767
768 switch (nLayOut) {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400769 case ButtonStyle::kLabel:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400770 rcLabel = rcBBox;
771 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400772 case ButtonStyle::kIcon:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400773 rcIcon = rcBBox;
774 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400775 case ButtonStyle::kIconTopLabelBottom:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400776 if (pIconStream) {
777 if (IsFloatZero(fFontSize)) {
778 fHeight = rcBBox.top - rcBBox.bottom;
779 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
780 rcBBox.bottom + fHeight * fAutoFontScale);
781 rcIcon =
782 CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
783 } else {
784 fHeight = rcLabelContent.Height();
785
786 if (rcBBox.bottom + fHeight > rcBBox.top) {
787 rcLabel = rcBBox;
788 } else {
789 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
790 rcBBox.bottom + fHeight);
791 rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
792 rcBBox.top);
793 }
794 }
795 } else {
796 rcLabel = rcBBox;
797 }
798 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400799 case ButtonStyle::kIconBottomLabelTop:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400800 if (pIconStream) {
801 if (IsFloatZero(fFontSize)) {
802 fHeight = rcBBox.top - rcBBox.bottom;
803 rcLabel =
804 CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
805 rcBBox.right, rcBBox.top);
806 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
807 rcLabel.bottom);
808 } else {
809 fHeight = rcLabelContent.Height();
810
811 if (rcBBox.bottom + fHeight > rcBBox.top) {
812 rcLabel = rcBBox;
813 } else {
814 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
815 rcBBox.right, rcBBox.top);
816 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
817 rcLabel.bottom);
818 }
819 }
820 } else {
821 rcLabel = rcBBox;
822 }
823 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400824 case ButtonStyle::kIconLeftLabelRight:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400825 if (pIconStream) {
826 if (IsFloatZero(fFontSize)) {
827 fWidth = rcBBox.right - rcBBox.left;
828 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
829 rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
830 rcBBox.bottom, rcBBox.right, rcBBox.top);
831 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
832 rcBBox.top);
833 } else {
834 if (rcLabelContent.Width() < fWidth) {
835 rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
836 rcBBox.bottom, rcBBox.right, rcBBox.top);
837 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
838 rcBBox.top);
839 } else {
840 rcLabel = rcBBox;
841 }
842 }
843 } else {
844 fWidth = rcLabelContent.Width();
845 if (rcBBox.left + fWidth > rcBBox.right) {
846 rcLabel = rcBBox;
847 } else {
848 rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
849 rcBBox.right, rcBBox.top);
850 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
851 rcBBox.top);
852 }
853 }
854 } else {
855 rcLabel = rcBBox;
856 }
857 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400858 case ButtonStyle::kIconRightLabelLeft:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400859 if (pIconStream) {
860 if (IsFloatZero(fFontSize)) {
861 fWidth = rcBBox.right - rcBBox.left;
862 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
863 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
864 rcBBox.left + fWidth * fAutoFontScale,
865 rcBBox.top);
866 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
867 rcBBox.top);
868 } else {
869 if (rcLabelContent.Width() < fWidth) {
870 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
871 rcBBox.left + rcLabelContent.Width(),
872 rcBBox.top);
873 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
874 rcBBox.top);
875 } else {
876 rcLabel = rcBBox;
877 }
878 }
879 } else {
880 fWidth = rcLabelContent.Width();
881 if (rcBBox.left + fWidth > rcBBox.right) {
882 rcLabel = rcBBox;
883 } else {
884 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
885 rcBBox.left + fWidth, rcBBox.top);
886 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
887 rcBBox.top);
888 }
889 }
890 } else {
891 rcLabel = rcBBox;
892 }
893 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400894 case ButtonStyle::kLabelOverIcon:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400895 rcLabel = rcBBox;
896 rcIcon = rcBBox;
897 break;
898 }
899
900 std::ostringstream sTemp;
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400901 sTemp << GenerateIconAppStream(IconFit, pIconStream, rcIcon);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400902
903 if (!rcLabel.IsEmpty()) {
904 pEdit->SetPlateRect(rcLabel);
905 CFX_ByteString sEdit =
Dan Sinclair14ddd422017-07-20 11:07:00 -0400906 GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f), true, 0);
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400907 if (sEdit.GetLength() > 0) {
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400908 AutoClosedCommand bt(&sTemp, kTextBeginOperator, kTextEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400909 sTemp << GetColorAppStream(crText, true) << sEdit;
910 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400911 }
912
913 if (sTemp.tellp() <= 0)
914 return CFX_ByteString();
915
916 std::ostringstream sAppStream;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400917 {
918 AutoClosedQCommand q(&sAppStream);
919 sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
920 << rcBBox.right - rcBBox.left << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400921 << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
922 << " " << kSetNonZeroWindingClipOperator << " "
923 << kEndPathNoFillOrStrokeOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400924 sAppStream << sTemp.str().c_str();
925 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400926 return CFX_ByteString(sAppStream);
927}
928
Dan Sinclair14ddd422017-07-20 11:07:00 -0400929CFX_ByteString GetBorderAppStreamInternal(const CFX_FloatRect& rect,
930 float fWidth,
931 const CFX_Color& color,
932 const CFX_Color& crLeftTop,
933 const CFX_Color& crRightBottom,
934 BorderStyle nStyle,
935 const CPWL_Dash& dash) {
936 std::ostringstream sAppStream;
937 CFX_ByteString sColor;
938
939 float fLeft = rect.left;
940 float fRight = rect.right;
941 float fTop = rect.top;
942 float fBottom = rect.bottom;
943
944 if (fWidth > 0.0f) {
945 float fHalfWidth = fWidth / 2.0f;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400946 AutoClosedQCommand q(&sAppStream);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400947
948 switch (nStyle) {
949 default:
950 case BorderStyle::SOLID:
951 sColor = GetColorAppStream(color, true);
952 if (sColor.GetLength() > 0) {
953 sAppStream << sColor;
954 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400955 << fTop - fBottom << " " << kAppendRectOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400956 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
957 << fRight - fLeft - fWidth * 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400958 << fTop - fBottom - fWidth * 2 << " "
959 << kAppendRectOperator << "\n";
960 sAppStream << kFillEvenOddOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400961 }
962 break;
963 case BorderStyle::DASH:
964 sColor = GetColorAppStream(color, false);
965 if (sColor.GetLength() > 0) {
966 sAppStream << sColor;
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400967 sAppStream << fWidth << " " << kSetLineWidthOperator << " ["
968 << dash.nDash << " " << dash.nGap << "] " << dash.nPhase
969 << " " << kSetDashOperator << "\n";
970 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
971 << kMoveToOperator << "\n";
972 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2 << " "
973 << kLineToOperator << "\n";
974 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2 << " "
975 << kLineToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400976 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400977 << " " << kLineToOperator << "\n";
978 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2 << " "
979 << kLineToOperator << " " << kStrokeOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400980 }
981 break;
982 case BorderStyle::BEVELED:
983 case BorderStyle::INSET:
984 sColor = GetColorAppStream(crLeftTop, true);
985 if (sColor.GetLength() > 0) {
986 sAppStream << sColor;
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400987 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
988 << kMoveToOperator << "\n";
989 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth << " "
990 << kLineToOperator << "\n";
991 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
992 << kLineToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400993 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400994 << " " << kLineToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400995 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400996 << " " << kLineToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -0400997 sAppStream << fLeft + fHalfWidth * 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -0400998 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
999 << " " << kFillOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001000 }
1001
1002 sColor = GetColorAppStream(crRightBottom, true);
1003 if (sColor.GetLength() > 0) {
1004 sAppStream << sColor;
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001005 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth << " "
1006 << kMoveToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001007 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001008 << " " << kLineToOperator << "\n";
1009 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1010 << kLineToOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001011 sAppStream << fLeft + fHalfWidth * 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001012 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
1013 << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001014 sAppStream << fRight - fHalfWidth * 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001015 << fBottom + fHalfWidth * 2 << " " << kLineToOperator
1016 << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001017 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001018 << " " << kLineToOperator << " " << kFillOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001019 }
1020
1021 sColor = GetColorAppStream(color, true);
1022 if (sColor.GetLength() > 0) {
1023 sAppStream << sColor;
1024 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001025 << fTop - fBottom << " " << kAppendRectOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001026 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
1027 << fRight - fLeft - fHalfWidth * 2 << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001028 << fTop - fBottom - fHalfWidth * 2 << " "
1029 << kAppendRectOperator << " " << kFillEvenOddOperator
1030 << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001031 }
1032 break;
1033 case BorderStyle::UNDERLINE:
1034 sColor = GetColorAppStream(color, false);
1035 if (sColor.GetLength() > 0) {
1036 sAppStream << sColor;
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001037 sAppStream << fWidth << " " << kSetLineWidthOperator << "\n";
1038 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " "
1039 << kMoveToOperator << "\n";
1040 sAppStream << fRight << " " << fBottom + fWidth / 2 << " "
1041 << kLineToOperator << " " << kStrokeOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001042 }
1043 break;
1044 }
Dan Sinclair14ddd422017-07-20 11:07:00 -04001045 }
1046
1047 return CFX_ByteString(sAppStream);
1048}
1049
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001050CFX_ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
1051 if (rcBBox.IsEmpty())
1052 return CFX_ByteString();
1053
1054 std::ostringstream sAppStream;
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001055 {
1056 AutoClosedQCommand q(&sAppStream);
1057 sAppStream << GetColorAppStream(CFX_Color(COLORTYPE_RGB, 220.0f / 255.0f,
1058 220.0f / 255.0f, 220.0f / 255.0f),
1059 true)
1060 << rcBBox.left << " " << rcBBox.bottom << " "
1061 << rcBBox.right - rcBBox.left << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001062 << rcBBox.top - rcBBox.bottom << " " << kAppendRectOperator
1063 << " " << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001064 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001065
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001066 {
1067 AutoClosedQCommand q(&sAppStream);
1068 sAppStream << GetBorderAppStreamInternal(
1069 rcBBox, 2, CFX_Color(COLORTYPE_GRAY, 0), CFX_Color(COLORTYPE_GRAY, 1),
1070 CFX_Color(COLORTYPE_GRAY, 0.5), BorderStyle::BEVELED,
1071 CPWL_Dash(3, 0, 0));
1072 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001073
1074 CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2,
1075 (rcBBox.top + rcBBox.bottom) / 2);
1076 if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) &&
1077 IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001078 AutoClosedQCommand q(&sAppStream);
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001079 sAppStream << " 0 " << kSetGrayOperator << "\n"
1080 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
1081 << kMoveToOperator << "\n"
1082 << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " "
1083 << kLineToOperator << "\n"
1084 << ptCenter.x << " " << ptCenter.y - 1.5f << " "
1085 << kLineToOperator << "\n"
1086 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " "
1087 << kLineToOperator << " " << kFillOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001088 }
1089
1090 return CFX_ByteString(sAppStream);
1091}
1092
Dan Sinclair14ddd422017-07-20 11:07:00 -04001093CFX_ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
1094 const CFX_Color& color) {
1095 std::ostringstream sAppStream;
1096 CFX_ByteString sColor = GetColorAppStream(color, true);
1097 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001098 AutoClosedQCommand q(&sAppStream);
1099 sAppStream << sColor << rect.left << " " << rect.bottom << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001100 << rect.right - rect.left << " " << rect.top - rect.bottom << " "
1101 << kAppendRectOperator << " " << kFillOperator << "\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001102 }
1103
1104 return CFX_ByteString(sAppStream);
1105}
1106
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001107} // namespace
1108
1109CPWL_AppStream::CPWL_AppStream(CPDFSDK_Widget* widget, CPDF_Dictionary* dict)
1110 : widget_(widget), dict_(dict) {}
1111
1112CPWL_AppStream::~CPWL_AppStream() {}
1113
1114void CPWL_AppStream::SetAsPushButton() {
1115 CPDF_FormControl* pControl = widget_->GetFormControl();
1116 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001117 ButtonStyle nLayout = ButtonStyle::kLabel;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001118 switch (pControl->GetTextPosition()) {
1119 case TEXTPOS_ICON:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001120 nLayout = ButtonStyle::kIcon;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001121 break;
1122 case TEXTPOS_BELOW:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001123 nLayout = ButtonStyle::kIconTopLabelBottom;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001124 break;
1125 case TEXTPOS_ABOVE:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001126 nLayout = ButtonStyle::kIconBottomLabelTop;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001127 break;
1128 case TEXTPOS_RIGHT:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001129 nLayout = ButtonStyle::kIconLeftLabelRight;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001130 break;
1131 case TEXTPOS_LEFT:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001132 nLayout = ButtonStyle::kIconRightLabelLeft;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001133 break;
1134 case TEXTPOS_OVERLAID:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001135 nLayout = ButtonStyle::kLabelOverIcon;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001136 break;
1137 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001138 nLayout = ButtonStyle::kLabel;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001139 break;
1140 }
1141
1142 CFX_Color crBackground;
1143 CFX_Color crBorder;
1144 int iColorType;
1145 float fc[4];
1146 pControl->GetOriginalBackgroundColor(iColorType, fc);
1147 if (iColorType > 0)
1148 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1149
1150 pControl->GetOriginalBorderColor(iColorType, fc);
1151 if (iColorType > 0)
1152 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1153
1154 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1155 CPWL_Dash dsBorder(3, 0, 0);
1156 CFX_Color crLeftTop;
1157 CFX_Color crRightBottom;
1158
1159 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1160 switch (nBorderStyle) {
1161 case BorderStyle::DASH:
1162 dsBorder = CPWL_Dash(3, 3, 0);
1163 break;
1164 case BorderStyle::BEVELED:
1165 fBorderWidth *= 2;
1166 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1167 crRightBottom = crBackground / 2.0f;
1168 break;
1169 case BorderStyle::INSET:
1170 fBorderWidth *= 2;
1171 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1172 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1173 break;
1174 default:
1175 break;
1176 }
1177
1178 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1179 CFX_Color crText(COLORTYPE_GRAY, 0);
1180 CFX_ByteString csNameTag;
1181 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1182 if (da.HasColor()) {
1183 da.GetColor(iColorType, fc);
1184 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1185 }
1186 float fFontSize = 12.0f;
1187 if (da.HasFont())
1188 csNameTag = da.GetFont(&fFontSize);
1189
1190 CFX_WideString csWCaption;
1191 CFX_WideString csNormalCaption;
1192 CFX_WideString csRolloverCaption;
1193 CFX_WideString csDownCaption;
1194 if (pControl->HasMKEntry("CA"))
1195 csNormalCaption = pControl->GetNormalCaption();
1196
1197 if (pControl->HasMKEntry("RC"))
1198 csRolloverCaption = pControl->GetRolloverCaption();
1199
1200 if (pControl->HasMKEntry("AC"))
1201 csDownCaption = pControl->GetDownCaption();
1202
1203 CPDF_Stream* pNormalIcon = nullptr;
1204 CPDF_Stream* pRolloverIcon = nullptr;
1205 CPDF_Stream* pDownIcon = nullptr;
1206 if (pControl->HasMKEntry("I"))
1207 pNormalIcon = pControl->GetNormalIcon();
1208
1209 if (pControl->HasMKEntry("RI"))
1210 pRolloverIcon = pControl->GetRolloverIcon();
1211
1212 if (pControl->HasMKEntry("IX"))
1213 pDownIcon = pControl->GetDownIcon();
1214
1215 if (pNormalIcon) {
1216 if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) {
1217 if (pImageDict->GetStringFor("Name").IsEmpty())
1218 pImageDict->SetNewFor<CPDF_String>("Name", "ImgA", false);
1219 }
1220 }
1221
1222 if (pRolloverIcon) {
1223 if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) {
1224 if (pImageDict->GetStringFor("Name").IsEmpty())
1225 pImageDict->SetNewFor<CPDF_String>("Name", "ImgB", false);
1226 }
1227 }
1228
1229 if (pDownIcon) {
1230 if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) {
1231 if (pImageDict->GetStringFor("Name").IsEmpty())
1232 pImageDict->SetNewFor<CPDF_String>("Name", "ImgC", false);
1233 }
1234 }
1235
1236 CPDF_IconFit iconFit = pControl->GetIconFit();
1237
1238 CBA_FontMap font_map(
1239 widget_.Get(),
1240 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1241 font_map.SetAPType("N");
1242
1243 CFX_ByteString csAP =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001244 GetRectFillAppStream(rcWindow, crBackground) +
1245 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1246 crRightBottom, nBorderStyle, dsBorder) +
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001247 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1248 &font_map, pNormalIcon, iconFit, csNormalCaption,
1249 crText, fFontSize, nLayout);
1250
1251 Write("N", csAP, "");
1252 if (pNormalIcon)
1253 AddImage("N", pNormalIcon);
1254
1255 CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
1256 if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
1257 if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
1258 csRolloverCaption = csNormalCaption;
1259 pRolloverIcon = pNormalIcon;
1260 }
1261
1262 font_map.SetAPType("R");
1263
1264 csAP =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001265 GetRectFillAppStream(rcWindow, crBackground) +
1266 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1267 crRightBottom, nBorderStyle, dsBorder) +
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001268 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1269 &font_map, pRolloverIcon, iconFit,
1270 csRolloverCaption, crText, fFontSize, nLayout);
1271
1272 Write("R", csAP, "");
1273 if (pRolloverIcon)
1274 AddImage("R", pRolloverIcon);
1275
1276 if (csDownCaption.IsEmpty() && !pDownIcon) {
1277 csDownCaption = csNormalCaption;
1278 pDownIcon = pNormalIcon;
1279 }
1280
1281 switch (nBorderStyle) {
1282 case BorderStyle::BEVELED: {
1283 CFX_Color crTemp = crLeftTop;
1284 crLeftTop = crRightBottom;
1285 crRightBottom = crTemp;
1286 break;
1287 }
1288 case BorderStyle::INSET: {
1289 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1290 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1291 break;
1292 }
1293 default:
1294 break;
1295 }
1296
1297 font_map.SetAPType("D");
1298
Dan Sinclair14ddd422017-07-20 11:07:00 -04001299 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);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001306
1307 Write("D", csAP, "");
1308 if (pDownIcon)
1309 AddImage("D", pDownIcon);
1310 } else {
1311 Remove("D");
1312 Remove("R");
1313 }
1314}
1315
1316void CPWL_AppStream::SetAsCheckBox() {
1317 CPDF_FormControl* pControl = widget_->GetFormControl();
1318 CFX_Color crBackground, crBorder, crText;
1319 int iColorType;
1320 float fc[4];
1321
1322 pControl->GetOriginalBackgroundColor(iColorType, fc);
1323 if (iColorType > 0)
1324 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1325
1326 pControl->GetOriginalBorderColor(iColorType, fc);
1327 if (iColorType > 0)
1328 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1329
1330 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1331 CPWL_Dash dsBorder(3, 0, 0);
1332 CFX_Color crLeftTop, crRightBottom;
1333
1334 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1335 switch (nBorderStyle) {
1336 case BorderStyle::DASH:
1337 dsBorder = CPWL_Dash(3, 3, 0);
1338 break;
1339 case BorderStyle::BEVELED:
1340 fBorderWidth *= 2;
1341 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1342 crRightBottom = crBackground / 2.0f;
1343 break;
1344 case BorderStyle::INSET:
1345 fBorderWidth *= 2;
1346 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1347 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1348 break;
1349 default:
1350 break;
1351 }
1352
1353 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1354 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1355 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1356 if (da.HasColor()) {
1357 da.GetColor(iColorType, fc);
1358 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1359 }
1360
Dan Sinclair14ddd422017-07-20 11:07:00 -04001361 CheckStyle nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001362 CFX_WideString csWCaption = pControl->GetNormalCaption();
1363 if (csWCaption.GetLength() > 0) {
1364 switch (csWCaption[0]) {
1365 case L'l':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001366 nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001367 break;
1368 case L'8':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001369 nStyle = CheckStyle::kCross;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001370 break;
1371 case L'u':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001372 nStyle = CheckStyle::kDiamond;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001373 break;
1374 case L'n':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001375 nStyle = CheckStyle::kSquare;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001376 break;
1377 case L'H':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001378 nStyle = CheckStyle::kStar;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001379 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -04001380 case L'4':
1381 default:
1382 nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001383 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001384 }
1385
1386 CFX_ByteString csAP_N_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001387 GetRectFillAppStream(rcWindow, crBackground) +
1388 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1389 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001390
1391 CFX_ByteString csAP_N_OFF = csAP_N_ON;
1392
1393 switch (nBorderStyle) {
1394 case BorderStyle::BEVELED: {
1395 CFX_Color crTemp = crLeftTop;
1396 crLeftTop = crRightBottom;
1397 crRightBottom = crTemp;
1398 break;
1399 }
1400 case BorderStyle::INSET: {
1401 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1402 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1403 break;
1404 }
1405 default:
1406 break;
1407 }
1408
1409 CFX_ByteString csAP_D_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001410 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1411 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1412 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001413
1414 CFX_ByteString csAP_D_OFF = csAP_D_ON;
1415
1416 csAP_N_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1417 csAP_D_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1418
1419 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1420 Write("N", csAP_N_OFF, "Off");
1421
1422 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1423 Write("D", csAP_D_OFF, "Off");
1424
1425 CFX_ByteString csAS = widget_->GetAppState();
1426 if (csAS.IsEmpty())
1427 widget_->SetAppState("Off");
1428}
1429
1430void CPWL_AppStream::SetAsRadioButton() {
1431 CPDF_FormControl* pControl = widget_->GetFormControl();
1432 CFX_Color crBackground;
1433 CFX_Color crBorder;
1434 CFX_Color crText;
1435 int iColorType;
1436 float fc[4];
1437
1438 pControl->GetOriginalBackgroundColor(iColorType, fc);
1439 if (iColorType > 0)
1440 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1441
1442 pControl->GetOriginalBorderColor(iColorType, fc);
1443 if (iColorType > 0)
1444 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1445
1446 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1447 CPWL_Dash dsBorder(3, 0, 0);
1448 CFX_Color crLeftTop;
1449 CFX_Color crRightBottom;
1450 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1451 switch (nBorderStyle) {
1452 case BorderStyle::DASH:
1453 dsBorder = CPWL_Dash(3, 3, 0);
1454 break;
1455 case BorderStyle::BEVELED:
1456 fBorderWidth *= 2;
1457 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1458 crRightBottom = crBackground / 2.0f;
1459 break;
1460 case BorderStyle::INSET:
1461 fBorderWidth *= 2;
1462 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1463 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1464 break;
1465 default:
1466 break;
1467 }
1468
1469 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1470 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1471 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1472 if (da.HasColor()) {
1473 da.GetColor(iColorType, fc);
1474 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1475 }
1476
Dan Sinclair14ddd422017-07-20 11:07:00 -04001477 CheckStyle nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001478 CFX_WideString csWCaption = pControl->GetNormalCaption();
1479 if (csWCaption.GetLength() > 0) {
1480 switch (csWCaption[0]) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001481 case L'8':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001482 nStyle = CheckStyle::kCross;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001483 break;
1484 case L'u':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001485 nStyle = CheckStyle::kDiamond;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001486 break;
1487 case L'n':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001488 nStyle = CheckStyle::kSquare;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001489 break;
1490 case L'H':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001491 nStyle = CheckStyle::kStar;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001492 break;
1493 case L'4':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001494 nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001495 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -04001496 case L'l':
1497 default:
1498 nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001499 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001500 }
1501
1502 CFX_ByteString csAP_N_ON;
1503 CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f);
Dan Sinclair14ddd422017-07-20 11:07:00 -04001504 if (nStyle == CheckStyle::kCircle) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001505 if (nBorderStyle == BorderStyle::BEVELED) {
1506 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1507 crRightBottom = crBackground - 0.25f;
1508 } else if (nBorderStyle == BorderStyle::INSET) {
1509 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5f);
1510 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75f);
1511 }
1512
1513 csAP_N_ON =
1514 GetCircleFillAppStream(rcCenter, crBackground) +
1515 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1516 crRightBottom, nBorderStyle, dsBorder);
1517 } else {
Dan Sinclair14ddd422017-07-20 11:07:00 -04001518 csAP_N_ON =
1519 GetRectFillAppStream(rcWindow, crBackground) +
1520 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1521 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001522 }
1523
1524 CFX_ByteString csAP_N_OFF = csAP_N_ON;
1525
1526 switch (nBorderStyle) {
1527 case BorderStyle::BEVELED: {
1528 CFX_Color crTemp = crLeftTop;
1529 crLeftTop = crRightBottom;
1530 crRightBottom = crTemp;
1531 break;
1532 }
1533 case BorderStyle::INSET: {
1534 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1535 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1536 break;
1537 }
1538 default:
1539 break;
1540 }
1541
1542 CFX_ByteString csAP_D_ON;
1543
Dan Sinclair14ddd422017-07-20 11:07:00 -04001544 if (nStyle == CheckStyle::kCircle) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001545 CFX_Color crBK = crBackground - 0.25f;
1546 if (nBorderStyle == BorderStyle::BEVELED) {
1547 crLeftTop = crBackground - 0.25f;
1548 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1549 crBK = crBackground;
1550 } else if (nBorderStyle == BorderStyle::INSET) {
1551 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1552 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1553 }
1554
1555 csAP_D_ON =
1556 GetCircleFillAppStream(rcCenter, crBK) +
1557 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1558 crRightBottom, nBorderStyle, dsBorder);
1559 } else {
1560 csAP_D_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001561 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1562 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1563 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001564 }
1565
1566 CFX_ByteString csAP_D_OFF = csAP_D_ON;
1567
1568 csAP_N_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1569 csAP_D_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1570
1571 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1572 Write("N", csAP_N_OFF, "Off");
1573
1574 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1575 Write("D", csAP_D_OFF, "Off");
1576
1577 CFX_ByteString csAS = widget_->GetAppState();
1578 if (csAS.IsEmpty())
1579 widget_->SetAppState("Off");
1580}
1581
1582void CPWL_AppStream::SetAsComboBox(const CFX_WideString* sValue) {
1583 CPDF_FormControl* pControl = widget_->GetFormControl();
1584 CPDF_FormField* pField = pControl->GetField();
1585 std::ostringstream sBody;
1586
1587 CFX_FloatRect rcClient = widget_->GetClientRect();
1588 CFX_FloatRect rcButton = rcClient;
1589 rcButton.left = rcButton.right - 13;
1590 rcButton.Normalize();
1591
Dan Sinclair6b0158f2017-07-24 09:42:55 -04001592 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001593 pEdit->EnableRefresh(false);
1594
1595 CBA_FontMap font_map(
1596 widget_.Get(),
1597 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1598 pEdit->SetFontMap(&font_map);
1599
1600 CFX_FloatRect rcEdit = rcClient;
1601 rcEdit.right = rcButton.left;
1602 rcEdit.Normalize();
1603
1604 pEdit->SetPlateRect(rcEdit);
1605 pEdit->SetAlignmentV(1, true);
1606
1607 float fFontSize = widget_->GetFontSize();
1608 if (IsFloatZero(fFontSize))
1609 pEdit->SetAutoFontSize(true, true);
1610 else
1611 pEdit->SetFontSize(fFontSize);
1612
1613 pEdit->Initialize();
1614
1615 if (sValue) {
1616 pEdit->SetText(*sValue);
1617 } else {
1618 int32_t nCurSel = pField->GetSelectedIndex(0);
1619 if (nCurSel < 0)
1620 pEdit->SetText(pField->GetValue());
1621 else
1622 pEdit->SetText(pField->GetOptionLabel(nCurSel));
1623 }
1624
1625 CFX_FloatRect rcContent = pEdit->GetContentRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001626 CFX_ByteString sEdit = GetEditAppStream(pEdit.get(), CFX_PointF(), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001627 if (sEdit.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001628 sBody << "/Tx ";
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001629 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1630 kMarkedSequenceEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001631 AutoClosedQCommand q(&sBody);
1632
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001633 if (rcContent.Width() > rcEdit.Width() ||
1634 rcContent.Height() > rcEdit.Height()) {
1635 sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001636 << " " << rcEdit.Height() << " " << kAppendRectOperator << "\n"
1637 << kSetNonZeroWindingClipOperator << "\n"
1638 << kEndPathNoFillOrStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001639 }
1640
1641 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001642 AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001643 sBody << GetColorAppStream(crText, true) << sEdit;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001644 }
1645
1646 sBody << GetDropButtonAppStream(rcButton);
1647 Write("N",
1648 GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody),
1649 "");
1650}
1651
1652void CPWL_AppStream::SetAsListBox() {
1653 CPDF_FormControl* pControl = widget_->GetFormControl();
1654 CPDF_FormField* pField = pControl->GetField();
1655 CFX_FloatRect rcClient = widget_->GetClientRect();
1656 std::ostringstream sBody;
1657
Dan Sinclair6b0158f2017-07-24 09:42:55 -04001658 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001659 pEdit->EnableRefresh(false);
1660
1661 CBA_FontMap font_map(
1662 widget_.Get(),
1663 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1664 pEdit->SetFontMap(&font_map);
1665 pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f));
1666
1667 float fFontSize = widget_->GetFontSize();
1668 pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
1669 pEdit->Initialize();
1670
1671 std::ostringstream sList;
1672 float fy = rcClient.top;
1673
1674 int32_t nTop = pField->GetTopVisibleIndex();
1675 int32_t nCount = pField->CountOptions();
1676 int32_t nSelCount = pField->CountSelectedItems();
1677
1678 for (int32_t i = nTop; i < nCount; ++i) {
1679 bool bSelected = false;
1680 for (int32_t j = 0; j < nSelCount; ++j) {
1681 if (pField->GetSelectedIndex(j) == i) {
1682 bSelected = true;
1683 break;
1684 }
1685 }
1686
1687 pEdit->SetText(pField->GetOptionLabel(i));
1688
1689 CFX_FloatRect rcContent = pEdit->GetContentRect();
1690 float fItemHeight = rcContent.Height();
1691
1692 if (bSelected) {
1693 CFX_FloatRect rcItem =
1694 CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001695 {
1696 AutoClosedQCommand q(&sList);
1697 sList << GetColorAppStream(CFX_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f,
1698 113.0f / 255.0f),
1699 true)
1700 << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001701 << " " << rcItem.Height() << " " << kAppendRectOperator << " "
1702 << kFillOperator << "\n";
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001703 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001704
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001705 AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001706 sList << GetColorAppStream(CFX_Color(COLORTYPE_GRAY, 1), true)
1707 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001708 } else {
1709 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001710
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001711 AutoClosedCommand bt(&sList, kTextBeginOperator, kTextEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001712 sList << GetColorAppStream(crText, true)
1713 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001714 }
1715
1716 fy -= fItemHeight;
1717 }
1718
1719 if (sList.tellp() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001720 sBody << "/Tx ";
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001721 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1722 kMarkedSequenceEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001723 AutoClosedQCommand q(&sBody);
1724
1725 sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001726 << " " << rcClient.Height() << " " << kAppendRectOperator << "\n"
1727 << kSetNonZeroWindingClipOperator << "\n"
1728 << kEndPathNoFillOrStrokeOperator << "\n"
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001729 << sList.str();
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001730 }
1731 Write("N",
1732 GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody),
1733 "");
1734}
1735
1736void CPWL_AppStream::SetAsTextField(const CFX_WideString* sValue) {
1737 CPDF_FormControl* pControl = widget_->GetFormControl();
1738 CPDF_FormField* pField = pControl->GetField();
1739 std::ostringstream sBody;
1740 std::ostringstream sLines;
1741
Dan Sinclair6b0158f2017-07-24 09:42:55 -04001742 auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>();
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001743 pEdit->EnableRefresh(false);
1744
1745 CBA_FontMap font_map(
1746 widget_.Get(),
1747 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1748 pEdit->SetFontMap(&font_map);
1749
1750 CFX_FloatRect rcClient = widget_->GetClientRect();
1751 pEdit->SetPlateRect(rcClient);
1752 pEdit->SetAlignmentH(pControl->GetControlAlignment(), true);
1753
1754 uint32_t dwFieldFlags = pField->GetFieldFlags();
1755 bool bMultiLine = (dwFieldFlags >> 12) & 1;
1756 if (bMultiLine) {
1757 pEdit->SetMultiLine(true, true);
1758 pEdit->SetAutoReturn(true, true);
1759 } else {
1760 pEdit->SetAlignmentV(1, true);
1761 }
1762
1763 uint16_t subWord = 0;
1764 if ((dwFieldFlags >> 13) & 1) {
1765 subWord = '*';
1766 pEdit->SetPasswordChar(subWord, true);
1767 }
1768
1769 int nMaxLen = pField->GetMaxLen();
1770 bool bCharArray = (dwFieldFlags >> 24) & 1;
1771 float fFontSize = widget_->GetFontSize();
1772
1773#ifdef PDF_ENABLE_XFA
1774 CFX_WideString sValueTmp;
1775 if (!sValue && widget_->GetMixXFAWidget()) {
1776 sValueTmp = widget_->GetValue(true);
1777 sValue = &sValueTmp;
1778 }
1779#endif // PDF_ENABLE_XFA
1780
1781 if (nMaxLen > 0) {
1782 if (bCharArray) {
1783 pEdit->SetCharArray(nMaxLen);
1784
1785 if (IsFloatZero(fFontSize)) {
1786 fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0),
1787 rcClient, nMaxLen);
1788 }
1789 } else {
1790 if (sValue)
1791 nMaxLen = sValue->GetLength();
1792 pEdit->SetLimitChar(nMaxLen);
1793 }
1794 }
1795
1796 if (IsFloatZero(fFontSize))
1797 pEdit->SetAutoFontSize(true, true);
1798 else
1799 pEdit->SetFontSize(fFontSize);
1800
1801 pEdit->Initialize();
1802 pEdit->SetText(sValue ? *sValue : pField->GetValue());
1803
1804 CFX_FloatRect rcContent = pEdit->GetContentRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001805 CFX_ByteString sEdit =
1806 GetEditAppStream(pEdit.get(), CFX_PointF(), !bCharArray, subWord);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001807
1808 if (sEdit.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001809 sBody << "/Tx ";
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001810 AutoClosedCommand bmc(&sBody, kMarkedSequenceBeginOperator,
1811 kMarkedSequenceEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001812 AutoClosedQCommand q(&sBody);
1813
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001814 if (rcContent.Width() > rcClient.Width() ||
1815 rcContent.Height() > rcClient.Height()) {
1816 sBody << rcClient.left << " " << rcClient.bottom << " "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001817 << rcClient.Width() << " " << rcClient.Height() << " "
1818 << kAppendRectOperator << "\n"
1819 << kSetNonZeroWindingClipOperator << "\n"
1820 << kEndPathNoFillOrStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001821 }
1822 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001823
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001824 AutoClosedCommand bt(&sBody, kTextBeginOperator, kTextEndOperator);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001825 sBody << GetColorAppStream(crText, true) << sEdit;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001826 }
1827
1828 if (bCharArray) {
1829 switch (widget_->GetBorderStyle()) {
1830 case BorderStyle::SOLID: {
1831 CFX_ByteString sColor =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001832 GetColorAppStream(widget_->GetBorderPWLColor(), false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001833 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001834 AutoClosedQCommand q(&sLines);
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001835 sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
1836 << "\n"
Dan Sinclair14ddd422017-07-20 11:07:00 -04001837 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001838 << " 2 " << kSetLineCapStyleOperator << " 0 "
1839 << kSetLineJoinStyleOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001840
1841 for (int32_t i = 1; i < nMaxLen; ++i) {
1842 sLines << rcClient.left +
1843 ((rcClient.right - rcClient.left) / nMaxLen) * i
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001844 << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001845 << rcClient.left +
1846 ((rcClient.right - rcClient.left) / nMaxLen) * i
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001847 << " " << rcClient.top << " " << kLineToOperator << " "
1848 << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001849 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001850 }
1851 break;
1852 }
1853 case BorderStyle::DASH: {
1854 CFX_ByteString sColor =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001855 GetColorAppStream(widget_->GetBorderPWLColor(), false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001856 if (sColor.GetLength() > 0) {
1857 CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001858 AutoClosedQCommand q(&sLines);
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001859 sLines << widget_->GetBorderWidth() << " " << kSetLineWidthOperator
1860 << "\n"
Dan Sinclair14ddd422017-07-20 11:07:00 -04001861 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001862 << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001863 << dsBorder.nPhase << " " << kSetDashOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001864
1865 for (int32_t i = 1; i < nMaxLen; ++i) {
1866 sLines << rcClient.left +
1867 ((rcClient.right - rcClient.left) / nMaxLen) * i
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001868 << " " << rcClient.bottom << " " << kMoveToOperator << "\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001869 << rcClient.left +
1870 ((rcClient.right - rcClient.left) / nMaxLen) * i
Dan Sinclairbeef5e42017-07-24 10:32:05 -04001871 << " " << rcClient.top << " " << kLineToOperator << " "
1872 << kStrokeOperator << "\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001873 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001874 }
1875 break;
1876 }
1877 default:
1878 break;
1879 }
1880 }
1881
1882 Write("N",
1883 GetBackgroundAppStream() + GetBorderAppStream() +
1884 CFX_ByteString(sLines) + CFX_ByteString(sBody),
1885 "");
1886}
1887
1888void CPWL_AppStream::AddImage(const CFX_ByteString& sAPType,
1889 CPDF_Stream* pImage) {
1890 CPDF_Stream* pStream = dict_->GetStreamFor(sAPType);
1891 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1892 CFX_ByteString sImageAlias = "IMG";
1893
1894 if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
1895 sImageAlias = pImageDict->GetStringFor("Name");
1896 if (sImageAlias.IsEmpty())
1897 sImageAlias = "IMG";
1898 }
1899
1900 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
1901 if (!pStreamResList)
1902 pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources");
1903
1904 CPDF_Dictionary* pXObject =
1905 pStreamResList->SetNewFor<CPDF_Dictionary>("XObject");
1906 pXObject->SetNewFor<CPDF_Reference>(sImageAlias,
1907 widget_->GetPageView()->GetPDFDocument(),
1908 pImage->GetObjNum());
1909}
1910
1911void CPWL_AppStream::Write(const CFX_ByteString& sAPType,
1912 const CFX_ByteString& sContents,
1913 const CFX_ByteString& sAPState) {
1914 CPDF_Stream* pStream = nullptr;
1915 CPDF_Dictionary* pParentDict = nullptr;
1916 if (sAPState.IsEmpty()) {
1917 pParentDict = dict_.Get();
1918 pStream = dict_->GetStreamFor(sAPType);
1919 } else {
1920 CPDF_Dictionary* pAPTypeDict = dict_->GetDictFor(sAPType);
1921 if (!pAPTypeDict)
1922 pAPTypeDict = dict_->SetNewFor<CPDF_Dictionary>(sAPType);
1923
1924 pParentDict = pAPTypeDict;
1925 pStream = pAPTypeDict->GetStreamFor(sAPState);
1926 }
1927
1928 if (!pStream) {
1929 CPDF_Document* doc = widget_->GetPageView()->GetPDFDocument();
1930 pStream = doc->NewIndirect<CPDF_Stream>();
1931 pParentDict->SetNewFor<CPDF_Reference>(sAPType, doc, pStream->GetObjNum());
1932 }
1933
1934 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1935 if (!pStreamDict) {
1936 auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>(
1937 widget_->GetPDFAnnot()->GetDocument()->GetByteStringPool());
1938 pStreamDict = pNewDict.get();
1939 pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
1940 pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
1941 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
1942 pStream->InitStream(nullptr, 0, std::move(pNewDict));
1943 }
1944 pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
1945 pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
Artem Strygin90555e02017-07-28 19:41:59 +03001946 pStream->SetDataAndRemoveFilter((uint8_t*)(sContents.c_str()),
1947 sContents.GetLength());
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001948}
1949
1950void CPWL_AppStream::Remove(const CFX_ByteString& sAPType) {
1951 dict_->RemoveFor(sAPType);
1952}
1953
1954CFX_ByteString CPWL_AppStream::GetBackgroundAppStream() const {
1955 CFX_Color crBackground = widget_->GetFillPWLColor();
1956 if (crBackground.nColorType != COLORTYPE_TRANSPARENT)
Dan Sinclair14ddd422017-07-20 11:07:00 -04001957 return GetRectFillAppStream(widget_->GetRotatedRect(), crBackground);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001958
1959 return CFX_ByteString();
1960}
1961
1962CFX_ByteString CPWL_AppStream::GetBorderAppStream() const {
1963 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1964 CFX_Color crBorder = widget_->GetBorderPWLColor();
1965 CFX_Color crBackground = widget_->GetFillPWLColor();
1966 CFX_Color crLeftTop;
1967 CFX_Color crRightBottom;
1968
1969 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1970 CPWL_Dash dsBorder(3, 0, 0);
1971
1972 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1973 switch (nBorderStyle) {
1974 case BorderStyle::DASH:
1975 dsBorder = CPWL_Dash(3, 3, 0);
1976 break;
1977 case BorderStyle::BEVELED:
1978 fBorderWidth *= 2;
1979 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1980 crRightBottom = crBackground / 2.0f;
1981 break;
1982 case BorderStyle::INSET:
1983 fBorderWidth *= 2;
1984 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1985 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1986 break;
1987 default:
1988 break;
1989 }
1990
Dan Sinclair14ddd422017-07-20 11:07:00 -04001991 return GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1992 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001993}