summaryrefslogtreecommitdiff
path: root/xfa/fxfa/cxfa_ffwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fxfa/cxfa_ffwidget.cpp')
-rw-r--r--xfa/fxfa/cxfa_ffwidget.cpp2048
1 files changed, 2048 insertions, 0 deletions
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
new file mode 100644
index 0000000000..504ce70ad9
--- /dev/null
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -0,0 +1,2048 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "xfa/fxfa/cxfa_ffwidget.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "core/fpdfapi/page/cpdf_pageobjectholder.h"
+#include "core/fxcodec/codec/ccodec_progressivedecoder.h"
+#include "core/fxcodec/fx_codec.h"
+#include "core/fxcrt/cfx_maybe_owned.h"
+#include "core/fxge/cfx_gemodule.h"
+#include "core/fxge/cfx_pathdata.h"
+#include "core/fxge/cfx_renderdevice.h"
+#include "xfa/fwl/fwl_widgethit.h"
+#include "xfa/fxfa/app/cxfa_textlayout.h"
+#include "xfa/fxfa/cxfa_eventparam.h"
+#include "xfa/fxfa/cxfa_ffapp.h"
+#include "xfa/fxfa/cxfa_ffdoc.h"
+#include "xfa/fxfa/cxfa_ffdocview.h"
+#include "xfa/fxfa/cxfa_ffpageview.h"
+#include "xfa/fxfa/cxfa_widgetacc.h"
+#include "xfa/fxfa/parser/cxfa_corner.h"
+#include "xfa/fxgraphics/cfx_color.h"
+#include "xfa/fxgraphics/cfx_graphics.h"
+#include "xfa/fxgraphics/cfx_path.h"
+#include "xfa/fxgraphics/cfx_pattern.h"
+#include "xfa/fxgraphics/cfx_shading.h"
+
+CXFA_FFWidget::CXFA_FFWidget(CXFA_WidgetAcc* pDataAcc)
+ : CXFA_ContentLayoutItem(pDataAcc->GetNode()),
+ m_pPageView(nullptr),
+ m_pDataAcc(pDataAcc) {}
+
+CXFA_FFWidget::~CXFA_FFWidget() {}
+
+const CFWL_App* CXFA_FFWidget::GetFWLApp() {
+ return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp();
+}
+
+CFX_RectF CXFA_FFWidget::GetWidgetRect() {
+ if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0)
+ RecacheWidgetRect();
+ return m_rtWidget;
+}
+
+CFX_RectF CXFA_FFWidget::RecacheWidgetRect() {
+ m_dwStatus |= XFA_WidgetStatus_RectCached;
+ m_rtWidget = GetRect(false);
+ return m_rtWidget;
+}
+
+CFX_RectF CXFA_FFWidget::GetRectWithoutRotate() {
+ CFX_RectF rtWidget = GetWidgetRect();
+ float fValue = 0;
+ switch (m_pDataAcc->GetRotate()) {
+ case 90:
+ rtWidget.top = rtWidget.bottom();
+ fValue = rtWidget.width;
+ rtWidget.width = rtWidget.height;
+ rtWidget.height = fValue;
+ break;
+ case 180:
+ rtWidget.left = rtWidget.right();
+ rtWidget.top = rtWidget.bottom();
+ break;
+ case 270:
+ rtWidget.left = rtWidget.right();
+ fValue = rtWidget.width;
+ rtWidget.width = rtWidget.height;
+ rtWidget.height = fValue;
+ break;
+ }
+ return rtWidget;
+}
+
+uint32_t CXFA_FFWidget::GetStatus() {
+ return m_dwStatus;
+}
+
+void CXFA_FFWidget::ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved) {
+ m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded;
+}
+
+CFX_RectF CXFA_FFWidget::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
+ if (bDrawFocus || !m_pPageView)
+ return CFX_RectF();
+ return m_pPageView->GetPageViewRect();
+}
+
+CXFA_WidgetAcc* CXFA_FFWidget::GetDataAcc() {
+ return m_pDataAcc;
+}
+
+bool CXFA_FFWidget::GetToolTip(CFX_WideString& wsToolTip) {
+ if (CXFA_Assist assist = m_pDataAcc->GetAssist()) {
+ if (CXFA_ToolTip toolTip = assist.GetToolTip()) {
+ return toolTip.GetTip(wsToolTip);
+ }
+ }
+ return GetCaptionText(wsToolTip);
+}
+
+void CXFA_FFWidget::RenderWidget(CFX_Graphics* pGS,
+ CFX_Matrix* pMatrix,
+ uint32_t dwStatus) {
+ if (!IsMatchVisibleStatus(dwStatus))
+ return;
+
+ CXFA_Border border = m_pDataAcc->GetBorder();
+ if (!border)
+ return;
+
+ CFX_RectF rtBorder = GetRectWithoutRotate();
+ CXFA_Margin margin = border.GetMargin();
+ if (margin)
+ XFA_RectWidthoutMargin(rtBorder, margin);
+
+ rtBorder.Normalize();
+ DrawBorder(pGS, border, rtBorder, pMatrix);
+}
+
+bool CXFA_FFWidget::IsLoaded() {
+ return !!m_pPageView;
+}
+bool CXFA_FFWidget::LoadWidget() {
+ PerformLayout();
+ return true;
+}
+void CXFA_FFWidget::UnloadWidget() {}
+bool CXFA_FFWidget::PerformLayout() {
+ RecacheWidgetRect();
+ return true;
+}
+bool CXFA_FFWidget::UpdateFWLData() {
+ return false;
+}
+void CXFA_FFWidget::UpdateWidgetProperty() {}
+void CXFA_FFWidget::DrawBorder(CFX_Graphics* pGS,
+ CXFA_Box box,
+ const CFX_RectF& rtBorder,
+ CFX_Matrix* pMatrix,
+ uint32_t dwFlags) {
+ XFA_DrawBox(box, pGS, rtBorder, pMatrix, dwFlags);
+}
+
+void CXFA_FFWidget::InvalidateWidget(const CFX_RectF* pRect) {
+ if (pRect) {
+ GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, *pRect);
+ return;
+ }
+
+ CFX_RectF rtWidget = GetBBox(XFA_WidgetStatus_Focused);
+ rtWidget.Inflate(2, 2);
+ GetDoc()->GetDocEnvironment()->InvalidateRect(m_pPageView, rtWidget);
+}
+
+void CXFA_FFWidget::AddInvalidateRect(const CFX_RectF* pRect) {
+ CFX_RectF rtWidget;
+ if (pRect) {
+ rtWidget = *pRect;
+ } else {
+ rtWidget = GetBBox(XFA_WidgetStatus_Focused);
+ rtWidget.Inflate(2, 2);
+ }
+ m_pDocView->AddInvalidateRect(m_pPageView, rtWidget);
+}
+
+bool CXFA_FFWidget::GetCaptionText(CFX_WideString& wsCap) {
+ CXFA_TextLayout* pCapTextlayout = m_pDataAcc->GetCaptionTextLayout();
+ if (!pCapTextlayout) {
+ return false;
+ }
+ pCapTextlayout->GetText(wsCap);
+ return true;
+}
+
+bool CXFA_FFWidget::IsFocused() {
+ return !!(m_dwStatus & XFA_WidgetStatus_Focused);
+}
+
+bool CXFA_FFWidget::OnMouseEnter() {
+ return false;
+}
+
+bool CXFA_FFWidget::OnMouseExit() {
+ return false;
+}
+
+bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnMouseWheel(uint32_t dwFlags,
+ int16_t zDelta,
+ const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) {
+ CXFA_FFWidget* pParent = GetParent();
+ if (pParent && !pParent->IsAncestorOf(pOldWidget)) {
+ pParent->OnSetFocus(pOldWidget);
+ }
+ m_dwStatus |= XFA_WidgetStatus_Focused;
+ CXFA_EventParam eParam;
+ eParam.m_eType = XFA_EVENT_Enter;
+ eParam.m_pTarget = m_pDataAcc;
+ m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Enter, &eParam);
+ return true;
+}
+
+bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) {
+ m_dwStatus &= ~XFA_WidgetStatus_Focused;
+ EventKillFocus();
+ if (pNewWidget) {
+ CXFA_FFWidget* pParent = GetParent();
+ if (pParent && !pParent->IsAncestorOf(pNewWidget)) {
+ pParent->OnKillFocus(pNewWidget);
+ }
+ }
+ return true;
+}
+
+bool CXFA_FFWidget::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
+ return false;
+}
+
+bool CXFA_FFWidget::OnChar(uint32_t dwChar, uint32_t dwFlags) {
+ return false;
+}
+
+FWL_WidgetHit CXFA_FFWidget::OnHitTest(const CFX_PointF& point) {
+ return FWL_WidgetHit::Unknown;
+}
+
+bool CXFA_FFWidget::OnSetCursor(const CFX_PointF& point) {
+ return false;
+}
+
+bool CXFA_FFWidget::CanUndo() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanRedo() {
+ return false;
+}
+
+bool CXFA_FFWidget::Undo() {
+ return false;
+}
+
+bool CXFA_FFWidget::Redo() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanCopy() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanCut() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanPaste() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanSelectAll() {
+ return false;
+}
+
+bool CXFA_FFWidget::CanDelete() {
+ return CanCut();
+}
+
+bool CXFA_FFWidget::CanDeSelect() {
+ return CanCopy();
+}
+
+bool CXFA_FFWidget::Copy(CFX_WideString& wsCopy) {
+ return false;
+}
+
+bool CXFA_FFWidget::Cut(CFX_WideString& wsCut) {
+ return false;
+}
+
+bool CXFA_FFWidget::Paste(const CFX_WideString& wsPaste) {
+ return false;
+}
+
+void CXFA_FFWidget::SelectAll() {}
+
+void CXFA_FFWidget::Delete() {}
+
+void CXFA_FFWidget::DeSelect() {}
+
+bool CXFA_FFWidget::GetSuggestWords(CFX_PointF pointf,
+ std::vector<CFX_ByteString>& sSuggest) {
+ return false;
+}
+bool CXFA_FFWidget::ReplaceSpellCheckWord(CFX_PointF pointf,
+ const CFX_ByteStringC& bsReplace) {
+ return false;
+}
+
+CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) {
+ CFX_Matrix mt = GetRotateMatrix();
+ if (mt.IsIdentity())
+ return point;
+
+ CFX_Matrix mtReverse;
+ mtReverse.SetReverse(mt);
+ return mtReverse.Transform(point);
+}
+
+static void XFA_GetMatrix(CFX_Matrix& m,
+ int32_t iRotate,
+ XFA_ATTRIBUTEENUM at,
+ const CFX_RectF& rt) {
+ if (!iRotate) {
+ return;
+ }
+ float fAnchorX = 0;
+ float fAnchorY = 0;
+ switch (at) {
+ case XFA_ATTRIBUTEENUM_TopLeft:
+ fAnchorX = rt.left, fAnchorY = rt.top;
+ break;
+ case XFA_ATTRIBUTEENUM_TopCenter:
+ fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.top;
+ break;
+ case XFA_ATTRIBUTEENUM_TopRight:
+ fAnchorX = rt.right(), fAnchorY = rt.top;
+ break;
+ case XFA_ATTRIBUTEENUM_MiddleLeft:
+ fAnchorX = rt.left, fAnchorY = (rt.top + rt.bottom()) / 2;
+ break;
+ case XFA_ATTRIBUTEENUM_MiddleCenter:
+ fAnchorX = (rt.left + rt.right()) / 2,
+ fAnchorY = (rt.top + rt.bottom()) / 2;
+ break;
+ case XFA_ATTRIBUTEENUM_MiddleRight:
+ fAnchorX = rt.right(), fAnchorY = (rt.top + rt.bottom()) / 2;
+ break;
+ case XFA_ATTRIBUTEENUM_BottomLeft:
+ fAnchorX = rt.left, fAnchorY = rt.bottom();
+ break;
+ case XFA_ATTRIBUTEENUM_BottomCenter:
+ fAnchorX = (rt.left + rt.right()) / 2, fAnchorY = rt.bottom();
+ break;
+ case XFA_ATTRIBUTEENUM_BottomRight:
+ fAnchorX = rt.right(), fAnchorY = rt.bottom();
+ break;
+ default:
+ break;
+ }
+ switch (iRotate) {
+ case 90:
+ m.a = 0, m.b = -1, m.c = 1, m.d = 0, m.e = fAnchorX - fAnchorY,
+ m.f = fAnchorX + fAnchorY;
+ break;
+ case 180:
+ m.a = -1, m.b = 0, m.c = 0, m.d = -1, m.e = fAnchorX * 2,
+ m.f = fAnchorY * 2;
+ break;
+ case 270:
+ m.a = 0, m.b = 1, m.c = -1, m.d = 0, m.e = fAnchorX + fAnchorY,
+ m.f = fAnchorY - fAnchorX;
+ break;
+ }
+}
+
+CFX_Matrix CXFA_FFWidget::GetRotateMatrix() {
+ CFX_Matrix mt;
+ int32_t iRotate = m_pDataAcc->GetRotate();
+ if (!iRotate)
+ return mt;
+
+ CFX_RectF rcWidget = GetRectWithoutRotate();
+ XFA_ATTRIBUTEENUM at = XFA_ATTRIBUTEENUM_TopLeft;
+ XFA_GetMatrix(mt, iRotate, at, rcWidget);
+
+ return mt;
+}
+
+bool CXFA_FFWidget::IsLayoutRectEmpty() {
+ CFX_RectF rtLayout = GetRectWithoutRotate();
+ return rtLayout.width < 0.1f && rtLayout.height < 0.1f;
+}
+CXFA_FFWidget* CXFA_FFWidget::GetParent() {
+ CXFA_Node* pParentNode =
+ m_pDataAcc->GetNode()->GetNodeItem(XFA_NODEITEM_Parent);
+ if (pParentNode) {
+ CXFA_WidgetAcc* pParentWidgetAcc =
+ static_cast<CXFA_WidgetAcc*>(pParentNode->GetWidgetData());
+ if (pParentWidgetAcc) {
+ return pParentWidgetAcc->GetNextWidget(nullptr);
+ }
+ }
+ return nullptr;
+}
+
+bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) {
+ if (!pWidget)
+ return false;
+
+ CXFA_Node* pNode = m_pDataAcc->GetNode();
+ CXFA_Node* pChildNode = pWidget->GetDataAcc()->GetNode();
+ while (pChildNode) {
+ if (pChildNode == pNode)
+ return true;
+
+ pChildNode = pChildNode->GetNodeItem(XFA_NODEITEM_Parent);
+ }
+ return false;
+}
+
+bool CXFA_FFWidget::PtInActiveRect(const CFX_PointF& point) {
+ return GetWidgetRect().Contains(point);
+}
+
+CXFA_FFDocView* CXFA_FFWidget::GetDocView() {
+ return m_pDocView;
+}
+
+void CXFA_FFWidget::SetDocView(CXFA_FFDocView* pDocView) {
+ m_pDocView = pDocView;
+}
+
+CXFA_FFDoc* CXFA_FFWidget::GetDoc() {
+ return m_pDocView->GetDoc();
+}
+
+CXFA_FFApp* CXFA_FFWidget::GetApp() {
+ return GetDoc()->GetApp();
+}
+
+IXFA_AppProvider* CXFA_FFWidget::GetAppProvider() {
+ return GetApp()->GetAppProvider();
+}
+
+bool CXFA_FFWidget::IsMatchVisibleStatus(uint32_t dwStatus) {
+ return !!(m_dwStatus & XFA_WidgetStatus_Visible);
+}
+
+void CXFA_FFWidget::EventKillFocus() {
+ if (m_dwStatus & XFA_WidgetStatus_Access) {
+ m_dwStatus &= ~XFA_WidgetStatus_Access;
+ return;
+ }
+ CXFA_EventParam eParam;
+ eParam.m_eType = XFA_EVENT_Exit;
+ eParam.m_pTarget = m_pDataAcc;
+ m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Exit, &eParam);
+}
+bool CXFA_FFWidget::IsButtonDown() {
+ return (m_dwStatus & XFA_WidgetStatus_ButtonDown) != 0;
+}
+void CXFA_FFWidget::SetButtonDown(bool bSet) {
+ bSet ? m_dwStatus |= XFA_WidgetStatus_ButtonDown
+ : m_dwStatus &= ~XFA_WidgetStatus_ButtonDown;
+}
+int32_t XFA_StrokeTypeSetLineDash(CFX_Graphics* pGraphics,
+ int32_t iStrokeType,
+ int32_t iCapType) {
+ switch (iStrokeType) {
+ case XFA_ATTRIBUTEENUM_DashDot: {
+ float dashArray[] = {4, 1, 2, 1};
+ if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
+ dashArray[1] = 2;
+ dashArray[3] = 2;
+ }
+ pGraphics->SetLineDash(0, dashArray, 4);
+ return FX_DASHSTYLE_DashDot;
+ }
+ case XFA_ATTRIBUTEENUM_DashDotDot: {
+ float dashArray[] = {4, 1, 2, 1, 2, 1};
+ if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
+ dashArray[1] = 2;
+ dashArray[3] = 2;
+ dashArray[5] = 2;
+ }
+ pGraphics->SetLineDash(0, dashArray, 6);
+ return FX_DASHSTYLE_DashDotDot;
+ }
+ case XFA_ATTRIBUTEENUM_Dashed: {
+ float dashArray[] = {5, 1};
+ if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
+ dashArray[1] = 2;
+ }
+ pGraphics->SetLineDash(0, dashArray, 2);
+ return FX_DASHSTYLE_Dash;
+ }
+ case XFA_ATTRIBUTEENUM_Dotted: {
+ float dashArray[] = {2, 1};
+ if (iCapType != XFA_ATTRIBUTEENUM_Butt) {
+ dashArray[1] = 2;
+ }
+ pGraphics->SetLineDash(0, dashArray, 2);
+ return FX_DASHSTYLE_Dot;
+ }
+ default:
+ break;
+ }
+ pGraphics->SetLineDash(FX_DASHSTYLE_Solid);
+ return FX_DASHSTYLE_Solid;
+}
+CFX_GraphStateData::LineCap XFA_LineCapToFXGE(int32_t iLineCap) {
+ switch (iLineCap) {
+ case XFA_ATTRIBUTEENUM_Round:
+ return CFX_GraphStateData::LineCapRound;
+ case XFA_ATTRIBUTEENUM_Butt:
+ return CFX_GraphStateData::LineCapButt;
+ default:
+ break;
+ }
+ return CFX_GraphStateData::LineCapSquare;
+}
+
+class CXFA_ImageRenderer {
+ public:
+ CXFA_ImageRenderer();
+ ~CXFA_ImageRenderer();
+
+ bool Start(CFX_RenderDevice* pDevice,
+ CFX_DIBSource* pDIBSource,
+ FX_ARGB bitmap_argb,
+ int bitmap_alpha,
+ const CFX_Matrix* pImage2Device,
+ uint32_t flags,
+ int blendType = FXDIB_BLEND_NORMAL);
+ bool Continue(IFX_Pause* pPause);
+
+ protected:
+ bool StartDIBSource();
+ void CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
+ int left,
+ int top,
+ FX_ARGB mask_argb,
+ int bitmap_alpha,
+ int blend_mode,
+ int Transparency);
+
+ CFX_RenderDevice* m_pDevice;
+ int m_Status;
+ CFX_Matrix m_ImageMatrix;
+ CFX_DIBSource* m_pDIBSource;
+ std::unique_ptr<CFX_DIBitmap> m_pCloneConvert;
+ int m_BitmapAlpha;
+ FX_ARGB m_FillArgb;
+ uint32_t m_Flags;
+ std::unique_ptr<CFX_ImageTransformer> m_pTransformer;
+ void* m_DeviceHandle;
+ int32_t m_BlendType;
+ bool m_Result;
+ bool m_bPrint;
+};
+
+CXFA_ImageRenderer::CXFA_ImageRenderer()
+ : m_pDevice(nullptr),
+ m_Status(0),
+ m_pDIBSource(nullptr),
+ m_BitmapAlpha(255),
+ m_FillArgb(0),
+ m_Flags(0),
+ m_DeviceHandle(nullptr),
+ m_BlendType(FXDIB_BLEND_NORMAL),
+ m_Result(true),
+ m_bPrint(false) {}
+
+CXFA_ImageRenderer::~CXFA_ImageRenderer() {
+ if (m_DeviceHandle)
+ m_pDevice->CancelDIBits(m_DeviceHandle);
+}
+
+bool CXFA_ImageRenderer::Start(CFX_RenderDevice* pDevice,
+ CFX_DIBSource* pDIBSource,
+ FX_ARGB bitmap_argb,
+ int bitmap_alpha,
+ const CFX_Matrix* pImage2Device,
+ uint32_t flags,
+ int blendType) {
+ m_pDevice = pDevice;
+ m_pDIBSource = pDIBSource;
+ m_FillArgb = bitmap_argb;
+ m_BitmapAlpha = bitmap_alpha;
+ m_ImageMatrix = *pImage2Device;
+ m_Flags = flags;
+ m_BlendType = blendType;
+ return StartDIBSource();
+}
+
+bool CXFA_ImageRenderer::StartDIBSource() {
+ if (m_pDevice->StartDIBitsWithBlend(m_pDIBSource, m_BitmapAlpha, m_FillArgb,
+ &m_ImageMatrix, m_Flags, m_DeviceHandle,
+ m_BlendType)) {
+ if (m_DeviceHandle) {
+ m_Status = 3;
+ return true;
+ }
+ return false;
+ }
+ CFX_FloatRect image_rect_f = m_ImageMatrix.GetUnitRect();
+ FX_RECT image_rect = image_rect_f.GetOuterRect();
+ int dest_width = image_rect.Width();
+ int dest_height = image_rect.Height();
+ if ((FXSYS_fabs(m_ImageMatrix.b) >= 0.5f || m_ImageMatrix.a == 0) ||
+ (FXSYS_fabs(m_ImageMatrix.c) >= 0.5f || m_ImageMatrix.d == 0)) {
+ if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
+ m_Result = false;
+ return false;
+ }
+ CFX_DIBSource* pDib = m_pDIBSource;
+ if (m_pDIBSource->HasAlpha() &&
+ !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE) &&
+ !(m_pDevice->GetRenderCaps() & FXRC_GET_BITS)) {
+ m_pCloneConvert = m_pDIBSource->CloneConvert(FXDIB_Rgb);
+ if (!m_pCloneConvert) {
+ m_Result = false;
+ return false;
+ }
+ pDib = m_pCloneConvert.get();
+ }
+ FX_RECT clip_box = m_pDevice->GetClipBox();
+ clip_box.Intersect(image_rect);
+ m_Status = 2;
+ m_pTransformer.reset(
+ new CFX_ImageTransformer(pDib, &m_ImageMatrix, m_Flags, &clip_box));
+ m_pTransformer->Start();
+ return true;
+ }
+ if (m_ImageMatrix.a < 0) {
+ dest_width = -dest_width;
+ }
+ if (m_ImageMatrix.d > 0) {
+ dest_height = -dest_height;
+ }
+ int dest_left, dest_top;
+ dest_left = dest_width > 0 ? image_rect.left : image_rect.right;
+ dest_top = dest_height > 0 ? image_rect.top : image_rect.bottom;
+ if (m_pDIBSource->IsOpaqueImage() && m_BitmapAlpha == 255) {
+ if (m_pDevice->StretchDIBitsWithFlagsAndBlend(
+ m_pDIBSource, dest_left, dest_top, dest_width, dest_height, m_Flags,
+ m_BlendType)) {
+ return false;
+ }
+ }
+ if (m_pDIBSource->IsAlphaMask()) {
+ if (m_BitmapAlpha != 255) {
+ m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
+ }
+ if (m_pDevice->StretchBitMaskWithFlags(m_pDIBSource, dest_left, dest_top,
+ dest_width, dest_height, m_FillArgb,
+ m_Flags)) {
+ return false;
+ }
+ }
+ if (m_bPrint && !(m_pDevice->GetRenderCaps() & FXRC_BLEND_MODE)) {
+ m_Result = false;
+ return true;
+ }
+ FX_RECT clip_box = m_pDevice->GetClipBox();
+ FX_RECT dest_rect = clip_box;
+ dest_rect.Intersect(image_rect);
+ FX_RECT dest_clip(
+ dest_rect.left - image_rect.left, dest_rect.top - image_rect.top,
+ dest_rect.right - image_rect.left, dest_rect.bottom - image_rect.top);
+ std::unique_ptr<CFX_DIBitmap> pStretched(
+ m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip));
+ if (pStretched) {
+ CompositeDIBitmap(pStretched.get(), dest_rect.left, dest_rect.top,
+ m_FillArgb, m_BitmapAlpha, m_BlendType, false);
+ }
+ return false;
+}
+
+bool CXFA_ImageRenderer::Continue(IFX_Pause* pPause) {
+ if (m_Status == 2) {
+ if (m_pTransformer->Continue(pPause))
+ return true;
+
+ std::unique_ptr<CFX_DIBitmap> pBitmap(m_pTransformer->DetachBitmap());
+ if (!pBitmap)
+ return false;
+
+ if (pBitmap->IsAlphaMask()) {
+ if (m_BitmapAlpha != 255)
+ m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha);
+ m_Result =
+ m_pDevice->SetBitMask(pBitmap.get(), m_pTransformer->result().left,
+ m_pTransformer->result().top, m_FillArgb);
+ } else {
+ if (m_BitmapAlpha != 255)
+ pBitmap->MultiplyAlpha(m_BitmapAlpha);
+ m_Result = m_pDevice->SetDIBitsWithBlend(
+ pBitmap.get(), m_pTransformer->result().left,
+ m_pTransformer->result().top, m_BlendType);
+ }
+ return false;
+ }
+ if (m_Status == 3)
+ return m_pDevice->ContinueDIBits(m_DeviceHandle, pPause);
+
+ return false;
+}
+
+void CXFA_ImageRenderer::CompositeDIBitmap(CFX_DIBitmap* pDIBitmap,
+ int left,
+ int top,
+ FX_ARGB mask_argb,
+ int bitmap_alpha,
+ int blend_mode,
+ int Transparency) {
+ if (!pDIBitmap) {
+ return;
+ }
+ bool bIsolated = !!(Transparency & PDFTRANS_ISOLATED);
+ bool bGroup = !!(Transparency & PDFTRANS_GROUP);
+ if (blend_mode == FXDIB_BLEND_NORMAL) {
+ if (!pDIBitmap->IsAlphaMask()) {
+ if (bitmap_alpha < 255) {
+ pDIBitmap->MultiplyAlpha(bitmap_alpha);
+ }
+ if (m_pDevice->SetDIBits(pDIBitmap, left, top)) {
+ return;
+ }
+ } else {
+ uint32_t fill_argb = (mask_argb);
+ if (bitmap_alpha < 255) {
+ ((uint8_t*)&fill_argb)[3] =
+ ((uint8_t*)&fill_argb)[3] * bitmap_alpha / 255;
+ }
+ if (m_pDevice->SetBitMask(pDIBitmap, left, top, fill_argb)) {
+ return;
+ }
+ }
+ }
+ bool bBackAlphaRequired = blend_mode && bIsolated;
+ bool bGetBackGround =
+ ((m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT)) ||
+ (!(m_pDevice->GetRenderCaps() & FXRC_ALPHA_OUTPUT) &&
+ (m_pDevice->GetRenderCaps() & FXRC_GET_BITS) && !bBackAlphaRequired);
+ if (bGetBackGround) {
+ if (bIsolated || !bGroup) {
+ if (pDIBitmap->IsAlphaMask()) {
+ return;
+ }
+ m_pDevice->SetDIBitsWithBlend(pDIBitmap, left, top, blend_mode);
+ } else {
+ FX_RECT rect(left, top, left + pDIBitmap->GetWidth(),
+ top + pDIBitmap->GetHeight());
+ rect.Intersect(m_pDevice->GetClipBox());
+ CFX_MaybeOwned<CFX_DIBitmap> pClone;
+ if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) {
+ pClone = m_pDevice->GetBackDrop()->Clone(&rect);
+ CFX_DIBitmap* pForeBitmap = m_pDevice->GetBitmap();
+ pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pForeBitmap, rect.left, rect.top);
+ left = left >= 0 ? 0 : left;
+ top = top >= 0 ? 0 : top;
+ if (!pDIBitmap->IsAlphaMask())
+ pClone->CompositeBitmap(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pDIBitmap, left, top, blend_mode);
+ else
+ pClone->CompositeMask(0, 0, pClone->GetWidth(), pClone->GetHeight(),
+ pDIBitmap, mask_argb, left, top, blend_mode);
+ } else {
+ pClone = pDIBitmap;
+ }
+ if (m_pDevice->GetBackDrop()) {
+ m_pDevice->SetDIBits(pClone.Get(), rect.left, rect.top);
+ } else {
+ if (pDIBitmap->IsAlphaMask())
+ return;
+ m_pDevice->SetDIBitsWithBlend(pDIBitmap, rect.left, rect.top,
+ blend_mode);
+ }
+ }
+ return;
+ }
+ if (!pDIBitmap->HasAlpha() ||
+ (m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) {
+ return;
+ }
+ std::unique_ptr<CFX_DIBitmap> pCloneConvert =
+ pDIBitmap->CloneConvert(FXDIB_Rgb);
+ if (!pCloneConvert)
+ return;
+
+ CXFA_ImageRenderer imageRender;
+ if (!imageRender.Start(m_pDevice, pCloneConvert.get(), m_FillArgb,
+ m_BitmapAlpha, &m_ImageMatrix, m_Flags)) {
+ return;
+ }
+ while (imageRender.Continue(nullptr))
+ continue;
+}
+
+void XFA_DrawImage(CFX_Graphics* pGS,
+ const CFX_RectF& rtImage,
+ CFX_Matrix* pMatrix,
+ CFX_DIBitmap* pDIBitmap,
+ int32_t iAspect,
+ int32_t iImageXDpi,
+ int32_t iImageYDpi,
+ int32_t iHorzAlign,
+ int32_t iVertAlign) {
+ if (rtImage.IsEmpty())
+ return;
+ if (!pDIBitmap || !pDIBitmap->GetBuffer())
+ return;
+
+ CFX_RectF rtFit(
+ rtImage.TopLeft(),
+ XFA_UnitPx2Pt((float)pDIBitmap->GetWidth(), (float)iImageXDpi),
+ XFA_UnitPx2Pt((float)pDIBitmap->GetHeight(), (float)iImageYDpi));
+ switch (iAspect) {
+ case XFA_ATTRIBUTEENUM_Fit: {
+ float f1 = rtImage.height / rtFit.height;
+ float f2 = rtImage.width / rtFit.width;
+ f1 = std::min(f1, f2);
+ rtFit.height = rtFit.height * f1;
+ rtFit.width = rtFit.width * f1;
+ } break;
+ case XFA_ATTRIBUTEENUM_Actual:
+ break;
+ case XFA_ATTRIBUTEENUM_Height: {
+ float f1 = rtImage.height / rtFit.height;
+ rtFit.height = rtImage.height;
+ rtFit.width = f1 * rtFit.width;
+ } break;
+ case XFA_ATTRIBUTEENUM_None:
+ rtFit.height = rtImage.height;
+ rtFit.width = rtImage.width;
+ break;
+ case XFA_ATTRIBUTEENUM_Width: {
+ float f1 = rtImage.width / rtFit.width;
+ rtFit.width = rtImage.width;
+ rtFit.height = rtFit.height * f1;
+ } break;
+ }
+ if (iHorzAlign == XFA_ATTRIBUTEENUM_Center) {
+ rtFit.left += (rtImage.width - rtFit.width) / 2;
+ } else if (iHorzAlign == XFA_ATTRIBUTEENUM_Right) {
+ rtFit.left = rtImage.right() - rtFit.width;
+ }
+ if (iVertAlign == XFA_ATTRIBUTEENUM_Middle) {
+ rtFit.top += (rtImage.height - rtFit.height) / 2;
+ } else if (iVertAlign == XFA_ATTRIBUTEENUM_Bottom) {
+ rtFit.top = rtImage.bottom() - rtImage.height;
+ }
+ CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
+ pRenderDevice->SaveState();
+
+ CFX_PathData path;
+ path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top);
+ pRenderDevice->SetClip_PathFill(&path, pMatrix, FXFILL_WINDING);
+
+ CFX_Matrix mtImage(1, 0, 0, -1, 0, 1);
+ mtImage.Concat(
+ CFX_Matrix(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top));
+ mtImage.Concat(*pMatrix);
+
+ CXFA_ImageRenderer imageRender;
+ bool bRet = imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage,
+ FXDIB_INTERPOL);
+ while (bRet)
+ bRet = imageRender.Continue(nullptr);
+
+ pRenderDevice->RestoreState(false);
+}
+
+static const uint8_t g_inv_base64[128] = {
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
+ 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+ 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255,
+};
+
+static uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) {
+ uint8_t* pCP;
+ int32_t i = 0, j = 0;
+ if (iLen == 0) {
+ iLen = FXSYS_strlen((char*)pStr);
+ }
+ pCP = FX_Alloc(uint8_t, iLen + 1);
+ for (; i < iLen; i++) {
+ if ((pStr[i] & 128) == 0) {
+ if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') {
+ pCP[j++] = pStr[i];
+ }
+ }
+ }
+ pCP[j] = '\0';
+ return pCP;
+}
+static int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) {
+ if (!pStr) {
+ return 0;
+ }
+ uint8_t* pBuffer =
+ XFA_RemoveBase64Whitespace((uint8_t*)pStr, FXSYS_strlen((char*)pStr));
+ if (!pBuffer) {
+ return 0;
+ }
+ int32_t iLen = FXSYS_strlen((char*)pBuffer);
+ int32_t i = 0, j = 0;
+ uint32_t dwLimb = 0;
+ for (; i + 3 < iLen; i += 4) {
+ if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
+ pBuffer[i + 3] == '=') {
+ if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
+ break;
+ }
+ if (pBuffer[i + 2] == '=') {
+ dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 1]]);
+ pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
+ j++;
+ } else {
+ dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 2]]);
+ pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
+ pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
+ j += 2;
+ }
+ } else {
+ dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
+ ((uint32_t)g_inv_base64[pBuffer[i + 3]]);
+ pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
+ pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
+ pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
+ j += 3;
+ }
+ }
+ FX_Free(pBuffer);
+ return j;
+}
+
+static const char g_base64_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char* XFA_Base64Encode(const uint8_t* buf, int32_t buf_len) {
+ char* out = nullptr;
+ int i, j;
+ uint32_t limb;
+ out = FX_Alloc(char, ((buf_len * 8 + 5) / 6) + 5);
+ for (i = 0, j = 0, limb = 0; i + 2 < buf_len; i += 3, j += 4) {
+ limb = ((uint32_t)buf[i] << 16) | ((uint32_t)buf[i + 1] << 8) |
+ ((uint32_t)buf[i + 2]);
+ out[j] = g_base64_chars[(limb >> 18) & 63];
+ out[j + 1] = g_base64_chars[(limb >> 12) & 63];
+ out[j + 2] = g_base64_chars[(limb >> 6) & 63];
+ out[j + 3] = g_base64_chars[(limb)&63];
+ }
+ switch (buf_len - i) {
+ case 0:
+ break;
+ case 1:
+ limb = ((uint32_t)buf[i]);
+ out[j++] = g_base64_chars[(limb >> 2) & 63];
+ out[j++] = g_base64_chars[(limb << 4) & 63];
+ out[j++] = '=';
+ out[j++] = '=';
+ break;
+ case 2:
+ limb = ((uint32_t)buf[i] << 8) | ((uint32_t)buf[i + 1]);
+ out[j++] = g_base64_chars[(limb >> 10) & 63];
+ out[j++] = g_base64_chars[(limb >> 4) & 63];
+ out[j++] = g_base64_chars[(limb << 2) & 63];
+ out[j++] = '=';
+ break;
+ default:
+ break;
+ }
+ out[j] = '\0';
+ return out;
+}
+FXCODEC_IMAGE_TYPE XFA_GetImageType(const CFX_WideString& wsType) {
+ CFX_WideString wsContentType(wsType);
+ wsContentType.MakeLower();
+ if (wsContentType == L"image/jpg")
+ return FXCODEC_IMAGE_JPG;
+ if (wsContentType == L"image/png")
+ return FXCODEC_IMAGE_PNG;
+ if (wsContentType == L"image/gif")
+ return FXCODEC_IMAGE_GIF;
+ if (wsContentType == L"image/bmp")
+ return FXCODEC_IMAGE_BMP;
+ if (wsContentType == L"image/tif")
+ return FXCODEC_IMAGE_TIF;
+ return FXCODEC_IMAGE_UNKNOWN;
+}
+CFX_DIBitmap* XFA_LoadImageData(CXFA_FFDoc* pDoc,
+ CXFA_Image* pImage,
+ bool& bNameImage,
+ int32_t& iImageXDpi,
+ int32_t& iImageYDpi) {
+ CFX_WideString wsHref;
+ pImage->GetHref(wsHref);
+ CFX_WideString wsImage;
+ pImage->GetContent(wsImage);
+ if (wsHref.IsEmpty() && wsImage.IsEmpty()) {
+ return nullptr;
+ }
+ CFX_WideString wsContentType;
+ pImage->GetContentType(wsContentType);
+ FXCODEC_IMAGE_TYPE type = XFA_GetImageType(wsContentType);
+ CFX_ByteString bsContent;
+ uint8_t* pImageBuffer = nullptr;
+ CFX_RetainPtr<IFX_SeekableReadStream> pImageFileRead;
+ if (wsImage.GetLength() > 0) {
+ XFA_ATTRIBUTEENUM iEncoding =
+ (XFA_ATTRIBUTEENUM)pImage->GetTransferEncoding();
+ if (iEncoding == XFA_ATTRIBUTEENUM_Base64) {
+ CFX_ByteString bsData = wsImage.UTF8Encode();
+ int32_t iLength = bsData.GetLength();
+ pImageBuffer = FX_Alloc(uint8_t, iLength);
+ int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer);
+ if (iRead > 0) {
+ pImageFileRead = IFX_MemoryStream::Create(pImageBuffer, iRead);
+ }
+ } else {
+ bsContent = CFX_ByteString::FromUnicode(wsImage);
+ pImageFileRead = IFX_MemoryStream::Create(
+ const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength());
+ }
+ } else {
+ CFX_WideString wsURL = wsHref;
+ if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") {
+ CFX_DIBitmap* pBitmap =
+ pDoc->GetPDFNamedImage(wsURL.AsStringC(), iImageXDpi, iImageYDpi);
+ if (pBitmap) {
+ bNameImage = true;
+ return pBitmap;
+ }
+ }
+ pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
+ }
+ if (!pImageFileRead) {
+ FX_Free(pImageBuffer);
+ return nullptr;
+ }
+ bNameImage = false;
+ CFX_DIBitmap* pBitmap =
+ XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
+ FX_Free(pImageBuffer);
+ return pBitmap;
+}
+static FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type,
+ int32_t iComponents,
+ int32_t iBitsPerComponent) {
+ FXDIB_Format dibFormat = FXDIB_Argb;
+ switch (type) {
+ case FXCODEC_IMAGE_BMP:
+ case FXCODEC_IMAGE_JPG:
+ case FXCODEC_IMAGE_TIF: {
+ dibFormat = FXDIB_Rgb32;
+ int32_t bpp = iComponents * iBitsPerComponent;
+ if (bpp <= 24) {
+ dibFormat = FXDIB_Rgb;
+ }
+ } break;
+ case FXCODEC_IMAGE_PNG:
+ default:
+ break;
+ }
+ return dibFormat;
+}
+
+CFX_DIBitmap* XFA_LoadImageFromBuffer(
+ const CFX_RetainPtr<IFX_SeekableReadStream>& pImageFileRead,
+ FXCODEC_IMAGE_TYPE type,
+ int32_t& iImageXDpi,
+ int32_t& iImageYDpi) {
+ CFX_GEModule* pGeModule = CFX_GEModule::Get();
+ if (!pGeModule)
+ return nullptr;
+
+ CCodec_ModuleMgr* pCodecMgr = pGeModule->GetCodecModule();
+ if (!pCodecMgr)
+ return nullptr;
+
+ CFX_DIBAttribute dibAttr;
+ CFX_DIBitmap* pBitmap = nullptr;
+ std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder =
+ pCodecMgr->CreateProgressiveDecoder();
+ pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false);
+ switch (dibAttr.m_wDPIUnit) {
+ case FXCODEC_RESUNIT_CENTIMETER:
+ dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI * 2.54f);
+ dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI * 2.54f);
+ break;
+ case FXCODEC_RESUNIT_METER:
+ dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI / (float)100 * 2.54f);
+ dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI / (float)100 * 2.54f);
+ break;
+ default:
+ break;
+ }
+ iImageXDpi = dibAttr.m_nXDPI > 1 ? dibAttr.m_nXDPI : (96);
+ iImageYDpi = dibAttr.m_nYDPI > 1 ? dibAttr.m_nYDPI : (96);
+ if (pProgressiveDecoder->GetWidth() > 0 &&
+ pProgressiveDecoder->GetHeight() > 0) {
+ type = pProgressiveDecoder->GetType();
+ int32_t iComponents = pProgressiveDecoder->GetNumComponents();
+ int32_t iBpc = pProgressiveDecoder->GetBPC();
+ FXDIB_Format dibFormat = XFA_GetDIBFormat(type, iComponents, iBpc);
+ pBitmap = new CFX_DIBitmap();
+ pBitmap->Create(pProgressiveDecoder->GetWidth(),
+ pProgressiveDecoder->GetHeight(), dibFormat);
+ pBitmap->Clear(0xffffffff);
+ int32_t nFrames;
+ if ((pProgressiveDecoder->GetFrames(nFrames) ==
+ FXCODEC_STATUS_DECODE_READY) &&
+ (nFrames > 0)) {
+ pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(),
+ pBitmap->GetHeight());
+ pProgressiveDecoder->ContinueDecode();
+ }
+ }
+ return pBitmap;
+}
+
+void XFA_RectWidthoutMargin(CFX_RectF& rt, const CXFA_Margin& mg, bool bUI) {
+ if (!mg) {
+ return;
+ }
+ float fLeftInset, fTopInset, fRightInset, fBottomInset;
+ mg.GetLeftInset(fLeftInset);
+ mg.GetTopInset(fTopInset);
+ mg.GetRightInset(fRightInset);
+ mg.GetBottomInset(fBottomInset);
+ rt.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
+}
+CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) {
+ if (XFA_IsCreateWidget(pLayoutItem->GetFormNode()->GetElementType()))
+ return static_cast<CXFA_FFWidget*>(pLayoutItem);
+ return nullptr;
+}
+bool XFA_IsCreateWidget(XFA_Element eType) {
+ return eType == XFA_Element::Field || eType == XFA_Element::Draw ||
+ eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup;
+}
+static void XFA_BOX_GetPath_Arc(CXFA_Box box,
+ CFX_RectF rtDraw,
+ CFX_Path& fillPath,
+ uint32_t dwFlags) {
+ float a, b;
+ a = rtDraw.width / 2.0f;
+ b = rtDraw.height / 2.0f;
+ if (box.IsCircular() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
+ a = b = std::min(a, b);
+ }
+ CFX_PointF center = rtDraw.Center();
+ rtDraw.left = center.x - a;
+ rtDraw.top = center.y - b;
+ rtDraw.width = a + a;
+ rtDraw.height = b + b;
+ float startAngle = 0, sweepAngle = 360;
+ bool bStart = box.GetStartAngle(startAngle);
+ bool bEnd = box.GetSweepAngle(sweepAngle);
+ if (!bStart && !bEnd) {
+ fillPath.AddEllipse(rtDraw);
+ return;
+ }
+ startAngle = -startAngle * FX_PI / 180.0f;
+ sweepAngle = -sweepAngle * FX_PI / 180.0f;
+ fillPath.AddArc(rtDraw.TopLeft(), rtDraw.Size(), startAngle, sweepAngle);
+}
+
+static void XFA_BOX_GetPath(CXFA_Box box,
+ const std::vector<CXFA_Stroke>& strokes,
+ CFX_RectF rtWidget,
+ CFX_Path& path,
+ int32_t nIndex,
+ bool bStart,
+ bool bCorner) {
+ ASSERT(nIndex >= 0 && nIndex < 8);
+ int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex;
+ CXFA_Corner corner1(strokes[n].GetNode());
+ CXFA_Corner corner2(strokes[(n + 2) % 8].GetNode());
+ float fRadius1 = bCorner ? corner1.GetRadius() : 0.0f;
+ float fRadius2 = bCorner ? corner2.GetRadius() : 0.0f;
+ bool bInverted = corner1.IsInverted();
+ float offsetY = 0.0f;
+ float offsetX = 0.0f;
+ bool bRound = corner1.GetJoinType() == XFA_ATTRIBUTEENUM_Round;
+ float halfAfter = 0.0f;
+ float halfBefore = 0.0f;
+ CXFA_Stroke stroke = strokes[nIndex];
+ if (stroke.IsCorner()) {
+ CXFA_Stroke edgeBefore = strokes[(nIndex + 1 * 8 - 1) % 8];
+ CXFA_Stroke edgeAfter = strokes[nIndex + 1];
+ if (stroke.IsInverted()) {
+ if (!stroke.SameStyles(edgeBefore)) {
+ halfBefore = edgeBefore.GetThickness() / 2;
+ }
+ if (!stroke.SameStyles(edgeAfter)) {
+ halfAfter = edgeAfter.GetThickness() / 2;
+ }
+ }
+ } else {
+ CXFA_Stroke edgeBefore = strokes[(nIndex + 8 - 2) % 8];
+ CXFA_Stroke edgeAfter = strokes[(nIndex + 2) % 8];
+ if (!bRound && !bInverted) {
+ halfBefore = edgeBefore.GetThickness() / 2;
+ halfAfter = edgeAfter.GetThickness() / 2;
+ }
+ }
+ float offsetEX = 0.0f;
+ float offsetEY = 0.0f;
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float vx = 1.0f;
+ float vy = 1.0f;
+ float nx = 1.0f;
+ float ny = 1.0f;
+ CFX_PointF cpStart;
+ CFX_PointF cp1;
+ CFX_PointF cp2;
+ if (bRound) {
+ sy = FX_PI / 2;
+ }
+ switch (nIndex) {
+ case 0:
+ case 1:
+ cp1 = rtWidget.TopLeft();
+ cp2 = rtWidget.TopRight();
+ if (nIndex == 0) {
+ cpStart.x = cp1.x - halfBefore;
+ cpStart.y = cp1.y + fRadius1, offsetY = -halfAfter;
+ } else {
+ cpStart.x = cp1.x + fRadius1 - halfBefore, cpStart.y = cp1.y,
+ offsetEX = halfAfter;
+ }
+ vx = 1, vy = 1;
+ nx = -1, ny = 0;
+ if (bRound) {
+ sx = bInverted ? FX_PI / 2 : FX_PI;
+ } else {
+ sx = 1, sy = 0;
+ }
+ break;
+ case 2:
+ case 3:
+ cp1 = rtWidget.TopRight();
+ cp2 = rtWidget.BottomRight();
+ if (nIndex == 2) {
+ cpStart.x = cp1.x - fRadius1, cpStart.y = cp1.y - halfBefore,
+ offsetX = halfAfter;
+ } else {
+ cpStart.x = cp1.x, cpStart.y = cp1.y + fRadius1 - halfBefore,
+ offsetEY = halfAfter;
+ }
+ vx = -1, vy = 1;
+ nx = 0, ny = -1;
+ if (bRound) {
+ sx = bInverted ? FX_PI : FX_PI * 3 / 2;
+ } else {
+ sx = 0, sy = 1;
+ }
+ break;
+ case 4:
+ case 5:
+ cp1 = rtWidget.BottomRight();
+ cp2 = rtWidget.BottomLeft();
+ if (nIndex == 4) {
+ cpStart.x = cp1.x + halfBefore, cpStart.y = cp1.y - fRadius1,
+ offsetY = halfAfter;
+ } else {
+ cpStart.x = cp1.x - fRadius1 + halfBefore, cpStart.y = cp1.y,
+ offsetEX = -halfAfter;
+ }
+ vx = -1, vy = -1;
+ nx = 1, ny = 0;
+ if (bRound) {
+ sx = bInverted ? FX_PI * 3 / 2 : 0;
+ } else {
+ sx = -1, sy = 0;
+ }
+ break;
+ case 6:
+ case 7:
+ cp1 = rtWidget.BottomLeft();
+ cp2 = rtWidget.TopLeft();
+ if (nIndex == 6) {
+ cpStart.x = cp1.x + fRadius1, cpStart.y = cp1.y + halfBefore,
+ offsetX = -halfAfter;
+ } else {
+ cpStart.x = cp1.x, cpStart.y = cp1.y - fRadius1 + halfBefore,
+ offsetEY = -halfAfter;
+ }
+ vx = 1;
+ vy = -1;
+ nx = 0;
+ ny = 1;
+ if (bRound) {
+ sx = bInverted ? 0 : FX_PI / 2;
+ } else {
+ sx = 0;
+ sy = -1;
+ }
+ break;
+ }
+ if (bStart) {
+ path.MoveTo(cpStart);
+ }
+ if (nIndex & 1) {
+ path.LineTo(CFX_PointF(cp2.x + fRadius2 * nx + offsetEX,
+ cp2.y + fRadius2 * ny + offsetEY));
+ return;
+ }
+ if (bRound) {
+ if (fRadius1 < 0)
+ sx -= FX_PI;
+ if (bInverted)
+ sy *= -1;
+
+ CFX_RectF rtRadius(cp1.x + offsetX * 2, cp1.y + offsetY * 2,
+ fRadius1 * 2 * vx - offsetX * 2,
+ fRadius1 * 2 * vy - offsetY * 2);
+ rtRadius.Normalize();
+ if (bInverted)
+ rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
+
+ path.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
+ } else {
+ CFX_PointF cp;
+ if (bInverted) {
+ cp.x = cp1.x + fRadius1 * vx;
+ cp.y = cp1.y + fRadius1 * vy;
+ } else {
+ cp = cp1;
+ }
+ path.LineTo(cp);
+ path.LineTo(CFX_PointF(cp1.x + fRadius1 * sx + offsetX,
+ cp1.y + fRadius1 * sy + offsetY));
+ }
+}
+static void XFA_BOX_GetFillPath(CXFA_Box box,
+ const std::vector<CXFA_Stroke>& strokes,
+ CFX_RectF rtWidget,
+ CFX_Path& fillPath,
+ uint16_t dwFlags) {
+ if (box.IsArc() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
+ CXFA_Edge edge = box.GetEdge(0);
+ float fThickness = edge.GetThickness();
+ if (fThickness < 0) {
+ fThickness = 0;
+ }
+ float fHalf = fThickness / 2;
+ int32_t iHand = box.GetHand();
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.Inflate(fHalf, fHalf);
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.Deflate(fHalf, fHalf);
+ }
+ XFA_BOX_GetPath_Arc(box, rtWidget, fillPath, dwFlags);
+ return;
+ }
+ bool bSameStyles = true;
+ CXFA_Stroke stroke1 = strokes[0];
+ for (int32_t i = 1; i < 8; i++) {
+ CXFA_Stroke stroke2 = strokes[i];
+ if (!stroke1.SameStyles(stroke2)) {
+ bSameStyles = false;
+ break;
+ }
+ stroke1 = stroke2;
+ }
+ if (bSameStyles) {
+ stroke1 = strokes[0];
+ for (int32_t i = 2; i < 8; i += 2) {
+ CXFA_Stroke stroke2 = strokes[i];
+ if (!stroke1.SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
+ XFA_STROKE_SAMESTYLE_Corner)) {
+ bSameStyles = false;
+ break;
+ }
+ stroke1 = stroke2;
+ }
+ if (bSameStyles) {
+ stroke1 = strokes[0];
+ if (stroke1.IsInverted()) {
+ bSameStyles = false;
+ }
+ if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square) {
+ bSameStyles = false;
+ }
+ }
+ }
+ if (bSameStyles) {
+ fillPath.AddRectangle(rtWidget.left, rtWidget.top, rtWidget.width,
+ rtWidget.height);
+ return;
+ }
+
+ for (int32_t i = 0; i < 8; i += 2) {
+ float sx = 0.0f;
+ float sy = 0.0f;
+ float vx = 1.0f;
+ float vy = 1.0f;
+ float nx = 1.0f;
+ float ny = 1.0f;
+ CFX_PointF cp1, cp2;
+ CXFA_Corner corner1(strokes[i].GetNode());
+ CXFA_Corner corner2(strokes[(i + 2) % 8].GetNode());
+ float fRadius1 = corner1.GetRadius();
+ float fRadius2 = corner2.GetRadius();
+ bool bInverted = corner1.IsInverted();
+ bool bRound = corner1.GetJoinType() == XFA_ATTRIBUTEENUM_Round;
+ if (bRound) {
+ sy = FX_PI / 2;
+ }
+ switch (i) {
+ case 0:
+ cp1 = rtWidget.TopLeft();
+ cp2 = rtWidget.TopRight();
+ vx = 1, vy = 1;
+ nx = -1, ny = 0;
+ if (bRound) {
+ sx = bInverted ? FX_PI / 2 : FX_PI;
+ } else {
+ sx = 1, sy = 0;
+ }
+ break;
+ case 2:
+ cp1 = rtWidget.TopRight();
+ cp2 = rtWidget.BottomRight();
+ vx = -1, vy = 1;
+ nx = 0, ny = -1;
+ if (bRound) {
+ sx = bInverted ? FX_PI : FX_PI * 3 / 2;
+ } else {
+ sx = 0, sy = 1;
+ }
+ break;
+ case 4:
+ cp1 = rtWidget.BottomRight();
+ cp2 = rtWidget.BottomLeft();
+ vx = -1, vy = -1;
+ nx = 1, ny = 0;
+ if (bRound) {
+ sx = bInverted ? FX_PI * 3 / 2 : 0;
+ } else {
+ sx = -1, sy = 0;
+ }
+ break;
+ case 6:
+ cp1 = rtWidget.BottomLeft();
+ cp2 = rtWidget.TopLeft();
+ vx = 1, vy = -1;
+ nx = 0, ny = 1;
+ if (bRound) {
+ sx = bInverted ? 0 : FX_PI / 2;
+ } else {
+ sx = 0;
+ sy = -1;
+ }
+ break;
+ }
+ if (i == 0)
+ fillPath.MoveTo(CFX_PointF(cp1.x, cp1.y + fRadius1));
+
+ if (bRound) {
+ if (fRadius1 < 0)
+ sx -= FX_PI;
+ if (bInverted)
+ sy *= -1;
+
+ CFX_RectF rtRadius(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy);
+ rtRadius.Normalize();
+ if (bInverted)
+ rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy);
+
+ fillPath.ArcTo(rtRadius.TopLeft(), rtRadius.Size(), sx, sy);
+ } else {
+ CFX_PointF cp;
+ if (bInverted) {
+ cp.x = cp1.x + fRadius1 * vx;
+ cp.y = cp1.y + fRadius1 * vy;
+ } else {
+ cp = cp1;
+ }
+ fillPath.LineTo(cp);
+ fillPath.LineTo(CFX_PointF(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy));
+ }
+ fillPath.LineTo(CFX_PointF(cp2.x + fRadius2 * nx, cp2.y + fRadius2 * ny));
+ }
+}
+static void XFA_BOX_Fill_Radial(CXFA_Box box,
+ CFX_Graphics* pGS,
+ CFX_Path& fillPath,
+ CFX_RectF rtFill,
+ CFX_Matrix* pMatrix) {
+ CXFA_Fill fill = box.GetFill();
+ FX_ARGB crStart, crEnd;
+ crStart = fill.GetColor();
+ int32_t iType = fill.GetRadial(crEnd);
+ if (iType != XFA_ATTRIBUTEENUM_ToEdge) {
+ FX_ARGB temp = crEnd;
+ crEnd = crStart;
+ crStart = temp;
+ }
+ CFX_Shading shading(rtFill.Center(), rtFill.Center(), 0,
+ FXSYS_sqrt(rtFill.Width() * rtFill.Width() +
+ rtFill.Height() * rtFill.Height()) /
+ 2,
+ true, true, crStart, crEnd);
+ CFX_Color cr(&shading);
+ pGS->SetFillColor(&cr);
+ pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
+}
+static void XFA_BOX_Fill_Pattern(CXFA_Box box,
+ CFX_Graphics* pGS,
+ CFX_Path& fillPath,
+ CFX_RectF rtFill,
+ CFX_Matrix* pMatrix) {
+ CXFA_Fill fill = box.GetFill();
+ FX_ARGB crStart, crEnd;
+ crStart = fill.GetColor();
+ int32_t iType = fill.GetPattern(crEnd);
+ FX_HatchStyle iHatch = FX_HatchStyle::Cross;
+ switch (iType) {
+ case XFA_ATTRIBUTEENUM_CrossDiagonal:
+ iHatch = FX_HatchStyle::DiagonalCross;
+ break;
+ case XFA_ATTRIBUTEENUM_DiagonalLeft:
+ iHatch = FX_HatchStyle::ForwardDiagonal;
+ break;
+ case XFA_ATTRIBUTEENUM_DiagonalRight:
+ iHatch = FX_HatchStyle::BackwardDiagonal;
+ break;
+ case XFA_ATTRIBUTEENUM_Horizontal:
+ iHatch = FX_HatchStyle::Horizontal;
+ break;
+ case XFA_ATTRIBUTEENUM_Vertical:
+ iHatch = FX_HatchStyle::Vertical;
+ break;
+ default:
+ break;
+ }
+
+ CFX_Pattern pattern(iHatch, crEnd, crStart);
+ CFX_Color cr(&pattern, 0x0);
+ pGS->SetFillColor(&cr);
+ pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
+}
+static void XFA_BOX_Fill_Linear(CXFA_Box box,
+ CFX_Graphics* pGS,
+ CFX_Path& fillPath,
+ CFX_RectF rtFill,
+ CFX_Matrix* pMatrix) {
+ CXFA_Fill fill = box.GetFill();
+ FX_ARGB crStart = fill.GetColor();
+ FX_ARGB crEnd;
+ int32_t iType = fill.GetLinear(crEnd);
+ CFX_PointF ptStart;
+ CFX_PointF ptEnd;
+ switch (iType) {
+ case XFA_ATTRIBUTEENUM_ToRight:
+ ptStart = CFX_PointF(rtFill.left, rtFill.top);
+ ptEnd = CFX_PointF(rtFill.right(), rtFill.top);
+ break;
+ case XFA_ATTRIBUTEENUM_ToBottom:
+ ptStart = CFX_PointF(rtFill.left, rtFill.top);
+ ptEnd = CFX_PointF(rtFill.left, rtFill.bottom());
+ break;
+ case XFA_ATTRIBUTEENUM_ToLeft:
+ ptStart = CFX_PointF(rtFill.right(), rtFill.top);
+ ptEnd = CFX_PointF(rtFill.left, rtFill.top);
+ break;
+ case XFA_ATTRIBUTEENUM_ToTop:
+ ptStart = CFX_PointF(rtFill.left, rtFill.bottom());
+ ptEnd = CFX_PointF(rtFill.left, rtFill.top);
+ break;
+ default:
+ break;
+ }
+ CFX_Shading shading(ptStart, ptEnd, false, false, crStart, crEnd);
+ CFX_Color cr(&shading);
+ pGS->SetFillColor(&cr);
+ pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
+}
+static void XFA_BOX_Fill(CXFA_Box box,
+ const std::vector<CXFA_Stroke>& strokes,
+ CFX_Graphics* pGS,
+ const CFX_RectF& rtWidget,
+ CFX_Matrix* pMatrix,
+ uint32_t dwFlags) {
+ CXFA_Fill fill = box.GetFill();
+ if (!fill || fill.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
+ return;
+
+ pGS->SaveGraphState();
+ CFX_Path fillPath;
+ XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath,
+ (dwFlags & XFA_DRAWBOX_ForceRound) != 0);
+ fillPath.Close();
+ XFA_Element eType = fill.GetFillType();
+ switch (eType) {
+ case XFA_Element::Radial:
+ XFA_BOX_Fill_Radial(box, pGS, fillPath, rtWidget, pMatrix);
+ break;
+ case XFA_Element::Pattern:
+ XFA_BOX_Fill_Pattern(box, pGS, fillPath, rtWidget, pMatrix);
+ break;
+ case XFA_Element::Linear:
+ XFA_BOX_Fill_Linear(box, pGS, fillPath, rtWidget, pMatrix);
+ break;
+ default: {
+ FX_ARGB cr;
+ if (eType == XFA_Element::Stipple) {
+ int32_t iRate = fill.GetStipple(cr);
+ if (iRate == 0) {
+ iRate = 100;
+ }
+ int32_t a = 0;
+ FX_COLORREF rgb;
+ ArgbDecode(cr, a, rgb);
+ cr = ArgbEncode(iRate * a / 100, rgb);
+ } else {
+ cr = fill.GetColor();
+ }
+ CFX_Color fillColor(cr);
+ pGS->SetFillColor(&fillColor);
+ pGS->FillPath(&fillPath, FXFILL_WINDING, pMatrix);
+ } break;
+ }
+ pGS->RestoreGraphState();
+}
+static void XFA_BOX_StrokePath(CXFA_Stroke stroke,
+ CFX_Path* pPath,
+ CFX_Graphics* pGS,
+ CFX_Matrix* pMatrix) {
+ if (!stroke || !stroke.IsVisible()) {
+ return;
+ }
+ float fThickness = stroke.GetThickness();
+ if (fThickness < 0.001f) {
+ return;
+ }
+ pGS->SaveGraphState();
+ if (stroke.IsCorner() && fThickness > 2 * stroke.GetRadius()) {
+ fThickness = 2 * stroke.GetRadius();
+ }
+ pGS->SetLineWidth(fThickness, true);
+ pGS->SetLineCap(CFX_GraphStateData::LineCapButt);
+ XFA_StrokeTypeSetLineDash(pGS, stroke.GetStrokeType(),
+ XFA_ATTRIBUTEENUM_Butt);
+ CFX_Color fxColor(stroke.GetColor());
+ pGS->SetStrokeColor(&fxColor);
+ pGS->StrokePath(pPath, pMatrix);
+ pGS->RestoreGraphState();
+}
+static void XFA_BOX_StrokeArc(CXFA_Box box,
+ CFX_Graphics* pGS,
+ CFX_RectF rtWidget,
+ CFX_Matrix* pMatrix,
+ uint32_t dwFlags) {
+ CXFA_Edge edge = box.GetEdge(0);
+ if (!edge || !edge.IsVisible()) {
+ return;
+ }
+ bool bVisible = false;
+ float fThickness = 0;
+ int32_t i3DType = box.Get3DStyle(bVisible, fThickness);
+ if (i3DType) {
+ if (bVisible && fThickness >= 0.001f) {
+ dwFlags |= XFA_DRAWBOX_Lowered3D;
+ }
+ }
+ float fHalf = edge.GetThickness() / 2;
+ if (fHalf < 0) {
+ fHalf = 0;
+ }
+ int32_t iHand = box.GetHand();
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.Inflate(fHalf, fHalf);
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.Deflate(fHalf, fHalf);
+ }
+ if ((dwFlags & XFA_DRAWBOX_ForceRound) == 0 ||
+ (dwFlags & XFA_DRAWBOX_Lowered3D) == 0) {
+ if (fHalf < 0.001f)
+ return;
+
+ CFX_Path arcPath;
+ XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, dwFlags);
+ XFA_BOX_StrokePath(edge, &arcPath, pGS, pMatrix);
+ return;
+ }
+ pGS->SaveGraphState();
+ pGS->SetLineWidth(fHalf);
+
+ float a, b;
+ a = rtWidget.width / 2.0f;
+ b = rtWidget.height / 2.0f;
+ if (dwFlags & XFA_DRAWBOX_ForceRound) {
+ a = std::min(a, b);
+ b = a;
+ }
+
+ CFX_PointF center = rtWidget.Center();
+ rtWidget.left = center.x - a;
+ rtWidget.top = center.y - b;
+ rtWidget.width = a + a;
+ rtWidget.height = b + b;
+
+ float startAngle = 0, sweepAngle = 360;
+ startAngle = startAngle * FX_PI / 180.0f;
+ sweepAngle = -sweepAngle * FX_PI / 180.0f;
+
+ CFX_Path arcPath;
+ arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
+ FX_PI);
+
+ CFX_Color cr(0xFF808080);
+ pGS->SetStrokeColor(&cr);
+ pGS->StrokePath(&arcPath, pMatrix);
+ arcPath.Clear();
+ arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
+ FX_PI);
+
+ cr.Set(0xFFFFFFFF);
+ pGS->SetStrokeColor(&cr);
+ pGS->StrokePath(&arcPath, pMatrix);
+ rtWidget.Deflate(fHalf, fHalf);
+ arcPath.Clear();
+ arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), 3.0f * FX_PI / 4.0f,
+ FX_PI);
+
+ cr.Set(0xFF404040);
+ pGS->SetStrokeColor(&cr);
+ pGS->StrokePath(&arcPath, pMatrix);
+ arcPath.Clear();
+ arcPath.AddArc(rtWidget.TopLeft(), rtWidget.Size(), -1.0f * FX_PI / 4.0f,
+ FX_PI);
+
+ cr.Set(0xFFC0C0C0);
+ pGS->SetStrokeColor(&cr);
+ pGS->StrokePath(&arcPath, pMatrix);
+ pGS->RestoreGraphState();
+}
+static void XFA_Draw3DRect(CFX_Graphics* pGraphic,
+ const CFX_RectF& rt,
+ float fLineWidth,
+ CFX_Matrix* pMatrix,
+ FX_ARGB argbTopLeft,
+ FX_ARGB argbBottomRight) {
+ CFX_Color crLT(argbTopLeft);
+ pGraphic->SetFillColor(&crLT);
+ float fBottom = rt.bottom();
+ float fRight = rt.right();
+ CFX_Path pathLT;
+ pathLT.MoveTo(CFX_PointF(rt.left, fBottom));
+ pathLT.LineTo(CFX_PointF(rt.left, rt.top));
+ pathLT.LineTo(CFX_PointF(fRight, rt.top));
+ pathLT.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
+ pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, rt.top + fLineWidth));
+ pathLT.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
+ pathLT.LineTo(CFX_PointF(rt.left, fBottom));
+ pGraphic->FillPath(&pathLT, FXFILL_WINDING, pMatrix);
+
+ CFX_Color crRB(argbBottomRight);
+ pGraphic->SetFillColor(&crRB);
+
+ CFX_Path pathRB;
+ pathRB.MoveTo(CFX_PointF(fRight, rt.top));
+ pathRB.LineTo(CFX_PointF(fRight, fBottom));
+ pathRB.LineTo(CFX_PointF(rt.left, fBottom));
+ pathRB.LineTo(CFX_PointF(rt.left + fLineWidth, fBottom - fLineWidth));
+ pathRB.LineTo(CFX_PointF(fRight - fLineWidth, fBottom - fLineWidth));
+ pathRB.LineTo(CFX_PointF(fRight - fLineWidth, rt.top + fLineWidth));
+ pathRB.LineTo(CFX_PointF(fRight, rt.top));
+ pGraphic->FillPath(&pathRB, FXFILL_WINDING, pMatrix);
+}
+static void XFA_BOX_Stroke_3DRect_Lowered(CFX_Graphics* pGS,
+ CFX_RectF rt,
+ float fThickness,
+ CFX_Matrix* pMatrix) {
+ float fHalfWidth = fThickness / 2.0f;
+ CFX_RectF rtInner(rt);
+ rtInner.Deflate(fHalfWidth, fHalfWidth);
+ CFX_Color cr(0xFF000000);
+ pGS->SetFillColor(&cr);
+ CFX_Path path;
+ path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
+ path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
+ pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
+ XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFF808080, 0xFFC0C0C0);
+}
+static void XFA_BOX_Stroke_3DRect_Raised(CFX_Graphics* pGS,
+ CFX_RectF rt,
+ float fThickness,
+ CFX_Matrix* pMatrix) {
+ float fHalfWidth = fThickness / 2.0f;
+ CFX_RectF rtInner(rt);
+ rtInner.Deflate(fHalfWidth, fHalfWidth);
+ CFX_Color cr(0xFF000000);
+ pGS->SetFillColor(&cr);
+ CFX_Path path;
+ path.AddRectangle(rt.left, rt.top, rt.width, rt.height);
+ path.AddRectangle(rtInner.left, rtInner.top, rtInner.width, rtInner.height);
+ pGS->FillPath(&path, FXFILL_ALTERNATE, pMatrix);
+ XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFFFFFFFF, 0xFF808080);
+}
+static void XFA_BOX_Stroke_3DRect_Etched(CFX_Graphics* pGS,
+ CFX_RectF rt,
+ float fThickness,
+ CFX_Matrix* pMatrix) {
+ float fHalfWidth = fThickness / 2.0f;
+ XFA_Draw3DRect(pGS, rt, fThickness, pMatrix, 0xFF808080, 0xFFFFFFFF);
+ CFX_RectF rtInner(rt);
+ rtInner.Deflate(fHalfWidth, fHalfWidth);
+ XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFFFFFFFF, 0xFF808080);
+}
+static void XFA_BOX_Stroke_3DRect_Embossed(CFX_Graphics* pGS,
+ CFX_RectF rt,
+ float fThickness,
+ CFX_Matrix* pMatrix) {
+ float fHalfWidth = fThickness / 2.0f;
+ XFA_Draw3DRect(pGS, rt, fThickness, pMatrix, 0xFF808080, 0xFF000000);
+ CFX_RectF rtInner(rt);
+ rtInner.Deflate(fHalfWidth, fHalfWidth);
+ XFA_Draw3DRect(pGS, rtInner, fHalfWidth, pMatrix, 0xFF000000, 0xFF808080);
+}
+static void XFA_BOX_Stroke_Rect(CXFA_Box box,
+ const std::vector<CXFA_Stroke>& strokes,
+ CFX_Graphics* pGS,
+ CFX_RectF rtWidget,
+ CFX_Matrix* pMatrix) {
+ bool bVisible = false;
+ float fThickness = 0;
+ int32_t i3DType = box.Get3DStyle(bVisible, fThickness);
+ if (i3DType) {
+ if (!bVisible || fThickness < 0.001f) {
+ return;
+ }
+ switch (i3DType) {
+ case XFA_ATTRIBUTEENUM_Lowered:
+ XFA_BOX_Stroke_3DRect_Lowered(pGS, rtWidget, fThickness, pMatrix);
+ break;
+ case XFA_ATTRIBUTEENUM_Raised:
+ XFA_BOX_Stroke_3DRect_Raised(pGS, rtWidget, fThickness, pMatrix);
+ break;
+ case XFA_ATTRIBUTEENUM_Etched:
+ XFA_BOX_Stroke_3DRect_Etched(pGS, rtWidget, fThickness, pMatrix);
+ break;
+ case XFA_ATTRIBUTEENUM_Embossed:
+ XFA_BOX_Stroke_3DRect_Embossed(pGS, rtWidget, fThickness, pMatrix);
+ break;
+ }
+ return;
+ }
+ bool bClose = false;
+ bool bSameStyles = true;
+ CXFA_Stroke stroke1 = strokes[0];
+ for (int32_t i = 1; i < 8; i++) {
+ CXFA_Stroke stroke2 = strokes[i];
+ if (!stroke1.SameStyles(stroke2)) {
+ bSameStyles = false;
+ break;
+ }
+ stroke1 = stroke2;
+ }
+ if (bSameStyles) {
+ stroke1 = strokes[0];
+ bClose = true;
+ for (int32_t i = 2; i < 8; i += 2) {
+ CXFA_Stroke stroke2 = strokes[i];
+ if (!stroke1.SameStyles(stroke2, XFA_STROKE_SAMESTYLE_NoPresence |
+ XFA_STROKE_SAMESTYLE_Corner)) {
+ bSameStyles = false;
+ break;
+ }
+ stroke1 = stroke2;
+ }
+ if (bSameStyles) {
+ stroke1 = strokes[0];
+ if (stroke1.IsInverted())
+ bSameStyles = false;
+ if (stroke1.GetJoinType() != XFA_ATTRIBUTEENUM_Square)
+ bSameStyles = false;
+ }
+ }
+ bool bStart = true;
+ CFX_Path path;
+ for (int32_t i = 0; i < 8; i++) {
+ CXFA_Stroke stroke = strokes[i];
+ if ((i % 1) == 0 && stroke.GetRadius() < 0) {
+ bool bEmpty = path.IsEmpty();
+ if (!bEmpty) {
+ XFA_BOX_StrokePath(stroke, &path, pGS, pMatrix);
+ path.Clear();
+ }
+ bStart = true;
+ continue;
+ }
+ XFA_BOX_GetPath(box, strokes, rtWidget, path, i, bStart, !bSameStyles);
+ CXFA_Stroke stroke2 = strokes[(i + 1) % 8];
+ bStart = !stroke.SameStyles(stroke2);
+ if (bStart) {
+ XFA_BOX_StrokePath(stroke, &path, pGS, pMatrix);
+ path.Clear();
+ }
+ }
+ bool bEmpty = path.IsEmpty();
+ if (!bEmpty) {
+ if (bClose) {
+ path.Close();
+ }
+ XFA_BOX_StrokePath(strokes[7], &path, pGS, pMatrix);
+ }
+}
+static void XFA_BOX_Stroke(CXFA_Box box,
+ const std::vector<CXFA_Stroke>& strokes,
+ CFX_Graphics* pGS,
+ CFX_RectF rtWidget,
+ CFX_Matrix* pMatrix,
+ uint32_t dwFlags) {
+ if (box.IsArc() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) {
+ XFA_BOX_StrokeArc(box, pGS, rtWidget, pMatrix, dwFlags);
+ return;
+ }
+ bool bVisible = false;
+ for (int32_t j = 0; j < 4; j++) {
+ if (strokes[j * 2 + 1].IsVisible()) {
+ bVisible = true;
+ break;
+ }
+ }
+ if (!bVisible) {
+ return;
+ }
+ for (int32_t i = 1; i < 8; i += 2) {
+ CXFA_Edge edge(strokes[i].GetNode());
+ float fThickness = edge.GetThickness();
+ if (fThickness < 0) {
+ fThickness = 0;
+ }
+ float fHalf = fThickness / 2;
+ int32_t iHand = box.GetHand();
+ switch (i) {
+ case 1:
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.top -= fHalf;
+ rtWidget.height += fHalf;
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.top += fHalf;
+ rtWidget.height -= fHalf;
+ }
+ break;
+ case 3:
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.width += fHalf;
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.width -= fHalf;
+ }
+ break;
+ case 5:
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.height += fHalf;
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.height -= fHalf;
+ }
+ break;
+ case 7:
+ if (iHand == XFA_ATTRIBUTEENUM_Left) {
+ rtWidget.left -= fHalf;
+ rtWidget.width += fHalf;
+ } else if (iHand == XFA_ATTRIBUTEENUM_Right) {
+ rtWidget.left += fHalf;
+ rtWidget.width -= fHalf;
+ }
+ break;
+ }
+ }
+ XFA_BOX_Stroke_Rect(box, strokes, pGS, rtWidget, pMatrix);
+}
+void XFA_DrawBox(CXFA_Box box,
+ CFX_Graphics* pGS,
+ const CFX_RectF& rtWidget,
+ CFX_Matrix* pMatrix,
+ uint32_t dwFlags) {
+ if (!box || box.GetPresence() != XFA_ATTRIBUTEENUM_Visible)
+ return;
+
+ XFA_Element eType = box.GetElementType();
+ if (eType != XFA_Element::Arc && eType != XFA_Element::Border &&
+ eType != XFA_Element::Rectangle) {
+ return;
+ }
+ std::vector<CXFA_Stroke> strokes;
+ if (!(dwFlags & XFA_DRAWBOX_ForceRound) && eType != XFA_Element::Arc)
+ box.GetStrokes(&strokes);
+
+ XFA_BOX_Fill(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
+ XFA_BOX_Stroke(box, strokes, pGS, rtWidget, pMatrix, dwFlags);
+}
+
+CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {}
+
+CXFA_CalcData::~CXFA_CalcData() {}