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