PWL_Utils.cpp revision 5ae9d0c6fd838a2967cca72aa5751b51dadc2769
1// Copyright 2014 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/PWL_Utils.h"
8
9#include <algorithm>
10#include <memory>
11
12#include "core/fpdfdoc/cpvt_word.h"
13#include "core/fxge/cfx_graphstatedata.h"
14#include "core/fxge/cfx_pathdata.h"
15#include "core/fxge/cfx_renderdevice.h"
16#include "fpdfsdk/fxedit/fxet_edit.h"
17#include "fpdfsdk/pdfwindow/PWL_Icon.h"
18#include "fpdfsdk/pdfwindow/PWL_Wnd.h"
19
20CFX_FloatRect CPWL_Utils::OffsetRect(const CFX_FloatRect& rect,
21                                     FX_FLOAT x,
22                                     FX_FLOAT y) {
23  return CFX_FloatRect(rect.left + x, rect.bottom + y, rect.right + x,
24                       rect.top + y);
25}
26
27CPVT_WordRange CPWL_Utils::OverlapWordRange(const CPVT_WordRange& wr1,
28                                            const CPVT_WordRange& wr2) {
29  CPVT_WordRange wrRet;
30
31  if (wr2.EndPos.WordCmp(wr1.BeginPos) < 0 ||
32      wr2.BeginPos.WordCmp(wr1.EndPos) > 0)
33    return wrRet;
34  if (wr1.EndPos.WordCmp(wr2.BeginPos) < 0 ||
35      wr1.BeginPos.WordCmp(wr2.EndPos) > 0)
36    return wrRet;
37
38  if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) {
39    wrRet.BeginPos = wr2.BeginPos;
40  } else {
41    wrRet.BeginPos = wr1.BeginPos;
42  }
43
44  if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) {
45    wrRet.EndPos = wr1.EndPos;
46  } else {
47    wrRet.EndPos = wr2.EndPos;
48  }
49
50  return wrRet;
51}
52
53CFX_ByteString CPWL_Utils::GetAP_Check(const CFX_FloatRect& crBBox) {
54  const FX_FLOAT fWidth = crBBox.right - crBBox.left;
55  const FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
56
57  CFX_PointF pts[8][3] = {{CFX_PointF(0.28f, 0.52f), CFX_PointF(0.27f, 0.48f),
58                           CFX_PointF(0.29f, 0.40f)},
59                          {CFX_PointF(0.30f, 0.33f), CFX_PointF(0.31f, 0.29f),
60                           CFX_PointF(0.31f, 0.28f)},
61                          {CFX_PointF(0.39f, 0.28f), CFX_PointF(0.49f, 0.29f),
62                           CFX_PointF(0.77f, 0.67f)},
63                          {CFX_PointF(0.76f, 0.68f), CFX_PointF(0.78f, 0.69f),
64                           CFX_PointF(0.76f, 0.75f)},
65                          {CFX_PointF(0.76f, 0.75f), CFX_PointF(0.73f, 0.80f),
66                           CFX_PointF(0.68f, 0.75f)},
67                          {CFX_PointF(0.68f, 0.74f), CFX_PointF(0.68f, 0.74f),
68                           CFX_PointF(0.44f, 0.47f)},
69                          {CFX_PointF(0.43f, 0.47f), CFX_PointF(0.40f, 0.47f),
70                           CFX_PointF(0.41f, 0.58f)},
71                          {CFX_PointF(0.40f, 0.60f), CFX_PointF(0.28f, 0.66f),
72                           CFX_PointF(0.30f, 0.56f)}};
73
74  for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
75    for (size_t j = 0; j < FX_ArraySize(pts[0]); ++j) {
76      pts[i][j].x = pts[i][j].x * fWidth + crBBox.left;
77      pts[i][j].y *= pts[i][j].y * fHeight + crBBox.bottom;
78    }
79  }
80
81  CFX_ByteTextBuf csAP;
82  csAP << pts[0][0].x << " " << pts[0][0].y << " m\n";
83
84  for (size_t i = 0; i < FX_ArraySize(pts); ++i) {
85    size_t nNext = i < FX_ArraySize(pts) - 1 ? i + 1 : 0;
86
87    FX_FLOAT px1 = pts[i][1].x - pts[i][0].x;
88    FX_FLOAT py1 = pts[i][1].y - pts[i][0].y;
89    FX_FLOAT px2 = pts[i][2].x - pts[nNext][0].x;
90    FX_FLOAT py2 = pts[i][2].y - pts[nNext][0].y;
91
92    csAP << pts[i][0].x + px1 * FX_BEZIER << " "
93         << pts[i][0].y + py1 * FX_BEZIER << " "
94         << pts[nNext][0].x + px2 * FX_BEZIER << " "
95         << pts[nNext][0].y + py2 * FX_BEZIER << " " << pts[nNext][0].x << " "
96         << pts[nNext][0].y << " c\n";
97  }
98
99  return csAP.MakeString();
100}
101
102CFX_ByteString CPWL_Utils::GetAP_Circle(const CFX_FloatRect& crBBox) {
103  CFX_ByteTextBuf csAP;
104
105  FX_FLOAT fWidth = crBBox.right - crBBox.left;
106  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
107
108  CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
109  CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
110  CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
111  CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
112
113  csAP << pt1.x << " " << pt1.y << " m\n";
114
115  FX_FLOAT px = pt2.x - pt1.x;
116  FX_FLOAT py = pt2.y - pt1.y;
117
118  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
119       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
120       << " c\n";
121
122  px = pt3.x - pt2.x;
123  py = pt2.y - pt3.y;
124
125  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
126       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
127
128  px = pt3.x - pt4.x;
129  py = pt3.y - pt4.y;
130
131  csAP << pt3.x << " " << pt3.y - py * FX_BEZIER << " "
132       << pt4.x + px * FX_BEZIER << " " << pt4.y << " " << pt4.x << " " << pt4.y
133       << " c\n";
134
135  px = pt4.x - pt1.x;
136  py = pt1.y - pt4.y;
137
138  csAP << pt4.x - px * FX_BEZIER << " " << pt4.y << " " << pt1.x << " "
139       << pt1.y - py * FX_BEZIER << " " << pt1.x << " " << pt1.y << " c\n";
140
141  return csAP.MakeString();
142}
143
144CFX_ByteString CPWL_Utils::GetAP_Cross(const CFX_FloatRect& crBBox) {
145  CFX_ByteTextBuf csAP;
146
147  csAP << crBBox.left << " " << crBBox.top << " m\n";
148  csAP << crBBox.right << " " << crBBox.bottom << " l\n";
149  csAP << crBBox.left << " " << crBBox.bottom << " m\n";
150  csAP << crBBox.right << " " << crBBox.top << " l\n";
151
152  return csAP.MakeString();
153}
154
155CFX_ByteString CPWL_Utils::GetAP_Diamond(const CFX_FloatRect& crBBox) {
156  CFX_ByteTextBuf csAP;
157
158  FX_FLOAT fWidth = crBBox.right - crBBox.left;
159  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
160
161  CFX_PointF pt1(crBBox.left, crBBox.bottom + fHeight / 2);
162  CFX_PointF pt2(crBBox.left + fWidth / 2, crBBox.top);
163  CFX_PointF pt3(crBBox.right, crBBox.bottom + fHeight / 2);
164  CFX_PointF pt4(crBBox.left + fWidth / 2, crBBox.bottom);
165
166  csAP << pt1.x << " " << pt1.y << " m\n";
167  csAP << pt2.x << " " << pt2.y << " l\n";
168  csAP << pt3.x << " " << pt3.y << " l\n";
169  csAP << pt4.x << " " << pt4.y << " l\n";
170  csAP << pt1.x << " " << pt1.y << " l\n";
171
172  return csAP.MakeString();
173}
174
175CFX_ByteString CPWL_Utils::GetAP_Square(const CFX_FloatRect& crBBox) {
176  CFX_ByteTextBuf csAP;
177
178  csAP << crBBox.left << " " << crBBox.top << " m\n";
179  csAP << crBBox.right << " " << crBBox.top << " l\n";
180  csAP << crBBox.right << " " << crBBox.bottom << " l\n";
181  csAP << crBBox.left << " " << crBBox.bottom << " l\n";
182  csAP << crBBox.left << " " << crBBox.top << " l\n";
183
184  return csAP.MakeString();
185}
186
187CFX_ByteString CPWL_Utils::GetAP_Star(const CFX_FloatRect& crBBox) {
188  CFX_ByteTextBuf csAP;
189
190  FX_FLOAT fRadius =
191      (crBBox.top - crBBox.bottom) / (1 + (FX_FLOAT)cos(FX_PI / 5.0f));
192  CFX_PointF ptCenter = CFX_PointF((crBBox.left + crBBox.right) / 2.0f,
193                                   (crBBox.top + crBBox.bottom) / 2.0f);
194
195  FX_FLOAT px[5], py[5];
196
197  FX_FLOAT fAngel = FX_PI / 10.0f;
198
199  for (int32_t i = 0; i < 5; i++) {
200    px[i] = ptCenter.x + fRadius * (FX_FLOAT)cos(fAngel);
201    py[i] = ptCenter.y + fRadius * (FX_FLOAT)sin(fAngel);
202
203    fAngel += FX_PI * 2 / 5.0f;
204  }
205
206  csAP << px[0] << " " << py[0] << " m\n";
207
208  int32_t nNext = 0;
209  for (int32_t j = 0; j < 5; j++) {
210    nNext += 2;
211    if (nNext >= 5)
212      nNext -= 5;
213    csAP << px[nNext] << " " << py[nNext] << " l\n";
214  }
215
216  return csAP.MakeString();
217}
218
219CFX_ByteString CPWL_Utils::GetAP_HalfCircle(const CFX_FloatRect& crBBox,
220                                            FX_FLOAT fRotate) {
221  CFX_ByteTextBuf csAP;
222
223  FX_FLOAT fWidth = crBBox.right - crBBox.left;
224  FX_FLOAT fHeight = crBBox.top - crBBox.bottom;
225
226  CFX_PointF pt1(-fWidth / 2, 0);
227  CFX_PointF pt2(0, fHeight / 2);
228  CFX_PointF pt3(fWidth / 2, 0);
229
230  FX_FLOAT px, py;
231
232  csAP << cos(fRotate) << " " << sin(fRotate) << " " << -sin(fRotate) << " "
233       << cos(fRotate) << " " << crBBox.left + fWidth / 2 << " "
234       << crBBox.bottom + fHeight / 2 << " cm\n";
235
236  csAP << pt1.x << " " << pt1.y << " m\n";
237
238  px = pt2.x - pt1.x;
239  py = pt2.y - pt1.y;
240
241  csAP << pt1.x << " " << pt1.y + py * FX_BEZIER << " "
242       << pt2.x - px * FX_BEZIER << " " << pt2.y << " " << pt2.x << " " << pt2.y
243       << " c\n";
244
245  px = pt3.x - pt2.x;
246  py = pt2.y - pt3.y;
247
248  csAP << pt2.x + px * FX_BEZIER << " " << pt2.y << " " << pt3.x << " "
249       << pt3.y + py * FX_BEZIER << " " << pt3.x << " " << pt3.y << " c\n";
250
251  return csAP.MakeString();
252}
253
254CFX_FloatRect CPWL_Utils::InflateRect(const CFX_FloatRect& rcRect,
255                                      FX_FLOAT fSize) {
256  if (rcRect.IsEmpty())
257    return rcRect;
258
259  CFX_FloatRect rcNew(rcRect.left - fSize, rcRect.bottom - fSize,
260                      rcRect.right + fSize, rcRect.top + fSize);
261  rcNew.Normalize();
262  return rcNew;
263}
264
265CFX_FloatRect CPWL_Utils::DeflateRect(const CFX_FloatRect& rcRect,
266                                      FX_FLOAT fSize) {
267  if (rcRect.IsEmpty())
268    return rcRect;
269
270  CFX_FloatRect rcNew(rcRect.left + fSize, rcRect.bottom + fSize,
271                      rcRect.right - fSize, rcRect.top - fSize);
272  rcNew.Normalize();
273  return rcNew;
274}
275
276CFX_FloatRect CPWL_Utils::ScaleRect(const CFX_FloatRect& rcRect,
277                                    FX_FLOAT fScale) {
278  FX_FLOAT fHalfWidth = (rcRect.right - rcRect.left) / 2.0f;
279  FX_FLOAT fHalfHeight = (rcRect.top - rcRect.bottom) / 2.0f;
280
281  CFX_PointF ptCenter = CFX_PointF((rcRect.left + rcRect.right) / 2,
282                                   (rcRect.top + rcRect.bottom) / 2);
283
284  return CFX_FloatRect(
285      ptCenter.x - fHalfWidth * fScale, ptCenter.y - fHalfHeight * fScale,
286      ptCenter.x + fHalfWidth * fScale, ptCenter.y + fHalfHeight * fScale);
287}
288
289CFX_ByteString CPWL_Utils::GetRectFillAppStream(const CFX_FloatRect& rect,
290                                                const CPWL_Color& color) {
291  CFX_ByteTextBuf sAppStream;
292  CFX_ByteString sColor = GetColorAppStream(color, true);
293  if (sColor.GetLength() > 0) {
294    sAppStream << "q\n" << sColor;
295    sAppStream << rect.left << " " << rect.bottom << " "
296               << rect.right - rect.left << " " << rect.top - rect.bottom
297               << " re f\nQ\n";
298  }
299
300  return sAppStream.MakeString();
301}
302
303CFX_ByteString CPWL_Utils::GetCircleFillAppStream(const CFX_FloatRect& rect,
304                                                  const CPWL_Color& color) {
305  CFX_ByteTextBuf sAppStream;
306  CFX_ByteString sColor = GetColorAppStream(color, true);
307  if (sColor.GetLength() > 0) {
308    sAppStream << "q\n" << sColor << CPWL_Utils::GetAP_Circle(rect) << "f\nQ\n";
309  }
310  return sAppStream.MakeString();
311}
312
313CFX_FloatRect CPWL_Utils::GetCenterSquare(const CFX_FloatRect& rect) {
314  FX_FLOAT fWidth = rect.right - rect.left;
315  FX_FLOAT fHeight = rect.top - rect.bottom;
316
317  FX_FLOAT fCenterX = (rect.left + rect.right) / 2.0f;
318  FX_FLOAT fCenterY = (rect.top + rect.bottom) / 2.0f;
319
320  FX_FLOAT fRadius = (fWidth > fHeight) ? fHeight / 2 : fWidth / 2;
321
322  return CFX_FloatRect(fCenterX - fRadius, fCenterY - fRadius,
323                       fCenterX + fRadius, fCenterY + fRadius);
324}
325
326CFX_ByteString CPWL_Utils::GetEditAppStream(CFX_Edit* pEdit,
327                                            const CFX_PointF& ptOffset,
328                                            const CPVT_WordRange* pRange,
329                                            bool bContinuous,
330                                            uint16_t SubWord) {
331  return CFX_Edit::GetEditAppearanceStream(pEdit, ptOffset, pRange, bContinuous,
332                                           SubWord);
333}
334
335CFX_ByteString CPWL_Utils::GetEditSelAppStream(CFX_Edit* pEdit,
336                                               const CFX_PointF& ptOffset,
337                                               const CPVT_WordRange* pRange) {
338  return CFX_Edit::GetSelectAppearanceStream(pEdit, ptOffset, pRange);
339}
340
341CFX_ByteString CPWL_Utils::GetPushButtonAppStream(const CFX_FloatRect& rcBBox,
342                                                  IPVT_FontMap* pFontMap,
343                                                  CPDF_Stream* pIconStream,
344                                                  CPDF_IconFit& IconFit,
345                                                  const CFX_WideString& sLabel,
346                                                  const CPWL_Color& crText,
347                                                  FX_FLOAT fFontSize,
348                                                  int32_t nLayOut) {
349  const FX_FLOAT fAutoFontScale = 1.0f / 3.0f;
350
351  std::unique_ptr<CFX_Edit> pEdit(new CFX_Edit);
352  pEdit->SetFontMap(pFontMap);
353  pEdit->SetAlignmentH(1, true);
354  pEdit->SetAlignmentV(1, true);
355  pEdit->SetMultiLine(false, true);
356  pEdit->SetAutoReturn(false, true);
357  if (IsFloatZero(fFontSize))
358    pEdit->SetAutoFontSize(true, true);
359  else
360    pEdit->SetFontSize(fFontSize);
361
362  pEdit->Initialize();
363  pEdit->SetText(sLabel);
364
365  CFX_FloatRect rcLabelContent = pEdit->GetContentRect();
366  CPWL_Icon Icon;
367  PWL_CREATEPARAM cp;
368  cp.dwFlags = PWS_VISIBLE;
369  Icon.Create(cp);
370  Icon.SetIconFit(&IconFit);
371  Icon.SetPDFStream(pIconStream);
372
373  CFX_FloatRect rcLabel = CFX_FloatRect(0, 0, 0, 0);
374  CFX_FloatRect rcIcon = CFX_FloatRect(0, 0, 0, 0);
375  FX_FLOAT fWidth = 0.0f;
376  FX_FLOAT fHeight = 0.0f;
377
378  switch (nLayOut) {
379    case PPBL_LABEL:
380      rcLabel = rcBBox;
381      rcIcon = CFX_FloatRect(0, 0, 0, 0);
382      break;
383    case PPBL_ICON:
384      rcIcon = rcBBox;
385      rcLabel = CFX_FloatRect(0, 0, 0, 0);
386      break;
387    case PPBL_ICONTOPLABELBOTTOM:
388
389      if (pIconStream) {
390        if (IsFloatZero(fFontSize)) {
391          fHeight = rcBBox.top - rcBBox.bottom;
392          rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
393                                  rcBBox.bottom + fHeight * fAutoFontScale);
394          rcIcon =
395              CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right, rcBBox.top);
396        } else {
397          fHeight = rcLabelContent.Height();
398
399          if (rcBBox.bottom + fHeight > rcBBox.top) {
400            rcIcon = CFX_FloatRect(0, 0, 0, 0);
401            rcLabel = rcBBox;
402          } else {
403            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
404                                    rcBBox.bottom + fHeight);
405            rcIcon = CFX_FloatRect(rcBBox.left, rcLabel.top, rcBBox.right,
406                                   rcBBox.top);
407          }
408        }
409      } else {
410        rcLabel = rcBBox;
411        rcIcon = CFX_FloatRect(0, 0, 0, 0);
412      }
413
414      break;
415    case PPBL_LABELTOPICONBOTTOM:
416
417      if (pIconStream) {
418        if (IsFloatZero(fFontSize)) {
419          fHeight = rcBBox.top - rcBBox.bottom;
420          rcLabel =
421              CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight * fAutoFontScale,
422                            rcBBox.right, rcBBox.top);
423          rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
424                                 rcLabel.bottom);
425        } else {
426          fHeight = rcLabelContent.Height();
427
428          if (rcBBox.bottom + fHeight > rcBBox.top) {
429            rcIcon = CFX_FloatRect(0, 0, 0, 0);
430            rcLabel = rcBBox;
431          } else {
432            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.top - fHeight,
433                                    rcBBox.right, rcBBox.top);
434            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcBBox.right,
435                                   rcLabel.bottom);
436          }
437        }
438      } else {
439        rcLabel = rcBBox;
440        rcIcon = CFX_FloatRect(0, 0, 0, 0);
441      }
442
443      break;
444    case PPBL_ICONLEFTLABELRIGHT:
445
446      if (pIconStream) {
447        if (IsFloatZero(fFontSize)) {
448          fWidth = rcBBox.right - rcBBox.left;
449          rcLabel = CFX_FloatRect(rcBBox.right - fWidth * fAutoFontScale,
450                                  rcBBox.bottom, rcBBox.right, rcBBox.top);
451          rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
452                                 rcBBox.top);
453
454          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
455          } else {
456            if (rcLabelContent.Width() < fWidth) {
457              rcLabel = CFX_FloatRect(rcBBox.right - rcLabelContent.Width(),
458                                      rcBBox.bottom, rcBBox.right, rcBBox.top);
459              rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
460                                     rcBBox.top);
461            } else {
462              rcLabel = rcBBox;
463              rcIcon = CFX_FloatRect(0, 0, 0, 0);
464            }
465          }
466        } else {
467          fWidth = rcLabelContent.Width();
468
469          if (rcBBox.left + fWidth > rcBBox.right) {
470            rcLabel = rcBBox;
471            rcIcon = CFX_FloatRect(0, 0, 0, 0);
472          } else {
473            rcLabel = CFX_FloatRect(rcBBox.right - fWidth, rcBBox.bottom,
474                                    rcBBox.right, rcBBox.top);
475            rcIcon = CFX_FloatRect(rcBBox.left, rcBBox.bottom, rcLabel.left,
476                                   rcBBox.top);
477          }
478        }
479      } else {
480        rcLabel = rcBBox;
481        rcIcon = CFX_FloatRect(0, 0, 0, 0);
482      }
483
484      break;
485    case PPBL_LABELLEFTICONRIGHT:
486
487      if (pIconStream) {
488        if (IsFloatZero(fFontSize)) {
489          fWidth = rcBBox.right - rcBBox.left;
490          rcLabel =
491              CFX_FloatRect(rcBBox.left, rcBBox.bottom,
492                            rcBBox.left + fWidth * fAutoFontScale, rcBBox.top);
493          rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
494                                 rcBBox.top);
495
496          if (rcLabelContent.Width() < fWidth * fAutoFontScale) {
497          } else {
498            if (rcLabelContent.Width() < fWidth) {
499              rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
500                                      rcBBox.left + rcLabelContent.Width(),
501                                      rcBBox.top);
502              rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
503                                     rcBBox.top);
504            } else {
505              rcLabel = rcBBox;
506              rcIcon = CFX_FloatRect(0, 0, 0, 0);
507            }
508          }
509        } else {
510          fWidth = rcLabelContent.Width();
511
512          if (rcBBox.left + fWidth > rcBBox.right) {
513            rcLabel = rcBBox;
514            rcIcon = CFX_FloatRect(0, 0, 0, 0);
515          } else {
516            rcLabel = CFX_FloatRect(rcBBox.left, rcBBox.bottom,
517                                    rcBBox.left + fWidth, rcBBox.top);
518            rcIcon = CFX_FloatRect(rcLabel.right, rcBBox.bottom, rcBBox.right,
519                                   rcBBox.top);
520          }
521        }
522      } else {
523        rcLabel = rcBBox;
524        rcIcon = CFX_FloatRect(0, 0, 0, 0);
525      }
526
527      break;
528    case PPBL_LABELOVERICON:
529      rcLabel = rcBBox;
530      rcIcon = rcBBox;
531      break;
532  }
533
534  CFX_ByteTextBuf sAppStream, sTemp;
535
536  if (!rcIcon.IsEmpty()) {
537    Icon.Move(rcIcon, false, false);
538    sTemp << Icon.GetImageAppStream();
539  }
540
541  Icon.Destroy();
542
543  if (!rcLabel.IsEmpty()) {
544    pEdit->SetPlateRect(rcLabel);
545    CFX_ByteString sEdit =
546        CPWL_Utils::GetEditAppStream(pEdit.get(), CFX_PointF(0.0f, 0.0f));
547    if (sEdit.GetLength() > 0) {
548      sTemp << "BT\n"
549            << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n";
550    }
551  }
552
553  if (sTemp.GetSize() > 0) {
554    sAppStream << "q\n"
555               << rcBBox.left << " " << rcBBox.bottom << " "
556               << rcBBox.right - rcBBox.left << " "
557               << rcBBox.top - rcBBox.bottom << " re W n\n";
558    sAppStream << sTemp << "Q\n";
559  }
560  return sAppStream.MakeString();
561}
562
563CFX_ByteString CPWL_Utils::GetColorAppStream(const CPWL_Color& color,
564                                             const bool& bFillOrStroke) {
565  CFX_ByteTextBuf sColorStream;
566
567  switch (color.nColorType) {
568    case COLORTYPE_RGB:
569      sColorStream << color.fColor1 << " " << color.fColor2 << " "
570                   << color.fColor3 << " " << (bFillOrStroke ? "rg" : "RG")
571                   << "\n";
572      break;
573    case COLORTYPE_GRAY:
574      sColorStream << color.fColor1 << " " << (bFillOrStroke ? "g" : "G")
575                   << "\n";
576      break;
577    case COLORTYPE_CMYK:
578      sColorStream << color.fColor1 << " " << color.fColor2 << " "
579                   << color.fColor3 << " " << color.fColor4 << " "
580                   << (bFillOrStroke ? "k" : "K") << "\n";
581      break;
582  }
583
584  return sColorStream.MakeString();
585}
586
587CFX_ByteString CPWL_Utils::GetBorderAppStream(const CFX_FloatRect& rect,
588                                              FX_FLOAT fWidth,
589                                              const CPWL_Color& color,
590                                              const CPWL_Color& crLeftTop,
591                                              const CPWL_Color& crRightBottom,
592                                              BorderStyle nStyle,
593                                              const CPWL_Dash& dash) {
594  CFX_ByteTextBuf sAppStream;
595  CFX_ByteString sColor;
596
597  FX_FLOAT fLeft = rect.left;
598  FX_FLOAT fRight = rect.right;
599  FX_FLOAT fTop = rect.top;
600  FX_FLOAT fBottom = rect.bottom;
601
602  if (fWidth > 0.0f) {
603    FX_FLOAT fHalfWidth = fWidth / 2.0f;
604
605    sAppStream << "q\n";
606
607    switch (nStyle) {
608      default:
609      case BorderStyle::SOLID:
610        sColor = CPWL_Utils::GetColorAppStream(color, true);
611        if (sColor.GetLength() > 0) {
612          sAppStream << sColor;
613          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
614                     << fTop - fBottom << " re\n";
615          sAppStream << fLeft + fWidth << " " << fBottom + fWidth << " "
616                     << fRight - fLeft - fWidth * 2 << " "
617                     << fTop - fBottom - fWidth * 2 << " re\n";
618          sAppStream << "f*\n";
619        }
620        break;
621      case BorderStyle::DASH:
622        sColor = CPWL_Utils::GetColorAppStream(color, false);
623        if (sColor.GetLength() > 0) {
624          sAppStream << sColor;
625          sAppStream << fWidth << " w"
626                     << " [" << dash.nDash << " " << dash.nGap << "] "
627                     << dash.nPhase << " d\n";
628          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
629                     << " m\n";
630          sAppStream << fLeft + fWidth / 2 << " " << fTop - fWidth / 2
631                     << " l\n";
632          sAppStream << fRight - fWidth / 2 << " " << fTop - fWidth / 2
633                     << " l\n";
634          sAppStream << fRight - fWidth / 2 << " " << fBottom + fWidth / 2
635                     << " l\n";
636          sAppStream << fLeft + fWidth / 2 << " " << fBottom + fWidth / 2
637                     << " l S\n";
638        }
639        break;
640      case BorderStyle::BEVELED:
641      case BorderStyle::INSET:
642        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, true);
643        if (sColor.GetLength() > 0) {
644          sAppStream << sColor;
645          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
646                     << " m\n";
647          sAppStream << fLeft + fHalfWidth << " " << fTop - fHalfWidth
648                     << " l\n";
649          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
650                     << " l\n";
651          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
652                     << " l\n";
653          sAppStream << fLeft + fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
654                     << " l\n";
655          sAppStream << fLeft + fHalfWidth * 2 << " "
656                     << fBottom + fHalfWidth * 2 << " l f\n";
657        }
658
659        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, true);
660        if (sColor.GetLength() > 0) {
661          sAppStream << sColor;
662          sAppStream << fRight - fHalfWidth << " " << fTop - fHalfWidth
663                     << " m\n";
664          sAppStream << fRight - fHalfWidth << " " << fBottom + fHalfWidth
665                     << " l\n";
666          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth
667                     << " l\n";
668          sAppStream << fLeft + fHalfWidth * 2 << " "
669                     << fBottom + fHalfWidth * 2 << " l\n";
670          sAppStream << fRight - fHalfWidth * 2 << " "
671                     << fBottom + fHalfWidth * 2 << " l\n";
672          sAppStream << fRight - fHalfWidth * 2 << " " << fTop - fHalfWidth * 2
673                     << " l f\n";
674        }
675
676        sColor = CPWL_Utils::GetColorAppStream(color, true);
677        if (sColor.GetLength() > 0) {
678          sAppStream << sColor;
679          sAppStream << fLeft << " " << fBottom << " " << fRight - fLeft << " "
680                     << fTop - fBottom << " re\n";
681          sAppStream << fLeft + fHalfWidth << " " << fBottom + fHalfWidth << " "
682                     << fRight - fLeft - fHalfWidth * 2 << " "
683                     << fTop - fBottom - fHalfWidth * 2 << " re f*\n";
684        }
685        break;
686      case BorderStyle::UNDERLINE:
687        sColor = CPWL_Utils::GetColorAppStream(color, false);
688        if (sColor.GetLength() > 0) {
689          sAppStream << sColor;
690          sAppStream << fWidth << " w\n";
691          sAppStream << fLeft << " " << fBottom + fWidth / 2 << " m\n";
692          sAppStream << fRight << " " << fBottom + fWidth / 2 << " l S\n";
693        }
694        break;
695    }
696
697    sAppStream << "Q\n";
698  }
699
700  return sAppStream.MakeString();
701}
702
703CFX_ByteString CPWL_Utils::GetCircleBorderAppStream(
704    const CFX_FloatRect& rect,
705    FX_FLOAT fWidth,
706    const CPWL_Color& color,
707    const CPWL_Color& crLeftTop,
708    const CPWL_Color& crRightBottom,
709    BorderStyle nStyle,
710    const CPWL_Dash& dash) {
711  CFX_ByteTextBuf sAppStream;
712  CFX_ByteString sColor;
713
714  if (fWidth > 0.0f) {
715    sAppStream << "q\n";
716
717    switch (nStyle) {
718      default:
719      case BorderStyle::SOLID:
720      case BorderStyle::UNDERLINE: {
721        sColor = CPWL_Utils::GetColorAppStream(color, false);
722        if (sColor.GetLength() > 0) {
723          sAppStream << "q\n" << fWidth << " w\n" << sColor
724                     << CPWL_Utils::GetAP_Circle(
725                            CPWL_Utils::DeflateRect(rect, fWidth / 2.0f))
726                     << " S\nQ\n";
727        }
728      } break;
729      case BorderStyle::DASH: {
730        sColor = CPWL_Utils::GetColorAppStream(color, false);
731        if (sColor.GetLength() > 0) {
732          sAppStream << "q\n" << fWidth << " w\n"
733                     << "[" << dash.nDash << " " << dash.nGap << "] "
734                     << dash.nPhase << " d\n" << sColor
735                     << CPWL_Utils::GetAP_Circle(
736                            CPWL_Utils::DeflateRect(rect, fWidth / 2.0f))
737                     << " S\nQ\n";
738        }
739      } break;
740      case BorderStyle::BEVELED: {
741        FX_FLOAT fHalfWidth = fWidth / 2.0f;
742
743        sColor = CPWL_Utils::GetColorAppStream(color, false);
744        if (sColor.GetLength() > 0) {
745          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
746                     << CPWL_Utils::GetAP_Circle(rect) << " S\nQ\n";
747        }
748
749        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false);
750        if (sColor.GetLength() > 0) {
751          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
752                     << CPWL_Utils::GetAP_HalfCircle(
753                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
754                            FX_PI / 4.0f)
755                     << " S\nQ\n";
756        }
757
758        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false);
759        if (sColor.GetLength() > 0) {
760          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
761                     << CPWL_Utils::GetAP_HalfCircle(
762                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
763                            FX_PI * 5 / 4.0f)
764                     << " S\nQ\n";
765        }
766      } break;
767      case BorderStyle::INSET: {
768        FX_FLOAT fHalfWidth = fWidth / 2.0f;
769
770        sColor = CPWL_Utils::GetColorAppStream(color, false);
771        if (sColor.GetLength() > 0) {
772          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
773                     << CPWL_Utils::GetAP_Circle(rect) << " S\nQ\n";
774        }
775
776        sColor = CPWL_Utils::GetColorAppStream(crLeftTop, false);
777        if (sColor.GetLength() > 0) {
778          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
779                     << CPWL_Utils::GetAP_HalfCircle(
780                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
781                            FX_PI / 4.0f)
782                     << " S\nQ\n";
783        }
784
785        sColor = CPWL_Utils::GetColorAppStream(crRightBottom, false);
786        if (sColor.GetLength() > 0) {
787          sAppStream << "q\n" << fHalfWidth << " w\n" << sColor
788                     << CPWL_Utils::GetAP_HalfCircle(
789                            CPWL_Utils::DeflateRect(rect, fHalfWidth * 0.75f),
790                            FX_PI * 5 / 4.0f)
791                     << " S\nQ\n";
792        }
793      } break;
794    }
795
796    sAppStream << "Q\n";
797  }
798
799  return sAppStream.MakeString();
800}
801
802CFX_ByteString CPWL_Utils::GetAppStream_Check(const CFX_FloatRect& rcBBox,
803                                              const CPWL_Color& crText) {
804  CFX_ByteTextBuf sAP;
805  sAP << "q\n"
806      << CPWL_Utils::GetColorAppStream(crText, true)
807      << CPWL_Utils::GetAP_Check(rcBBox) << "f\nQ\n";
808  return sAP.MakeString();
809}
810
811CFX_ByteString CPWL_Utils::GetAppStream_Circle(const CFX_FloatRect& rcBBox,
812                                               const CPWL_Color& crText) {
813  CFX_ByteTextBuf sAP;
814  sAP << "q\n"
815      << CPWL_Utils::GetColorAppStream(crText, true)
816      << CPWL_Utils::GetAP_Circle(rcBBox) << "f\nQ\n";
817  return sAP.MakeString();
818}
819
820CFX_ByteString CPWL_Utils::GetAppStream_Cross(const CFX_FloatRect& rcBBox,
821                                              const CPWL_Color& crText) {
822  CFX_ByteTextBuf sAP;
823  sAP << "q\n"
824      << CPWL_Utils::GetColorAppStream(crText, false)
825      << CPWL_Utils::GetAP_Cross(rcBBox) << "S\nQ\n";
826  return sAP.MakeString();
827}
828
829CFX_ByteString CPWL_Utils::GetAppStream_Diamond(const CFX_FloatRect& rcBBox,
830                                                const CPWL_Color& crText) {
831  CFX_ByteTextBuf sAP;
832  sAP << "q\n1 w\n"
833      << CPWL_Utils::GetColorAppStream(crText, true)
834      << CPWL_Utils::GetAP_Diamond(rcBBox) << "f\nQ\n";
835  return sAP.MakeString();
836}
837
838CFX_ByteString CPWL_Utils::GetAppStream_Square(const CFX_FloatRect& rcBBox,
839                                               const CPWL_Color& crText) {
840  CFX_ByteTextBuf sAP;
841  sAP << "q\n"
842      << CPWL_Utils::GetColorAppStream(crText, true)
843      << CPWL_Utils::GetAP_Square(rcBBox) << "f\nQ\n";
844  return sAP.MakeString();
845}
846
847CFX_ByteString CPWL_Utils::GetAppStream_Star(const CFX_FloatRect& rcBBox,
848                                             const CPWL_Color& crText) {
849  CFX_ByteTextBuf sAP;
850  sAP << "q\n"
851      << CPWL_Utils::GetColorAppStream(crText, true)
852      << CPWL_Utils::GetAP_Star(rcBBox) << "f\nQ\n";
853  return sAP.MakeString();
854}
855
856CFX_ByteString CPWL_Utils::GetCheckBoxAppStream(const CFX_FloatRect& rcBBox,
857                                                int32_t nStyle,
858                                                const CPWL_Color& crText) {
859  CFX_FloatRect rcCenter = GetCenterSquare(rcBBox);
860  switch (nStyle) {
861    default:
862    case PCS_CHECK:
863      return GetAppStream_Check(rcCenter, crText);
864    case PCS_CIRCLE:
865      return GetAppStream_Circle(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
866    case PCS_CROSS:
867      return GetAppStream_Cross(rcCenter, crText);
868    case PCS_DIAMOND:
869      return GetAppStream_Diamond(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
870    case PCS_SQUARE:
871      return GetAppStream_Square(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
872    case PCS_STAR:
873      return GetAppStream_Star(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
874  }
875}
876
877CFX_ByteString CPWL_Utils::GetRadioButtonAppStream(const CFX_FloatRect& rcBBox,
878                                                   int32_t nStyle,
879                                                   const CPWL_Color& crText) {
880  CFX_FloatRect rcCenter = GetCenterSquare(rcBBox);
881  switch (nStyle) {
882    default:
883    case PCS_CHECK:
884      return GetAppStream_Check(rcCenter, crText);
885    case PCS_CIRCLE:
886      return GetAppStream_Circle(ScaleRect(rcCenter, 1.0f / 2.0f), crText);
887    case PCS_CROSS:
888      return GetAppStream_Cross(rcCenter, crText);
889    case PCS_DIAMOND:
890      return GetAppStream_Diamond(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
891    case PCS_SQUARE:
892      return GetAppStream_Square(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
893    case PCS_STAR:
894      return GetAppStream_Star(ScaleRect(rcCenter, 2.0f / 3.0f), crText);
895  }
896}
897
898CFX_ByteString CPWL_Utils::GetDropButtonAppStream(const CFX_FloatRect& rcBBox) {
899  CFX_ByteTextBuf sAppStream;
900
901  if (!rcBBox.IsEmpty()) {
902    sAppStream << "q\n"
903               << CPWL_Utils::GetColorAppStream(
904                      CPWL_Color(COLORTYPE_RGB, 220.0f / 255.0f,
905                                 220.0f / 255.0f, 220.0f / 255.0f),
906                      true);
907    sAppStream << rcBBox.left << " " << rcBBox.bottom << " "
908               << rcBBox.right - rcBBox.left << " "
909               << rcBBox.top - rcBBox.bottom << " re f\n";
910    sAppStream << "Q\n";
911
912    sAppStream << "q\n"
913               << CPWL_Utils::GetBorderAppStream(
914                      rcBBox, 2, CPWL_Color(COLORTYPE_GRAY, 0),
915                      CPWL_Color(COLORTYPE_GRAY, 1),
916                      CPWL_Color(COLORTYPE_GRAY, 0.5), BorderStyle::BEVELED,
917                      CPWL_Dash(3, 0, 0))
918               << "Q\n";
919
920    CFX_PointF ptCenter = CFX_PointF((rcBBox.left + rcBBox.right) / 2,
921                                     (rcBBox.top + rcBBox.bottom) / 2);
922    if (IsFloatBigger(rcBBox.right - rcBBox.left, 6) &&
923        IsFloatBigger(rcBBox.top - rcBBox.bottom, 6)) {
924      sAppStream << "q\n"
925                 << " 0 g\n";
926      sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " m\n";
927      sAppStream << ptCenter.x + 3 << " " << ptCenter.y + 1.5f << " l\n";
928      sAppStream << ptCenter.x << " " << ptCenter.y - 1.5f << " l\n";
929      sAppStream << ptCenter.x - 3 << " " << ptCenter.y + 1.5f << " l f\n";
930      sAppStream << "Q\n";
931    }
932  }
933
934  return sAppStream.MakeString();
935}
936
937void CPWL_Utils::DrawFillRect(CFX_RenderDevice* pDevice,
938                              CFX_Matrix* pUser2Device,
939                              const CFX_FloatRect& rect,
940                              const FX_COLORREF& color) {
941  CFX_PathData path;
942  CFX_FloatRect rcTemp(rect);
943  path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
944  pDevice->DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_WINDING);
945}
946
947void CPWL_Utils::DrawFillArea(CFX_RenderDevice* pDevice,
948                              CFX_Matrix* pUser2Device,
949                              const CFX_PointF* pPts,
950                              int32_t nCount,
951                              const FX_COLORREF& color) {
952  CFX_PathData path;
953  path.AppendPoint(pPts[0], FXPT_TYPE::MoveTo, false);
954  for (int32_t i = 1; i < nCount; i++)
955    path.AppendPoint(pPts[i], FXPT_TYPE::LineTo, false);
956
957  pDevice->DrawPath(&path, pUser2Device, nullptr, color, 0, FXFILL_ALTERNATE);
958}
959
960void CPWL_Utils::DrawStrokeRect(CFX_RenderDevice* pDevice,
961                                CFX_Matrix* pUser2Device,
962                                const CFX_FloatRect& rect,
963                                const FX_COLORREF& color,
964                                FX_FLOAT fWidth) {
965  CFX_PathData path;
966  CFX_FloatRect rcTemp(rect);
967  path.AppendRect(rcTemp.left, rcTemp.bottom, rcTemp.right, rcTemp.top);
968
969  CFX_GraphStateData gsd;
970  gsd.m_LineWidth = fWidth;
971
972  pDevice->DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
973}
974
975void CPWL_Utils::DrawStrokeLine(CFX_RenderDevice* pDevice,
976                                CFX_Matrix* pUser2Device,
977                                const CFX_PointF& ptMoveTo,
978                                const CFX_PointF& ptLineTo,
979                                const FX_COLORREF& color,
980                                FX_FLOAT fWidth) {
981  CFX_PathData path;
982  path.AppendPoint(ptMoveTo, FXPT_TYPE::MoveTo, false);
983  path.AppendPoint(ptLineTo, FXPT_TYPE::LineTo, false);
984
985  CFX_GraphStateData gsd;
986  gsd.m_LineWidth = fWidth;
987
988  pDevice->DrawPath(&path, pUser2Device, &gsd, 0, color, FXFILL_ALTERNATE);
989}
990
991void CPWL_Utils::DrawFillRect(CFX_RenderDevice* pDevice,
992                              CFX_Matrix* pUser2Device,
993                              const CFX_FloatRect& rect,
994                              const CPWL_Color& color,
995                              int32_t nTransparency) {
996  CPWL_Utils::DrawFillRect(pDevice, pUser2Device, rect,
997                           color.ToFXColor(nTransparency));
998}
999
1000void CPWL_Utils::DrawShadow(CFX_RenderDevice* pDevice,
1001                            CFX_Matrix* pUser2Device,
1002                            bool bVertical,
1003                            bool bHorizontal,
1004                            CFX_FloatRect rect,
1005                            int32_t nTransparency,
1006                            int32_t nStartGray,
1007                            int32_t nEndGray) {
1008  FX_FLOAT fStepGray = 1.0f;
1009
1010  if (bVertical) {
1011    fStepGray = (nEndGray - nStartGray) / rect.Height();
1012
1013    for (FX_FLOAT fy = rect.bottom + 0.5f; fy <= rect.top - 0.5f; fy += 1.0f) {
1014      int32_t nGray = nStartGray + (int32_t)(fStepGray * (fy - rect.bottom));
1015      CPWL_Utils::DrawStrokeLine(
1016          pDevice, pUser2Device, CFX_PointF(rect.left, fy),
1017          CFX_PointF(rect.right, fy),
1018          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
1019    }
1020  }
1021
1022  if (bHorizontal) {
1023    fStepGray = (nEndGray - nStartGray) / rect.Width();
1024
1025    for (FX_FLOAT fx = rect.left + 0.5f; fx <= rect.right - 0.5f; fx += 1.0f) {
1026      int32_t nGray = nStartGray + (int32_t)(fStepGray * (fx - rect.left));
1027      CPWL_Utils::DrawStrokeLine(
1028          pDevice, pUser2Device, CFX_PointF(fx, rect.bottom),
1029          CFX_PointF(fx, rect.top),
1030          ArgbEncode(nTransparency, nGray, nGray, nGray), 1.5f);
1031    }
1032  }
1033}
1034
1035void CPWL_Utils::DrawBorder(CFX_RenderDevice* pDevice,
1036                            CFX_Matrix* pUser2Device,
1037                            const CFX_FloatRect& rect,
1038                            FX_FLOAT fWidth,
1039                            const CPWL_Color& color,
1040                            const CPWL_Color& crLeftTop,
1041                            const CPWL_Color& crRightBottom,
1042                            BorderStyle nStyle,
1043                            int32_t nTransparency) {
1044  FX_FLOAT fLeft = rect.left;
1045  FX_FLOAT fRight = rect.right;
1046  FX_FLOAT fTop = rect.top;
1047  FX_FLOAT fBottom = rect.bottom;
1048
1049  if (fWidth > 0.0f) {
1050    FX_FLOAT fHalfWidth = fWidth / 2.0f;
1051
1052    switch (nStyle) {
1053      default:
1054      case BorderStyle::SOLID: {
1055        CFX_PathData path;
1056        path.AppendRect(fLeft, fBottom, fRight, fTop);
1057        path.AppendRect(fLeft + fWidth, fBottom + fWidth, fRight - fWidth,
1058                        fTop - fWidth);
1059        pDevice->DrawPath(&path, pUser2Device, nullptr,
1060                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
1061        break;
1062      }
1063      case BorderStyle::DASH: {
1064        CFX_PathData path;
1065        path.AppendPoint(
1066            CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
1067            FXPT_TYPE::MoveTo, false);
1068        path.AppendPoint(
1069            CFX_PointF(fLeft + fWidth / 2.0f, fTop - fWidth / 2.0f),
1070            FXPT_TYPE::LineTo, false);
1071        path.AppendPoint(
1072            CFX_PointF(fRight - fWidth / 2.0f, fTop - fWidth / 2.0f),
1073            FXPT_TYPE::LineTo, false);
1074        path.AppendPoint(
1075            CFX_PointF(fRight - fWidth / 2.0f, fBottom + fWidth / 2.0f),
1076            FXPT_TYPE::LineTo, false);
1077        path.AppendPoint(
1078            CFX_PointF(fLeft + fWidth / 2.0f, fBottom + fWidth / 2.0f),
1079            FXPT_TYPE::LineTo, false);
1080
1081        CFX_GraphStateData gsd;
1082        gsd.SetDashCount(2);
1083        gsd.m_DashArray[0] = 3.0f;
1084        gsd.m_DashArray[1] = 3.0f;
1085        gsd.m_DashPhase = 0;
1086
1087        gsd.m_LineWidth = fWidth;
1088        pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
1089                          color.ToFXColor(nTransparency), FXFILL_WINDING);
1090        break;
1091      }
1092      case BorderStyle::BEVELED:
1093      case BorderStyle::INSET: {
1094        CFX_GraphStateData gsd;
1095        gsd.m_LineWidth = fHalfWidth;
1096
1097        CFX_PathData pathLT;
1098
1099        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1100                           FXPT_TYPE::MoveTo, false);
1101        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fTop - fHalfWidth),
1102                           FXPT_TYPE::LineTo, false);
1103        pathLT.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1104                           FXPT_TYPE::LineTo, false);
1105        pathLT.AppendPoint(
1106            CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
1107            FXPT_TYPE::LineTo, false);
1108        pathLT.AppendPoint(
1109            CFX_PointF(fLeft + fHalfWidth * 2, fTop - fHalfWidth * 2),
1110            FXPT_TYPE::LineTo, false);
1111        pathLT.AppendPoint(
1112            CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
1113            FXPT_TYPE::LineTo, false);
1114        pathLT.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1115                           FXPT_TYPE::LineTo, false);
1116
1117        pDevice->DrawPath(&pathLT, pUser2Device, &gsd,
1118                          crLeftTop.ToFXColor(nTransparency), 0,
1119                          FXFILL_ALTERNATE);
1120
1121        CFX_PathData pathRB;
1122        pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1123                           FXPT_TYPE::MoveTo, false);
1124        pathRB.AppendPoint(
1125            CFX_PointF(fRight - fHalfWidth, fBottom + fHalfWidth),
1126            FXPT_TYPE::LineTo, false);
1127        pathRB.AppendPoint(CFX_PointF(fLeft + fHalfWidth, fBottom + fHalfWidth),
1128                           FXPT_TYPE::LineTo, false);
1129        pathRB.AppendPoint(
1130            CFX_PointF(fLeft + fHalfWidth * 2, fBottom + fHalfWidth * 2),
1131            FXPT_TYPE::LineTo, false);
1132        pathRB.AppendPoint(
1133            CFX_PointF(fRight - fHalfWidth * 2, fBottom + fHalfWidth * 2),
1134            FXPT_TYPE::LineTo, false);
1135        pathRB.AppendPoint(
1136            CFX_PointF(fRight - fHalfWidth * 2, fTop - fHalfWidth * 2),
1137            FXPT_TYPE::LineTo, false);
1138        pathRB.AppendPoint(CFX_PointF(fRight - fHalfWidth, fTop - fHalfWidth),
1139                           FXPT_TYPE::LineTo, false);
1140
1141        pDevice->DrawPath(&pathRB, pUser2Device, &gsd,
1142                          crRightBottom.ToFXColor(nTransparency), 0,
1143                          FXFILL_ALTERNATE);
1144
1145        CFX_PathData path;
1146
1147        path.AppendRect(fLeft, fBottom, fRight, fTop);
1148        path.AppendRect(fLeft + fHalfWidth, fBottom + fHalfWidth,
1149                        fRight - fHalfWidth, fTop - fHalfWidth);
1150
1151        pDevice->DrawPath(&path, pUser2Device, &gsd,
1152                          color.ToFXColor(nTransparency), 0, FXFILL_ALTERNATE);
1153        break;
1154      }
1155      case BorderStyle::UNDERLINE: {
1156        CFX_PathData path;
1157        path.AppendPoint(CFX_PointF(fLeft, fBottom + fWidth / 2),
1158                         FXPT_TYPE::MoveTo, false);
1159        path.AppendPoint(CFX_PointF(fRight, fBottom + fWidth / 2),
1160                         FXPT_TYPE::LineTo, false);
1161
1162        CFX_GraphStateData gsd;
1163        gsd.m_LineWidth = fWidth;
1164
1165        pDevice->DrawPath(&path, pUser2Device, &gsd, 0,
1166                          color.ToFXColor(nTransparency), FXFILL_ALTERNATE);
1167        break;
1168      }
1169    }
1170  }
1171}
1172
1173