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