diff options
Diffstat (limited to 'xfa/fxfa/app/xfa_ffwidget.cpp')
-rw-r--r-- | xfa/fxfa/app/xfa_ffwidget.cpp | 1961 |
1 files changed, 1961 insertions, 0 deletions
diff --git a/xfa/fxfa/app/xfa_ffwidget.cpp b/xfa/fxfa/app/xfa_ffwidget.cpp new file mode 100644 index 0000000000..315394629d --- /dev/null +++ b/xfa/fxfa/app/xfa_ffwidget.cpp @@ -0,0 +1,1961 @@ +// 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/app/xfa_ffwidget.h" + +#include <algorithm> + +#include "core/include/fpdfapi/fpdf_page.h" +#include "core/include/fxcodec/fx_codec.h" +#include "xfa/fxfa/app/xfa_ffapp.h" +#include "xfa/fxfa/app/xfa_ffdoc.h" +#include "xfa/fxfa/app/xfa_ffdocview.h" +#include "xfa/fxfa/app/xfa_ffpageview.h" +#include "xfa/fxfa/app/xfa_textlayout.h" +#include "xfa/include/fxgraphics/fx_graphics.h" + +CXFA_FFWidget::CXFA_FFWidget(CXFA_FFPageView* pPageView, + CXFA_WidgetAcc* pDataAcc) + : CXFA_ContentLayoutItem(pDataAcc->GetNode()), + m_pPageView(pPageView), + m_pDataAcc(pDataAcc) { + m_rtWidget.Set(0, 0, 0, 0); +} +CXFA_FFWidget::~CXFA_FFWidget() {} +IXFA_PageView* CXFA_FFWidget::GetPageView() { + return m_pPageView; +} +void CXFA_FFWidget::SetPageView(IXFA_PageView* pPageView) { + m_pPageView = static_cast<CXFA_FFPageView*>(pPageView); +} +void CXFA_FFWidget::GetWidgetRect(CFX_RectF& rtWidget) { + if ((m_dwStatus & XFA_WIDGETSTATUS_RectCached) == 0) { + m_dwStatus |= XFA_WIDGETSTATUS_RectCached; + GetRect(m_rtWidget); + } + rtWidget = m_rtWidget; +} +CFX_RectF CXFA_FFWidget::ReCacheWidgetRect() { + m_dwStatus |= XFA_WIDGETSTATUS_RectCached; + GetRect(m_rtWidget); + return m_rtWidget; +} +void CXFA_FFWidget::GetRectWithoutRotate(CFX_RectF& rtWidget) { + GetWidgetRect(rtWidget); + FX_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; + } +} +FX_DWORD CXFA_FFWidget::GetStatus() { + return m_dwStatus; +} + +void CXFA_FFWidget::ModifyStatus(FX_DWORD dwAdded, FX_DWORD dwRemoved) { + m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded; +} + +FX_BOOL CXFA_FFWidget::GetBBox(CFX_RectF& rtBox, + FX_DWORD dwStatus, + FX_BOOL bDrawFocus) { + if (bDrawFocus) + return FALSE; + if (m_pPageView) + m_pPageView->GetPageViewRect(rtBox); + return TRUE; +} + +CXFA_WidgetAcc* CXFA_FFWidget::GetDataAcc() { + return m_pDataAcc; +} +FX_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, + FX_DWORD dwStatus, + int32_t iRotate) { + if (!IsMatchVisibleStatus(dwStatus)) { + return; + } + CXFA_Border border = m_pDataAcc->GetBorder(); + if (border) { + CFX_RectF rtBorder; + GetRectWithoutRotate(rtBorder); + CXFA_Margin margin = border.GetMargin(); + if (margin) { + XFA_RectWidthoutMargin(rtBorder, margin); + } + rtBorder.Normalize(); + DrawBorder(pGS, border, rtBorder, pMatrix); + } +} +FX_BOOL CXFA_FFWidget::IsLoaded() { + return m_pPageView != NULL; +} +FX_BOOL CXFA_FFWidget::LoadWidget() { + PerformLayout(); + return TRUE; +} +void CXFA_FFWidget::UnloadWidget() {} +FX_BOOL CXFA_FFWidget::PerformLayout() { + ReCacheWidgetRect(); + return TRUE; +} +FX_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, + FX_DWORD dwFlags) { + XFA_DrawBox(box, pGS, rtBorder, pMatrix, dwFlags); +} +void CXFA_FFWidget::InvalidateWidget(const CFX_RectF* pRect) { + if (!pRect) { + CFX_RectF rtWidget; + GetBBox(rtWidget, XFA_WIDGETSTATUS_Focused); + rtWidget.Inflate(2, 2); + GetDoc()->GetDocProvider()->InvalidateRect(m_pPageView, rtWidget, + XFA_INVALIDATE_CurrentPage); + } else { + GetDoc()->GetDocProvider()->InvalidateRect(m_pPageView, *pRect, + XFA_INVALIDATE_CurrentPage); + } +} +void CXFA_FFWidget::AddInvalidateRect(const CFX_RectF* pRect) { + CFX_RectF rtWidget; + if (pRect) { + rtWidget = *pRect; + } else { + GetBBox(rtWidget, XFA_WIDGETSTATUS_Focused); + rtWidget.Inflate(2, 2); + } + m_pDocView->AddInvalidateRect(m_pPageView, rtWidget); +} +FX_BOOL CXFA_FFWidget::GetCaptionText(CFX_WideString& wsCap) { + CXFA_TextLayout* pCapTextlayout = m_pDataAcc->GetCaptionTextLayout(); + if (!pCapTextlayout) { + return FALSE; + } + pCapTextlayout->GetText(wsCap); + return TRUE; +} +FX_BOOL CXFA_FFWidget::IsFocused() { + return m_dwStatus & XFA_WIDGETSTATUS_Focused; +} +FX_BOOL CXFA_FFWidget::OnMouseEnter() { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnMouseExit() { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnLButtonDown(FX_DWORD dwFlags, + FX_FLOAT fx, + FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnLButtonUp(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnLButtonDblClk(FX_DWORD dwFlags, + FX_FLOAT fx, + FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnMouseMove(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnMouseWheel(FX_DWORD dwFlags, + int16_t zDelta, + FX_FLOAT fx, + FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnRButtonDown(FX_DWORD dwFlags, + FX_FLOAT fx, + FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnRButtonUp(FX_DWORD dwFlags, FX_FLOAT fx, FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnRButtonDblClk(FX_DWORD dwFlags, + FX_FLOAT fx, + FX_FLOAT fy) { + return FALSE; +} + +FX_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; +} +FX_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; +} +FX_BOOL CXFA_FFWidget::OnKeyDown(FX_DWORD dwKeyCode, FX_DWORD dwFlags) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnKeyUp(FX_DWORD dwKeyCode, FX_DWORD dwFlags) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnChar(FX_DWORD dwChar, FX_DWORD dwFlags) { + return FALSE; +} +FX_DWORD CXFA_FFWidget::OnHitTest(FX_FLOAT fx, FX_FLOAT fy) { + return FALSE; +} +FX_BOOL CXFA_FFWidget::OnSetCursor(FX_FLOAT fx, FX_FLOAT fy) { + return FALSE; +} +void CXFA_FFWidget::Rotate2Normal(FX_FLOAT& fx, FX_FLOAT& fy) { + CFX_Matrix mt; + GetRotateMatrix(mt); + if (mt.IsIdentity()) { + return; + } + CFX_Matrix mtReverse; + mtReverse.SetReverse(mt); + mtReverse.TransformPoint(fx, fy); +} +static void XFA_GetMatrix(CFX_Matrix& m, + int32_t iRotate, + int32_t at, + const CFX_RectF& rt) { + if (!iRotate) { + return; + } + FX_FLOAT fAnchorX, fAnchorY; + 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; + } + 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; + } +} +void CXFA_FFWidget::GetRotateMatrix(CFX_Matrix& mt) { + mt.Set(1, 0, 0, 1, 0, 0); + int32_t iRotate = m_pDataAcc->GetRotate(); + if (!iRotate) { + return; + } + CFX_RectF rcWidget; + GetRectWithoutRotate(rcWidget); + XFA_ATTRIBUTEENUM at = XFA_ATTRIBUTEENUM_TopLeft; + XFA_GetMatrix(mt, iRotate, at, rcWidget); +} +FX_BOOL CXFA_FFWidget::IsLayoutRectEmpty() { + CFX_RectF rtLayout; + GetRectWithoutRotate(rtLayout); + 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 = + (CXFA_WidgetAcc*)pParentNode->GetWidgetData(); + if (pParentWidgetAcc) { + return pParentWidgetAcc->GetNextWidget(NULL); + } + } + return NULL; +} +FX_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; +} +FX_BOOL CXFA_FFWidget::PtInActiveRect(FX_FLOAT fx, FX_FLOAT fy) { + CFX_RectF rtWidget; + GetWidgetRect(rtWidget); + if (rtWidget.Contains(fx, fy)) { + return TRUE; + } + return FALSE; +} +CXFA_FFDocView* CXFA_FFWidget::GetDocView() { + return m_pDocView; +} +CXFA_FFDoc* CXFA_FFWidget::GetDoc() { + return (CXFA_FFDoc*)m_pDocView->GetDoc(); +} +CXFA_FFApp* CXFA_FFWidget::GetApp() { + return GetDoc()->GetApp(); +} +IXFA_AppProvider* CXFA_FFWidget::GetAppProvider() { + return GetApp()->GetAppProvider(); +} +void CXFA_FFWidget::GetMinMaxWidth(FX_FLOAT fMinWidth, FX_FLOAT fMaxWidth) { + fMinWidth = fMaxWidth = 0; + FX_FLOAT fWidth = 0; + if (m_pDataAcc->GetWidth(fWidth)) { + fMinWidth = fMaxWidth = fWidth; + } else { + m_pDataAcc->GetMinWidth(fMinWidth); + m_pDataAcc->GetMaxWidth(fMaxWidth); + } +} +void CXFA_FFWidget::GetMinMaxHeight(FX_FLOAT fMinHeight, FX_FLOAT fMaxHeight) { + fMinHeight = fMaxHeight = 0; + FX_FLOAT fHeight = 0; + if (m_pDataAcc->GetHeight(fHeight)) { + fMinHeight = fMaxHeight = fHeight; + } else { + m_pDataAcc->GetMinHeight(fMinHeight); + m_pDataAcc->GetMaxHeight(fMaxHeight); + } +} +FX_BOOL CXFA_FFWidget::IsMatchVisibleStatus(FX_DWORD 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); +} +FX_BOOL CXFA_FFWidget::IsButtonDown() { + return (m_dwStatus & XFA_WIDGETSTATUS_ButtonDown) != 0; +} +void CXFA_FFWidget::SetButtonDown(FX_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: { + FX_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: { + FX_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: { + FX_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: { + FX_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(); + FX_BOOL Start(CFX_RenderDevice* pDevice, + CFX_DIBSource* pDIBSource, + FX_ARGB bitmap_argb, + int bitmap_alpha, + const CFX_Matrix* pImage2Device, + FX_DWORD flags, + int blendType = FXDIB_BLEND_NORMAL); + FX_BOOL Continue(IFX_Pause* pPause); + + protected: + CFX_RenderDevice* m_pDevice; + int m_Status; + CFX_Matrix m_ImageMatrix; + CFX_DIBSource* m_pDIBSource; + CFX_DIBitmap* m_pCloneConvert; + int m_BitmapAlpha; + FX_ARGB m_FillArgb; + FX_DWORD m_Flags; + CFX_ImageTransformer* m_pTransformer; + void* m_DeviceHandle; + int32_t m_BlendType; + FX_BOOL m_Result; + FX_BOOL m_bPrint; + FX_BOOL StartDIBSource(); + void CompositeDIBitmap(CFX_DIBitmap* pDIBitmap, + int left, + int top, + FX_ARGB mask_argb, + int bitmap_alpha, + int blend_mode, + int Transparency); +}; +CXFA_ImageRenderer::CXFA_ImageRenderer() { + m_pDevice = NULL; + m_Status = 0; + m_pDIBSource = NULL; + m_pCloneConvert = NULL; + m_BitmapAlpha = 255; + m_FillArgb = 0; + m_Flags = 0; + m_pTransformer = NULL; + m_DeviceHandle = NULL; + m_BlendType = FXDIB_BLEND_NORMAL; + m_Result = TRUE; + m_bPrint = FALSE; +} +CXFA_ImageRenderer::~CXFA_ImageRenderer() { + if (m_pCloneConvert) { + delete m_pCloneConvert; + } + if (m_pTransformer) { + delete m_pTransformer; + } + if (m_DeviceHandle) { + m_pDevice->CancelDIBits(m_DeviceHandle); + } +} +FX_BOOL CXFA_ImageRenderer::Start(CFX_RenderDevice* pDevice, + CFX_DIBSource* pDIBSource, + FX_ARGB bitmap_argb, + int bitmap_alpha, + const CFX_Matrix* pImage2Device, + FX_DWORD 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(); +} +FX_BOOL CXFA_ImageRenderer::StartDIBSource() { + if (m_pDevice->StartDIBits(m_pDIBSource, m_BitmapAlpha, m_FillArgb, + &m_ImageMatrix, m_Flags, m_DeviceHandle, 0, NULL, + 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.GetOutterRect(); + 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; + } + FX_RECT clip_box = m_pDevice->GetClipBox(); + clip_box.Intersect(image_rect); + m_Status = 2; + m_pTransformer = new CFX_ImageTransformer; + m_pTransformer->Start(pDib, &m_ImageMatrix, m_Flags, &clip_box); + 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->StretchDIBits(m_pDIBSource, dest_left, dest_top, dest_width, + dest_height, m_Flags, NULL, m_BlendType)) { + return FALSE; + } + } + if (m_pDIBSource->IsAlphaMask()) { + if (m_BitmapAlpha != 255) { + m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); + } + if (m_pDevice->StretchBitMask(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); + CFX_DIBitmap* pStretched = + m_pDIBSource->StretchTo(dest_width, dest_height, m_Flags, &dest_clip); + if (pStretched) { + CompositeDIBitmap(pStretched, dest_rect.left, dest_rect.top, m_FillArgb, + m_BitmapAlpha, m_BlendType, FALSE); + delete pStretched; + pStretched = NULL; + } + return FALSE; +} +FX_BOOL CXFA_ImageRenderer::Continue(IFX_Pause* pPause) { + if (m_Status == 2) { + if (m_pTransformer->Continue(pPause)) { + return TRUE; + } + CFX_DIBitmap* pBitmap = m_pTransformer->m_Storer.Detach(); + if (pBitmap == NULL) { + return FALSE; + } + if (pBitmap->IsAlphaMask()) { + if (m_BitmapAlpha != 255) { + m_FillArgb = FXARGB_MUL_ALPHA(m_FillArgb, m_BitmapAlpha); + } + m_Result = m_pDevice->SetBitMask(pBitmap, m_pTransformer->m_ResultLeft, + m_pTransformer->m_ResultTop, m_FillArgb); + } else { + if (m_BitmapAlpha != 255) { + pBitmap->MultiplyAlpha(m_BitmapAlpha); + } + m_Result = m_pDevice->SetDIBits(pBitmap, m_pTransformer->m_ResultLeft, + m_pTransformer->m_ResultTop, m_BlendType); + } + delete pBitmap; + return FALSE; + } else 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 == NULL) { + return; + } + FX_BOOL bIsolated = Transparency & PDFTRANS_ISOLATED; + FX_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 { + FX_DWORD 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; + } + } + } + FX_BOOL bBackAlphaRequired = blend_mode && bIsolated; + FX_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->SetDIBits(pDIBitmap, left, top, blend_mode); + } else { + FX_RECT rect(left, top, left + pDIBitmap->GetWidth(), + top + pDIBitmap->GetHeight()); + rect.Intersect(m_pDevice->GetClipBox()); + CFX_DIBitmap* pClone = NULL; + FX_BOOL bClone = FALSE; + if (m_pDevice->GetBackDrop() && m_pDevice->GetBitmap()) { + bClone = TRUE; + 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, rect.left, rect.top); + } else { + if (pDIBitmap->IsAlphaMask()) { + return; + } + m_pDevice->SetDIBits(pDIBitmap, rect.left, rect.top, blend_mode); + } + if (bClone) { + delete pClone; + } + } + return; + } + if (pDIBitmap->HasAlpha() && + !(m_pDevice->GetRenderCaps() & FXRC_ALPHA_IMAGE)) { + CFX_DIBitmap* pCloneConvert = pDIBitmap->CloneConvert(FXDIB_Rgb); + if (!pCloneConvert) { + return; + } + CXFA_ImageRenderer imageRender; + FX_BOOL bRet = imageRender.Start(m_pDevice, pCloneConvert, m_FillArgb, + m_BitmapAlpha, &m_ImageMatrix, m_Flags); + while (bRet) { + bRet = imageRender.Continue(NULL); + } + delete pCloneConvert; + return; + } +} +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; + } + FX_FLOAT fWidth = + XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetWidth(), (FX_FLOAT)iImageXDpi); + FX_FLOAT fHeight = + XFA_UnitPx2Pt((FX_FLOAT)pDIBitmap->GetHeight(), (FX_FLOAT)iImageYDpi); + CFX_RectF rtFit; + rtFit.Set(rtImage.left, rtImage.top, fWidth, fHeight); + switch (iAspect) { + case XFA_ATTRIBUTEENUM_Fit: { + FX_FLOAT f1 = rtImage.height / rtFit.height; + FX_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: { + FX_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: { + FX_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(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top); + mtImage.Concat(*pMatrix); + CXFA_ImageRenderer imageRender; + FX_BOOL bRet = imageRender.Start(pRenderDevice, pDIBitmap, 0, 255, &mtImage, + FXDIB_INTERPOL); + while (bRet) { + bRet = imageRender.Continue(NULL); + } + pRenderDevice->RestoreState(); +} + +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((FX_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 FX_CHAR* pStr, uint8_t* pOutBuffer) { + if (pStr == NULL) { + return 0; + } + uint8_t* pBuffer = + XFA_RemoveBase64Whitespace((uint8_t*)pStr, FXSYS_strlen((FX_CHAR*)pStr)); + if (pBuffer == NULL) { + return 0; + } + int32_t iLen = FXSYS_strlen((FX_CHAR*)pBuffer); + int32_t i = 0, j = 0; + FX_DWORD 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 = ((FX_DWORD)g_inv_base64[pBuffer[i]] << 6) | + ((FX_DWORD)g_inv_base64[pBuffer[i + 1]]); + pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF; + j++; + } else { + dwLimb = ((FX_DWORD)g_inv_base64[pBuffer[i]] << 12) | + ((FX_DWORD)g_inv_base64[pBuffer[i + 1]] << 6) | + ((FX_DWORD)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 = ((FX_DWORD)g_inv_base64[pBuffer[i]] << 18) | + ((FX_DWORD)g_inv_base64[pBuffer[i + 1]] << 12) | + ((FX_DWORD)g_inv_base64[pBuffer[i + 2]] << 6) | + ((FX_DWORD)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 FX_CHAR g_base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +FX_CHAR* XFA_Base64Encode(const uint8_t* buf, int32_t buf_len) { + FX_CHAR* out = NULL; + int i, j; + FX_DWORD limb; + out = FX_Alloc(FX_CHAR, ((buf_len * 8 + 5) / 6) + 5); + for (i = 0, j = 0, limb = 0; i + 2 < buf_len; i += 3, j += 4) { + limb = ((FX_DWORD)buf[i] << 16) | ((FX_DWORD)buf[i + 1] << 8) | + ((FX_DWORD)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 = ((FX_DWORD)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 = ((FX_DWORD)buf[i] << 8) | ((FX_DWORD)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_WideStringC& wsType) { + CFX_WideString wsContentType(wsType); + wsContentType.MakeLower(); + if (wsContentType == FX_WSTRC(L"image/jpg")) { + return FXCODEC_IMAGE_JPG; + } + if (wsContentType == FX_WSTRC(L"image/png")) { + return FXCODEC_IMAGE_PNG; + } + if (wsContentType == FX_WSTRC(L"image/gif")) { + return FXCODEC_IMAGE_GIF; + } + if (wsContentType == FX_WSTRC(L"image/bmp")) { + return FXCODEC_IMAGE_BMP; + } + if (wsContentType == FX_WSTRC(L"image/tif")) { + return FXCODEC_IMAGE_TIF; + } + return FXCODEC_IMAGE_UNKNOWN; +} +CFX_DIBitmap* XFA_LoadImageData(CXFA_FFDoc* pDoc, + CXFA_Image* pImage, + FX_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 NULL; + } + CFX_WideString wsContentType; + pImage->GetContentType(wsContentType); + FXCODEC_IMAGE_TYPE type = XFA_GetImageType(wsContentType); + CFX_ByteString bsContent; + uint8_t* pImageBuffer = NULL; + IFX_FileRead* pImageFileRead = NULL; + 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((const FX_CHAR*)bsData, pImageBuffer); + if (iRead > 0) { + pImageFileRead = FX_CreateMemoryStream(pImageBuffer, iRead); + } + } else { + bsContent = CFX_ByteString::FromUnicode(wsImage); + pImageFileRead = FX_CreateMemoryStream( + (uint8_t*)(const uint8_t*)bsContent, bsContent.GetLength()); + } + } else { + CFX_WideString wsURL = wsHref; + if (wsURL.Left(7) != FX_WSTRC(L"http://") && + wsURL.Left(6) != FX_WSTRC(L"ftp://")) { + CFX_DIBitmap* pBitmap = + pDoc->GetPDFNamedImage(wsURL, iImageXDpi, iImageYDpi); + if (pBitmap) { + bNameImage = TRUE; + return pBitmap; + } + } + pImageFileRead = pDoc->GetDocProvider()->OpenLinkedFile(pDoc, wsURL); + } + if (!pImageFileRead) { + FX_Free(pImageBuffer); + return NULL; + } + bNameImage = FALSE; + CFX_DIBitmap* pBitmap = + XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi); + FX_Free(pImageBuffer); + pImageFileRead->Release(); + 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(IFX_FileRead* pImageFileRead, + FXCODEC_IMAGE_TYPE type, + int32_t& iImageXDpi, + int32_t& iImageYDpi) { + CFX_GEModule* pGeModule = CFX_GEModule::Get(); + if (!pGeModule) { + return NULL; + } + CCodec_ModuleMgr* pCodecMgr = pGeModule->GetCodecModule(); + if (!pCodecMgr) { + return NULL; + } + CFX_DIBAttribute dibAttr; + CFX_DIBitmap* pBitmap = NULL; + ICodec_ProgressiveDecoder* pProgressiveDecoder = + pCodecMgr->CreateProgressiveDecoder(); + pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr); + 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 / (FX_FLOAT)100 * 2.54f); + dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI / (FX_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(); + } + } + delete pProgressiveDecoder; + return pBitmap; +} +void XFA_RectWidthoutMargin(CFX_RectF& rt, const CXFA_Margin& mg, FX_BOOL bUI) { + if (!mg) { + return; + } + FX_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) { + XFA_ELEMENT iType = pLayoutItem->GetFormNode()->GetClassID(); + if (XFA_IsCreateWidget(iType)) { + return static_cast<CXFA_FFWidget*>(pLayoutItem); + } + return nullptr; +} +FX_BOOL XFA_IsCreateWidget(XFA_ELEMENT iType) { + return iType == XFA_ELEMENT_Field || iType == XFA_ELEMENT_Draw || + iType == XFA_ELEMENT_Subform || iType == XFA_ELEMENT_ExclGroup; +} +static void XFA_BOX_GetPath_Arc(CXFA_Box box, + CFX_RectF rtDraw, + CFX_Path& fillPath, + FX_DWORD dwFlags) { + FX_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; + FX_FLOAT startAngle = 0, sweepAngle = 360; + FX_BOOL bStart = box.GetStartAngle(startAngle); + FX_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.left, rtDraw.top, rtDraw.width, rtDraw.height, + startAngle, sweepAngle); +} +static void XFA_BOX_GetPath(CXFA_Box box, + const CXFA_StrokeArray& strokes, + CFX_RectF rtWidget, + CFX_Path& path, + int32_t nIndex, + FX_BOOL bStart, + FX_BOOL bCorner) { + FXSYS_assert(nIndex >= 0 && nIndex < 8); + FX_BOOL bInverted, bRound; + FX_FLOAT fRadius1, fRadius2, sx, sy, vx, vy, nx, ny, offsetY, offsetX, + offsetEX, offsetEY; + CFX_PointF cpStart, cp, cp1, cp2; + CFX_RectF rtRadius; + int32_t n = (nIndex & 1) ? nIndex - 1 : nIndex; + CXFA_Corner corner1(strokes[n].GetNode()); + CXFA_Corner corner2(strokes[(n + 2) % 8].GetNode()); + fRadius1 = bCorner ? corner1.GetRadius() : 0; + fRadius2 = bCorner ? corner2.GetRadius() : 0; + bInverted = corner1.IsInverted(); + offsetY = 0.0f; + offsetX = 0.0f; + bRound = corner1.GetJoinType() == XFA_ATTRIBUTEENUM_Round; + FX_FLOAT halfAfter = 0.0f; + FX_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; } + } + } + offsetEX = 0.0f; + offsetEY = 0.0f; + 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.x, cpStart.y); + } + if (nIndex & 1) { + path.LineTo(cp2.x + fRadius2 * nx + offsetEX, + cp2.y + fRadius2 * ny + offsetEY); + return; + } + if (bRound) { + if (fRadius1 < 0) { + sx -= FX_PI; + } + if (bInverted) { + sy *= -1; + } + rtRadius.Set(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.left, rtRadius.top, rtRadius.width, rtRadius.height, sx, + sy); + } else { + if (bInverted) { + cp.x = cp1.x + fRadius1 * vx, cp.y = cp1.y + fRadius1 * vy; + } else { + cp = cp1; + } + path.LineTo(cp.x, cp.y); + path.LineTo(cp1.x + fRadius1 * sx + offsetX, + cp1.y + fRadius1 * sy + offsetY); + } +} +static void XFA_BOX_GetFillPath(CXFA_Box box, + const CXFA_StrokeArray& strokes, + CFX_RectF rtWidget, + CFX_Path& fillPath, + FX_WORD dwFlags) { + if (box.IsArc() || (dwFlags & XFA_DRAWBOX_ForceRound) != 0) { + CXFA_Edge edge = box.GetEdge(0); + FX_FLOAT fThickness = edge.GetThickness(); + if (fThickness < 0) { + fThickness = 0; + } + FX_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; + } + FX_BOOL bSameStyles = TRUE; + int32_t i; + CXFA_Stroke stroke1 = strokes[0]; + for (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 (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; + } + FX_BOOL bInverted, bRound; + FX_FLOAT fRadius1, fRadius2, sx, sy, vx, vy, nx, ny; + CFX_PointF cp, cp1, cp2; + CFX_RectF rtRadius; + for (int32_t i = 0; i < 8; i += 2) { + CXFA_Corner corner1(strokes[i].GetNode()); + CXFA_Corner corner2(strokes[(i + 2) % 8].GetNode()); + fRadius1 = corner1.GetRadius(); + fRadius2 = corner2.GetRadius(); + bInverted = corner1.IsInverted(); + 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(cp1.x, cp1.y + fRadius1); + } + if (bRound) { + if (fRadius1 < 0) { + sx -= FX_PI; + } + if (bInverted) { + sy *= -1; + } + rtRadius.Set(cp1.x, cp1.y, fRadius1 * 2 * vx, fRadius1 * 2 * vy); + rtRadius.Normalize(); + if (bInverted) { + rtRadius.Offset(-fRadius1 * vx, -fRadius1 * vy); + } + fillPath.ArcTo(rtRadius.left, rtRadius.top, rtRadius.width, + rtRadius.height, sx, sy); + } else { + if (bInverted) { + cp.x = cp1.x + fRadius1 * vx, cp.y = cp1.y + fRadius1 * vy; + } else { + cp = cp1; + } + fillPath.LineTo(cp.x, cp.y); + fillPath.LineTo(cp1.x + fRadius1 * sx, cp1.y + fRadius1 * sy); + } + fillPath.LineTo(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); + CFX_Shading shading; + if (iType != XFA_ATTRIBUTEENUM_ToEdge) { + FX_ARGB temp = crEnd; + crEnd = crStart; + crStart = temp; + } + shading.CreateRadial(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); + int32_t 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; + pattern.Create(iHatch, crEnd, crStart); + CFX_Color cr(&pattern); + 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; + shading.CreateAxial(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 CXFA_StrokeArray& strokes, + CFX_Graphics* pGS, + const CFX_RectF& rtWidget, + CFX_Matrix* pMatrix, + FX_DWORD dwFlags) { + CXFA_Fill fill = box.GetFill(); + if (!fill || fill.GetPresence() != XFA_ATTRIBUTEENUM_Visible) { + return; + } + pGS->SaveGraphState(); + CFX_Path fillPath; + fillPath.Create(); + XFA_BOX_GetFillPath(box, strokes, rtWidget, fillPath, + (dwFlags & XFA_DRAWBOX_ForceRound) != 0); + fillPath.Close(); + int32_t 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; + } + FX_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, + FX_DWORD dwFlags) { + CXFA_Edge edge = box.GetEdge(0); + if (!edge || !edge.IsVisible()) { + return; + } + FX_BOOL bVisible = FALSE; + FX_FLOAT fThickness = 0; + int32_t i3DType = box.Get3DStyle(bVisible, fThickness); + if (i3DType) { + if (bVisible && fThickness >= 0.001f) { + dwFlags |= XFA_DRAWBOX_Lowered3D; + } + } + FX_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; + arcPath.Create(); + XFA_BOX_GetPath_Arc(box, rtWidget, arcPath, dwFlags); + XFA_BOX_StrokePath(edge, &arcPath, pGS, pMatrix); + return; + } + pGS->SaveGraphState(); + pGS->SetLineWidth(fHalf); + FX_FLOAT a, b; + a = rtWidget.width / 2.0f; + b = rtWidget.height / 2.0f; + if (dwFlags & XFA_DRAWBOX_ForceRound) { + a = b = std::min(a, b); + } + CFX_PointF center = rtWidget.Center(); + rtWidget.left = center.x - a; + rtWidget.top = center.y - b; + rtWidget.width = a + a; + rtWidget.height = b + b; + FX_FLOAT startAngle = 0, sweepAngle = 360; + startAngle = startAngle * FX_PI / 180.0f; + sweepAngle = -sweepAngle * FX_PI / 180.0f; + CFX_Path arcPath; + arcPath.Create(); + arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height, + 3.0f * FX_PI / 4.0f, FX_PI); + CFX_Color cr(0xFF808080); + pGS->SetStrokeColor(&cr); + pGS->StrokePath(&arcPath, pMatrix); + arcPath.Clear(); + arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height, + -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.left, rtWidget.top, rtWidget.width, rtWidget.height, + 3.0f * FX_PI / 4.0f, FX_PI); + cr.Set(0xFF404040); + pGS->SetStrokeColor(&cr); + pGS->StrokePath(&arcPath, pMatrix); + arcPath.Clear(); + arcPath.AddArc(rtWidget.left, rtWidget.top, rtWidget.width, rtWidget.height, + -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, + FX_FLOAT fLineWidth, + CFX_Matrix* pMatrix, + FX_ARGB argbTopLeft, + FX_ARGB argbBottomRight) { + CFX_Color crLT(argbTopLeft); + pGraphic->SetFillColor(&crLT); + FX_FLOAT fBottom = rt.bottom(); + FX_FLOAT fRight = rt.right(); + CFX_Path pathLT; + pathLT.Create(); + pathLT.MoveTo(rt.left, fBottom); + pathLT.LineTo(rt.left, rt.top); + pathLT.LineTo(fRight, rt.top); + pathLT.LineTo(fRight - fLineWidth, rt.top + fLineWidth); + pathLT.LineTo(rt.left + fLineWidth, rt.top + fLineWidth); + pathLT.LineTo(rt.left + fLineWidth, fBottom - fLineWidth); + pathLT.LineTo(rt.left, fBottom); + pGraphic->FillPath(&pathLT, FXFILL_WINDING, pMatrix); + CFX_Color crRB(argbBottomRight); + pGraphic->SetFillColor(&crRB); + CFX_Path pathRB; + pathRB.Create(); + pathRB.MoveTo(fRight, rt.top); + pathRB.LineTo(fRight, fBottom); + pathRB.LineTo(rt.left, fBottom); + pathRB.LineTo(rt.left + fLineWidth, fBottom - fLineWidth); + pathRB.LineTo(fRight - fLineWidth, fBottom - fLineWidth); + pathRB.LineTo(fRight - fLineWidth, rt.top + fLineWidth); + pathRB.LineTo(fRight, rt.top); + pGraphic->FillPath(&pathRB, FXFILL_WINDING, pMatrix); +} +static void XFA_BOX_Stroke_3DRect_Lowered(CFX_Graphics* pGS, + CFX_RectF rt, + FX_FLOAT fThickness, + CFX_Matrix* pMatrix) { + FX_FLOAT fHalfWidth = fThickness / 2.0f; + CFX_RectF rtInner(rt); + rtInner.Deflate(fHalfWidth, fHalfWidth); + CFX_Color cr(0xFF000000); + pGS->SetFillColor(&cr); + CFX_Path path; + path.Create(); + 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, + FX_FLOAT fThickness, + CFX_Matrix* pMatrix) { + FX_FLOAT fHalfWidth = fThickness / 2.0f; + CFX_RectF rtInner(rt); + rtInner.Deflate(fHalfWidth, fHalfWidth); + CFX_Color cr(0xFF000000); + pGS->SetFillColor(&cr); + CFX_Path path; + path.Create(); + 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, + FX_FLOAT fThickness, + CFX_Matrix* pMatrix) { + FX_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, + FX_FLOAT fThickness, + CFX_Matrix* pMatrix) { + FX_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 CXFA_StrokeArray& strokes, + CFX_Graphics* pGS, + CFX_RectF rtWidget, + CFX_Matrix* pMatrix) { + FX_BOOL bVisible = FALSE; + FX_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; + } + FX_BOOL bClose = FALSE; + FX_BOOL bSameStyles = TRUE; + int32_t i; + CXFA_Stroke stroke1 = strokes[0]; + for (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 (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; + } + } + } + FX_BOOL bStart = TRUE; + CFX_Path path; + path.Create(); + for (i = 0; i < 8; i++) { + CXFA_Stroke stroke1 = strokes[i]; + if ((i % 1) == 0 && stroke1.GetRadius() < 0) { + FX_BOOL bEmpty = path.IsEmpty(); + if (!bEmpty) { + XFA_BOX_StrokePath(stroke1, &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 = !stroke1.SameStyles(stroke2); + if (bStart) { + XFA_BOX_StrokePath(stroke1, &path, pGS, pMatrix); + path.Clear(); + } + } + FX_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 CXFA_StrokeArray& strokes, + CFX_Graphics* pGS, + CFX_RectF rtWidget, + CFX_Matrix* pMatrix, + FX_DWORD 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()); + FX_FLOAT fThickness = edge.GetThickness(); + if (fThickness < 0) { + fThickness = 0; + } + FX_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, + FX_DWORD dwFlags) { + if (!box || box.GetPresence() != XFA_ATTRIBUTEENUM_Visible) { + return; + } + int32_t iType = box.GetClassID(); + if (iType != XFA_ELEMENT_Arc && iType != XFA_ELEMENT_Border && + iType != XFA_ELEMENT_Rectangle) { + return; + } + CXFA_StrokeArray strokes; + if (!(dwFlags & XFA_DRAWBOX_ForceRound) && iType != XFA_ELEMENT_Arc) { + box.GetStrokes(strokes); + } + XFA_BOX_Fill(box, strokes, pGS, rtWidget, pMatrix, dwFlags); + XFA_BOX_Stroke(box, strokes, pGS, rtWidget, pMatrix, dwFlags); +} |