// 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 <algorithm> | |
#include "xfa/src/foxitlib.h" | |
#include "xfa/src/fxfa/src/common/xfa_common.h" | |
#include "xfa_ffapp.h" | |
#include "xfa_ffdoc.h" | |
#include "xfa_ffdocview.h" | |
#include "xfa_ffwidget.h" | |
#include "xfa_ffpageview.h" | |
#include "xfa_textlayout.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; | |
} | |
#ifndef _XFA_EMB | |
if (m_pPageView) { | |
m_pPageView->GetPageViewRect(rtBox); | |
} | |
return TRUE; | |
#endif | |
GetWidgetRect(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.IsExistInXML()) { | |
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 != NULL && !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 != NULL) { | |
CXFA_FFWidget* pParent = GetParent(); | |
if (pParent != NULL && !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 != NULL) { | |
CXFA_WidgetAcc* pParentWidgetAcc = | |
(CXFA_WidgetAcc*)pParentNode->GetWidgetData(); | |
if (pParentWidgetAcc != NULL) { | |
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 != NULL) { | |
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(); | |
} | |
const static 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 != NULL) { | |
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 = (CXFA_Node*)strokes[n]; | |
CXFA_Corner corner2 = (CXFA_Node*)strokes[(n + 2) % 8]; | |
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 = (CXFA_Node*)strokes[i]; | |
CXFA_Corner corner2 = (CXFA_Node*)strokes[(i + 2) % 8]; | |
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, crEnd; | |
crStart = fill.GetColor(); | |
int32_t iType = fill.GetLinear(crEnd); | |
CFX_PointF ptStart, ptEnd; | |
switch (iType) { | |
case XFA_ATTRIBUTEENUM_ToRight: | |
ptStart.Set(rtFill.left, rtFill.top); | |
ptEnd.Set(rtFill.right(), rtFill.top); | |
break; | |
case XFA_ATTRIBUTEENUM_ToBottom: | |
ptStart.Set(rtFill.left, rtFill.top); | |
ptEnd.Set(rtFill.left, rtFill.bottom()); | |
break; | |
case XFA_ATTRIBUTEENUM_ToLeft: | |
ptStart.Set(rtFill.right(), rtFill.top); | |
ptEnd.Set(rtFill.left, rtFill.top); | |
break; | |
case XFA_ATTRIBUTEENUM_ToTop: | |
ptStart.Set(rtFill.left, rtFill.bottom()); | |
ptEnd.Set(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.IsExistInXML() || 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.IsExistInXML() || !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.IsExistInXML() || !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; | |
} | |
FX_BOOL bVisible = FALSE; | |
for (int32_t j = 0; j < 4; j++) { | |
bVisible |= strokes[j * 2 + 1].IsVisible(); | |
if (bVisible) { | |
break; | |
} | |
} | |
if (!bVisible) { | |
return; | |
} | |
for (int32_t i = 1; i < 8; i += 2) { | |
CXFA_Edge edge = (CXFA_Node*)strokes[i]; | |
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); | |
} |