Home | History | Annotate | Download | only in app
      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 "xfa/fxfa/xfa_ffwidget.h"
      8 
      9 #include <algorithm>
     10 #include <memory>
     11 #include <vector>
     12 
     13 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
     14 #include "core/fxcodec/codec/ccodec_progressivedecoder.h"
     15 #include "core/fxcodec/fx_codec.h"
     16 #include "core/fxcrt/cfx_maybe_owned.h"
     17 #include "core/fxge/cfx_gemodule.h"
     18 #include "core/fxge/cfx_pathdata.h"
     19 #include "core/fxge/cfx_renderdevice.h"
     20 #include "xfa/fwl/fwl_widgethit.h"
     21 #include "xfa/fxfa/app/cxfa_textlayout.h"
     22 #include "xfa/fxfa/cxfa_eventparam.h"
     23 #include "xfa/fxfa/fxfa_widget.h"
     24 #include "xfa/fxfa/parser/cxfa_corner.h"
     25 #include "xfa/fxfa/xfa_ffapp.h"
     26 #include "xfa/fxfa/xfa_ffdoc.h"
     27 #include "xfa/fxfa/xfa_ffdocview.h"
     28 #include "xfa/fxfa/xfa_ffpageview.h"
     29 #include "xfa/fxgraphics/cfx_color.h"
     30 #include "xfa/fxgraphics/cfx_graphics.h"
     31 #include "xfa/fxgraphics/cfx_path.h"
     32 #include "xfa/fxgraphics/cfx_pattern.h"
     33 #include "xfa/fxgraphics/cfx_shading.h"
     34 
     35 CXFA_FFWidget::CXFA_FFWidget(CXFA_WidgetAcc* pDataAcc)
     36     : CXFA_ContentLayoutItem(pDataAcc->GetNode()),
     37       m_pPageView(nullptr),
     38       m_pDataAcc(pDataAcc) {}
     39 
     40 CXFA_FFWidget::~CXFA_FFWidget() {}
     41 
     42 const CFWL_App* CXFA_FFWidget::GetFWLApp() {
     43   return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp();
     44 }
     45 
     46 CFX_RectF CXFA_FFWidget::GetWidgetRect() {
     47   if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0)
     48     RecacheWidgetRect();
     49   return m_rtWidget;
     50 }
     51 
     52 CFX_RectF CXFA_FFWidget::RecacheWidgetRect() {
     53   m_dwStatus |= XFA_WidgetStatus_RectCached;
     54   m_rtWidget = GetRect(false);
     55   return m_rtWidget;
     56 }
     57 
     58 CFX_RectF CXFA_FFWidget::GetRectWithoutRotate() {
     59   CFX_RectF rtWidget = GetWidgetRect();
     60   FX_FLOAT fValue = 0;
     61   switch (m_pDataAcc->GetRotate()) {
     62     case 90:
     63       rtWidget.top = rtWidget.bottom();
     64       fValue = rtWidget.width;
     65       rtWidget.width = rtWidget.height;
     66       rtWidget.height = fValue;
     67       break;
     68     case 180:
     69       rtWidget.left = rtWidget.right();
     70       rtWidget.top = rtWidget.bottom();
     71       break;
     72     case 270:
     73       rtWidget.left = rtWidget.right();
     74       fValue = rtWidget.width;
     75       rtWidget.width = rtWidget.height;
     76       rtWidget.height = fValue;
     77       break;
     78   }
     79   return rtWidget;
     80 }
     81 
     82 uint32_t CXFA_FFWidget::GetStatus() {
     83   return m_dwStatus;
     84 }
     85 
     86 void CXFA_FFWidget::ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved) {
     87   m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded;
     88 }
     89 
     90 CFX_RectF CXFA_FFWidget::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
     91   if (bDrawFocus || !m_pPageView)
     92     return CFX_RectF();
     93   return m_pPageView->GetPageViewRect();
     94 }
     95 
     96 CXFA_WidgetAcc* CXFA_FFWidget::GetDataAcc() {
     97   return m_pDataAcc;
     98 }
     99 
    100 bool CXFA_FFWidget::GetToolTip(CFX_WideString& wsToolTip) {
    101   if (CXFA_Assist assist = m_pDataAcc->GetAssist()) {
    102     if (CXFA_ToolTip toolTip = assist.GetToolTip()) {
    103       return toolTip.GetTip(wsToolTip);
    104     }
    105   }
    106   return GetCaptionText(wsToolTip);
    107 }
    108 
    109 void CXFA_FFWidget::RenderWidget(CFX_Graphics* pGS,
    110                                  CFX_Matrix* pMatrix,
    111                                  uint32_t dwStatus) {
    112   if (!IsMatchVisibleStatus(dwStatus))
    113     return;
    114 
    115   CXFA_Border border = m_pDataAcc->GetBorder();
    116   if (!border)
    117     return;
    118 
    119   CFX_RectF rtBorder = GetRectWithoutRotate();
    120   CXFA_Margin margin = border.GetMargin();
    121   if (margin)
    122     XFA_RectWidthoutMargin(rtBorder, margin);
    123 
    124   rtBorder.Normalize();
    125   DrawBorder(pGS, border, rtBorder, pMatrix);
    126 }
    127 
    128 bool CXFA_FFWidget::IsLoaded() {
    129   return !!m_pPageView;
    130 }
    131 bool CXFA_FFWidget::LoadWidget() {
    132   PerformLayout();
    133   return true;
    134 }
    135 void CXFA_FFWidget::UnloadWidget() {}
    136 bool CXFA_FFWidget::PerformLayout() {
    137   RecacheWidgetRect();
    138   return true;
    139 }
    140 bool CXFA_FFWidget::UpdateFWLData() {
    141   return false;
    142 }
    143 void CXFA_FFWidget::UpdateWidgetProperty() {}
    144 void CXFA_FFWidget::DrawBorder(CFX_Graphics* pGS,
    145                                CXFA_Box box,
    146                                const CFX_RectF& rtBorder,
    147                                CFX_Matrix* pMatrix,
    148                                uint32_t dwFlags) {
    149   XFA_DrawBox(box, pGS, rtBorder, pMatrix, dwFlags);
    150 }
    151 
    152 void CXFA_FFWidget::InvalidateWidget(const CFX_RectF* pRect) {
    153   if (pRect) {
    154     GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, *pRect,
    155                                                   XFA_INVALIDATE_CurrentPage);
    156     return;
    157   }
    158 
    159   CFX_RectF rtWidget = GetBBox(XFA_WidgetStatus_Focused);
    160   rtWidget.Inflate(2, 2);
    161   GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, rtWidget,
    162                                                 XFA_INVALIDATE_CurrentPage);
    163 }
    164 
    165 void CXFA_FFWidget::AddInvalidateRect(const CFX_RectF* pRect) {
    166   CFX_RectF rtWidget;
    167   if (pRect) {
    168     rtWidget = *pRect;
    169   } else {
    170     rtWidget = GetBBox(XFA_WidgetStatus_Focused);
    171     rtWidget.Inflate(2, 2);
    172   }
    173   m_pDocView->AddInvalidateRect(m_pPageView, rtWidget);
    174 }
    175 
    176 bool CXFA_FFWidget::GetCaptionText(CFX_WideString& wsCap) {
    177   CXFA_TextLayout* pCapTextlayout = m_pDataAcc->GetCaptionTextLayout();
    178   if (!pCapTextlayout) {
    179     return false;
    180   }
    181   pCapTextlayout->GetText(wsCap);
    182   return true;
    183 }
    184 
    185 bool CXFA_FFWidget::IsFocused() {
    186   return !!(m_dwStatus & XFA_WidgetStatus_Focused);
    187 }
    188 
    189 bool CXFA_FFWidget::OnMouseEnter() {
    190   return false;
    191 }
    192 
    193 bool CXFA_FFWidget::OnMouseExit() {
    194   return false;
    195 }
    196 
    197 bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    198   return false;
    199 }
    200 
    201 bool CXFA_FFWidget::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    202   return false;
    203 }
    204 
    205 bool CXFA_FFWidget::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
    206   return false;
    207 }
    208 
    209 bool CXFA_FFWidget::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
    210   return false;
    211 }
    212 
    213 bool CXFA_FFWidget::OnMouseWheel(uint32_t dwFlags,
    214                                  int16_t zDelta,
    215                                  const CFX_PointF& point) {
    216   return false;
    217 }
    218 
    219 bool CXFA_FFWidget::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    220   return false;
    221 }
    222 
    223 bool CXFA_FFWidget::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    224   return false;
    225 }
    226 
    227 bool CXFA_FFWidget::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
    228   return false;
    229 }
    230 
    231 bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) {
    232   CXFA_FFWidget* pParent = GetParent();
    233   if (pParent && !pParent->IsAncestorOf(pOldWidget)) {
    234     pParent->OnSetFocus(pOldWidget);
    235   }
    236   m_dwStatus |= XFA_WidgetStatus_Focused;
    237   CXFA_EventParam eParam;
    238   eParam.m_eType = XFA_EVENT_Enter;
    239   eParam.m_pTarget = m_pDataAcc;
    240   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Enter, &eParam);
    241   return true;
    242 }
    243 
    244 bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) {
    245   m_dwStatus &= ~XFA_WidgetStatus_Focused;
    246   EventKillFocus();
    247   if (pNewWidget) {
    248     CXFA_FFWidget* pParent = GetParent();
    249     if (pParent && !pParent->IsAncestorOf(pNewWidget)) {
    250       pParent->OnKillFocus(pNewWidget);
    251     }
    252   }
    253   return true;
    254 }
    255 
    256 bool CXFA_FFWidget::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
    257   return false;
    258 }
    259 
    260 bool CXFA_FFWidget::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
    261   return false;
    262 }
    263 
    264 bool CXFA_FFWidget::OnChar(uint32_t dwChar, uint32_t dwFlags) {
    265   return false;
    266 }
    267 
    268 FWL_WidgetHit CXFA_FFWidget::OnHitTest(const CFX_PointF& point) {
    269   return FWL_WidgetHit::Unknown;
    270 }
    271 
    272 bool CXFA_FFWidget::OnSetCursor(const CFX_PointF& point) {
    273   return false;
    274 }
    275 
    276 bool CXFA_FFWidget::CanUndo() {
    277   return false;
    278 }
    279 
    280 bool CXFA_FFWidget::CanRedo() {
    281   return false;
    282 }
    283 
    284 bool CXFA_FFWidget::Undo() {
    285   return false;
    286 }
    287 
    288 bool CXFA_FFWidget::Redo() {
    289   return false;
    290 }
    291 
    292 bool CXFA_FFWidget::CanCopy() {
    293   return false;
    294 }
    295 
    296 bool CXFA_FFWidget::CanCut() {
    297   return false;
    298 }
    299 
    300 bool CXFA_FFWidget::CanPaste() {
    301   return false;
    302 }
    303 
    304 bool CXFA_FFWidget::CanSelectAll() {
    305   return false;
    306 }
    307 
    308 bool CXFA_FFWidget::CanDelete() {
    309   return CanCut();
    310 }
    311 
    312 bool CXFA_FFWidget::CanDeSelect() {
    313   return CanCopy();
    314 }
    315 
    316 bool CXFA_FFWidget::Copy(CFX_WideString& wsCopy) {
    317   return false;
    318 }
    319 
    320 bool CXFA_FFWidget::Cut(CFX_WideString& wsCut) {
    321   return false;
    322 }
    323 
    324 bool CXFA_FFWidget::Paste(const CFX_WideString& wsPaste) {
    325   return false;
    326 }
    327 
    328 void CXFA_FFWidget::SelectAll() {}
    329 
    330 void CXFA_FFWidget::Delete() {}
    331 
    332 void CXFA_FFWidget::DeSelect() {}
    333 
    334 bool CXFA_FFWidget::GetSuggestWords(CFX_PointF pointf,
    335                                     std::vector<CFX_ByteString>& sSuggest) {
    336   return false;
    337 }
    338 bool CXFA_FFWidget::ReplaceSpellCheckWord(CFX_PointF pointf,
    339                                           const CFX_ByteStringC& bsReplace) {
    340   return false;
    341 }
    342 
    343 CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) {
    344   CFX_Matrix mt = GetRotateMatrix();
    345   if (mt.IsIdentity())
    346     return point;
    347 
    348   CFX_Matrix mtReverse;
    349   mtReverse.SetReverse(mt);
    350   return mtReverse.Transform(point);
    351 }
    352 
    353 static void XFA_GetMatrix(CFX_Matrix& m,
    354                           int32_t iRotate,
    355                           XFA_ATTRIBUTEENUM at,
    356                           const CFX_RectF& rt) {
    357   if (!iRotate) {
    358     return;
    359   }
    360   FX_FLOAT fAnchorX = 0;
    361   FX_FLOAT fAnchorY = 0;
    362   switch (at) {
    363     case XFA_ATTRIBUTEENUM_TopLeft:
    364       fAnchorX = rt.left, fAnchorY = rt.top;
    365       break;
    366     case XFA_ATTRIBUTEENUM_TopCenter:
    367       fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.top;
    368       break;
    369     case XFA_ATTRIBUTEENUM_TopRight:
    370       fAnchorX = rt.right(), fAnchorY = rt.top;
    371       break;
    372     case XFA_ATTRIBUTEENUM_MiddleLeft:
    373       fAnchorX = rt.left, fAnchorY = (rt.top + rt.bottom()) / 2;
    374       break;
    375     case XFA_ATTRIBUTEENUM_MiddleCenter:
    376       fAnchorX = (rt.left + rt.right()) / 2,
    377       fAnchorY = (rt.top + rt.bottom()) / 2;
    378       break;
    379     case XFA_ATTRIBUTEENUM_MiddleRight:
    380       fAnchorX = rt.right(), fAnchorY = (rt.top + rt.bottom()) / 2;
    381       break;
    382     case XFA_ATTRIBUTEENUM_BottomLeft:
    383       fAnchorX = rt.left, fAnchorY = rt.bottom();
    384       break;
    385     case XFA_ATTRIBUTEENUM_BottomCenter:
    386       fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.bottom();
    387       break;
    388     case XFA_ATTRIBUTEENUM_BottomRight:
    389       fAnchorX = rt.right(), fAnchorY = rt.bottom();
    390       break;
    391     default:
    392       break;
    393   }
    394   switch (iRotate) {
    395     case 90:
    396       m.a = 0, m.b = -1, m.c = 1, m.d = 0, m.e = fAnchorX - fAnchorY,
    397       m.f = fAnchorX + fAnchorY;
    398       break;
    399     case 180:
    400       m.a = -1, m.b = 0, m.c = 0, m.d = -1, m.e = fAnchorX * 2,
    401       m.f = fAnchorY * 2;
    402       break;
    403     case 270:
    404       m.a = 0, m.b = 1, m.c = -1, m.d = 0, m.e = fAnchorX + fAnchorY,
    405       m.f = fAnchorY - fAnchorX;
    406       break;
    407   }
    408 }
    409 
    410 CFX_Matrix CXFA_FFWidget::GetRotateMatrix() {
    411   CFX_Matrix mt;
    412   int32_t iRotate = m_pDataAcc->GetRotate();
    413   if (!iRotate)
    414     return mt;
    415 
    416   CFX_RectF rcWidget = GetRectWithoutRotate();
    417   XFA_ATTRIBUTEENUM at = XFA_ATTRIBUTEENUM_TopLeft;
    418   XFA_GetMatrix(mt, iRotate, at, rcWidget);
    419 
    420   return mt;
    421 }
    422 
    423 bool CXFA_FFWidget::IsLayoutRectEmpty() {
    424   CFX_RectF rtLayout = GetRectWithoutRotate();
    425   return rtLayout.width < 0.1f && rtLayout.height < 0.1f;
    426 }
    427 CXFA_FFWidget* CXFA_FFWidget::GetParent() {
    428   CXFA_Node* pParentNode =
    429       m_pDataAcc->GetNode()->GetNodeItem(XFA_NODEITEM_Parent);
    430   if (pParentNode) {
    431     CXFA_WidgetAcc* pParentWidgetAcc =
    432         static_cast<CXFA_WidgetAcc*>(pParentNode->GetWidgetData());
    433     if (pParentWidgetAcc) {
    434       return pParentWidgetAcc->GetNextWidget(nullptr);
    435     }
    436   }
    437   return nullptr;
    438 }
    439 
    440 bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) {
    441   if (!pWidget)
    442     return false;
    443 
    444   CXFA_Node* pNode = m_pDataAcc->GetNode();
    445   CXFA_Node* pChildNode = pWidget->GetDataAcc()->GetNode();
    446   while (pChildNode) {
    447     if (pChildNode == pNode)
    448       return true;
    449 
    450     pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_Parent);
    451   }
    452   return false;
    453 }
    454 
    455 bool CXFA_FFWidget::PtInActiveRect(const CFX_PointF& point) {
    456   return GetWidgetRect().Contains(point);
    457 }
    458 
    459 CXFA_FFDocView* CXFA_FFWidget::GetDocView() {
    460   return m_pDocView;
    461 }
    462 
    463 void CXFA_FFWidget::SetDocView(CXFA_FFDocView* pDocView) {
    464   m_pDocView = pDocView;
    465 }
    466 
    467 CXFA_FFDoc* CXFA_FFWidget::GetDoc() {
    468   return m_pDocView->GetDoc();
    469 }
    470 
    471 CXFA_FFApp* CXFA_FFWidget::GetApp() {
    472   return GetDoc()->GetApp();
    473 }
    474 
    475 IXFA_AppProvider* CXFA_FFWidget::GetAppProvider() {
    476   return GetApp()->GetAppProvider();
    477 }
    478 
    479 bool CXFA_FFWidget::IsMatchVisibleStatus(uint32_t dwStatus) {
    480   return !!(m_dwStatus & XFA_WidgetStatus_Visible);
    481 }
    482 
    483 void CXFA_FFWidget::EventKillFocus() {
    484   if (m_dwStatus & XFA_WidgetStatus_Access) {
    485     m_dwStatus &= ~XFA_WidgetStatus_Access;
    486     return;
    487   }
    488   CXFA_EventParam eParam;
    489   eParam.m_eType = XFA_EVENT_Exit;
    490   eParam.m_pTarget = m_pDataAcc;
    491   m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Exit, &eParam);
    492 }
    493 bool CXFA_FFWidget::IsButtonDown() {
    494   return (m_dwStatus & XFA_WidgetStatus_ButtonDown) != 0;
    495 }
    496 void CXFA_FFWidget::SetButtonDown(bool bSet) {
    497   bSet ? m_dwStatus |= XFA_WidgetStatus_ButtonDown
    498        : m_dwStatus &= ~XFA_WidgetStatus_ButtonDown;
    499 }
    500 int32_t XFA_StrokeTypeSetLineDash(CFX_Graphics* pGraphics,
    501                                   int32_t iStrokeType,
    502                                   int32_t iCapType) {
    503   switch (iStrokeType) {
    504     case XFA_ATTRIBUTEENUM_DashDot: {
    505       FX_FLOAT dashArray[] = {4, 1, 2, 1};
    506       if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
    507         dashArray[1] = 2;
    508         dashArray[3] = 2;
    509       }
    510       pGraphics->SetLineDash(0, dashArray, 4);
    511       return FX_DASHSTYLE_DashDot;
    512     }
    513     case XFA_ATTRIBUTEENUM_DashDotDot: {
    514       FX_FLOAT dashArray[] = {4, 1, 2, 1, 2, 1};
    515       if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
    516         dashArray[1] = 2;
    517         dashArray[3] = 2;
    518         dashArray[5] = 2;
    519       }
    520       pGraphics->SetLineDash(0, dashArray, 6);
    521       return FX_DASHSTYLE_DashDotDot;
    522     }
    523     case XFA_ATTRIBUTEENUM_Dashed: {
    524       FX_FLOAT dashArray[] = {5, 1};
    525       if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
    526         dashArray[1] = 2;
    527       }
    528       pGraphics->SetLineDash(0, dashArray, 2);
    529       return FX_DASHSTYLE_Dash;
    530     }
    531     case XFA_ATTRIBUTEENUM_Dotted: {
    532       FX_FLOAT dashArray[] = {2, 1};
    533       if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
    534         dashArray[1] = 2;
    535       }
    536       pGraphics->SetLineDash(0, dashArray, 2);
    537       return FX_DASHSTYLE_Dot;
    538     }
    539     default:
    540       break;
    541   }
    542   pGraphics->SetLineDash(FX_DASHSTYLE_Solid);
    543   return FX_DASHSTYLE_Solid;
    544 }
    545 CFX_GraphStateData::LineCap XFA_LineCapToFXGE(int32_t iLineCap) {
    546   switch (iLineCap) {
    547     case XFA_ATTRIBUTEENUM_Round:
    548       return CFX_GraphStateData::LineCapRound;
    549     case XFA_ATTRIBUTEENUM_Butt:
    550       return CFX_GraphStateData::LineCapButt;
    551     default:
    552       break;
    553   }
    554   return CFX_GraphStateData::LineCapSquare;
    555 }
    556 
    557 class CXFA_ImageRenderer {
    558  public:
    559   CXFA_ImageRenderer();
    560   ~CXFA_ImageRenderer();
    561 
    562   bool Start(CFX_RenderDevice* pDevice,
    563              CFX_DIBSource* pDIBSource,
    564              FX_ARGB bitmap_argb,
    565              int bitmap_alpha,
    566              const CFX_Matrix* pImage2Device,
    567              uint32_t flags,
    568              int blendType = FXDIB_BLEND_NORMAL);
    569   bool Continue(IFX_Pause* pPause);
    570 
    571  protected:
    572   bool StartDIBSource();
    573   void CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
    574                          int left,
    575                          int top,
    576                          FX_ARGB mask_argb,
    577                          int bitmap_alpha,
    578                          int blend_mode,
    579                          int Transparency);
    580 
    581   CFX_RenderDevice* m_pDevice;
    582   int m_Status;
    583   CFX_Matrix m_ImageMatrix;
    584   CFX_DIBSource* m_pDIBSource;
    585   std::unique_ptr<CFX_DIBitmap> m_pCloneConvert;
    586   int m_BitmapAlpha;
    587   FX_ARGB m_FillArgb;
    588   uint32_t m_Flags;
    589   std::unique_ptr<CFX_ImageTransformer> m_pTransformer;
    590   void* m_DeviceHandle;
    591   int32_t m_BlendType;
    592   bool m_Result;
    593   bool m_bPrint;
    594 };
    595 
    596 CXFA_ImageRenderer::CXFA_ImageRenderer()
    597     : m_pDevice(nullptr),
    598       m_Status(0),
    599       m_pDIBSource(nullptr),
    600       m_BitmapAlpha(255),
    601       m_FillArgb(0),
    602       m_Flags(0),
    603       m_DeviceHandle(nullptr),
    604       m_BlendType(FXDIB_BLEND_NORMAL),
    605       m_Result(true),
    606       m_bPrint(false) {}
    607 
    608 CXFA_ImageRenderer::~CXFA_ImageRenderer() {
    609   if (m_DeviceHandle)
    610     m_pDevice->CancelDIBits(m_DeviceHandle);
    611 }
    612 
    613 bool CXFA_ImageRenderer::Start(CFX_RenderDevice* pDevice,
    614                                CFX_DIBSource* pDIBSource,
    615                                FX_ARGB bitmap_argb,
    616                                int bitmap_alpha,
    617                                const CFX_Matrix* pImage2Device,
    618                                uint32_t flags,
    619                                int blendType) {
    620   m_pDevice = pDevice;
    621   m_pDIBSource = pDIBSource;
    622   m_FillArgb = bitmap_argb;
    623   m_BitmapAlpha = bitmap_alpha;
    624   m_ImageMatrix = *pImage2Device;
    625   m_Flags = flags;
    626   m_BlendType = blendType;
    627   return StartDIBSource();
    628 }
    629 
    630 bool CXFA_ImageRenderer::StartDIBSource() {
    631   if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, m_BitmapAlpha, m_FillArgb,
    632                                       &m_ImageMatrix, m_Flags, m_DeviceHandle,
    633                                       m_BlendType)) {
    634     if (m_DeviceHandle) {
    635       m_Status = 3;
    636       return true;
    637     }
    638     return false;
    639   }
    640   CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
    641   FX_RECT image_rect = image_rect_f.GetOuterRect();
    642   int dest_width = image_rect.Width();
    643   int dest_height = image_rect.Height();
    644   if ((FXSYS_fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
    645       (FXSYS_fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
    646     if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
    647       m_Result = false;
    648       return false;
    649     }
    650     CFX_DIBSource* pDib = m_pDIBSource;
    651     if (m_pDIBSource->HasAlpha() &&
    652         !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) &&
    653         !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
    654       m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb);
    655       if (!m_pCloneConvert) {
    656         m_Result = false;
    657         return false;
    658       }
    659       pDib = m_pCloneConvert.get();
    660     }
    661     FX_RECT clip_box = m_pDevice->GetClipBox();
    662     clip_box.Intersect(image_rect);
    663     m_Status = 2;
    664     m_pTransformer.reset(
    665         new CFX_ImageTransformer(pDib, &m_ImageMatrix, m_Flags, &clip_box));
    666     m_pTransformer->Start();
    667     return true;
    668   }
    669   if (m_ImageMatrix.a < 0) {
    670     dest_width = -dest_width;
    671   }
    672   if (m_ImageMatrix.d > 0) {
    673     dest_height = -dest_height;
    674   }
    675   int dest_left, dest_top;
    676   dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
    677   dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
    678   if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) {
    679     if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
    680             m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_Flags,
    681             m_BlendType)) {
    682       return false;
    683     }
    684   }
    685   if (m_pDIBSource->IsAlphaMask()) {
    686     if (m_BitmapAlpha != 255) {
    687       m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
    688     }
    689     if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top,
    690                                            dest_width, dest_height, m_FillArgb,
    691                                            m_Flags)) {
    692       return false;
    693     }
    694   }
    695   if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
    696     m_Result = false;
    697     return true;
    698   }
    699   FX_RECT clip_box = m_pDevice->GetClipBox();
    700   FX_RECT dest_rect = clip_box;
    701   dest_rect.Intersect(image_rect);
    702   FX_RECT dest_clip(
    703       dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
    704       dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
    705   std::unique_ptr<CFX_DIBitmap> pStretched(
    706       m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip));
    707   if (pStretched) {
    708     CompositeDIBitmap(pStretched.get(), dest_rect.left, dest_rect.top,
    709                       m_FillArgb, m_BitmapAlpha, m_BlendType, false);
    710   }
    711   return false;
    712 }
    713 
    714 bool CXFA_ImageRenderer::Continue(IFX_Pause* pPause) {
    715   if (m_Status == 2) {
    716     if (m_pTransformer->Continue(pPause))
    717       return true;
    718 
    719     std::unique_ptr<CFX_DIBitmap> pBitmap(m_pTransformer->DetachBitmap());
    720     if (!pBitmap)
    721       return false;
    722 
    723     if (pBitmap->IsAlphaMask()) {
    724       if (m_BitmapAlpha != 255)
    725         m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
    726       m_Result =
    727           m_pDevice->SetBitMask(pBitmap.get(), m_pTransformer->result().left,
    728                                 m_pTransformer->result().top, m_FillArgb);
    729     } else {
    730       if (m_BitmapAlpha != 255)
    731         pBitmap->MultiplyAlpha(m_BitmapAlpha);
    732       m_Result = m_pDevice->SetDIBitsWithBlend(
    733           pBitmap.get(), m_pTransformer->result().left,
    734           m_pTransformer->result().top, m_BlendType);
    735     }
    736     return false;
    737   }
    738   if (m_Status == 3)
    739     return m_pDevice->ContinueDIBits(m_DeviceHandle, pPause);
    740 
    741   return false;
    742 }
    743 
    744 void CXFA_ImageRenderer::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
    745                                            int left,
    746                                            int top,
    747                                            FX_ARGB mask_argb,
    748                                            int bitmap_alpha,
    749                                            int blend_mode,
    750                                            int Transparency) {
    751   if (!pDIBitmap) {
    752     return;
    753   }
    754   bool bIsolated = !!(Transparency & PDFTRANS_ISOLATED);
    755   bool bGroup = !!(Transparency & PDFTRANS_GROUP);
    756   if (blend_mode == FXDIB_BLEND_NORMAL) {
    757     if (!pDIBitmap->IsAlphaMask()) {
    758       if (bitmap_alpha < 255) {
    759         pDIBitmap->MultiplyAlpha(bitmap_alpha);
    760       }
    761       if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
    762         return;
    763       }
    764     } else {
    765       uint32_t fill_argb = (mask_argb);
    766       if (bitmap_alpha < 255) {
    767         ((uint8_t*)&fill_argb)[3] =
    768             ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255;
    769       }
    770       if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
    771         return;
    772       }
    773     }
    774   }
    775   bool bBackAlphaRequired = blend_mode && bIsolated;
    776   bool bGetBackGround =
    777       ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
    778       (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
    779        (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
    780   if (bGetBackGround) {
    781     if (bIsolated || !bGroup) {
    782       if (pDIBitmap->IsAlphaMask()) {
    783         return;
    784       }
    785       m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
    786     } else {
    787       FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
    788                    top + pDIBitmap->GetHeight());
    789       rect.Intersect(m_pDevice->GetClipBox());
    790       CFX_MaybeOwned<CFX_DIBitmap> pClone;
    791       if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
    792         pClone = m_pDevice->GetBackDrop()->Clone(&rect);
    793         CFX_DIBitmap* pForeBitmap = m_pDevice->GetBitmap();
    794         pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
    795                                 pForeBitmap, rect.left, rect.top);
    796         left = left >= 0 ? 0 : left;
    797         top = top >= 0 ? 0 : top;
    798         if (!pDIBitmap->IsAlphaMask())
    799           pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
    800                                   pDIBitmap, left, top, blend_mode);
    801         else
    802           pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
    803                                 pDIBitmap, mask_argb, left, top, blend_mode);
    804       } else {
    805         pClone = pDIBitmap;
    806       }
    807       if (m_pDevice->GetBackDrop()) {
    808         m_pDevice->SetDIBits(pClone.Get(), rect.left, rect.top);
    809       } else {
    810         if (pDIBitmap->IsAlphaMask())
    811           return;
    812         m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
    813                                       blend_mode);
    814       }
    815     }
    816     return;
    817   }
    818   if (!pDIBitmap->HasAlpha() ||
    819       (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) {
    820     return;
    821   }
    822   std::unique_ptr<CFX_DIBitmap> pCloneConvert =
    823       pDIBitmap->CloneConvert(FXDIB_Rgb);
    824   if (!pCloneConvert)
    825     return;
    826 
    827   CXFA_ImageRenderer imageRender;
    828   if (!imageRender.Start(m_pDevice, pCloneConvert.get(), m_FillArgb,
    829                          m_BitmapAlpha, &m_ImageMatrix, m_Flags)) {
    830     return;
    831   }
    832   while (imageRender.Continue(nullptr))
    833     continue;
    834 }
    835 
    836 void XFA_DrawImage(CFX_Graphics* pGS,
    837                    const CFX_RectF& rtImage,
    838                    CFX_Matrix* pMatrix,
    839                    CFX_DIBitmap* pDIBitmap,
    840                    int32_t iAspect,
    841                    int32_t iImageXDpi,
    842                    int32_t iImageYDpi,
    843                    int32_t iHorzAlign,
    844                    int32_t iVertAlign) {
    845   if (rtImage.IsEmpty())
    846     return;
    847   if (!pDIBitmap || !pDIBitmap->GetBuffer())
    848     return;
    849 
    850   CFX_RectF rtFit(
    851       rtImage.TopLeft(),
    852       XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetWidth(), (FX_FLOAT)iImageXDpi),
    853       XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetHeight(), (FX_FLOAT)iImageYDpi));
    854   switch (iAspect) {
    855     case XFA_ATTRIBUTEENUM_Fit: {
    856       FX_FLOAT f1 = rtImage.height / rtFit.height;
    857       FX_FLOAT f2 = rtImage.width / rtFit.width;
    858       f1 = std::min(f1, f2);
    859       rtFit.height = rtFit.height * f1;
    860       rtFit.width = rtFit.width * f1;
    861     } break;
    862     case XFA_ATTRIBUTEENUM_Actual:
    863       break;
    864     case XFA_ATTRIBUTEENUM_Height: {
    865       FX_FLOAT f1 = rtImage.height / rtFit.height;
    866       rtFit.height = rtImage.height;
    867       rtFit.width = f1 * rtFit.width;
    868     } break;
    869     case XFA_ATTRIBUTEENUM_None:
    870       rtFit.height = rtImage.height;
    871       rtFit.width = rtImage.width;
    872       break;
    873     case XFA_ATTRIBUTEENUM_Width: {
    874       FX_FLOAT f1 = rtImage.width / rtFit.width;
    875       rtFit.width = rtImage.width;
    876       rtFit.height = rtFit.height * f1;
    877     } break;
    878   }
    879   if (iHorzAlign == XFA_ATTRIBUTEENUM_Center) {
    880     rtFit.left += (rtImage.width - rtFit.width) / 2;
    881   } else if (iHorzAlign == XFA_ATTRIBUTEENUM_Right) {
    882     rtFit.left = rtImage.right() - rtFit.width;
    883   }
    884   if (iVertAlign == XFA_ATTRIBUTEENUM_Middle) {
    885     rtFit.top += (rtImage.height - rtFit.height) / 2;
    886   } else if (iVertAlign == XFA_ATTRIBUTEENUM_Bottom) {
    887     rtFit.top = rtImage.bottom() - rtImage.height;
    888   }
    889   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
    890   pRenderDevice->SaveState();
    891 
    892   CFX_PathData path;
    893   path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top);
    894   pRenderDevice->SetClip_PathFill(&path, pMatrix, FXFILL_WINDING);
    895 
    896   CFX_Matrix mtImage(1, 0, 0, -1, 0, 1);
    897   mtImage.Concat(
    898       CFX_Matrix(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top));
    899   mtImage.Concat(*pMatrix);
    900 
    901   CXFA_ImageRenderer imageRender;
    902   bool bRet = imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage,
    903                                 FXDIB_INTERPOL);
    904   while (bRet)
    905     bRet = imageRender.Continue(nullptr);
    906 
    907   pRenderDevice->RestoreState(false);
    908 }
    909 
    910 static const uint8_t g_inv_base64[128] = {
    911     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    912     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
    913     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62,  255,
    914     255, 255, 63,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  255, 255,
    915     255, 255, 255, 255, 255, 0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
    916     10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
    917     25,  255, 255, 255, 255, 255, 255, 26,  27,  28,  29,  30,  31,  32,  33,
    918     34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
    919     49,  50,  51,  255, 255, 255, 255, 255,
    920 };
    921 
    922 static uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) {
    923   uint8_t* pCP;
    924   int32_t i = 0, j = 0;
    925   if (iLen == 0) {
    926     iLen = FXSYS_strlen((FX_CHAR*)pStr);
    927   }
    928   pCP = FX_Alloc(uint8_t, iLen + 1);
    929   for (; i < iLen; i++) {
    930     if ((pStr[i] & 128) == 0) {
    931       if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') {
    932         pCP[j++] = pStr[i];
    933       }
    934     }
    935   }
    936   pCP[j] = '\0';
    937   return pCP;
    938 }
    939 static int32_t XFA_Base64Decode(const FX_CHAR* pStr, uint8_t* pOutBuffer) {
    940   if (!pStr) {
    941     return 0;
    942   }
    943   uint8_t* pBuffer =
    944       XFA_RemoveBase64Whitespace((uint8_t*)pStr, FXSYS_strlen((FX_CHAR*)pStr));
    945   if (!pBuffer) {
    946     return 0;
    947   }
    948   int32_t iLen = FXSYS_strlen((FX_CHAR*)pBuffer);
    949   int32_t i = 0, j = 0;
    950   uint32_t dwLimb = 0;
    951   for (; i + 3 < iLen; i += 4) {
    952     if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
    953         pBuffer[i + 3] == '=') {
    954       if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
    955         break;
    956       }
    957       if (pBuffer[i + 2] == '=') {
    958         dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
    959                  ((uint32_t)g_inv_base64[pBuffer[i + 1]]);
    960         pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
    961         j++;
    962       } else {
    963         dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
    964                  ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
    965                  ((uint32_t)g_inv_base64[pBuffer[i + 2]]);
    966         pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
    967         pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
    968         j += 2;
    969       }
    970     } else {
    971       dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
    972                ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
    973                ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
    974                ((uint32_t)g_inv_base64[pBuffer[i + 3]]);
    975       pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
    976       pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
    977       pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
    978       j += 3;
    979     }
    980   }
    981   FX_Free(pBuffer);
    982   return j;
    983 }
    984 
    985 static const FX_CHAR g_base64_chars[] =
    986     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    987 
    988 FX_CHAR* XFA_Base64Encode(const uint8_t* buf, int32_t buf_len) {
    989   FX_CHAR* out = nullptr;
    990   int i, j;
    991   uint32_t limb;
    992   out = FX_Alloc(FX_CHAR, ((buf_len * 8 + 5) / 6) + 5);
    993   for (i = 0, j = 0, limb = 0; i + 2 < buf_len; i += 3, j += 4) {
    994     limb = ((uint32_t)buf[i] << 16) | ((uint32_t)buf[i + 1] << 8) |
    995            ((uint32_t)buf[i + 2]);
    996     out[j] = g_base64_chars[(limb >> 18) & 63];
    997     out[j + 1] = g_base64_chars[(limb >> 12) & 63];
    998     out[j + 2] = g_base64_chars[(limb >> 6) & 63];
    999     out[j + 3] = g_base64_chars[(limb)&63];
   1000   }
   1001   switch (buf_len - i) {
   1002     case 0:
   1003       break;
   1004     case 1:
   1005       limb = ((uint32_t)buf[i]);
   1006       out[j++] = g_base64_chars[(limb >> 2) & 63];
   1007       out[j++] = g_base64_chars[(limb << 4) & 63];
   1008       out[j++] = '=';
   1009       out[j++] = '=';
   1010       break;
   1011     case 2:
   1012       limb = ((uint32_t)buf[i] << 8) | ((uint32_t)buf[i + 1]);
   1013       out[j++] = g_base64_chars[(limb >> 10) & 63];
   1014       out[j++] = g_base64_chars[(limb >> 4) & 63];
   1015       out[j++] = g_base64_chars[(limb << 2) & 63];
   1016       out[j++] = '=';
   1017       break;
   1018     default:
   1019       break;
   1020   }
   1021   out[j] = '\0';
   1022   return out;
   1023 }
   1024 FXCODEC_IMAGE_TYPE XFA_GetImageType(const CFX_WideString& wsType) {
   1025   CFX_WideString wsContentType(wsType);
   1026   wsContentType.MakeLower();
   1027   if (wsContentType == L"image/jpg")
   1028     return FXCODEC_IMAGE_JPG;
   1029   if (wsContentType == L"image/png")
   1030     return FXCODEC_IMAGE_PNG;
   1031   if (wsContentType == L"image/gif")
   1032     return FXCODEC_IMAGE_GIF;
   1033   if (wsContentType == L"image/bmp")
   1034     return FXCODEC_IMAGE_BMP;
   1035   if (wsContentType == L"image/tif")
   1036     return FXCODEC_IMAGE_TIF;
   1037   return FXCODEC_IMAGE_UNKNOWN;
   1038 }
   1039 CFX_DIBitmap* XFA_LoadImageData(CXFA_FFDoc* pDoc,
   1040                                 CXFA_Image* pImage,
   1041                                 bool& bNameImage,
   1042                                 int32_t& iImageXDpi,
   1043                                 int32_t& iImageYDpi) {
   1044   CFX_WideString wsHref;
   1045   pImage->GetHref(wsHref);
   1046   CFX_WideString wsImage;
   1047   pImage->GetContent(wsImage);
   1048   if (wsHref.IsEmpty() && wsImage.IsEmpty()) {
   1049     return nullptr;
   1050   }
   1051   CFX_WideString wsContentType;
   1052   pImage->GetContentType(wsContentType);
   1053   FXCODEC_IMAGE_TYPE type = XFA_GetImageType(wsContentType);
   1054   CFX_ByteString bsContent;
   1055   uint8_t* pImageBuffer = nullptr;
   1056   CFX_RetainPtr<IFX_SeekableReadStream> pImageFileRead;
   1057   if (wsImage.GetLength() > 0) {
   1058     XFA_ATTRIBUTEENUM iEncoding =
   1059         (XFA_ATTRIBUTEENUM)pImage->GetTransferEncoding();
   1060     if (iEncoding == XFA_ATTRIBUTEENUM_Base64) {
   1061       CFX_ByteString bsData = wsImage.UTF8Encode();
   1062       int32_t iLength = bsData.GetLength();
   1063       pImageBuffer = FX_Alloc(uint8_t, iLength);
   1064       int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer);
   1065       if (iRead > 0) {
   1066         pImageFileRead = IFX_MemoryStream::Create(pImageBuffer, iRead);
   1067       }
   1068     } else {
   1069       bsContent = CFX_ByteString::FromUnicode(wsImage);
   1070       pImageFileRead = IFX_MemoryStream::Create(
   1071           const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength());
   1072     }
   1073   } else {
   1074     CFX_WideString wsURL = wsHref;
   1075     if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") {
   1076       CFX_DIBitmap* pBitmap =
   1077           pDoc->GetPDFNamedImage(wsURL.AsStringC(), iImageXDpi, iImageYDpi);
   1078       if (pBitmap) {
   1079         bNameImage = true;
   1080         return pBitmap;
   1081       }
   1082     }
   1083     pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
   1084   }
   1085   if (!pImageFileRead) {
   1086     FX_Free(pImageBuffer);
   1087     return nullptr;
   1088   }
   1089   bNameImage = false;
   1090   CFX_DIBitmap* pBitmap =
   1091       XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
   1092   FX_Free(pImageBuffer);
   1093   return pBitmap;
   1094 }
   1095 static FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type,
   1096                                      int32_t iComponents,
   1097                                      int32_t iBitsPerComponent) {
   1098   FXDIB_Format dibFormat = FXDIB_Argb;
   1099   switch (type) {
   1100     case FXCODEC_IMAGE_BMP:
   1101     case FXCODEC_IMAGE_JPG:
   1102     case FXCODEC_IMAGE_TIF: {
   1103       dibFormat = FXDIB_Rgb32;
   1104       int32_t bpp = iComponents * iBitsPerComponent;
   1105       if (bpp <= 24) {
   1106         dibFormat = FXDIB_Rgb;
   1107       }
   1108     } break;
   1109     case FXCODEC_IMAGE_PNG:
   1110     default:
   1111       break;
   1112   }
   1113   return dibFormat;
   1114 }
   1115 
   1116 CFX_DIBitmap* XFA_LoadImageFromBuffer(
   1117     const CFX_RetainPtr<IFX_SeekableReadStream>& pImageFileRead,
   1118     FXCODEC_IMAGE_TYPE type,
   1119     int32_t& iImageXDpi,
   1120     int32_t& iImageYDpi) {
   1121   CFX_GEModule* pGeModule = CFX_GEModule::Get();
   1122   if (!pGeModule)
   1123     return nullptr;
   1124 
   1125   CCodec_ModuleMgr* pCodecMgr = pGeModule->GetCodecModule();
   1126   if (!pCodecMgr)
   1127     return nullptr;
   1128 
   1129   CFX_DIBAttribute dibAttr;
   1130   CFX_DIBitmap* pBitmap = nullptr;
   1131   std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder =
   1132       pCodecMgr->CreateProgressiveDecoder();
   1133   pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false);
   1134   switch (dibAttr.m_wDPIUnit) {
   1135     case FXCODEC_RESUNIT_CENTIMETER:
   1136       dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI * 2.54f);
   1137       dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI * 2.54f);
   1138       break;
   1139     case FXCODEC_RESUNIT_METER:
   1140       dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI / (FX_FLOAT)100 * 2.54f);
   1141       dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI / (FX_FLOAT)100 * 2.54f);
   1142       break;
   1143     default:
   1144       break;
   1145   }
   1146   iImageXDpi = dibAttr.m_nXDPI > 1 ? dibAttr.m_nXDPI : (96);
   1147   iImageYDpi = dibAttr.m_nYDPI > 1 ? dibAttr.m_nYDPI : (96);
   1148   if (pProgressiveDecoder->GetWidth() > 0 &&
   1149       pProgressiveDecoder->GetHeight() > 0) {
   1150     type = pProgressiveDecoder->GetType();
   1151     int32_t iComponents = pProgressiveDecoder->GetNumComponents();
   1152     int32_t iBpc = pProgressiveDecoder->GetBPC();
   1153     FXDIB_Format dibFormat = XFA_GetDIBFormat(type, iComponents, iBpc);
   1154     pBitmap = new CFX_DIBitmap();
   1155     pBitmap->Create(pProgressiveDecoder->GetWidth(),
   1156                     pProgressiveDecoder->GetHeight(), dibFormat);
   1157     pBitmap->Clear(0xffffffff);
   1158     int32_t nFrames;
   1159     if ((pProgressiveDecoder->GetFrames(nFrames) ==
   1160          FXCODEC_STATUS_DECODE_READY) &&
   1161         (nFrames > 0)) {
   1162       pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(),
   1163                                        pBitmap->GetHeight());
   1164       pProgressiveDecoder->ContinueDecode();
   1165     }
   1166   }
   1167   return pBitmap;
   1168 }
   1169 
   1170 void XFA_RectWidthoutMargin(CFX_RectF& rt, const CXFA_Margin& mg, bool bUI) {
   1171   if (!mg) {
   1172     return;
   1173   }
   1174   FX_FLOAT fLeftInset, fTopInset, fRightInset, fBottomInset;
   1175   mg.GetLeftInset(fLeftInset);
   1176   mg.GetTopInset(fTopInset);
   1177   mg.GetRightInset(fRightInset);
   1178   mg.GetBottomInset(fBottomInset);
   1179   rt.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
   1180 }
   1181 CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) {
   1182   if (XFA_IsCreateWidget(pLayoutItem->GetFormNode()->GetElementType()))
   1183     return static_cast<CXFA_FFWidget*>(pLayoutItem);
   1184   return nullptr;
   1185 }
   1186 bool XFA_IsCreateWidget(XFA_Element eType) {
   1187   return eType == XFA_Element::Field || eType == XFA_Element::Draw ||
   1188          eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup;
   1189 }
   1190 static void XFA_BOX_GetPath_Arc(CXFA_Box box,
   1191                                 CFX_RectF rtDraw,
   1192                                 CFX_Path& fillPath,
   1193                                 uint32_t dwFlags) {
   1194   FX_FLOAT a, b;
   1195   a = rtDraw.width / 2.0f;
   1196   b = rtDraw.height / 2.0f;
   1197   if (box.IsCircular() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
   1198     a = b = std::min(a, b);
   1199   }
   1200   CFX_PointF center = rtDraw.Center();
   1201   rtDraw.left = center.x - a;
   1202   rtDraw.top = center.y - b;
   1203   rtDraw.width = a + a;
   1204   rtDraw.height = b + b;
   1205   FX_FLOAT startAngle = 0, sweepAngle = 360;
   1206   bool bStart = box.GetStartAngle(startAngle);
   1207   bool bEnd = box.GetSweepAngle(sweepAngle);
   1208   if (!bStart && !bEnd) {
   1209     fillPath.AddEllipse(rtDraw);
   1210     return;
   1211   }
   1212   startAngle = -startAngle * FX_PI / 180.0f;
   1213   sweepAngle = -sweepAngle * FX_PI / 180.0f;
   1214   fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(), startAngle, sweepAngle);
   1215 }
   1216 
   1217 static void XFA_BOX_GetPath(CXFA_Box box,
   1218                             const std::vector<CXFA_Stroke>& strokes,
   1219                             CFX_RectF rtWidget,
   1220                             CFX_Path& path,
   1221                             int32_t nIndex,
   1222                             bool bStart,
   1223                             bool bCorner) {
   1224   ASSERT(nIndex >= 0 && nIndex < 8);
   1225   int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex;
   1226   CXFA_Corner corner1(strokes[n].GetNode());
   1227   CXFA_Corner corner2(strokes[(n + 2) % 8].GetNode());
   1228   FX_FLOAT fRadius1 = bCorner ? corner1.GetRadius() : 0.0f;
   1229   FX_FLOAT fRadius2 = bCorner ? corner2.GetRadius() : 0.0f;
   1230   bool bInverted = corner1.IsInverted();
   1231   FX_FLOAT offsetY = 0.0f;
   1232   FX_FLOAT offsetX = 0.0f;
   1233   bool bRound = corner1.GetJoinType() == XFA_ATTRIBUTEENUM_Round;
   1234   FX_FLOAT halfAfter = 0.0f;
   1235   FX_FLOAT halfBefore = 0.0f;
   1236   CXFA_Stroke stroke = strokes[nIndex];
   1237   if (stroke.IsCorner()) {
   1238     CXFA_Stroke edgeBefore = strokes[(nIndex + 1 * 8 - 1) % 8];
   1239     CXFA_Stroke edgeAfter = strokes[nIndex + 1];
   1240     if (stroke.IsInverted()) {
   1241       if (!stroke.SameStyles(edgeBefore)) {
   1242         halfBefore = edgeBefore.GetThickness() / 2;
   1243       }
   1244       if (!stroke.SameStyles(edgeAfter)) {
   1245         halfAfter = edgeAfter.GetThickness() / 2;
   1246       }
   1247     }
   1248   } else {
   1249     CXFA_Stroke edgeBefore = strokes[(nIndex + 8 - 2) % 8];
   1250     CXFA_Stroke edgeAfter = strokes[(nIndex + 2) % 8];
   1251     if (!bRound && !bInverted) {
   1252       halfBefore = edgeBefore.GetThickness() / 2;
   1253       halfAfter = edgeAfter.GetThickness() / 2;
   1254     }
   1255   }
   1256   FX_FLOAT offsetEX = 0.0f;
   1257   FX_FLOAT offsetEY = 0.0f;
   1258   FX_FLOAT sx = 0.0f;
   1259   FX_FLOAT sy = 0.0f;
   1260   FX_FLOAT vx = 1.0f;
   1261   FX_FLOAT vy = 1.0f;
   1262   FX_FLOAT nx = 1.0f;
   1263   FX_FLOAT ny = 1.0f;
   1264   CFX_PointF cpStart;
   1265   CFX_PointF cp1;
   1266   CFX_PointF cp2;
   1267   if (bRound) {
   1268     sy = FX_PI / 2;
   1269   }
   1270   switch (nIndex) {
   1271     case 0:
   1272     case 1:
   1273       cp1 = rtWidget.TopLeft();
   1274       cp2 = rtWidget.TopRight();
   1275       if (nIndex == 0) {
   1276         cpStart.x = cp1.x - halfBefore;
   1277         cpStart.y = cp1.y + fRadius1, offsetY = -halfAfter;
   1278       } else {
   1279         cpStart.x = cp1.x + fRadius1 - halfBefore, cpStart.y = cp1.y,
   1280         offsetEX = halfAfter;
   1281       }
   1282       vx = 1, vy = 1;
   1283       nx = -1, ny = 0;
   1284       if (bRound) {
   1285         sx = bInverted ? FX_PI / 2 : FX_PI;
   1286       } else {
   1287         sx = 1, sy = 0;
   1288       }
   1289       break;
   1290     case 2:
   1291     case 3:
   1292       cp1 = rtWidget.TopRight();
   1293       cp2 = rtWidget.BottomRight();
   1294       if (nIndex == 2) {
   1295         cpStart.x = cp1.x - fRadius1, cpStart.y = cp1.y - halfBefore,
   1296         offsetX = halfAfter;
   1297       } else {
   1298         cpStart.x = cp1.x, cpStart.y = cp1.y + fRadius1 - halfBefore,
   1299         offsetEY = halfAfter;
   1300       }
   1301       vx = -1, vy = 1;
   1302       nx = 0, ny = -1;
   1303       if (bRound) {
   1304         sx = bInverted ? FX_PI : FX_PI * 3 / 2;
   1305       } else {
   1306         sx = 0, sy = 1;
   1307       }
   1308       break;
   1309     case 4:
   1310     case 5:
   1311       cp1 = rtWidget.BottomRight();
   1312       cp2 = rtWidget.BottomLeft();
   1313       if (nIndex == 4) {
   1314         cpStart.x = cp1.x + halfBefore, cpStart.y = cp1.y - fRadius1,
   1315         offsetY = halfAfter;
   1316       } else {
   1317         cpStart.x = cp1.x - fRadius1 + halfBefore, cpStart.y = cp1.y,
   1318         offsetEX = -halfAfter;
   1319       }
   1320       vx = -1, vy = -1;
   1321       nx = 1, ny = 0;
   1322       if (bRound) {
   1323         sx = bInverted ? FX_PI * 3 / 2 : 0;
   1324       } else {
   1325         sx = -1, sy = 0;
   1326       }
   1327       break;
   1328     case 6:
   1329     case 7:
   1330       cp1 = rtWidget.BottomLeft();
   1331       cp2 = rtWidget.TopLeft();
   1332       if (nIndex == 6) {
   1333         cpStart.x = cp1.x + fRadius1, cpStart.y = cp1.y + halfBefore,
   1334         offsetX = -halfAfter;
   1335       } else {
   1336         cpStart.x = cp1.x, cpStart.y = cp1.y - fRadius1 + halfBefore,
   1337         offsetEY = -halfAfter;
   1338       }
   1339       vx = 1;
   1340       vy = -1;
   1341       nx = 0;
   1342       ny = 1;
   1343       if (bRound) {
   1344         sx = bInverted ? 0 : FX_PI / 2;
   1345       } else {
   1346         sx = 0;
   1347         sy = -1;
   1348       }
   1349       break;
   1350   }
   1351   if (bStart) {
   1352     path.MoveTo(cpStart);
   1353   }
   1354   if (nIndex & 1) {
   1355     path.LineTo(CFX_PointF(cp2.x + fRadius2 * nx + offsetEX,
   1356                            cp2.y + fRadius2 * ny + offsetEY));
   1357     return;
   1358   }
   1359   if (bRound) {
   1360     if (fRadius1 < 0)
   1361       sx -= FX_PI;
   1362     if (bInverted)
   1363       sy *= -1;
   1364 
   1365     CFX_RectF rtRadius(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
   1366                        fRadius1 * 2 * vx - offsetX * 2,
   1367                        fRadius1 * 2 * vy - offsetY * 2);
   1368     rtRadius.Normalize();
   1369     if (bInverted)
   1370       rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
   1371 
   1372     path.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
   1373   } else {
   1374     CFX_PointF cp;
   1375     if (bInverted) {
   1376       cp.x = cp1.x + fRadius1 * vx;
   1377       cp.y = cp1.y + fRadius1 * vy;
   1378     } else {
   1379       cp = cp1;
   1380     }
   1381     path.LineTo(cp);
   1382     path.LineTo(CFX_PointF(cp1.x + fRadius1 * sx + offsetX,
   1383                            cp1.y + fRadius1 * sy + offsetY));
   1384   }
   1385 }
   1386 static void XFA_BOX_GetFillPath(CXFA_Box box,
   1387                                 const std::vector<CXFA_Stroke>& strokes,
   1388                                 CFX_RectF rtWidget,
   1389                                 CFX_Path& fillPath,
   1390                                 uint16_t dwFlags) {
   1391   if (box.IsArc() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
   1392     CXFA_Edge edge = box.GetEdge(0);
   1393     FX_FLOAT fThickness = edge.GetThickness();
   1394     if (fThickness < 0) {
   1395       fThickness = 0;
   1396     }
   1397     FX_FLOAT fHalf = fThickness / 2;
   1398     int32_t iHand = box.GetHand();
   1399     if (iHand == XFA_ATTRIBUTEENUM_Left) {
   1400       rtWidget.Inflate(fHalf, fHalf);
   1401     } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   1402       rtWidget.Deflate(fHalf, fHalf);
   1403     }
   1404     XFA_BOX_GetPath_Arc(box, rtWidget, fillPath, dwFlags);
   1405     return;
   1406   }
   1407   bool bSameStyles = true;
   1408   CXFA_Stroke stroke1 = strokes[0];
   1409   for (int32_t i = 1; i < 8; i++) {
   1410     CXFA_Stroke stroke2 = strokes[i];
   1411     if (!stroke1.SameStyles(stroke2)) {
   1412       bSameStyles = false;
   1413       break;
   1414     }
   1415     stroke1 = stroke2;
   1416   }
   1417   if (bSameStyles) {
   1418     stroke1 = strokes[0];
   1419     for (int32_t i = 2; i < 8; i += 2) {
   1420       CXFA_Stroke stroke2 = strokes[i];
   1421       if (!stroke1.SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
   1422                                            XFA_STROKE_SAMESTYLE_Corner)) {
   1423         bSameStyles = false;
   1424         break;
   1425       }
   1426       stroke1 = stroke2;
   1427     }
   1428     if (bSameStyles) {
   1429       stroke1 = strokes[0];
   1430       if (stroke1.IsInverted()) {
   1431         bSameStyles = false;
   1432       }
   1433       if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square) {
   1434         bSameStyles = false;
   1435       }
   1436     }
   1437   }
   1438   if (bSameStyles) {
   1439     fillPath.AddRectangle(rtWidget.left, rtWidget.top, rtWidget.width,
   1440                           rtWidget.height);
   1441     return;
   1442   }
   1443 
   1444   for (int32_t i = 0; i < 8; i += 2) {
   1445     FX_FLOAT sx = 0.0f;
   1446     FX_FLOAT sy = 0.0f;
   1447     FX_FLOAT vx = 1.0f;
   1448     FX_FLOAT vy = 1.0f;
   1449     FX_FLOAT nx = 1.0f;
   1450     FX_FLOAT ny = 1.0f;
   1451     CFX_PointF cp1, cp2;
   1452     CXFA_Corner corner1(strokes[i].GetNode());
   1453     CXFA_Corner corner2(strokes[(i + 2) % 8].GetNode());
   1454     FX_FLOAT fRadius1 = corner1.GetRadius();
   1455     FX_FLOAT fRadius2 = corner2.GetRadius();
   1456     bool bInverted = corner1.IsInverted();
   1457     bool bRound = corner1.GetJoinType() == XFA_ATTRIBUTEENUM_Round;
   1458     if (bRound) {
   1459       sy = FX_PI / 2;
   1460     }
   1461     switch (i) {
   1462       case 0:
   1463         cp1 = rtWidget.TopLeft();
   1464         cp2 = rtWidget.TopRight();
   1465         vx = 1, vy = 1;
   1466         nx = -1, ny = 0;
   1467         if (bRound) {
   1468           sx = bInverted ? FX_PI / 2 : FX_PI;
   1469         } else {
   1470           sx = 1, sy = 0;
   1471         }
   1472         break;
   1473       case 2:
   1474         cp1 = rtWidget.TopRight();
   1475         cp2 = rtWidget.BottomRight();
   1476         vx = -1, vy = 1;
   1477         nx = 0, ny = -1;
   1478         if (bRound) {
   1479           sx = bInverted ? FX_PI : FX_PI * 3 / 2;
   1480         } else {
   1481           sx = 0, sy = 1;
   1482         }
   1483         break;
   1484       case 4:
   1485         cp1 = rtWidget.BottomRight();
   1486         cp2 = rtWidget.BottomLeft();
   1487         vx = -1, vy = -1;
   1488         nx = 1, ny = 0;
   1489         if (bRound) {
   1490           sx = bInverted ? FX_PI * 3 / 2 : 0;
   1491         } else {
   1492           sx = -1, sy = 0;
   1493         }
   1494         break;
   1495       case 6:
   1496         cp1 = rtWidget.BottomLeft();
   1497         cp2 = rtWidget.TopLeft();
   1498         vx = 1, vy = -1;
   1499         nx = 0, ny = 1;
   1500         if (bRound) {
   1501           sx = bInverted ? 0 : FX_PI / 2;
   1502         } else {
   1503           sx = 0;
   1504           sy = -1;
   1505         }
   1506         break;
   1507     }
   1508     if (i == 0)
   1509       fillPath.MoveTo(CFX_PointF(cp1.x, cp1.y + fRadius1));
   1510 
   1511     if (bRound) {
   1512       if (fRadius1 < 0)
   1513         sx -= FX_PI;
   1514       if (bInverted)
   1515         sy *= -1;
   1516 
   1517       CFX_RectF rtRadius(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
   1518       rtRadius.Normalize();
   1519       if (bInverted)
   1520         rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
   1521 
   1522       fillPath.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
   1523     } else {
   1524       CFX_PointF cp;
   1525       if (bInverted) {
   1526         cp.x = cp1.x + fRadius1 * vx;
   1527         cp.y = cp1.y + fRadius1 * vy;
   1528       } else {
   1529         cp = cp1;
   1530       }
   1531       fillPath.LineTo(cp);
   1532       fillPath.LineTo(CFX_PointF(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy));
   1533     }
   1534     fillPath.LineTo(CFX_PointF(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny));
   1535   }
   1536 }
   1537 static void XFA_BOX_Fill_Radial(CXFA_Box box,
   1538                                 CFX_Graphics* pGS,
   1539                                 CFX_Path& fillPath,
   1540                                 CFX_RectF rtFill,
   1541                                 CFX_Matrix* pMatrix) {
   1542   CXFA_Fill fill = box.GetFill();
   1543   FX_ARGB crStart, crEnd;
   1544   crStart = fill.GetColor();
   1545   int32_t iType = fill.GetRadial(crEnd);
   1546   if (iType != XFA_ATTRIBUTEENUM_ToEdge) {
   1547     FX_ARGB temp = crEnd;
   1548     crEnd = crStart;
   1549     crStart = temp;
   1550   }
   1551   CFX_Shading shading(rtFill.Center(), rtFill.Center(), 0,
   1552                       FXSYS_sqrt(rtFill.Width() * rtFill.Width() +
   1553                                  rtFill.Height() * rtFill.Height()) /
   1554                           2,
   1555                       true, true, crStart, crEnd);
   1556   CFX_Color cr(&shading);
   1557   pGS->SetFillColor(&cr);
   1558   pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
   1559 }
   1560 static void XFA_BOX_Fill_Pattern(CXFA_Box box,
   1561                                  CFX_Graphics* pGS,
   1562                                  CFX_Path& fillPath,
   1563                                  CFX_RectF rtFill,
   1564                                  CFX_Matrix* pMatrix) {
   1565   CXFA_Fill fill = box.GetFill();
   1566   FX_ARGB crStart, crEnd;
   1567   crStart = fill.GetColor();
   1568   int32_t iType = fill.GetPattern(crEnd);
   1569   FX_HatchStyle iHatch = FX_HatchStyle::Cross;
   1570   switch (iType) {
   1571     case XFA_ATTRIBUTEENUM_CrossDiagonal:
   1572       iHatch = FX_HatchStyle::DiagonalCross;
   1573       break;
   1574     case XFA_ATTRIBUTEENUM_DiagonalLeft:
   1575       iHatch = FX_HatchStyle::ForwardDiagonal;
   1576       break;
   1577     case XFA_ATTRIBUTEENUM_DiagonalRight:
   1578       iHatch = FX_HatchStyle::BackwardDiagonal;
   1579       break;
   1580     case XFA_ATTRIBUTEENUM_Horizontal:
   1581       iHatch = FX_HatchStyle::Horizontal;
   1582       break;
   1583     case XFA_ATTRIBUTEENUM_Vertical:
   1584       iHatch = FX_HatchStyle::Vertical;
   1585       break;
   1586     default:
   1587       break;
   1588   }
   1589 
   1590   CFX_Pattern pattern(iHatch, crEnd, crStart);
   1591   CFX_Color cr(&pattern, 0x0);
   1592   pGS->SetFillColor(&cr);
   1593   pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
   1594 }
   1595 static void XFA_BOX_Fill_Linear(CXFA_Box box,
   1596                                 CFX_Graphics* pGS,
   1597                                 CFX_Path& fillPath,
   1598                                 CFX_RectF rtFill,
   1599                                 CFX_Matrix* pMatrix) {
   1600   CXFA_Fill fill = box.GetFill();
   1601   FX_ARGB crStart = fill.GetColor();
   1602   FX_ARGB crEnd;
   1603   int32_t iType = fill.GetLinear(crEnd);
   1604   CFX_PointF ptStart;
   1605   CFX_PointF ptEnd;
   1606   switch (iType) {
   1607     case XFA_ATTRIBUTEENUM_ToRight:
   1608       ptStart = CFX_PointF(rtFill.left, rtFill.top);
   1609       ptEnd = CFX_PointF(rtFill.right(), rtFill.top);
   1610       break;
   1611     case XFA_ATTRIBUTEENUM_ToBottom:
   1612       ptStart = CFX_PointF(rtFill.left, rtFill.top);
   1613       ptEnd = CFX_PointF(rtFill.left, rtFill.bottom());
   1614       break;
   1615     case XFA_ATTRIBUTEENUM_ToLeft:
   1616       ptStart = CFX_PointF(rtFill.right(), rtFill.top);
   1617       ptEnd = CFX_PointF(rtFill.left, rtFill.top);
   1618       break;
   1619     case XFA_ATTRIBUTEENUM_ToTop:
   1620       ptStart = CFX_PointF(rtFill.left, rtFill.bottom());
   1621       ptEnd = CFX_PointF(rtFill.left, rtFill.top);
   1622       break;
   1623     default:
   1624       break;
   1625   }
   1626   CFX_Shading shading(ptStart, ptEnd, false, false, crStart, crEnd);
   1627   CFX_Color cr(&shading);
   1628   pGS->SetFillColor(&cr);
   1629   pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
   1630 }
   1631 static void XFA_BOX_Fill(CXFA_Box box,
   1632                          const std::vector<CXFA_Stroke>& strokes,
   1633                          CFX_Graphics* pGS,
   1634                          const CFX_RectF& rtWidget,
   1635                          CFX_Matrix* pMatrix,
   1636                          uint32_t dwFlags) {
   1637   CXFA_Fill fill = box.GetFill();
   1638   if (!fill || fill.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
   1639     return;
   1640 
   1641   pGS->SaveGraphState();
   1642   CFX_Path fillPath;
   1643   XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath,
   1644                       (dwFlags & XFA_DRAWBOX_ForceRound) != 0);
   1645   fillPath.Close();
   1646   XFA_Element eType = fill.GetFillType();
   1647   switch (eType) {
   1648     case XFA_Element::Radial:
   1649       XFA_BOX_Fill_Radial(box, pGS, fillPath, rtWidget, pMatrix);
   1650       break;
   1651     case XFA_Element::Pattern:
   1652       XFA_BOX_Fill_Pattern(box, pGS, fillPath, rtWidget, pMatrix);
   1653       break;
   1654     case XFA_Element::Linear:
   1655       XFA_BOX_Fill_Linear(box, pGS, fillPath, rtWidget, pMatrix);
   1656       break;
   1657     default: {
   1658       FX_ARGB cr;
   1659       if (eType == XFA_Element::Stipple) {
   1660         int32_t iRate = fill.GetStipple(cr);
   1661         if (iRate == 0) {
   1662           iRate = 100;
   1663         }
   1664         int32_t a = 0;
   1665         FX_COLORREF rgb;
   1666         ArgbDecode(cr, a, rgb);
   1667         cr = ArgbEncode(iRate * a / 100, rgb);
   1668       } else {
   1669         cr = fill.GetColor();
   1670       }
   1671       CFX_Color fillColor(cr);
   1672       pGS->SetFillColor(&fillColor);
   1673       pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
   1674     } break;
   1675   }
   1676   pGS->RestoreGraphState();
   1677 }
   1678 static void XFA_BOX_StrokePath(CXFA_Stroke stroke,
   1679                                CFX_Path* pPath,
   1680                                CFX_Graphics* pGS,
   1681                                CFX_Matrix* pMatrix) {
   1682   if (!stroke || !stroke.IsVisible()) {
   1683     return;
   1684   }
   1685   FX_FLOAT fThickness = stroke.GetThickness();
   1686   if (fThickness < 0.001f) {
   1687     return;
   1688   }
   1689   pGS->SaveGraphState();
   1690   if (stroke.IsCorner() && fThickness > 2 * stroke.GetRadius()) {
   1691     fThickness = 2 * stroke.GetRadius();
   1692   }
   1693   pGS->SetLineWidth(fThickness, true);
   1694   pGS->SetLineCap(CFX_GraphStateData::LineCapButt);
   1695   XFA_StrokeTypeSetLineDash(pGS, stroke.GetStrokeType(),
   1696                             XFA_ATTRIBUTEENUM_Butt);
   1697   CFX_Color fxColor(stroke.GetColor());
   1698   pGS->SetStrokeColor(&fxColor);
   1699   pGS->StrokePath(pPath, pMatrix);
   1700   pGS->RestoreGraphState();
   1701 }
   1702 static void XFA_BOX_StrokeArc(CXFA_Box box,
   1703                               CFX_Graphics* pGS,
   1704                               CFX_RectF rtWidget,
   1705                               CFX_Matrix* pMatrix,
   1706                               uint32_t dwFlags) {
   1707   CXFA_Edge edge = box.GetEdge(0);
   1708   if (!edge || !edge.IsVisible()) {
   1709     return;
   1710   }
   1711   bool bVisible = false;
   1712   FX_FLOAT fThickness = 0;
   1713   int32_t i3DType = box.Get3DStyle(bVisible, fThickness);
   1714   if (i3DType) {
   1715     if (bVisible && fThickness >= 0.001f) {
   1716       dwFlags |= XFA_DRAWBOX_Lowered3D;
   1717     }
   1718   }
   1719   FX_FLOAT fHalf = edge.GetThickness() / 2;
   1720   if (fHalf < 0) {
   1721     fHalf = 0;
   1722   }
   1723   int32_t iHand = box.GetHand();
   1724   if (iHand == XFA_ATTRIBUTEENUM_Left) {
   1725     rtWidget.Inflate(fHalf, fHalf);
   1726   } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   1727     rtWidget.Deflate(fHalf, fHalf);
   1728   }
   1729   if ((dwFlags & XFA_DRAWBOX_ForceRound) == 0 ||
   1730       (dwFlags & XFA_DRAWBOX_Lowered3D) == 0) {
   1731     if (fHalf < 0.001f)
   1732       return;
   1733 
   1734     CFX_Path arcPath;
   1735     XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, dwFlags);
   1736     XFA_BOX_StrokePath(edge, &arcPath, pGS, pMatrix);
   1737     return;
   1738   }
   1739   pGS->SaveGraphState();
   1740   pGS->SetLineWidth(fHalf);
   1741 
   1742   FX_FLOAT a, b;
   1743   a = rtWidget.width / 2.0f;
   1744   b = rtWidget.height / 2.0f;
   1745   if (dwFlags & XFA_DRAWBOX_ForceRound) {
   1746     a = std::min(a, b);
   1747     b = a;
   1748   }
   1749 
   1750   CFX_PointF center = rtWidget.Center();
   1751   rtWidget.left = center.x - a;
   1752   rtWidget.top = center.y - b;
   1753   rtWidget.width = a + a;
   1754   rtWidget.height = b + b;
   1755 
   1756   FX_FLOAT startAngle = 0, sweepAngle = 360;
   1757   startAngle = startAngle * FX_PI / 180.0f;
   1758   sweepAngle = -sweepAngle * FX_PI / 180.0f;
   1759 
   1760   CFX_Path arcPath;
   1761   arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
   1762                  FX_PI);
   1763 
   1764   CFX_Color cr(0xFF808080);
   1765   pGS->SetStrokeColor(&cr);
   1766   pGS->StrokePath(&arcPath, pMatrix);
   1767   arcPath.Clear();
   1768   arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
   1769                  FX_PI);
   1770 
   1771   cr.Set(0xFFFFFFFF);
   1772   pGS->SetStrokeColor(&cr);
   1773   pGS->StrokePath(&arcPath, pMatrix);
   1774   rtWidget.Deflate(fHalf, fHalf);
   1775   arcPath.Clear();
   1776   arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
   1777                  FX_PI);
   1778 
   1779   cr.Set(0xFF404040);
   1780   pGS->SetStrokeColor(&cr);
   1781   pGS->StrokePath(&arcPath, pMatrix);
   1782   arcPath.Clear();
   1783   arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
   1784                  FX_PI);
   1785 
   1786   cr.Set(0xFFC0C0C0);
   1787   pGS->SetStrokeColor(&cr);
   1788   pGS->StrokePath(&arcPath, pMatrix);
   1789   pGS->RestoreGraphState();
   1790 }
   1791 static void XFA_Draw3DRect(CFX_Graphics* pGraphic,
   1792                            const CFX_RectF& rt,
   1793                            FX_FLOAT fLineWidth,
   1794                            CFX_Matrix* pMatrix,
   1795                            FX_ARGB argbTopLeft,
   1796                            FX_ARGB argbBottomRight) {
   1797   CFX_Color crLT(argbTopLeft);
   1798   pGraphic->SetFillColor(&crLT);
   1799   FX_FLOAT fBottom = rt.bottom();
   1800   FX_FLOAT fRight = rt.right();
   1801   CFX_Path pathLT;
   1802   pathLT.MoveTo(CFX_PointF(rt.left, fBottom));
   1803   pathLT.LineTo(CFX_PointF(rt.left, rt.top));
   1804   pathLT.LineTo(CFX_PointF(fRight, rt.top));
   1805   pathLT.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
   1806   pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, rt.top + fLineWidth));
   1807   pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
   1808   pathLT.LineTo(CFX_PointF(rt.left, fBottom));
   1809   pGraphic->FillPath(&pathLT, FXFILL_WINDING, pMatrix);
   1810 
   1811   CFX_Color crRB(argbBottomRight);
   1812   pGraphic->SetFillColor(&crRB);
   1813 
   1814   CFX_Path pathRB;
   1815   pathRB.MoveTo(CFX_PointF(fRight, rt.top));
   1816   pathRB.LineTo(CFX_PointF(fRight, fBottom));
   1817   pathRB.LineTo(CFX_PointF(rt.left, fBottom));
   1818   pathRB.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
   1819   pathRB.LineTo(CFX_PointF(fRight - fLineWidth, fBottom - fLineWidth));
   1820   pathRB.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
   1821   pathRB.LineTo(CFX_PointF(fRight, rt.top));
   1822   pGraphic->FillPath(&pathRB, FXFILL_WINDING, pMatrix);
   1823 }
   1824 static void XFA_BOX_Stroke_3DRect_Lowered(CFX_Graphics* pGS,
   1825                                           CFX_RectF rt,
   1826                                           FX_FLOAT fThickness,
   1827                                           CFX_Matrix* pMatrix) {
   1828   FX_FLOAT fHalfWidth = fThickness / 2.0f;
   1829   CFX_RectF rtInner(rt);
   1830   rtInner.Deflate(fHalfWidth, fHalfWidth);
   1831   CFX_Color cr(0xFF000000);
   1832   pGS->SetFillColor(&cr);
   1833   CFX_Path path;
   1834   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
   1835   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
   1836   pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
   1837   XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFF808080, 0xFFC0C0C0);
   1838 }
   1839 static void XFA_BOX_Stroke_3DRect_Raised(CFX_Graphics* pGS,
   1840                                          CFX_RectF rt,
   1841                                          FX_FLOAT fThickness,
   1842                                          CFX_Matrix* pMatrix) {
   1843   FX_FLOAT fHalfWidth = fThickness / 2.0f;
   1844   CFX_RectF rtInner(rt);
   1845   rtInner.Deflate(fHalfWidth, fHalfWidth);
   1846   CFX_Color cr(0xFF000000);
   1847   pGS->SetFillColor(&cr);
   1848   CFX_Path path;
   1849   path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
   1850   path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
   1851   pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
   1852   XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFFFFFFFF, 0xFF808080);
   1853 }
   1854 static void XFA_BOX_Stroke_3DRect_Etched(CFX_Graphics* pGS,
   1855                                          CFX_RectF rt,
   1856                                          FX_FLOAT fThickness,
   1857                                          CFX_Matrix* pMatrix) {
   1858   FX_FLOAT fHalfWidth = fThickness / 2.0f;
   1859   XFA_Draw3DRect(pGS, rt, fThickness, pMatrix, 0xFF808080, 0xFFFFFFFF);
   1860   CFX_RectF rtInner(rt);
   1861   rtInner.Deflate(fHalfWidth, fHalfWidth);
   1862   XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFFFFFFFF, 0xFF808080);
   1863 }
   1864 static void XFA_BOX_Stroke_3DRect_Embossed(CFX_Graphics* pGS,
   1865                                            CFX_RectF rt,
   1866                                            FX_FLOAT fThickness,
   1867                                            CFX_Matrix* pMatrix) {
   1868   FX_FLOAT fHalfWidth = fThickness / 2.0f;
   1869   XFA_Draw3DRect(pGS, rt, fThickness, pMatrix, 0xFF808080, 0xFF000000);
   1870   CFX_RectF rtInner(rt);
   1871   rtInner.Deflate(fHalfWidth, fHalfWidth);
   1872   XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFF000000, 0xFF808080);
   1873 }
   1874 static void XFA_BOX_Stroke_Rect(CXFA_Box box,
   1875                                 const std::vector<CXFA_Stroke>& strokes,
   1876                                 CFX_Graphics* pGS,
   1877                                 CFX_RectF rtWidget,
   1878                                 CFX_Matrix* pMatrix) {
   1879   bool bVisible = false;
   1880   FX_FLOAT fThickness = 0;
   1881   int32_t i3DType = box.Get3DStyle(bVisible, fThickness);
   1882   if (i3DType) {
   1883     if (!bVisible || fThickness < 0.001f) {
   1884       return;
   1885     }
   1886     switch (i3DType) {
   1887       case XFA_ATTRIBUTEENUM_Lowered:
   1888         XFA_BOX_Stroke_3DRect_Lowered(pGS, rtWidget, fThickness, pMatrix);
   1889         break;
   1890       case XFA_ATTRIBUTEENUM_Raised:
   1891         XFA_BOX_Stroke_3DRect_Raised(pGS, rtWidget, fThickness, pMatrix);
   1892         break;
   1893       case XFA_ATTRIBUTEENUM_Etched:
   1894         XFA_BOX_Stroke_3DRect_Etched(pGS, rtWidget, fThickness, pMatrix);
   1895         break;
   1896       case XFA_ATTRIBUTEENUM_Embossed:
   1897         XFA_BOX_Stroke_3DRect_Embossed(pGS, rtWidget, fThickness, pMatrix);
   1898         break;
   1899     }
   1900     return;
   1901   }
   1902   bool bClose = false;
   1903   bool bSameStyles = true;
   1904   CXFA_Stroke stroke1 = strokes[0];
   1905   for (int32_t i = 1; i < 8; i++) {
   1906     CXFA_Stroke stroke2 = strokes[i];
   1907     if (!stroke1.SameStyles(stroke2)) {
   1908       bSameStyles = false;
   1909       break;
   1910     }
   1911     stroke1 = stroke2;
   1912   }
   1913   if (bSameStyles) {
   1914     stroke1 = strokes[0];
   1915     bClose = true;
   1916     for (int32_t i = 2; i < 8; i += 2) {
   1917       CXFA_Stroke stroke2 = strokes[i];
   1918       if (!stroke1.SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
   1919                                            XFA_STROKE_SAMESTYLE_Corner)) {
   1920         bSameStyles = false;
   1921         break;
   1922       }
   1923       stroke1 = stroke2;
   1924     }
   1925     if (bSameStyles) {
   1926       stroke1 = strokes[0];
   1927       if (stroke1.IsInverted())
   1928         bSameStyles = false;
   1929       if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square)
   1930         bSameStyles = false;
   1931     }
   1932   }
   1933   bool bStart = true;
   1934   CFX_Path path;
   1935   for (int32_t i = 0; i < 8; i++) {
   1936     CXFA_Stroke stroke = strokes[i];
   1937     if ((i % 1) == 0 && stroke.GetRadius() < 0) {
   1938       bool bEmpty = path.IsEmpty();
   1939       if (!bEmpty) {
   1940         XFA_BOX_StrokePath(stroke, &path, pGS, pMatrix);
   1941         path.Clear();
   1942       }
   1943       bStart = true;
   1944       continue;
   1945     }
   1946     XFA_BOX_GetPath(box, strokes, rtWidget, path, i, bStart, !bSameStyles);
   1947     CXFA_Stroke stroke2 = strokes[(i + 1) % 8];
   1948     bStart = !stroke.SameStyles(stroke2);
   1949     if (bStart) {
   1950       XFA_BOX_StrokePath(stroke, &path, pGS, pMatrix);
   1951       path.Clear();
   1952     }
   1953   }
   1954   bool bEmpty = path.IsEmpty();
   1955   if (!bEmpty) {
   1956     if (bClose) {
   1957       path.Close();
   1958     }
   1959     XFA_BOX_StrokePath(strokes[7], &path, pGS, pMatrix);
   1960   }
   1961 }
   1962 static void XFA_BOX_Stroke(CXFA_Box box,
   1963                            const std::vector<CXFA_Stroke>& strokes,
   1964                            CFX_Graphics* pGS,
   1965                            CFX_RectF rtWidget,
   1966                            CFX_Matrix* pMatrix,
   1967                            uint32_t dwFlags) {
   1968   if (box.IsArc() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
   1969     XFA_BOX_StrokeArc(box, pGS, rtWidget, pMatrix, dwFlags);
   1970     return;
   1971   }
   1972   bool bVisible = false;
   1973   for (int32_t j = 0; j < 4; j++) {
   1974     if (strokes[j * 2 + 1].IsVisible()) {
   1975       bVisible = true;
   1976       break;
   1977     }
   1978   }
   1979   if (!bVisible) {
   1980     return;
   1981   }
   1982   for (int32_t i = 1; i < 8; i += 2) {
   1983     CXFA_Edge edge(strokes[i].GetNode());
   1984     FX_FLOAT fThickness = edge.GetThickness();
   1985     if (fThickness < 0) {
   1986       fThickness = 0;
   1987     }
   1988     FX_FLOAT fHalf = fThickness / 2;
   1989     int32_t iHand = box.GetHand();
   1990     switch (i) {
   1991       case 1:
   1992         if (iHand == XFA_ATTRIBUTEENUM_Left) {
   1993           rtWidget.top -= fHalf;
   1994           rtWidget.height += fHalf;
   1995         } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   1996           rtWidget.top += fHalf;
   1997           rtWidget.height -= fHalf;
   1998         }
   1999         break;
   2000       case 3:
   2001         if (iHand == XFA_ATTRIBUTEENUM_Left) {
   2002           rtWidget.width += fHalf;
   2003         } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   2004           rtWidget.width -= fHalf;
   2005         }
   2006         break;
   2007       case 5:
   2008         if (iHand == XFA_ATTRIBUTEENUM_Left) {
   2009           rtWidget.height += fHalf;
   2010         } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   2011           rtWidget.height -= fHalf;
   2012         }
   2013         break;
   2014       case 7:
   2015         if (iHand == XFA_ATTRIBUTEENUM_Left) {
   2016           rtWidget.left -= fHalf;
   2017           rtWidget.width += fHalf;
   2018         } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
   2019           rtWidget.left += fHalf;
   2020           rtWidget.width -= fHalf;
   2021         }
   2022         break;
   2023     }
   2024   }
   2025   XFA_BOX_Stroke_Rect(box, strokes, pGS, rtWidget, pMatrix);
   2026 }
   2027 void XFA_DrawBox(CXFA_Box box,
   2028                  CFX_Graphics* pGS,
   2029                  const CFX_RectF& rtWidget,
   2030                  CFX_Matrix* pMatrix,
   2031                  uint32_t dwFlags) {
   2032   if (!box || box.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
   2033     return;
   2034 
   2035   XFA_Element eType = box.GetElementType();
   2036   if (eType != XFA_Element::Arc && eType != XFA_Element::Border &&
   2037       eType != XFA_Element::Rectangle) {
   2038     return;
   2039   }
   2040   std::vector<CXFA_Stroke> strokes;
   2041   if (!(dwFlags & XFA_DRAWBOX_ForceRound) && eType != XFA_Element::Arc)
   2042     box.GetStrokes(&strokes);
   2043 
   2044   XFA_BOX_Fill(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
   2045   XFA_BOX_Stroke(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
   2046 }
   2047 
   2048 CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {}
   2049 
   2050 CXFA_CalcData::~CXFA_CalcData() {}
   2051