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