Home | History | Annotate | Download | only in pdfwindow
      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 
     20 CFX_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 
     27 CPVT_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 
     53 CFX_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 
    102 CFX_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 
    144 CFX_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 
    155 CFX_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 
    175 CFX_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 
    187 CFX_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 
    219 CFX_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 
    254 CFX_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 
    265 CFX_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 
    276 CFX_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 
    289 CFX_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 
    303 CFX_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 
    313 CFX_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 
    326 CFX_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 
    335 CFX_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 
    341 CFX_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 
    563 CFX_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 
    587 CFX_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 
    703 CFX_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 
    802 CFX_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 
    811 CFX_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 
    820 CFX_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 
    829 CFX_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 
    838 CFX_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 
    847 CFX_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 
    856 CFX_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 
    877 CFX_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 
    898 CFX_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 
    937 void 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 
    947 void 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 
    960 void 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 
    975 void 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 
    991 void 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 
   1000 void 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 
   1035 void 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