blob: 969c521d6862f4cac10737bb954cd85a48ebdade [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
7#include "fpdfsdk/pdfwindow/cpwl_appstream.h"
8
9#include <utility>
10
11#include "core/fpdfapi/parser/cpdf_dictionary.h"
12#include "core/fpdfapi/parser/cpdf_document.h"
13#include "core/fpdfapi/parser/cpdf_name.h"
14#include "core/fpdfapi/parser/cpdf_number.h"
15#include "core/fpdfapi/parser/cpdf_reference.h"
16#include "core/fpdfapi/parser/cpdf_stream.h"
17#include "core/fpdfapi/parser/cpdf_string.h"
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"
25#include "fpdfsdk/fxedit/fxet_edit.h"
26#include "fpdfsdk/pdfwindow/cpwl_edit.h"
27#include "fpdfsdk/pdfwindow/cpwl_icon.h"
Dan Sinclaircb2ea422017-07-19 15:24:49 -040028#include "fpdfsdk/pdfwindow/cpwl_wnd.h"
29
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 Sinclaire03f8b12017-07-20 11:08:21 -040046class AutoClosedCommand {
47 public:
48 AutoClosedCommand(std::ostringstream* stream,
49 CFX_ByteString open,
50 CFX_ByteString close)
51 : stream_(stream), close_(close) {
52 *stream_ << open << "\n";
53 }
54
55 virtual ~AutoClosedCommand() { *stream_ << close_ << "\n"; }
56
57 private:
58 std::ostringstream* stream_;
59 CFX_ByteString close_;
60};
61
62class AutoClosedQCommand : public AutoClosedCommand {
63 public:
64 explicit AutoClosedQCommand(std::ostringstream* stream)
65 : AutoClosedCommand(stream, "q", "Q") {}
66 ~AutoClosedQCommand() override {}
67};
68
Dan Sinclair14ddd422017-07-20 11:07:00 -040069CFX_ByteString GetColorAppStream(const CFX_Color& color,
70 const bool& bFillOrStroke) {
71 std::ostringstream sColorStream;
72
73 switch (color.nColorType) {
74 case COLORTYPE_RGB:
75 sColorStream << color.fColor1 << " " << color.fColor2 << " "
76 << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG")
77 << "\n";
78 break;
79 case COLORTYPE_GRAY:
80 sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G")
81 << "\n";
82 break;
83 case COLORTYPE_CMYK:
84 sColorStream << color.fColor1 << " " << color.fColor2 << " "
85 << color.fColor3 << " " << color.fColor4 << " "
86 << (bFillOrStroke ? "k" : "K") << "\n";
87 break;
88 }
89
90 return CFX_ByteString(sColorStream);
91}
92
Dan Sinclaircb2ea422017-07-19 15:24:49 -040093CFX_ByteString GetAP_Check(const CFX_FloatRect& crBBox) {
94 const float fWidth = crBBox.right - crBBox.left;
95 const float fHeight = crBBox.top - crBBox.bottom;
96
97 CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f),
98 CFX_PointF(0.29f, 0.40f)},
99 {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f),
100 CFX_PointF(0.31f, 0.28f)},
101 {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f),
102 CFX_PointF(0.77f, 0.67f)},
103 {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f),
104 CFX_PointF(0.76f, 0.75f)},
105 {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f),
106 CFX_PointF(0.68f, 0.75f)},
107 {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f),
108 CFX_PointF(0.44f, 0.47f)},
109 {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f),
110 CFX_PointF(0.41f, 0.58f)},
111 {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f),
112 CFX_PointF(0.30f, 0.56f)}};
113
114 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
115 for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) {
116 pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
117 pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
118 }
119 }
120
121 std::ostringstream csAP;
122 csAP << pts[0][0].x << " " << pts[0][0].y << " m\n";
123
124 for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
125 size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
126
127 float px1 = pts[i][1].x - pts[i][0].x;
128 float py1 = pts[i][1].y - pts[i][0].y;
129 float px2 = pts[i][2].x - pts[nNext][0].x;
130 float py2 = pts[i][2].y - pts[nNext][0].y;
131
132 csAP << pts[i][0].x + px1 * FX_BEZIER << " "
133 << pts[i][0].y + py1 * FX_BEZIER << " "
134 << pts[nNext][0].x + px2 * FX_BEZIER << " "
135 << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
136 << pts[nNext][0].y << " c\n";
137 }
138
139 return CFX_ByteString(csAP);
140}
141
142CFX_ByteString GetAP_Circle(const CFX_FloatRect& crBBox) {
143 std::ostringstream csAP;
144
145 float fWidth = crBBox.right - crBBox.left;
146 float fHeight = crBBox.top - crBBox.bottom;
147
148 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
149 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
150 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
151 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
152
153 csAP << pt1.x << " " << pt1.y << " m\n";
154
155 float px = pt2.x - pt1.x;
156 float py = pt2.y - pt1.y;
157
158 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
159 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
160 << " c\n";
161
162 px = pt3.x - pt2.x;
163 py = pt2.y - pt3.y;
164
165 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
166 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
167
168 px = pt3.x - pt4.x;
169 py = pt3.y - pt4.y;
170
171 csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
172 << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
173 << " c\n";
174
175 px = pt4.x - pt1.x;
176 py = pt1.y - pt4.y;
177
178 csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
179 << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " c\n";
180
181 return CFX_ByteString(csAP);
182}
183
184CFX_ByteString GetAP_Cross(const CFX_FloatRect& crBBox) {
185 std::ostringstream csAP;
186
187 csAP << crBBox.left << " " << crBBox.top << " m\n";
188 csAP << crBBox.right << " " << crBBox.bottom << " l\n";
189 csAP << crBBox.left << " " << crBBox.bottom << " m\n";
190 csAP << crBBox.right << " " << crBBox.top << " l\n";
191
192 return CFX_ByteString(csAP);
193}
194
195CFX_ByteString GetAP_Diamond(const CFX_FloatRect& crBBox) {
196 std::ostringstream csAP;
197
198 float fWidth = crBBox.right - crBBox.left;
199 float fHeight = crBBox.top - crBBox.bottom;
200
201 CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
202 CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
203 CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
204 CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
205
206 csAP << pt1.x << " " << pt1.y << " m\n";
207 csAP << pt2.x << " " << pt2.y << " l\n";
208 csAP << pt3.x << " " << pt3.y << " l\n";
209 csAP << pt4.x << " " << pt4.y << " l\n";
210 csAP << pt1.x << " " << pt1.y << " l\n";
211
212 return CFX_ByteString(csAP);
213}
214
215CFX_ByteString GetAP_Square(const CFX_FloatRect& crBBox) {
216 std::ostringstream csAP;
217
218 csAP << crBBox.left << " " << crBBox.top << " m\n";
219 csAP << crBBox.right << " " << crBBox.top << " l\n";
220 csAP << crBBox.right << " " << crBBox.bottom << " l\n";
221 csAP << crBBox.left << " " << crBBox.bottom << " l\n";
222 csAP << crBBox.left << " " << crBBox.top << " l\n";
223
224 return CFX_ByteString(csAP);
225}
226
227CFX_ByteString GetAP_Star(const CFX_FloatRect& crBBox) {
228 std::ostringstream csAP;
229
230 float fRadius = (crBBox.top - crBBox.bottom) / (1 + (float)cos(FX_PI / 5.0f));
231 CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
232 (crBBox.top + crBBox.bottom) / 2.0f);
233
234 float px[5];
235 float py[5];
236 float fAngel = FX_PI / 10.0f;
237 for (int32_t i = 0; i < 5; i++) {
238 px[i] = ptCenter.x + fRadius * (float)cos(fAngel);
239 py[i] = ptCenter.y + fRadius * (float)sin(fAngel);
240 fAngel += FX_PI * 2 / 5.0f;
241 }
242
243 csAP << px[0] << " " << py[0] << " m\n";
244
245 int32_t nNext = 0;
246 for (int32_t j = 0; j < 5; j++) {
247 nNext += 2;
248 if (nNext >= 5)
249 nNext -= 5;
250 csAP << px[nNext] << " " << py[nNext] << " l\n";
251 }
252
253 return CFX_ByteString(csAP);
254}
255
256CFX_ByteString GetAP_HalfCircle(const CFX_FloatRect& crBBox, float fRotate) {
257 std::ostringstream csAP;
258
259 float fWidth = crBBox.right - crBBox.left;
260 float fHeight = crBBox.top - crBBox.bottom;
261
262 CFX_PointF pt1(-fWidth / 2, 0);
263 CFX_PointF pt2(0, fHeight / 2);
264 CFX_PointF pt3(fWidth / 2, 0);
265
266 float px;
267 float py;
268
269 csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
270 << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
271 << crBBox.bottom + fHeight / 2 << " cm\n";
272
273 csAP << pt1.x << " " << pt1.y << " m\n";
274
275 px = pt2.x - pt1.x;
276 py = pt2.y - pt1.y;
277
278 csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
279 << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
280 << " c\n";
281
282 px = pt3.x - pt2.x;
283 py = pt2.y - pt3.y;
284
285 csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
286 << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
287
288 return CFX_ByteString(csAP);
289}
290
291CFX_ByteString GetAppStream_Check(const CFX_FloatRect& rcBBox,
292 const CFX_Color& crText) {
293 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400294 {
295 AutoClosedQCommand q(&sAP);
296 sAP << GetColorAppStream(crText, true) << GetAP_Check(rcBBox) << "f\n";
297 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400298 return CFX_ByteString(sAP);
299}
300
301CFX_ByteString GetAppStream_Circle(const CFX_FloatRect& rcBBox,
302 const CFX_Color& crText) {
303 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400304 {
305 AutoClosedQCommand q(&sAP);
306 sAP << GetColorAppStream(crText, true) << GetAP_Circle(rcBBox) << "f\n";
307 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400308 return CFX_ByteString(sAP);
309}
310
311CFX_ByteString GetAppStream_Cross(const CFX_FloatRect& rcBBox,
312 const CFX_Color& crText) {
313 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400314 {
315 AutoClosedQCommand q(&sAP);
316 sAP << GetColorAppStream(crText, false) << GetAP_Cross(rcBBox) << "S\n";
317 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400318 return CFX_ByteString(sAP);
319}
320
321CFX_ByteString GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
322 const CFX_Color& crText) {
323 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400324 {
325 AutoClosedQCommand q(&sAP);
326 sAP << "1 w\n"
327 << GetColorAppStream(crText, true) << GetAP_Diamond(rcBBox) << "f\n";
328 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400329 return CFX_ByteString(sAP);
330}
331
332CFX_ByteString GetAppStream_Square(const CFX_FloatRect& rcBBox,
333 const CFX_Color& crText) {
334 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400335 {
336 AutoClosedQCommand q(&sAP);
337 sAP << GetColorAppStream(crText, true) << GetAP_Square(rcBBox) << "f\n";
338 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400339 return CFX_ByteString(sAP);
340}
341
342CFX_ByteString GetAppStream_Star(const CFX_FloatRect& rcBBox,
343 const CFX_Color& crText) {
344 std::ostringstream sAP;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400345 {
346 AutoClosedQCommand q(&sAP);
347 sAP << GetColorAppStream(crText, true) << GetAP_Star(rcBBox) << "f\n";
348 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400349 return CFX_ByteString(sAP);
350}
351
352CFX_ByteString GetCircleFillAppStream(const CFX_FloatRect& rect,
353 const CFX_Color& color) {
354 std::ostringstream sAppStream;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400355 CFX_ByteString sColor = GetColorAppStream(color, true);
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400356 if (sColor.GetLength() > 0) {
357 AutoClosedQCommand q(&sAppStream);
358 sAppStream << sColor << GetAP_Circle(rect) << "f\n";
359 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400360 return CFX_ByteString(sAppStream);
361}
362
363CFX_ByteString GetCircleBorderAppStream(const CFX_FloatRect& rect,
364 float fWidth,
365 const CFX_Color& color,
366 const CFX_Color& crLeftTop,
367 const CFX_Color& crRightBottom,
368 BorderStyle nStyle,
369 const CPWL_Dash& dash) {
370 std::ostringstream sAppStream;
371 CFX_ByteString sColor;
372
373 if (fWidth > 0.0f) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400374 AutoClosedQCommand q(&sAppStream);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400375
376 float fHalfWidth = fWidth / 2.0f;
377 CFX_FloatRect rect_by_2 = rect.GetDeflated(fHalfWidth, fHalfWidth);
378
379 float div = fHalfWidth * 0.75f;
380 CFX_FloatRect rect_by_75 = rect.GetDeflated(div, div);
381 switch (nStyle) {
382 default:
383 case BorderStyle::SOLID:
384 case BorderStyle::UNDERLINE: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400385 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400386 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400387 AutoClosedQCommand q2(&sAppStream);
388 sAppStream << fWidth << " w\n"
389 << sColor << GetAP_Circle(rect_by_2) << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400390 }
391 } break;
392 case BorderStyle::DASH: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400393 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400394 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400395 AutoClosedQCommand q2(&sAppStream);
396 sAppStream << fWidth << " w\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400397 << "[" << dash.nDash << " " << dash.nGap << "] "
398 << dash.nPhase << " d\n"
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400399 << sColor << GetAP_Circle(rect_by_2) << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400400 }
401 } break;
402 case BorderStyle::BEVELED: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400403 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400404 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400405 AutoClosedQCommand q2(&sAppStream);
406 sAppStream << fHalfWidth << " w\n"
407 << sColor << GetAP_Circle(rect) << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400408 }
409
Dan Sinclair14ddd422017-07-20 11:07:00 -0400410 sColor = GetColorAppStream(crLeftTop, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400411 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400412 AutoClosedQCommand q2(&sAppStream);
413 sAppStream << fHalfWidth << " w\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400414 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400415 << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400416 }
417
Dan Sinclair14ddd422017-07-20 11:07:00 -0400418 sColor = GetColorAppStream(crRightBottom, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400419 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400420 AutoClosedQCommand q2(&sAppStream);
421 sAppStream << fHalfWidth << " w\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400422 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400423 << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400424 }
425 } break;
426 case BorderStyle::INSET: {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400427 sColor = GetColorAppStream(color, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400428 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400429 AutoClosedQCommand q2(&sAppStream);
430 sAppStream << fHalfWidth << " w\n"
431 << sColor << GetAP_Circle(rect) << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400432 }
433
Dan Sinclair14ddd422017-07-20 11:07:00 -0400434 sColor = GetColorAppStream(crLeftTop, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400435 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400436 AutoClosedQCommand q2(&sAppStream);
437 sAppStream << fHalfWidth << " w\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400438 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI / 4.0f)
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400439 << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400440 }
441
Dan Sinclair14ddd422017-07-20 11:07:00 -0400442 sColor = GetColorAppStream(crRightBottom, false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400443 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400444 AutoClosedQCommand q2(&sAppStream);
445 sAppStream << fHalfWidth << " w\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400446 << sColor << GetAP_HalfCircle(rect_by_75, FX_PI * 5 / 4.0f)
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400447 << " S\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400448 }
449 } break;
450 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400451 }
452 return CFX_ByteString(sAppStream);
453}
454
455CFX_ByteString GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400456 CheckStyle nStyle,
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400457 const CFX_Color& crText) {
458 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
459 switch (nStyle) {
460 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -0400461 case CheckStyle::kCheck:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400462 return GetAppStream_Check(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400463 case CheckStyle::kCircle:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400464 rcCenter.Scale(2.0f / 3.0f);
465 return GetAppStream_Circle(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400466 case CheckStyle::kCross:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400467 return GetAppStream_Cross(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400468 case CheckStyle::kDiamond:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400469 rcCenter.Scale(2.0f / 3.0f);
470 return GetAppStream_Diamond(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400471 case CheckStyle::kSquare:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400472 rcCenter.Scale(2.0f / 3.0f);
473 return GetAppStream_Square(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400474 case CheckStyle::kStar:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400475 rcCenter.Scale(2.0f / 3.0f);
476 return GetAppStream_Star(rcCenter, crText);
477 }
478}
479
480CFX_ByteString GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400481 CheckStyle nStyle,
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400482 const CFX_Color& crText) {
483 CFX_FloatRect rcCenter = rcBBox.GetCenterSquare();
484 switch (nStyle) {
485 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -0400486 case CheckStyle::kCheck:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400487 return GetAppStream_Check(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400488 case CheckStyle::kCircle:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400489 rcCenter.Scale(1.0f / 2.0f);
490 return GetAppStream_Circle(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400491 case CheckStyle::kCross:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400492 return GetAppStream_Cross(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400493 case CheckStyle::kDiamond:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400494 rcCenter.Scale(2.0f / 3.0f);
495 return GetAppStream_Diamond(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400496 case CheckStyle::kSquare:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400497 rcCenter.Scale(2.0f / 3.0f);
498 return GetAppStream_Square(rcCenter, crText);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400499 case CheckStyle::kStar:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400500 rcCenter.Scale(2.0f / 3.0f);
501 return GetAppStream_Star(rcCenter, crText);
502 }
503}
504
Dan Sinclair14ddd422017-07-20 11:07:00 -0400505CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
506 int32_t nFontIndex,
507 float fFontSize) {
508 if (!pFontMap)
509 return CFX_ByteString();
510
511 CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
512 if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
513 return CFX_ByteString();
514
515 std::ostringstream sRet;
516 sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
517 return CFX_ByteString(sRet);
518}
519
520CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) {
521 if (strWords.GetLength() > 0)
522 return PDF_EncodeString(strWords, false) + " Tj\n";
523 return CFX_ByteString();
524}
525
526CFX_ByteString GetEditAppStream(CFX_Edit* pEdit,
527 const CFX_PointF& ptOffset,
528 bool bContinuous,
529 uint16_t SubWord) {
530 CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
531 pIterator->SetAt(0);
532
533 std::ostringstream sEditStream;
534 std::ostringstream sWords;
535 int32_t nCurFontIndex = -1;
536 CFX_PointF ptOld;
537 CFX_PointF ptNew;
538 CPVT_WordPlace oldplace;
539
540 while (pIterator->NextWord()) {
541 CPVT_WordPlace place = pIterator->GetAt();
542 if (bContinuous) {
543 if (place.LineCmp(oldplace) != 0) {
544 if (sWords.tellp() > 0) {
545 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
546 sWords.str("");
547 }
548
549 CPVT_Word word;
550 if (pIterator->GetWord(word)) {
551 ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
552 word.ptWord.y + ptOffset.y);
553 } else {
554 CPVT_Line line;
555 pIterator->GetLine(line);
556 ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
557 line.ptLine.y + ptOffset.y);
558 }
559
560 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
561 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
562 << " Td\n";
563
564 ptOld = ptNew;
565 }
566 }
567
568 CPVT_Word word;
569 if (pIterator->GetWord(word)) {
570 if (word.nFontIndex != nCurFontIndex) {
571 if (sWords.tellp() > 0) {
572 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
573 sWords.str("");
574 }
575 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
576 word.fFontSize);
577 nCurFontIndex = word.nFontIndex;
578 }
579
580 sWords << GetPDFWordString(pEdit->GetFontMap(), nCurFontIndex,
581 word.Word, SubWord);
582 }
583
584 oldplace = place;
585 } else {
586 CPVT_Word word;
587 if (pIterator->GetWord(word)) {
588 ptNew =
589 CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
590
591 if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
592 sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
593 << " Td\n";
594 ptOld = ptNew;
595 }
596
597 if (word.nFontIndex != nCurFontIndex) {
598 sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
599 word.fFontSize);
600 nCurFontIndex = word.nFontIndex;
601 }
602
603 sEditStream << GetWordRenderString(GetPDFWordString(
604 pEdit->GetFontMap(), nCurFontIndex, word.Word, SubWord));
605 }
606 }
607 }
608
609 if (sWords.tellp() > 0) {
610 sEditStream << GetWordRenderString(CFX_ByteString(sWords));
611 sWords.str("");
612 }
613
614 std::ostringstream sAppStream;
615 if (sEditStream.tellp() > 0) {
616 int32_t nHorzScale = pEdit->GetHorzScale();
617 if (nHorzScale != 100) {
618 sAppStream << nHorzScale << " Tz\n";
619 }
620
621 float fCharSpace = pEdit->GetCharSpace();
622 if (!IsFloatZero(fCharSpace)) {
623 sAppStream << fCharSpace << " Tc\n";
624 }
625
626 sAppStream << sEditStream.str();
627 }
628
629 return CFX_ByteString(sAppStream);
630}
631
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400632CFX_ByteString GenerateIconAppStream(CPDF_IconFit& fit,
633 CPDF_Stream* pIconStream,
634 const CFX_FloatRect& rcIcon) {
635 if (rcIcon.IsEmpty() || !pIconStream)
636 return CFX_ByteString();
637
638 CPWL_Icon icon;
639 PWL_CREATEPARAM cp;
640 cp.dwFlags = PWS_VISIBLE;
641 icon.Create(cp);
642 icon.SetIconFit(&fit);
643 icon.SetPDFStream(pIconStream);
644 icon.Move(rcIcon, false, false);
645
646 CFX_ByteString sAlias = icon.GetImageAlias();
647 if (sAlias.GetLength() <= 0)
648 return CFX_ByteString();
649
650 CFX_FloatRect rcPlate = icon.GetClientRect();
651 CFX_Matrix mt = icon.GetImageMatrix().GetInverse();
652
653 float fHScale;
654 float fVScale;
655 std::tie(fHScale, fVScale) = icon.GetScale();
656
657 float fx;
658 float fy;
659 std::tie(fx, fy) = icon.GetImageOffset();
660
661 std::ostringstream str;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400662 {
663 AutoClosedQCommand q(&str);
664 str << rcPlate.left << " " << rcPlate.bottom << " "
665 << rcPlate.right - rcPlate.left << " " << rcPlate.top - rcPlate.bottom
666 << " re W n\n";
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400667
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400668 str << fHScale << " 0 0 " << fVScale << " " << rcPlate.left + fx << " "
669 << rcPlate.bottom + fy << " cm\n";
670 str << mt.a << " " << mt.b << " " << mt.c << " " << mt.d << " " << mt.e
671 << " " << mt.f << " cm\n";
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400672
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400673 str << "0 g 0 G 1 w /" << sAlias << " Do\n";
674 }
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400675 icon.Destroy();
676
677 return CFX_ByteString(str);
678}
679
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400680CFX_ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
681 IPVT_FontMap* pFontMap,
682 CPDF_Stream* pIconStream,
683 CPDF_IconFit& IconFit,
684 const CFX_WideString& sLabel,
685 const CFX_Color& crText,
686 float fFontSize,
Dan Sinclair14ddd422017-07-20 11:07:00 -0400687 ButtonStyle nLayOut) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400688 const float fAutoFontScale = 1.0f / 3.0f;
689
690 auto pEdit = pdfium::MakeUnique<CFX_Edit>();
691 pEdit->SetFontMap(pFontMap);
692 pEdit->SetAlignmentH(1, true);
693 pEdit->SetAlignmentV(1, true);
694 pEdit->SetMultiLine(false, true);
695 pEdit->SetAutoReturn(false, true);
696 if (IsFloatZero(fFontSize))
697 pEdit->SetAutoFontSize(true, true);
698 else
699 pEdit->SetFontSize(fFontSize);
700
701 pEdit->Initialize();
702 pEdit->SetText(sLabel);
703
704 CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400705 CFX_FloatRect rcLabel;
706 CFX_FloatRect rcIcon;
707 float fWidth = 0.0f;
708 float fHeight = 0.0f;
709
710 switch (nLayOut) {
Dan Sinclair14ddd422017-07-20 11:07:00 -0400711 case ButtonStyle::kLabel:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400712 rcLabel = rcBBox;
713 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400714 case ButtonStyle::kIcon:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400715 rcIcon = rcBBox;
716 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400717 case ButtonStyle::kIconTopLabelBottom:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400718 if (pIconStream) {
719 if (IsFloatZero(fFontSize)) {
720 fHeight = rcBBox.top - rcBBox.bottom;
721 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
722 rcBBox.bottom + fHeight * fAutoFontScale);
723 rcIcon =
724 CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
725 } else {
726 fHeight = rcLabelContent.Height();
727
728 if (rcBBox.bottom + fHeight > rcBBox.top) {
729 rcLabel = rcBBox;
730 } else {
731 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
732 rcBBox.bottom + fHeight);
733 rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
734 rcBBox.top);
735 }
736 }
737 } else {
738 rcLabel = rcBBox;
739 }
740 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400741 case ButtonStyle::kIconBottomLabelTop:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400742 if (pIconStream) {
743 if (IsFloatZero(fFontSize)) {
744 fHeight = rcBBox.top - rcBBox.bottom;
745 rcLabel =
746 CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
747 rcBBox.right, rcBBox.top);
748 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
749 rcLabel.bottom);
750 } else {
751 fHeight = rcLabelContent.Height();
752
753 if (rcBBox.bottom + fHeight > rcBBox.top) {
754 rcLabel = rcBBox;
755 } else {
756 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
757 rcBBox.right, rcBBox.top);
758 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
759 rcLabel.bottom);
760 }
761 }
762 } else {
763 rcLabel = rcBBox;
764 }
765 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400766 case ButtonStyle::kIconLeftLabelRight:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400767 if (pIconStream) {
768 if (IsFloatZero(fFontSize)) {
769 fWidth = rcBBox.right - rcBBox.left;
770 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
771 rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
772 rcBBox.bottom, rcBBox.right, rcBBox.top);
773 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
774 rcBBox.top);
775 } else {
776 if (rcLabelContent.Width() < fWidth) {
777 rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
778 rcBBox.bottom, rcBBox.right, rcBBox.top);
779 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
780 rcBBox.top);
781 } else {
782 rcLabel = rcBBox;
783 }
784 }
785 } else {
786 fWidth = rcLabelContent.Width();
787 if (rcBBox.left + fWidth > rcBBox.right) {
788 rcLabel = rcBBox;
789 } else {
790 rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
791 rcBBox.right, rcBBox.top);
792 rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
793 rcBBox.top);
794 }
795 }
796 } else {
797 rcLabel = rcBBox;
798 }
799 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400800 case ButtonStyle::kIconRightLabelLeft:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400801 if (pIconStream) {
802 if (IsFloatZero(fFontSize)) {
803 fWidth = rcBBox.right - rcBBox.left;
804 if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
805 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
806 rcBBox.left + fWidth * fAutoFontScale,
807 rcBBox.top);
808 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
809 rcBBox.top);
810 } else {
811 if (rcLabelContent.Width() < fWidth) {
812 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
813 rcBBox.left + rcLabelContent.Width(),
814 rcBBox.top);
815 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
816 rcBBox.top);
817 } else {
818 rcLabel = rcBBox;
819 }
820 }
821 } else {
822 fWidth = rcLabelContent.Width();
823 if (rcBBox.left + fWidth > rcBBox.right) {
824 rcLabel = rcBBox;
825 } else {
826 rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
827 rcBBox.left + fWidth, rcBBox.top);
828 rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
829 rcBBox.top);
830 }
831 }
832 } else {
833 rcLabel = rcBBox;
834 }
835 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -0400836 case ButtonStyle::kLabelOverIcon:
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400837 rcLabel = rcBBox;
838 rcIcon = rcBBox;
839 break;
840 }
841
842 std::ostringstream sTemp;
Dan Sinclairdc11ec82017-07-20 11:08:03 -0400843 sTemp << GenerateIconAppStream(IconFit, pIconStream, rcIcon);
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400844
845 if (!rcLabel.IsEmpty()) {
846 pEdit->SetPlateRect(rcLabel);
847 CFX_ByteString sEdit =
Dan Sinclair14ddd422017-07-20 11:07:00 -0400848 GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f), true, 0);
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400849 if (sEdit.GetLength() > 0) {
850 AutoClosedCommand bt(&sTemp, "BT", "ET");
851 sTemp << GetColorAppStream(crText, true) << sEdit;
852 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400853 }
854
855 if (sTemp.tellp() <= 0)
856 return CFX_ByteString();
857
858 std::ostringstream sAppStream;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400859 {
860 AutoClosedQCommand q(&sAppStream);
861 sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
862 << rcBBox.right - rcBBox.left << " "
863 << rcBBox.top - rcBBox.bottom << " re W n\n";
864 sAppStream << sTemp.str().c_str();
865 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400866 return CFX_ByteString(sAppStream);
867}
868
Dan Sinclair14ddd422017-07-20 11:07:00 -0400869CFX_ByteString GetBorderAppStreamInternal(const CFX_FloatRect& rect,
870 float fWidth,
871 const CFX_Color& color,
872 const CFX_Color& crLeftTop,
873 const CFX_Color& crRightBottom,
874 BorderStyle nStyle,
875 const CPWL_Dash& dash) {
876 std::ostringstream sAppStream;
877 CFX_ByteString sColor;
878
879 float fLeft = rect.left;
880 float fRight = rect.right;
881 float fTop = rect.top;
882 float fBottom = rect.bottom;
883
884 if (fWidth > 0.0f) {
885 float fHalfWidth = fWidth / 2.0f;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400886 AutoClosedQCommand q(&sAppStream);
Dan Sinclair14ddd422017-07-20 11:07:00 -0400887
888 switch (nStyle) {
889 default:
890 case BorderStyle::SOLID:
891 sColor = GetColorAppStream(color, true);
892 if (sColor.GetLength() > 0) {
893 sAppStream << sColor;
894 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
895 << fTop - fBottom << " re\n";
896 sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
897 << fRight - fLeft - fWidth * 2 << " "
898 << fTop - fBottom - fWidth * 2 << " re\n";
899 sAppStream << "f*\n";
900 }
901 break;
902 case BorderStyle::DASH:
903 sColor = GetColorAppStream(color, false);
904 if (sColor.GetLength() > 0) {
905 sAppStream << sColor;
906 sAppStream << fWidth << " w"
907 << " [" << dash.nDash << " " << dash.nGap << "] "
908 << dash.nPhase << " d\n";
909 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
910 << " m\n";
911 sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
912 << " l\n";
913 sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
914 << " l\n";
915 sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
916 << " l\n";
917 sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
918 << " l S\n";
919 }
920 break;
921 case BorderStyle::BEVELED:
922 case BorderStyle::INSET:
923 sColor = GetColorAppStream(crLeftTop, true);
924 if (sColor.GetLength() > 0) {
925 sAppStream << sColor;
926 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
927 << " m\n";
928 sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
929 << " l\n";
930 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
931 << " l\n";
932 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
933 << " l\n";
934 sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
935 << " l\n";
936 sAppStream << fLeft + fHalfWidth * 2 << " "
937 << fBottom + fHalfWidth * 2 << " l f\n";
938 }
939
940 sColor = GetColorAppStream(crRightBottom, true);
941 if (sColor.GetLength() > 0) {
942 sAppStream << sColor;
943 sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
944 << " m\n";
945 sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
946 << " l\n";
947 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
948 << " l\n";
949 sAppStream << fLeft + fHalfWidth * 2 << " "
950 << fBottom + fHalfWidth * 2 << " l\n";
951 sAppStream << fRight - fHalfWidth * 2 << " "
952 << fBottom + fHalfWidth * 2 << " l\n";
953 sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
954 << " l f\n";
955 }
956
957 sColor = GetColorAppStream(color, true);
958 if (sColor.GetLength() > 0) {
959 sAppStream << sColor;
960 sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
961 << fTop - fBottom << " re\n";
962 sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
963 << fRight - fLeft - fHalfWidth * 2 << " "
964 << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
965 }
966 break;
967 case BorderStyle::UNDERLINE:
968 sColor = GetColorAppStream(color, false);
969 if (sColor.GetLength() > 0) {
970 sAppStream << sColor;
971 sAppStream << fWidth << " w\n";
972 sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
973 sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
974 }
975 break;
976 }
Dan Sinclair14ddd422017-07-20 11:07:00 -0400977 }
978
979 return CFX_ByteString(sAppStream);
980}
981
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400982CFX_ByteString GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
983 if (rcBBox.IsEmpty())
984 return CFX_ByteString();
985
986 std::ostringstream sAppStream;
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400987 {
988 AutoClosedQCommand q(&sAppStream);
989 sAppStream << GetColorAppStream(CFX_Color(COLORTYPE_RGB, 220.0f / 255.0f,
990 220.0f / 255.0f, 220.0f / 255.0f),
991 true)
992 << rcBBox.left << " " << rcBBox.bottom << " "
993 << rcBBox.right - rcBBox.left << " "
994 << rcBBox.top - rcBBox.bottom << " re f\n";
995 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -0400996
Dan Sinclaire03f8b12017-07-20 11:08:21 -0400997 {
998 AutoClosedQCommand q(&sAppStream);
999 sAppStream << GetBorderAppStreamInternal(
1000 rcBBox, 2, CFX_Color(COLORTYPE_GRAY, 0), CFX_Color(COLORTYPE_GRAY, 1),
1001 CFX_Color(COLORTYPE_GRAY, 0.5), BorderStyle::BEVELED,
1002 CPWL_Dash(3, 0, 0));
1003 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001004
1005 CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2,
1006 (rcBBox.top + rcBBox.bottom) / 2);
1007 if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) &&
1008 IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001009 AutoClosedQCommand q(&sAppStream);
1010 sAppStream << " 0 g\n"
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001011 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n"
1012 << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n"
1013 << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n"
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001014 << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001015 }
1016
1017 return CFX_ByteString(sAppStream);
1018}
1019
Dan Sinclair14ddd422017-07-20 11:07:00 -04001020CFX_ByteString GetRectFillAppStream(const CFX_FloatRect& rect,
1021 const CFX_Color& color) {
1022 std::ostringstream sAppStream;
1023 CFX_ByteString sColor = GetColorAppStream(color, true);
1024 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001025 AutoClosedQCommand q(&sAppStream);
1026 sAppStream << sColor << rect.left << " " << rect.bottom << " "
Dan Sinclair14ddd422017-07-20 11:07:00 -04001027 << rect.right - rect.left << " " << rect.top - rect.bottom
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001028 << " re f\n";
Dan Sinclair14ddd422017-07-20 11:07:00 -04001029 }
1030
1031 return CFX_ByteString(sAppStream);
1032}
1033
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001034} // namespace
1035
1036CPWL_AppStream::CPWL_AppStream(CPDFSDK_Widget* widget, CPDF_Dictionary* dict)
1037 : widget_(widget), dict_(dict) {}
1038
1039CPWL_AppStream::~CPWL_AppStream() {}
1040
1041void CPWL_AppStream::SetAsPushButton() {
1042 CPDF_FormControl* pControl = widget_->GetFormControl();
1043 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001044 ButtonStyle nLayout = ButtonStyle::kLabel;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001045 switch (pControl->GetTextPosition()) {
1046 case TEXTPOS_ICON:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001047 nLayout = ButtonStyle::kIcon;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001048 break;
1049 case TEXTPOS_BELOW:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001050 nLayout = ButtonStyle::kIconTopLabelBottom;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001051 break;
1052 case TEXTPOS_ABOVE:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001053 nLayout = ButtonStyle::kIconBottomLabelTop;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001054 break;
1055 case TEXTPOS_RIGHT:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001056 nLayout = ButtonStyle::kIconLeftLabelRight;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001057 break;
1058 case TEXTPOS_LEFT:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001059 nLayout = ButtonStyle::kIconRightLabelLeft;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001060 break;
1061 case TEXTPOS_OVERLAID:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001062 nLayout = ButtonStyle::kLabelOverIcon;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001063 break;
1064 default:
Dan Sinclair14ddd422017-07-20 11:07:00 -04001065 nLayout = ButtonStyle::kLabel;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001066 break;
1067 }
1068
1069 CFX_Color crBackground;
1070 CFX_Color crBorder;
1071 int iColorType;
1072 float fc[4];
1073 pControl->GetOriginalBackgroundColor(iColorType, fc);
1074 if (iColorType > 0)
1075 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1076
1077 pControl->GetOriginalBorderColor(iColorType, fc);
1078 if (iColorType > 0)
1079 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1080
1081 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1082 CPWL_Dash dsBorder(3, 0, 0);
1083 CFX_Color crLeftTop;
1084 CFX_Color crRightBottom;
1085
1086 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1087 switch (nBorderStyle) {
1088 case BorderStyle::DASH:
1089 dsBorder = CPWL_Dash(3, 3, 0);
1090 break;
1091 case BorderStyle::BEVELED:
1092 fBorderWidth *= 2;
1093 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1094 crRightBottom = crBackground / 2.0f;
1095 break;
1096 case BorderStyle::INSET:
1097 fBorderWidth *= 2;
1098 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1099 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1100 break;
1101 default:
1102 break;
1103 }
1104
1105 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1106 CFX_Color crText(COLORTYPE_GRAY, 0);
1107 CFX_ByteString csNameTag;
1108 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1109 if (da.HasColor()) {
1110 da.GetColor(iColorType, fc);
1111 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1112 }
1113 float fFontSize = 12.0f;
1114 if (da.HasFont())
1115 csNameTag = da.GetFont(&fFontSize);
1116
1117 CFX_WideString csWCaption;
1118 CFX_WideString csNormalCaption;
1119 CFX_WideString csRolloverCaption;
1120 CFX_WideString csDownCaption;
1121 if (pControl->HasMKEntry("CA"))
1122 csNormalCaption = pControl->GetNormalCaption();
1123
1124 if (pControl->HasMKEntry("RC"))
1125 csRolloverCaption = pControl->GetRolloverCaption();
1126
1127 if (pControl->HasMKEntry("AC"))
1128 csDownCaption = pControl->GetDownCaption();
1129
1130 CPDF_Stream* pNormalIcon = nullptr;
1131 CPDF_Stream* pRolloverIcon = nullptr;
1132 CPDF_Stream* pDownIcon = nullptr;
1133 if (pControl->HasMKEntry("I"))
1134 pNormalIcon = pControl->GetNormalIcon();
1135
1136 if (pControl->HasMKEntry("RI"))
1137 pRolloverIcon = pControl->GetRolloverIcon();
1138
1139 if (pControl->HasMKEntry("IX"))
1140 pDownIcon = pControl->GetDownIcon();
1141
1142 if (pNormalIcon) {
1143 if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) {
1144 if (pImageDict->GetStringFor("Name").IsEmpty())
1145 pImageDict->SetNewFor<CPDF_String>("Name", "ImgA", false);
1146 }
1147 }
1148
1149 if (pRolloverIcon) {
1150 if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) {
1151 if (pImageDict->GetStringFor("Name").IsEmpty())
1152 pImageDict->SetNewFor<CPDF_String>("Name", "ImgB", false);
1153 }
1154 }
1155
1156 if (pDownIcon) {
1157 if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) {
1158 if (pImageDict->GetStringFor("Name").IsEmpty())
1159 pImageDict->SetNewFor<CPDF_String>("Name", "ImgC", false);
1160 }
1161 }
1162
1163 CPDF_IconFit iconFit = pControl->GetIconFit();
1164
1165 CBA_FontMap font_map(
1166 widget_.Get(),
1167 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1168 font_map.SetAPType("N");
1169
1170 CFX_ByteString csAP =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001171 GetRectFillAppStream(rcWindow, crBackground) +
1172 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1173 crRightBottom, nBorderStyle, dsBorder) +
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001174 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1175 &font_map, pNormalIcon, iconFit, csNormalCaption,
1176 crText, fFontSize, nLayout);
1177
1178 Write("N", csAP, "");
1179 if (pNormalIcon)
1180 AddImage("N", pNormalIcon);
1181
1182 CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode();
1183 if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) {
1184 if (csRolloverCaption.IsEmpty() && !pRolloverIcon) {
1185 csRolloverCaption = csNormalCaption;
1186 pRolloverIcon = pNormalIcon;
1187 }
1188
1189 font_map.SetAPType("R");
1190
1191 csAP =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001192 GetRectFillAppStream(rcWindow, crBackground) +
1193 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1194 crRightBottom, nBorderStyle, dsBorder) +
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001195 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1196 &font_map, pRolloverIcon, iconFit,
1197 csRolloverCaption, crText, fFontSize, nLayout);
1198
1199 Write("R", csAP, "");
1200 if (pRolloverIcon)
1201 AddImage("R", pRolloverIcon);
1202
1203 if (csDownCaption.IsEmpty() && !pDownIcon) {
1204 csDownCaption = csNormalCaption;
1205 pDownIcon = pNormalIcon;
1206 }
1207
1208 switch (nBorderStyle) {
1209 case BorderStyle::BEVELED: {
1210 CFX_Color crTemp = crLeftTop;
1211 crLeftTop = crRightBottom;
1212 crRightBottom = crTemp;
1213 break;
1214 }
1215 case BorderStyle::INSET: {
1216 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1217 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1218 break;
1219 }
1220 default:
1221 break;
1222 }
1223
1224 font_map.SetAPType("D");
1225
Dan Sinclair14ddd422017-07-20 11:07:00 -04001226 csAP =
1227 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1228 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1229 crRightBottom, nBorderStyle, dsBorder) +
1230 GetPushButtonAppStream(iconFit.GetFittingBounds() ? rcWindow : rcClient,
1231 &font_map, pDownIcon, iconFit, csDownCaption,
1232 crText, fFontSize, nLayout);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001233
1234 Write("D", csAP, "");
1235 if (pDownIcon)
1236 AddImage("D", pDownIcon);
1237 } else {
1238 Remove("D");
1239 Remove("R");
1240 }
1241}
1242
1243void CPWL_AppStream::SetAsCheckBox() {
1244 CPDF_FormControl* pControl = widget_->GetFormControl();
1245 CFX_Color crBackground, crBorder, crText;
1246 int iColorType;
1247 float fc[4];
1248
1249 pControl->GetOriginalBackgroundColor(iColorType, fc);
1250 if (iColorType > 0)
1251 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1252
1253 pControl->GetOriginalBorderColor(iColorType, fc);
1254 if (iColorType > 0)
1255 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1256
1257 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1258 CPWL_Dash dsBorder(3, 0, 0);
1259 CFX_Color crLeftTop, crRightBottom;
1260
1261 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1262 switch (nBorderStyle) {
1263 case BorderStyle::DASH:
1264 dsBorder = CPWL_Dash(3, 3, 0);
1265 break;
1266 case BorderStyle::BEVELED:
1267 fBorderWidth *= 2;
1268 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1269 crRightBottom = crBackground / 2.0f;
1270 break;
1271 case BorderStyle::INSET:
1272 fBorderWidth *= 2;
1273 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1274 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1275 break;
1276 default:
1277 break;
1278 }
1279
1280 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1281 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1282 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1283 if (da.HasColor()) {
1284 da.GetColor(iColorType, fc);
1285 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1286 }
1287
Dan Sinclair14ddd422017-07-20 11:07:00 -04001288 CheckStyle nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001289 CFX_WideString csWCaption = pControl->GetNormalCaption();
1290 if (csWCaption.GetLength() > 0) {
1291 switch (csWCaption[0]) {
1292 case L'l':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001293 nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001294 break;
1295 case L'8':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001296 nStyle = CheckStyle::kCross;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001297 break;
1298 case L'u':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001299 nStyle = CheckStyle::kDiamond;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001300 break;
1301 case L'n':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001302 nStyle = CheckStyle::kSquare;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001303 break;
1304 case L'H':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001305 nStyle = CheckStyle::kStar;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001306 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -04001307 case L'4':
1308 default:
1309 nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001310 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001311 }
1312
1313 CFX_ByteString csAP_N_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001314 GetRectFillAppStream(rcWindow, crBackground) +
1315 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1316 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001317
1318 CFX_ByteString csAP_N_OFF = csAP_N_ON;
1319
1320 switch (nBorderStyle) {
1321 case BorderStyle::BEVELED: {
1322 CFX_Color crTemp = crLeftTop;
1323 crLeftTop = crRightBottom;
1324 crRightBottom = crTemp;
1325 break;
1326 }
1327 case BorderStyle::INSET: {
1328 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1329 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1330 break;
1331 }
1332 default:
1333 break;
1334 }
1335
1336 CFX_ByteString csAP_D_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001337 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1338 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1339 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001340
1341 CFX_ByteString csAP_D_OFF = csAP_D_ON;
1342
1343 csAP_N_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1344 csAP_D_ON += GetCheckBoxAppStream(rcClient, nStyle, crText);
1345
1346 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1347 Write("N", csAP_N_OFF, "Off");
1348
1349 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1350 Write("D", csAP_D_OFF, "Off");
1351
1352 CFX_ByteString csAS = widget_->GetAppState();
1353 if (csAS.IsEmpty())
1354 widget_->SetAppState("Off");
1355}
1356
1357void CPWL_AppStream::SetAsRadioButton() {
1358 CPDF_FormControl* pControl = widget_->GetFormControl();
1359 CFX_Color crBackground;
1360 CFX_Color crBorder;
1361 CFX_Color crText;
1362 int iColorType;
1363 float fc[4];
1364
1365 pControl->GetOriginalBackgroundColor(iColorType, fc);
1366 if (iColorType > 0)
1367 crBackground = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1368
1369 pControl->GetOriginalBorderColor(iColorType, fc);
1370 if (iColorType > 0)
1371 crBorder = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1372
1373 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1374 CPWL_Dash dsBorder(3, 0, 0);
1375 CFX_Color crLeftTop;
1376 CFX_Color crRightBottom;
1377 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1378 switch (nBorderStyle) {
1379 case BorderStyle::DASH:
1380 dsBorder = CPWL_Dash(3, 3, 0);
1381 break;
1382 case BorderStyle::BEVELED:
1383 fBorderWidth *= 2;
1384 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1385 crRightBottom = crBackground / 2.0f;
1386 break;
1387 case BorderStyle::INSET:
1388 fBorderWidth *= 2;
1389 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1390 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1391 break;
1392 default:
1393 break;
1394 }
1395
1396 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1397 CFX_FloatRect rcClient = rcWindow.GetDeflated(fBorderWidth, fBorderWidth);
1398 CPDF_DefaultAppearance da = pControl->GetDefaultAppearance();
1399 if (da.HasColor()) {
1400 da.GetColor(iColorType, fc);
1401 crText = CFX_Color(iColorType, fc[0], fc[1], fc[2], fc[3]);
1402 }
1403
Dan Sinclair14ddd422017-07-20 11:07:00 -04001404 CheckStyle nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001405 CFX_WideString csWCaption = pControl->GetNormalCaption();
1406 if (csWCaption.GetLength() > 0) {
1407 switch (csWCaption[0]) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001408 case L'8':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001409 nStyle = CheckStyle::kCross;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001410 break;
1411 case L'u':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001412 nStyle = CheckStyle::kDiamond;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001413 break;
1414 case L'n':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001415 nStyle = CheckStyle::kSquare;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001416 break;
1417 case L'H':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001418 nStyle = CheckStyle::kStar;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001419 break;
1420 case L'4':
Dan Sinclair14ddd422017-07-20 11:07:00 -04001421 nStyle = CheckStyle::kCheck;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001422 break;
Dan Sinclair14ddd422017-07-20 11:07:00 -04001423 case L'l':
1424 default:
1425 nStyle = CheckStyle::kCircle;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001426 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001427 }
1428
1429 CFX_ByteString csAP_N_ON;
1430 CFX_FloatRect rcCenter = rcWindow.GetCenterSquare().GetDeflated(1.0f, 1.0f);
Dan Sinclair14ddd422017-07-20 11:07:00 -04001431 if (nStyle == CheckStyle::kCircle) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001432 if (nBorderStyle == BorderStyle::BEVELED) {
1433 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1434 crRightBottom = crBackground - 0.25f;
1435 } else if (nBorderStyle == BorderStyle::INSET) {
1436 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5f);
1437 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75f);
1438 }
1439
1440 csAP_N_ON =
1441 GetCircleFillAppStream(rcCenter, crBackground) +
1442 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1443 crRightBottom, nBorderStyle, dsBorder);
1444 } else {
Dan Sinclair14ddd422017-07-20 11:07:00 -04001445 csAP_N_ON =
1446 GetRectFillAppStream(rcWindow, crBackground) +
1447 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1448 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001449 }
1450
1451 CFX_ByteString csAP_N_OFF = csAP_N_ON;
1452
1453 switch (nBorderStyle) {
1454 case BorderStyle::BEVELED: {
1455 CFX_Color crTemp = crLeftTop;
1456 crLeftTop = crRightBottom;
1457 crRightBottom = crTemp;
1458 break;
1459 }
1460 case BorderStyle::INSET: {
1461 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1462 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1463 break;
1464 }
1465 default:
1466 break;
1467 }
1468
1469 CFX_ByteString csAP_D_ON;
1470
Dan Sinclair14ddd422017-07-20 11:07:00 -04001471 if (nStyle == CheckStyle::kCircle) {
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001472 CFX_Color crBK = crBackground - 0.25f;
1473 if (nBorderStyle == BorderStyle::BEVELED) {
1474 crLeftTop = crBackground - 0.25f;
1475 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1476 crBK = crBackground;
1477 } else if (nBorderStyle == BorderStyle::INSET) {
1478 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0);
1479 crRightBottom = CFX_Color(COLORTYPE_GRAY, 1);
1480 }
1481
1482 csAP_D_ON =
1483 GetCircleFillAppStream(rcCenter, crBK) +
1484 GetCircleBorderAppStream(rcCenter, fBorderWidth, crBorder, crLeftTop,
1485 crRightBottom, nBorderStyle, dsBorder);
1486 } else {
1487 csAP_D_ON =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001488 GetRectFillAppStream(rcWindow, crBackground - 0.25f) +
1489 GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1490 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001491 }
1492
1493 CFX_ByteString csAP_D_OFF = csAP_D_ON;
1494
1495 csAP_N_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1496 csAP_D_ON += GetRadioButtonAppStream(rcClient, nStyle, crText);
1497
1498 Write("N", csAP_N_ON, pControl->GetCheckedAPState());
1499 Write("N", csAP_N_OFF, "Off");
1500
1501 Write("D", csAP_D_ON, pControl->GetCheckedAPState());
1502 Write("D", csAP_D_OFF, "Off");
1503
1504 CFX_ByteString csAS = widget_->GetAppState();
1505 if (csAS.IsEmpty())
1506 widget_->SetAppState("Off");
1507}
1508
1509void CPWL_AppStream::SetAsComboBox(const CFX_WideString* sValue) {
1510 CPDF_FormControl* pControl = widget_->GetFormControl();
1511 CPDF_FormField* pField = pControl->GetField();
1512 std::ostringstream sBody;
1513
1514 CFX_FloatRect rcClient = widget_->GetClientRect();
1515 CFX_FloatRect rcButton = rcClient;
1516 rcButton.left = rcButton.right - 13;
1517 rcButton.Normalize();
1518
1519 auto pEdit = pdfium::MakeUnique<CFX_Edit>();
1520 pEdit->EnableRefresh(false);
1521
1522 CBA_FontMap font_map(
1523 widget_.Get(),
1524 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1525 pEdit->SetFontMap(&font_map);
1526
1527 CFX_FloatRect rcEdit = rcClient;
1528 rcEdit.right = rcButton.left;
1529 rcEdit.Normalize();
1530
1531 pEdit->SetPlateRect(rcEdit);
1532 pEdit->SetAlignmentV(1, true);
1533
1534 float fFontSize = widget_->GetFontSize();
1535 if (IsFloatZero(fFontSize))
1536 pEdit->SetAutoFontSize(true, true);
1537 else
1538 pEdit->SetFontSize(fFontSize);
1539
1540 pEdit->Initialize();
1541
1542 if (sValue) {
1543 pEdit->SetText(*sValue);
1544 } else {
1545 int32_t nCurSel = pField->GetSelectedIndex(0);
1546 if (nCurSel < 0)
1547 pEdit->SetText(pField->GetValue());
1548 else
1549 pEdit->SetText(pField->GetOptionLabel(nCurSel));
1550 }
1551
1552 CFX_FloatRect rcContent = pEdit->GetContentRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001553 CFX_ByteString sEdit = GetEditAppStream(pEdit.get(), CFX_PointF(), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001554 if (sEdit.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001555 sBody << "/Tx ";
1556 AutoClosedCommand bmc(&sBody, "BMC", "EMC");
1557 AutoClosedQCommand q(&sBody);
1558
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001559 if (rcContent.Width() > rcEdit.Width() ||
1560 rcContent.Height() > rcEdit.Height()) {
1561 sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width()
1562 << " " << rcEdit.Height() << " re\nW\nn\n";
1563 }
1564
1565 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001566 AutoClosedCommand bt(&sBody, "BT", "ET");
1567 sBody << GetColorAppStream(crText, true) << sEdit;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001568 }
1569
1570 sBody << GetDropButtonAppStream(rcButton);
1571 Write("N",
1572 GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody),
1573 "");
1574}
1575
1576void CPWL_AppStream::SetAsListBox() {
1577 CPDF_FormControl* pControl = widget_->GetFormControl();
1578 CPDF_FormField* pField = pControl->GetField();
1579 CFX_FloatRect rcClient = widget_->GetClientRect();
1580 std::ostringstream sBody;
1581
1582 auto pEdit = pdfium::MakeUnique<CFX_Edit>();
1583 pEdit->EnableRefresh(false);
1584
1585 CBA_FontMap font_map(
1586 widget_.Get(),
1587 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1588 pEdit->SetFontMap(&font_map);
1589 pEdit->SetPlateRect(CFX_FloatRect(rcClient.left, 0.0f, rcClient.right, 0.0f));
1590
1591 float fFontSize = widget_->GetFontSize();
1592 pEdit->SetFontSize(IsFloatZero(fFontSize) ? 12.0f : fFontSize);
1593 pEdit->Initialize();
1594
1595 std::ostringstream sList;
1596 float fy = rcClient.top;
1597
1598 int32_t nTop = pField->GetTopVisibleIndex();
1599 int32_t nCount = pField->CountOptions();
1600 int32_t nSelCount = pField->CountSelectedItems();
1601
1602 for (int32_t i = nTop; i < nCount; ++i) {
1603 bool bSelected = false;
1604 for (int32_t j = 0; j < nSelCount; ++j) {
1605 if (pField->GetSelectedIndex(j) == i) {
1606 bSelected = true;
1607 break;
1608 }
1609 }
1610
1611 pEdit->SetText(pField->GetOptionLabel(i));
1612
1613 CFX_FloatRect rcContent = pEdit->GetContentRect();
1614 float fItemHeight = rcContent.Height();
1615
1616 if (bSelected) {
1617 CFX_FloatRect rcItem =
1618 CFX_FloatRect(rcClient.left, fy - fItemHeight, rcClient.right, fy);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001619 {
1620 AutoClosedQCommand q(&sList);
1621 sList << GetColorAppStream(CFX_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f,
1622 113.0f / 255.0f),
1623 true)
1624 << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width()
1625 << " " << rcItem.Height() << " re f\n";
1626 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001627
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001628 AutoClosedCommand bt(&sList, "BT", "ET");
1629 sList << GetColorAppStream(CFX_Color(COLORTYPE_GRAY, 1), true)
1630 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001631 } else {
1632 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001633
1634 AutoClosedCommand bt(&sList, "BT", "ET");
1635 sList << GetColorAppStream(crText, true)
1636 << GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, fy), true, 0);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001637 }
1638
1639 fy -= fItemHeight;
1640 }
1641
1642 if (sList.tellp() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001643 sBody << "/Tx ";
1644 AutoClosedCommand bmc(&sBody, "BMC", "EMC");
1645 AutoClosedQCommand q(&sBody);
1646
1647 sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width()
1648 << " " << rcClient.Height() << " re\nW\nn\n"
1649 << sList.str();
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001650 }
1651 Write("N",
1652 GetBackgroundAppStream() + GetBorderAppStream() + CFX_ByteString(sBody),
1653 "");
1654}
1655
1656void CPWL_AppStream::SetAsTextField(const CFX_WideString* sValue) {
1657 CPDF_FormControl* pControl = widget_->GetFormControl();
1658 CPDF_FormField* pField = pControl->GetField();
1659 std::ostringstream sBody;
1660 std::ostringstream sLines;
1661
1662 auto pEdit = pdfium::MakeUnique<CFX_Edit>();
1663 pEdit->EnableRefresh(false);
1664
1665 CBA_FontMap font_map(
1666 widget_.Get(),
1667 widget_->GetInterForm()->GetFormFillEnv()->GetSysHandler());
1668 pEdit->SetFontMap(&font_map);
1669
1670 CFX_FloatRect rcClient = widget_->GetClientRect();
1671 pEdit->SetPlateRect(rcClient);
1672 pEdit->SetAlignmentH(pControl->GetControlAlignment(), true);
1673
1674 uint32_t dwFieldFlags = pField->GetFieldFlags();
1675 bool bMultiLine = (dwFieldFlags >> 12) & 1;
1676 if (bMultiLine) {
1677 pEdit->SetMultiLine(true, true);
1678 pEdit->SetAutoReturn(true, true);
1679 } else {
1680 pEdit->SetAlignmentV(1, true);
1681 }
1682
1683 uint16_t subWord = 0;
1684 if ((dwFieldFlags >> 13) & 1) {
1685 subWord = '*';
1686 pEdit->SetPasswordChar(subWord, true);
1687 }
1688
1689 int nMaxLen = pField->GetMaxLen();
1690 bool bCharArray = (dwFieldFlags >> 24) & 1;
1691 float fFontSize = widget_->GetFontSize();
1692
1693#ifdef PDF_ENABLE_XFA
1694 CFX_WideString sValueTmp;
1695 if (!sValue && widget_->GetMixXFAWidget()) {
1696 sValueTmp = widget_->GetValue(true);
1697 sValue = &sValueTmp;
1698 }
1699#endif // PDF_ENABLE_XFA
1700
1701 if (nMaxLen > 0) {
1702 if (bCharArray) {
1703 pEdit->SetCharArray(nMaxLen);
1704
1705 if (IsFloatZero(fFontSize)) {
1706 fFontSize = CPWL_Edit::GetCharArrayAutoFontSize(font_map.GetPDFFont(0),
1707 rcClient, nMaxLen);
1708 }
1709 } else {
1710 if (sValue)
1711 nMaxLen = sValue->GetLength();
1712 pEdit->SetLimitChar(nMaxLen);
1713 }
1714 }
1715
1716 if (IsFloatZero(fFontSize))
1717 pEdit->SetAutoFontSize(true, true);
1718 else
1719 pEdit->SetFontSize(fFontSize);
1720
1721 pEdit->Initialize();
1722 pEdit->SetText(sValue ? *sValue : pField->GetValue());
1723
1724 CFX_FloatRect rcContent = pEdit->GetContentRect();
Dan Sinclair14ddd422017-07-20 11:07:00 -04001725 CFX_ByteString sEdit =
1726 GetEditAppStream(pEdit.get(), CFX_PointF(), !bCharArray, subWord);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001727
1728 if (sEdit.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001729 sBody << "/Tx ";
1730 AutoClosedCommand bmc(&sBody, "BMC", "EMC");
1731 AutoClosedQCommand q(&sBody);
1732
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001733 if (rcContent.Width() > rcClient.Width() ||
1734 rcContent.Height() > rcClient.Height()) {
1735 sBody << rcClient.left << " " << rcClient.bottom << " "
1736 << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n";
1737 }
1738 CFX_Color crText = widget_->GetTextPWLColor();
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001739
1740 AutoClosedCommand bt(&sBody, "BT", "ET");
1741 sBody << GetColorAppStream(crText, true) << sEdit;
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001742 }
1743
1744 if (bCharArray) {
1745 switch (widget_->GetBorderStyle()) {
1746 case BorderStyle::SOLID: {
1747 CFX_ByteString sColor =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001748 GetColorAppStream(widget_->GetBorderPWLColor(), false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001749 if (sColor.GetLength() > 0) {
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001750 AutoClosedQCommand q(&sLines);
1751 sLines << widget_->GetBorderWidth() << " w\n"
Dan Sinclair14ddd422017-07-20 11:07:00 -04001752 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001753 << " 2 J 0 j\n";
1754
1755 for (int32_t i = 1; i < nMaxLen; ++i) {
1756 sLines << rcClient.left +
1757 ((rcClient.right - rcClient.left) / nMaxLen) * i
1758 << " " << rcClient.bottom << " m\n"
1759 << rcClient.left +
1760 ((rcClient.right - rcClient.left) / nMaxLen) * i
1761 << " " << rcClient.top << " l S\n";
1762 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001763 }
1764 break;
1765 }
1766 case BorderStyle::DASH: {
1767 CFX_ByteString sColor =
Dan Sinclair14ddd422017-07-20 11:07:00 -04001768 GetColorAppStream(widget_->GetBorderPWLColor(), false);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001769 if (sColor.GetLength() > 0) {
1770 CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0);
Dan Sinclaire03f8b12017-07-20 11:08:21 -04001771 AutoClosedQCommand q(&sLines);
1772 sLines << widget_->GetBorderWidth() << " w\n"
Dan Sinclair14ddd422017-07-20 11:07:00 -04001773 << GetColorAppStream(widget_->GetBorderPWLColor(), false)
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001774 << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] "
1775 << dsBorder.nPhase << " d\n";
1776
1777 for (int32_t i = 1; i < nMaxLen; ++i) {
1778 sLines << rcClient.left +
1779 ((rcClient.right - rcClient.left) / nMaxLen) * i
1780 << " " << rcClient.bottom << " m\n"
1781 << rcClient.left +
1782 ((rcClient.right - rcClient.left) / nMaxLen) * i
1783 << " " << rcClient.top << " l S\n";
1784 }
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001785 }
1786 break;
1787 }
1788 default:
1789 break;
1790 }
1791 }
1792
1793 Write("N",
1794 GetBackgroundAppStream() + GetBorderAppStream() +
1795 CFX_ByteString(sLines) + CFX_ByteString(sBody),
1796 "");
1797}
1798
1799void CPWL_AppStream::AddImage(const CFX_ByteString& sAPType,
1800 CPDF_Stream* pImage) {
1801 CPDF_Stream* pStream = dict_->GetStreamFor(sAPType);
1802 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1803 CFX_ByteString sImageAlias = "IMG";
1804
1805 if (CPDF_Dictionary* pImageDict = pImage->GetDict()) {
1806 sImageAlias = pImageDict->GetStringFor("Name");
1807 if (sImageAlias.IsEmpty())
1808 sImageAlias = "IMG";
1809 }
1810
1811 CPDF_Dictionary* pStreamResList = pStreamDict->GetDictFor("Resources");
1812 if (!pStreamResList)
1813 pStreamResList = pStreamDict->SetNewFor<CPDF_Dictionary>("Resources");
1814
1815 CPDF_Dictionary* pXObject =
1816 pStreamResList->SetNewFor<CPDF_Dictionary>("XObject");
1817 pXObject->SetNewFor<CPDF_Reference>(sImageAlias,
1818 widget_->GetPageView()->GetPDFDocument(),
1819 pImage->GetObjNum());
1820}
1821
1822void CPWL_AppStream::Write(const CFX_ByteString& sAPType,
1823 const CFX_ByteString& sContents,
1824 const CFX_ByteString& sAPState) {
1825 CPDF_Stream* pStream = nullptr;
1826 CPDF_Dictionary* pParentDict = nullptr;
1827 if (sAPState.IsEmpty()) {
1828 pParentDict = dict_.Get();
1829 pStream = dict_->GetStreamFor(sAPType);
1830 } else {
1831 CPDF_Dictionary* pAPTypeDict = dict_->GetDictFor(sAPType);
1832 if (!pAPTypeDict)
1833 pAPTypeDict = dict_->SetNewFor<CPDF_Dictionary>(sAPType);
1834
1835 pParentDict = pAPTypeDict;
1836 pStream = pAPTypeDict->GetStreamFor(sAPState);
1837 }
1838
1839 if (!pStream) {
1840 CPDF_Document* doc = widget_->GetPageView()->GetPDFDocument();
1841 pStream = doc->NewIndirect<CPDF_Stream>();
1842 pParentDict->SetNewFor<CPDF_Reference>(sAPType, doc, pStream->GetObjNum());
1843 }
1844
1845 CPDF_Dictionary* pStreamDict = pStream->GetDict();
1846 if (!pStreamDict) {
1847 auto pNewDict = pdfium::MakeUnique<CPDF_Dictionary>(
1848 widget_->GetPDFAnnot()->GetDocument()->GetByteStringPool());
1849 pStreamDict = pNewDict.get();
1850 pStreamDict->SetNewFor<CPDF_Name>("Type", "XObject");
1851 pStreamDict->SetNewFor<CPDF_Name>("Subtype", "Form");
1852 pStreamDict->SetNewFor<CPDF_Number>("FormType", 1);
1853 pStream->InitStream(nullptr, 0, std::move(pNewDict));
1854 }
1855 pStreamDict->SetMatrixFor("Matrix", widget_->GetMatrix());
1856 pStreamDict->SetRectFor("BBox", widget_->GetRotatedRect());
1857 pStream->SetData((uint8_t*)(sContents.c_str()), sContents.GetLength());
1858}
1859
1860void CPWL_AppStream::Remove(const CFX_ByteString& sAPType) {
1861 dict_->RemoveFor(sAPType);
1862}
1863
1864CFX_ByteString CPWL_AppStream::GetBackgroundAppStream() const {
1865 CFX_Color crBackground = widget_->GetFillPWLColor();
1866 if (crBackground.nColorType != COLORTYPE_TRANSPARENT)
Dan Sinclair14ddd422017-07-20 11:07:00 -04001867 return GetRectFillAppStream(widget_->GetRotatedRect(), crBackground);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001868
1869 return CFX_ByteString();
1870}
1871
1872CFX_ByteString CPWL_AppStream::GetBorderAppStream() const {
1873 CFX_FloatRect rcWindow = widget_->GetRotatedRect();
1874 CFX_Color crBorder = widget_->GetBorderPWLColor();
1875 CFX_Color crBackground = widget_->GetFillPWLColor();
1876 CFX_Color crLeftTop;
1877 CFX_Color crRightBottom;
1878
1879 float fBorderWidth = static_cast<float>(widget_->GetBorderWidth());
1880 CPWL_Dash dsBorder(3, 0, 0);
1881
1882 BorderStyle nBorderStyle = widget_->GetBorderStyle();
1883 switch (nBorderStyle) {
1884 case BorderStyle::DASH:
1885 dsBorder = CPWL_Dash(3, 3, 0);
1886 break;
1887 case BorderStyle::BEVELED:
1888 fBorderWidth *= 2;
1889 crLeftTop = CFX_Color(COLORTYPE_GRAY, 1);
1890 crRightBottom = crBackground / 2.0f;
1891 break;
1892 case BorderStyle::INSET:
1893 fBorderWidth *= 2;
1894 crLeftTop = CFX_Color(COLORTYPE_GRAY, 0.5);
1895 crRightBottom = CFX_Color(COLORTYPE_GRAY, 0.75);
1896 break;
1897 default:
1898 break;
1899 }
1900
Dan Sinclair14ddd422017-07-20 11:07:00 -04001901 return GetBorderAppStreamInternal(rcWindow, fBorderWidth, crBorder, crLeftTop,
1902 crRightBottom, nBorderStyle, dsBorder);
Dan Sinclaircb2ea422017-07-19 15:24:49 -04001903}