blob: 97adff30acd0385d3cc207fe74c434df6b863eb0 [file] [log] [blame]
// 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_ffwidgetacc.h"
#include <algorithm>
#include <memory>
#include <vector>
#include "fxjs/cfxjse_value.h"
#include "third_party/base/ptr_util.h"
#include "third_party/base/stl_util.h"
#include "xfa/fde/tto/fde_textout.h"
#include "xfa/fde/xml/fde_xml_imp.h"
#include "xfa/fxfa/app/xfa_ffcheckbutton.h"
#include "xfa/fxfa/app/xfa_ffchoicelist.h"
#include "xfa/fxfa/app/xfa_fffield.h"
#include "xfa/fxfa/app/xfa_fwladapter.h"
#include "xfa/fxfa/cxfa_eventparam.h"
#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
#include "xfa/fxfa/parser/cxfa_scriptcontext.h"
#include "xfa/fxfa/parser/xfa_localevalue.h"
#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
#include "xfa/fxfa/xfa_ffapp.h"
#include "xfa/fxfa/xfa_ffdoc.h"
#include "xfa/fxfa/xfa_ffdocview.h"
#include "xfa/fxfa/xfa_ffpageview.h"
#include "xfa/fxfa/xfa_ffwidget.h"
#include "xfa/fxfa/xfa_fontmgr.h"
static void XFA_FFDeleteCalcData(void* pData) {
if (pData) {
delete ((CXFA_CalcData*)pData);
}
}
static XFA_MAPDATABLOCKCALLBACKINFO gs_XFADeleteCalcData = {
XFA_FFDeleteCalcData, nullptr};
class CXFA_WidgetLayoutData {
public:
CXFA_WidgetLayoutData() : m_fWidgetHeight(-1) {}
virtual ~CXFA_WidgetLayoutData() {}
FX_FLOAT m_fWidgetHeight;
};
class CXFA_TextLayoutData : public CXFA_WidgetLayoutData {
public:
CXFA_TextLayoutData() {}
~CXFA_TextLayoutData() override {}
CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
void LoadText(CXFA_WidgetAcc* pAcc) {
if (m_pTextLayout)
return;
m_pTextProvider =
pdfium::MakeUnique<CXFA_TextProvider>(pAcc, XFA_TEXTPROVIDERTYPE_Text);
m_pTextLayout = pdfium::MakeUnique<CXFA_TextLayout>(m_pTextProvider.get());
}
private:
std::unique_ptr<CXFA_TextLayout> m_pTextLayout;
std::unique_ptr<CXFA_TextProvider> m_pTextProvider;
};
class CXFA_ImageLayoutData : public CXFA_WidgetLayoutData {
public:
CXFA_ImageLayoutData()
: m_pDIBitmap(nullptr),
m_bNamedImage(false),
m_iImageXDpi(0),
m_iImageYDpi(0) {}
~CXFA_ImageLayoutData() override {
if (m_pDIBitmap && !m_bNamedImage)
delete m_pDIBitmap;
}
bool LoadImageData(CXFA_WidgetAcc* pAcc) {
if (m_pDIBitmap)
return true;
CXFA_Value value = pAcc->GetFormValue();
if (!value)
return false;
CXFA_Image imageObj = value.GetImage();
if (!imageObj)
return false;
CXFA_FFDoc* pFFDoc = pAcc->GetDoc();
pAcc->SetImageImage(XFA_LoadImageData(pFFDoc, &imageObj, m_bNamedImage,
m_iImageXDpi, m_iImageYDpi));
return !!m_pDIBitmap;
}
CFX_DIBitmap* m_pDIBitmap;
bool m_bNamedImage;
int32_t m_iImageXDpi;
int32_t m_iImageYDpi;
};
class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
public:
CXFA_FieldLayoutData() {}
~CXFA_FieldLayoutData() override {}
bool LoadCaption(CXFA_WidgetAcc* pAcc) {
if (m_pCapTextLayout)
return true;
CXFA_Caption caption = pAcc->GetCaption();
if (!caption || caption.GetPresence() == XFA_ATTRIBUTEENUM_Hidden)
return false;
m_pCapTextProvider.reset(
new CXFA_TextProvider(pAcc, XFA_TEXTPROVIDERTYPE_Caption));
m_pCapTextLayout =
pdfium::MakeUnique<CXFA_TextLayout>(m_pCapTextProvider.get());
return true;
}
std::unique_ptr<CXFA_TextLayout> m_pCapTextLayout;
std::unique_ptr<CXFA_TextProvider> m_pCapTextProvider;
std::unique_ptr<CFDE_TextOut> m_pTextOut;
std::vector<FX_FLOAT> m_FieldSplitArray;
};
class CXFA_TextEditData : public CXFA_FieldLayoutData {
public:
};
class CXFA_ImageEditData : public CXFA_FieldLayoutData {
public:
CXFA_ImageEditData()
: m_pDIBitmap(nullptr),
m_bNamedImage(false),
m_iImageXDpi(0),
m_iImageYDpi(0) {}
~CXFA_ImageEditData() override {
if (m_pDIBitmap && !m_bNamedImage)
delete m_pDIBitmap;
}
bool LoadImageData(CXFA_WidgetAcc* pAcc) {
if (m_pDIBitmap)
return true;
CXFA_Value value = pAcc->GetFormValue();
if (!value)
return false;
CXFA_Image imageObj = value.GetImage();
CXFA_FFDoc* pFFDoc = pAcc->GetDoc();
pAcc->SetImageEditImage(XFA_LoadImageData(pFFDoc, &imageObj, m_bNamedImage,
m_iImageXDpi, m_iImageYDpi));
return !!m_pDIBitmap;
}
CFX_DIBitmap* m_pDIBitmap;
bool m_bNamedImage;
int32_t m_iImageXDpi;
int32_t m_iImageYDpi;
};
CXFA_WidgetAcc::CXFA_WidgetAcc(CXFA_FFDocView* pDocView, CXFA_Node* pNode)
: CXFA_WidgetData(pNode),
m_pDocView(pDocView),
m_nRecursionDepth(0) {}
CXFA_WidgetAcc::~CXFA_WidgetAcc() {}
bool CXFA_WidgetAcc::GetName(CFX_WideString& wsName, int32_t iNameType) {
if (iNameType == 0) {
m_pNode->TryCData(XFA_ATTRIBUTE_Name, wsName);
return !wsName.IsEmpty();
}
m_pNode->GetSOMExpression(wsName);
if (iNameType == 2 && wsName.GetLength() >= 15) {
CFX_WideStringC wsPre = L"xfa[0].form[0].";
if (wsPre == CFX_WideStringC(wsName.c_str(), wsPre.GetLength())) {
wsName.Delete(0, wsPre.GetLength());
}
}
return true;
}
CXFA_Node* CXFA_WidgetAcc::GetDatasets() {
return m_pNode->GetBindData();
}
bool CXFA_WidgetAcc::ProcessValueChanged() {
m_pDocView->AddValidateWidget(this);
m_pDocView->AddCalculateWidgetAcc(this);
m_pDocView->RunCalculateWidgets();
m_pDocView->RunValidate();
return true;
}
void CXFA_WidgetAcc::ResetData() {
CFX_WideString wsValue;
XFA_Element eUIType = GetUIType();
switch (eUIType) {
case XFA_Element::ImageEdit: {
CXFA_Value imageValue = GetDefaultValue();
CXFA_Image image = imageValue.GetImage();
CFX_WideString wsContentType, wsHref;
if (image) {
image.GetContent(wsValue);
image.GetContentType(wsContentType);
image.GetHref(wsHref);
}
SetImageEdit(wsContentType, wsHref, wsValue);
} break;
case XFA_Element::ExclGroup: {
CXFA_Node* pNextChild = m_pNode->GetNodeItem(
XFA_NODEITEM_FirstChild, XFA_ObjectType::ContainerNode);
while (pNextChild) {
CXFA_Node* pChild = pNextChild;
CXFA_WidgetAcc* pAcc =
static_cast<CXFA_WidgetAcc*>(pChild->GetWidgetData());
if (!pAcc) {
continue;
}
CXFA_Value defValue(nullptr);
if (wsValue.IsEmpty() && (defValue = pAcc->GetDefaultValue())) {
defValue.GetChildValueContent(wsValue);
SetValue(wsValue, XFA_VALUEPICTURE_Raw);
pAcc->SetValue(wsValue, XFA_VALUEPICTURE_Raw);
} else {
CXFA_Node* pItems = pChild->GetChild(0, XFA_Element::Items);
if (!pItems) {
continue;
}
CFX_WideString itemText;
if (pItems->CountChildren(XFA_Element::Unknown) > 1) {
itemText = pItems->GetChild(1, XFA_Element::Unknown)->GetContent();
}
pAcc->SetValue(itemText, XFA_VALUEPICTURE_Raw);
}
pNextChild = pChild->GetNodeItem(XFA_NODEITEM_NextSibling,
XFA_ObjectType::ContainerNode);
}
} break;
case XFA_Element::ChoiceList:
ClearAllSelections();
default:
if (CXFA_Value defValue = GetDefaultValue()) {
defValue.GetChildValueContent(wsValue);
}
SetValue(wsValue, XFA_VALUEPICTURE_Raw);
break;
}
}
void CXFA_WidgetAcc::SetImageEdit(const CFX_WideString& wsContentType,
const CFX_WideString& wsHref,
const CFX_WideString& wsData) {
CXFA_Image image = GetFormValue().GetImage();
if (image) {
image.SetContentType(CFX_WideString(wsContentType));
image.SetHref(wsHref);
}
CFX_WideString wsFormatValue(wsData);
GetFormatDataValue(wsData, wsFormatValue);
m_pNode->SetContent(wsData, wsFormatValue, true);
CXFA_Node* pBind = GetDatasets();
if (!pBind) {
image.SetTransferEncoding(XFA_ATTRIBUTEENUM_Base64);
return;
}
pBind->SetCData(XFA_ATTRIBUTE_ContentType, wsContentType);
CXFA_Node* pHrefNode = pBind->GetNodeItem(XFA_NODEITEM_FirstChild);
if (pHrefNode) {
pHrefNode->SetCData(XFA_ATTRIBUTE_Value, wsHref);
} else {
CFDE_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
ASSERT(pXMLNode && pXMLNode->GetType() == FDE_XMLNODE_Element);
static_cast<CFDE_XMLElement*>(pXMLNode)->SetString(L"href", wsHref);
}
}
CXFA_WidgetAcc* CXFA_WidgetAcc::GetExclGroup() {
CXFA_Node* pExcl = m_pNode->GetNodeItem(XFA_NODEITEM_Parent);
if (!pExcl || pExcl->GetElementType() != XFA_Element::ExclGroup) {
return nullptr;
}
return static_cast<CXFA_WidgetAcc*>(pExcl->GetWidgetData());
}
CXFA_FFDocView* CXFA_WidgetAcc::GetDocView() {
return m_pDocView;
}
CXFA_FFDoc* CXFA_WidgetAcc::GetDoc() {
return m_pDocView->GetDoc();
}
CXFA_FFApp* CXFA_WidgetAcc::GetApp() {
return GetDoc()->GetApp();
}
IXFA_AppProvider* CXFA_WidgetAcc::GetAppProvider() {
return GetApp()->GetAppProvider();
}
int32_t CXFA_WidgetAcc::ProcessEvent(int32_t iActivity,
CXFA_EventParam* pEventParam) {
if (GetElementType() == XFA_Element::Draw) {
return XFA_EVENTERROR_NotExist;
}
int32_t iRet = XFA_EVENTERROR_NotExist;
CXFA_NodeArray eventArray;
int32_t iCounts =
GetEventByActivity(iActivity, eventArray, pEventParam->m_bIsFormReady);
for (int32_t i = 0; i < iCounts; i++) {
CXFA_Event event(eventArray[i]);
int32_t result = ProcessEvent(event, pEventParam);
if (i == 0) {
iRet = result;
} else if (result == XFA_EVENTERROR_Success) {
iRet = result;
}
}
return iRet;
}
int32_t CXFA_WidgetAcc::ProcessEvent(CXFA_Event& event,
CXFA_EventParam* pEventParam) {
if (!event)
return XFA_EVENTERROR_NotExist;
switch (event.GetEventType()) {
case XFA_Element::Execute:
break;
case XFA_Element::Script: {
CXFA_Script script = event.GetScript();
return ExecuteScript(script, pEventParam);
} break;
case XFA_Element::SignData:
break;
case XFA_Element::Submit: {
CXFA_Submit submit = event.GetSubmit();
return GetDoc()->GetDocEnvironment()->SubmitData(GetDoc(), submit);
}
default:
break;
}
return XFA_EVENTERROR_NotExist;
}
int32_t CXFA_WidgetAcc::ProcessCalculate() {
if (GetElementType() == XFA_Element::Draw)
return XFA_EVENTERROR_NotExist;
CXFA_Calculate calc = GetCalculate();
if (!calc)
return XFA_EVENTERROR_NotExist;
if (GetNode()->IsUserInteractive())
return XFA_EVENTERROR_Disabled;
CXFA_EventParam EventParam;
EventParam.m_eType = XFA_EVENT_Calculate;
CXFA_Script script = calc.GetScript();
int32_t iRet = ExecuteScript(script, &EventParam);
if (iRet != XFA_EVENTERROR_Success)
return iRet;
if (GetRawValue() != EventParam.m_wsResult) {
SetValue(EventParam.m_wsResult, XFA_VALUEPICTURE_Raw);
UpdateUIDisplay();
}
return XFA_EVENTERROR_Success;
}
void CXFA_WidgetAcc::ProcessScriptTestValidate(CXFA_Validate validate,
int32_t iRet,
CFXJSE_Value* pRetValue,
bool bVersionFlag) {
if (iRet == XFA_EVENTERROR_Success && pRetValue) {
if (pRetValue->IsBoolean() && !pRetValue->ToBoolean()) {
IXFA_AppProvider* pAppProvider = GetAppProvider();
if (!pAppProvider) {
return;
}
CFX_WideString wsTitle = pAppProvider->GetAppTitle();
CFX_WideString wsScriptMsg;
validate.GetScriptMessageText(wsScriptMsg);
int32_t eScriptTest = validate.GetScriptTest();
if (eScriptTest == XFA_ATTRIBUTEENUM_Warning) {
if (GetNode()->IsUserInteractive())
return;
if (wsScriptMsg.IsEmpty())
wsScriptMsg = GetValidateMessage(false, bVersionFlag);
if (bVersionFlag) {
pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning,
XFA_MB_OK);
return;
}
if (pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Warning,
XFA_MB_YesNo) == XFA_IDYes) {
GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
}
} else {
if (wsScriptMsg.IsEmpty())
wsScriptMsg = GetValidateMessage(true, bVersionFlag);
pAppProvider->MsgBox(wsScriptMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
}
}
}
}
int32_t CXFA_WidgetAcc::ProcessFormatTestValidate(CXFA_Validate validate,
bool bVersionFlag) {
CFX_WideString wsRawValue = GetRawValue();
if (!wsRawValue.IsEmpty()) {
CFX_WideString wsPicture;
validate.GetPicture(wsPicture);
if (wsPicture.IsEmpty()) {
return XFA_EVENTERROR_NotExist;
}
IFX_Locale* pLocale = GetLocal();
if (!pLocale) {
return XFA_EVENTERROR_NotExist;
}
CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
if (!lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale)) {
IXFA_AppProvider* pAppProvider = GetAppProvider();
if (!pAppProvider) {
return XFA_EVENTERROR_NotExist;
}
CFX_WideString wsFormatMsg;
validate.GetFormatMessageText(wsFormatMsg);
CFX_WideString wsTitle = pAppProvider->GetAppTitle();
int32_t eFormatTest = validate.GetFormatTest();
if (eFormatTest == XFA_ATTRIBUTEENUM_Error) {
if (wsFormatMsg.IsEmpty())
wsFormatMsg = GetValidateMessage(true, bVersionFlag);
pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Error, XFA_MB_OK);
return XFA_EVENTERROR_Success;
}
if (GetNode()->IsUserInteractive())
return XFA_EVENTERROR_NotExist;
if (wsFormatMsg.IsEmpty())
wsFormatMsg = GetValidateMessage(false, bVersionFlag);
if (bVersionFlag) {
pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
XFA_MB_OK);
return XFA_EVENTERROR_Success;
}
if (pAppProvider->MsgBox(wsFormatMsg, wsTitle, XFA_MBICON_Warning,
XFA_MB_YesNo) == XFA_IDYes) {
GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
}
return XFA_EVENTERROR_Success;
}
}
return XFA_EVENTERROR_NotExist;
}
int32_t CXFA_WidgetAcc::ProcessNullTestValidate(CXFA_Validate validate,
int32_t iFlags,
bool bVersionFlag) {
CFX_WideString wsValue;
GetValue(wsValue, XFA_VALUEPICTURE_Raw);
if (!wsValue.IsEmpty()) {
return XFA_EVENTERROR_Success;
}
if (m_bIsNull && (m_bPreNull == m_bIsNull)) {
return XFA_EVENTERROR_Success;
}
int32_t eNullTest = validate.GetNullTest();
CFX_WideString wsNullMsg;
validate.GetNullMessageText(wsNullMsg);
if (iFlags & 0x01) {
int32_t iRet = XFA_EVENTERROR_Success;
if (eNullTest != XFA_ATTRIBUTEENUM_Disabled) {
iRet = XFA_EVENTERROR_Error;
}
if (!wsNullMsg.IsEmpty()) {
if (eNullTest != XFA_ATTRIBUTEENUM_Disabled) {
m_pDocView->m_arrNullTestMsg.push_back(wsNullMsg);
return XFA_EVENTERROR_Error;
}
return XFA_EVENTERROR_Success;
}
return iRet;
}
if (wsNullMsg.IsEmpty() && bVersionFlag &&
eNullTest != XFA_ATTRIBUTEENUM_Disabled) {
return XFA_EVENTERROR_Error;
}
IXFA_AppProvider* pAppProvider = GetAppProvider();
if (!pAppProvider) {
return XFA_EVENTERROR_NotExist;
}
CFX_WideString wsCaptionName;
CFX_WideString wsTitle = pAppProvider->GetAppTitle();
switch (eNullTest) {
case XFA_ATTRIBUTEENUM_Error: {
if (wsNullMsg.IsEmpty()) {
wsCaptionName = GetValidateCaptionName(bVersionFlag);
wsNullMsg.Format(L"%s cannot be blank.", wsCaptionName.c_str());
}
pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Status, XFA_MB_OK);
return XFA_EVENTERROR_Error;
}
case XFA_ATTRIBUTEENUM_Warning: {
if (GetNode()->IsUserInteractive())
return true;
if (wsNullMsg.IsEmpty()) {
wsCaptionName = GetValidateCaptionName(bVersionFlag);
wsNullMsg.Format(
L"%s cannot be blank. To ignore validations for %s, click Ignore.",
wsCaptionName.c_str(), wsCaptionName.c_str());
}
if (pAppProvider->MsgBox(wsNullMsg, wsTitle, XFA_MBICON_Warning,
XFA_MB_YesNo) == XFA_IDYes) {
GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
}
return XFA_EVENTERROR_Error;
}
case XFA_ATTRIBUTEENUM_Disabled:
default:
break;
}
return XFA_EVENTERROR_Success;
}
CFX_WideString CXFA_WidgetAcc::GetValidateCaptionName(bool bVersionFlag) {
CFX_WideString wsCaptionName;
if (!bVersionFlag) {
if (CXFA_Caption caption = GetCaption()) {
if (CXFA_Value capValue = caption.GetValue()) {
if (CXFA_Text capText = capValue.GetText())
capText.GetContent(wsCaptionName);
}
}
}
if (wsCaptionName.IsEmpty())
GetName(wsCaptionName);
return wsCaptionName;
}
CFX_WideString CXFA_WidgetAcc::GetValidateMessage(bool bError,
bool bVersionFlag) {
CFX_WideString wsCaptionName = GetValidateCaptionName(bVersionFlag);
CFX_WideString wsMessage;
if (bVersionFlag) {
wsMessage.Format(L"%s validation failed", wsCaptionName.c_str());
return wsMessage;
}
if (bError) {
wsMessage.Format(L"The value you entered for %s is invalid.",
wsCaptionName.c_str());
return wsMessage;
}
wsMessage.Format(
L"The value you entered for %s is invalid. To ignore "
L"validations for %s, click Ignore.",
wsCaptionName.c_str(), wsCaptionName.c_str());
return wsMessage;
}
int32_t CXFA_WidgetAcc::ProcessValidate(int32_t iFlags) {
if (GetElementType() == XFA_Element::Draw) {
return XFA_EVENTERROR_NotExist;
}
CXFA_Validate validate = GetValidate();
if (!validate) {
return XFA_EVENTERROR_NotExist;
}
bool bInitDoc = validate.GetNode()->NeedsInitApp();
bool bStatus = m_pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
int32_t iFormat = 0;
CFXJSE_Value* pRetValue = nullptr;
int32_t iRet = XFA_EVENTERROR_NotExist;
CXFA_Script script = validate.GetScript();
if (script) {
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_Validate;
eParam.m_pTarget = this;
iRet = ExecuteScript(script, &eParam,
((bInitDoc || bStatus) && GetRawValue().IsEmpty())
? nullptr
: &pRetValue);
}
XFA_VERSION version = GetDoc()->GetXFADoc()->GetCurVersionMode();
bool bVersionFlag = false;
if (version < XFA_VERSION_208) {
bVersionFlag = true;
}
if (bInitDoc) {
validate.GetNode()->ClearFlag(XFA_NodeFlag_NeedsInitApp);
} else {
iFormat = ProcessFormatTestValidate(validate, bVersionFlag);
if (!bVersionFlag) {
bVersionFlag = GetDoc()->GetXFADoc()->HasFlag(XFA_DOCFLAG_Scripting);
}
iRet |= ProcessNullTestValidate(validate, iFlags, bVersionFlag);
}
if (iFormat != XFA_EVENTERROR_Success) {
ProcessScriptTestValidate(validate, iRet, pRetValue, bVersionFlag);
}
delete pRetValue;
return iRet | iFormat;
}
int32_t CXFA_WidgetAcc::ExecuteScript(CXFA_Script script,
CXFA_EventParam* pEventParam,
CFXJSE_Value** pRetValue) {
static const uint32_t MAX_RECURSION_DEPTH = 2;
if (m_nRecursionDepth > MAX_RECURSION_DEPTH)
return XFA_EVENTERROR_Success;
ASSERT(pEventParam);
if (!script) {
return XFA_EVENTERROR_NotExist;
}
if (script.GetRunAt() == XFA_ATTRIBUTEENUM_Server) {
return XFA_EVENTERROR_Disabled;
}
CFX_WideString wsExpression;
script.GetExpression(wsExpression);
if (wsExpression.IsEmpty()) {
return XFA_EVENTERROR_NotExist;
}
XFA_SCRIPTTYPE eScriptType = script.GetContentType();
if (eScriptType == XFA_SCRIPTTYPE_Unkown) {
return XFA_EVENTERROR_Success;
}
CXFA_FFDoc* pDoc = GetDoc();
CXFA_ScriptContext* pContext = pDoc->GetXFADoc()->GetScriptContext();
pContext->SetEventParam(*pEventParam);
pContext->SetRunAtType((XFA_ATTRIBUTEENUM)script.GetRunAt());
CXFA_NodeArray refNodes;
if (pEventParam->m_eType == XFA_EVENT_InitCalculate ||
pEventParam->m_eType == XFA_EVENT_Calculate) {
pContext->SetNodesOfRunScript(&refNodes);
}
std::unique_ptr<CFXJSE_Value> pTmpRetValue(
new CFXJSE_Value(pContext->GetRuntime()));
++m_nRecursionDepth;
bool bRet = pContext->RunScript((XFA_SCRIPTLANGTYPE)eScriptType,
wsExpression.AsStringC(), pTmpRetValue.get(),
m_pNode);
--m_nRecursionDepth;
int32_t iRet = XFA_EVENTERROR_Error;
if (bRet) {
iRet = XFA_EVENTERROR_Success;
if (pEventParam->m_eType == XFA_EVENT_Calculate ||
pEventParam->m_eType == XFA_EVENT_InitCalculate) {
if (!pTmpRetValue->IsUndefined()) {
if (!pTmpRetValue->IsNull())
pEventParam->m_wsResult = pTmpRetValue->ToWideString();
iRet = XFA_EVENTERROR_Success;
} else {
iRet = XFA_EVENTERROR_Error;
}
if (pEventParam->m_eType == XFA_EVENT_InitCalculate) {
if ((iRet == XFA_EVENTERROR_Success) &&
(GetRawValue() != pEventParam->m_wsResult)) {
SetValue(pEventParam->m_wsResult, XFA_VALUEPICTURE_Raw);
m_pDocView->AddValidateWidget(this);
}
}
int32_t iRefs = refNodes.GetSize();
for (int32_t r = 0; r < iRefs; r++) {
CXFA_WidgetAcc* pRefAcc =
static_cast<CXFA_WidgetAcc*>(refNodes[r]->GetWidgetData());
if (pRefAcc && pRefAcc == this) {
continue;
}
CXFA_Node* pRefNode = refNodes[r];
CXFA_CalcData* pGlobalData =
(CXFA_CalcData*)pRefNode->GetUserData(XFA_CalcData);
if (!pGlobalData) {
pGlobalData = new CXFA_CalcData;
pRefNode->SetUserData(XFA_CalcData, pGlobalData,
&gs_XFADeleteCalcData);
}
if (!pdfium::ContainsValue(pGlobalData->m_Globals, this))
pGlobalData->m_Globals.push_back(this);
}
}
}
if (pRetValue)
*pRetValue = pTmpRetValue.release();
pContext->SetNodesOfRunScript(nullptr);
return iRet;
}
CXFA_FFWidget* CXFA_WidgetAcc::GetNextWidget(CXFA_FFWidget* pWidget) {
CXFA_LayoutItem* pLayout = nullptr;
if (pWidget) {
pLayout = pWidget->GetNext();
} else {
pLayout = m_pDocView->GetXFALayout()->GetLayoutItem(m_pNode);
}
return static_cast<CXFA_FFWidget*>(pLayout);
}
void CXFA_WidgetAcc::UpdateUIDisplay(CXFA_FFWidget* pExcept) {
CXFA_FFWidget* pWidget = nullptr;
while ((pWidget = GetNextWidget(pWidget)) != nullptr) {
if (pWidget == pExcept || !pWidget->IsLoaded() ||
(GetUIType() != XFA_Element::CheckButton && pWidget->IsFocused())) {
continue;
}
pWidget->UpdateFWLData();
pWidget->AddInvalidateRect();
}
}
void CXFA_WidgetAcc::CalcCaptionSize(CFX_SizeF& szCap) {
CXFA_Caption caption = GetCaption();
if (!caption || caption.GetPresence() != XFA_ATTRIBUTEENUM_Visible) {
return;
}
LoadCaption();
XFA_Element eUIType = GetUIType();
int32_t iCapPlacement = caption.GetPlacementType();
FX_FLOAT fCapReserve = caption.GetReserve();
const bool bVert = iCapPlacement == XFA_ATTRIBUTEENUM_Top ||
iCapPlacement == XFA_ATTRIBUTEENUM_Bottom;
const bool bReserveExit = fCapReserve > 0.01;
CXFA_TextLayout* pCapTextLayout =
static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
->m_pCapTextLayout.get();
if (pCapTextLayout) {
if (!bVert && eUIType != XFA_Element::Button) {
szCap.x = fCapReserve;
}
CFX_SizeF minSize;
pCapTextLayout->CalcSize(minSize, szCap, szCap);
if (bReserveExit) {
bVert ? szCap.y = fCapReserve : szCap.x = fCapReserve;
}
} else {
FX_FLOAT fFontSize = 10.0f;
if (CXFA_Font font = caption.GetFont()) {
fFontSize = font.GetFontSize();
} else if (CXFA_Font widgetfont = GetFont()) {
fFontSize = widgetfont.GetFontSize();
}
if (bVert) {
szCap.y = fCapReserve > 0 ? fCapReserve : fFontSize;
} else {
szCap.x = fCapReserve > 0 ? fCapReserve : 0;
szCap.y = fFontSize;
}
}
if (CXFA_Margin mgCap = caption.GetMargin()) {
FX_FLOAT fLeftInset, fTopInset, fRightInset, fBottomInset;
mgCap.GetLeftInset(fLeftInset);
mgCap.GetTopInset(fTopInset);
mgCap.GetRightInset(fRightInset);
mgCap.GetBottomInset(fBottomInset);
if (bReserveExit) {
bVert ? (szCap.x += fLeftInset + fRightInset)
: (szCap.y += fTopInset + fBottomInset);
} else {
szCap.x += fLeftInset + fRightInset;
szCap.y += fTopInset + fBottomInset;
}
}
}
bool CXFA_WidgetAcc::CalculateFieldAutoSize(CFX_SizeF& size) {
CFX_SizeF szCap;
CalcCaptionSize(szCap);
CFX_RectF rtUIMargin = GetUIMargin();
size.x += rtUIMargin.left + rtUIMargin.width;
size.y += rtUIMargin.top + rtUIMargin.height;
if (szCap.x > 0 && szCap.y > 0) {
int32_t iCapPlacement = GetCaption().GetPlacementType();
switch (iCapPlacement) {
case XFA_ATTRIBUTEENUM_Left:
case XFA_ATTRIBUTEENUM_Right:
case XFA_ATTRIBUTEENUM_Inline: {
size.x += szCap.x;
size.y = std::max(size.y, szCap.y);
} break;
case XFA_ATTRIBUTEENUM_Top:
case XFA_ATTRIBUTEENUM_Bottom: {
size.y += szCap.y;
size.x = std::max(size.x, szCap.x);
}
default:
break;
}
}
return CalculateWidgetAutoSize(size);
}
bool CXFA_WidgetAcc::CalculateWidgetAutoSize(CFX_SizeF& size) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fLeftInset, fTopInset, fRightInset, fBottomInset;
mgWidget.GetLeftInset(fLeftInset);
mgWidget.GetTopInset(fTopInset);
mgWidget.GetRightInset(fRightInset);
mgWidget.GetBottomInset(fBottomInset);
size.x += fLeftInset + fRightInset;
size.y += fTopInset + fBottomInset;
}
CXFA_Para para = GetPara();
if (para) {
size.x += para.GetMarginLeft();
size.x += para.GetTextIndent();
}
FX_FLOAT fVal = 0, fMin = 0, fMax = 0;
if (GetWidth(fVal)) {
size.x = fVal;
} else {
if (GetMinWidth(fMin)) {
size.x = std::max(size.x, fMin);
}
if (GetMaxWidth(fMax) && fMax > 0) {
size.x = std::min(size.x, fMax);
}
}
fVal = 0, fMin = 0, fMax = 0;
if (GetHeight(fVal)) {
size.y = fVal;
} else {
if (GetMinHeight(fMin)) {
size.y = std::max(size.y, fMin);
}
if (GetMaxHeight(fMax) && fMax > 0) {
size.y = std::min(size.y, fMax);
}
}
return true;
}
void CXFA_WidgetAcc::CalculateTextContentSize(CFX_SizeF& size) {
FX_FLOAT fFontSize = GetFontSize();
CFX_WideString wsText;
GetValue(wsText, XFA_VALUEPICTURE_Display);
if (wsText.IsEmpty()) {
size.y += fFontSize;
return;
}
FX_WCHAR wcEnter = '\n';
FX_WCHAR wsLast = wsText.GetAt(wsText.GetLength() - 1);
if (wsLast == wcEnter) {
wsText = wsText + wcEnter;
}
CXFA_FieldLayoutData* layoutData =
static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
if (!layoutData->m_pTextOut) {
layoutData->m_pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
CFDE_TextOut* pTextOut = layoutData->m_pTextOut.get();
pTextOut->SetFont(GetFDEFont());
pTextOut->SetFontSize(fFontSize);
pTextOut->SetLineBreakTolerance(fFontSize * 0.2f);
pTextOut->SetLineSpace(GetLineHeight());
uint32_t dwStyles = FDE_TTOSTYLE_LastLineHeight;
if (GetUIType() == XFA_Element::TextEdit && IsMultiLine()) {
dwStyles |= FDE_TTOSTYLE_LineWrap;
}
pTextOut->SetStyles(dwStyles);
}
layoutData->m_pTextOut->CalcLogicSize(wsText.c_str(), wsText.GetLength(),
size);
}
bool CXFA_WidgetAcc::CalculateTextEditAutoSize(CFX_SizeF& size) {
if (size.x > 0) {
CFX_SizeF szOrz = size;
CFX_SizeF szCap;
CalcCaptionSize(szCap);
bool bCapExit = szCap.x > 0.01 && szCap.y > 0.01;
int32_t iCapPlacement = XFA_ATTRIBUTEENUM_Unknown;
if (bCapExit) {
iCapPlacement = GetCaption().GetPlacementType();
switch (iCapPlacement) {
case XFA_ATTRIBUTEENUM_Left:
case XFA_ATTRIBUTEENUM_Right:
case XFA_ATTRIBUTEENUM_Inline: {
size.x -= szCap.x;
}
default:
break;
}
}
CFX_RectF rtUIMargin = GetUIMargin();
size.x -= rtUIMargin.left + rtUIMargin.width;
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fLeftInset, fRightInset;
mgWidget.GetLeftInset(fLeftInset);
mgWidget.GetRightInset(fRightInset);
size.x -= fLeftInset + fRightInset;
}
CalculateTextContentSize(size);
size.y += rtUIMargin.top + rtUIMargin.height;
if (bCapExit) {
switch (iCapPlacement) {
case XFA_ATTRIBUTEENUM_Left:
case XFA_ATTRIBUTEENUM_Right:
case XFA_ATTRIBUTEENUM_Inline: {
size.y = std::max(size.y, szCap.y);
} break;
case XFA_ATTRIBUTEENUM_Top:
case XFA_ATTRIBUTEENUM_Bottom: {
size.y += szCap.y;
}
default:
break;
}
}
size.x = szOrz.x;
return CalculateWidgetAutoSize(size);
}
CalculateTextContentSize(size);
return CalculateFieldAutoSize(size);
}
bool CXFA_WidgetAcc::CalculateCheckButtonAutoSize(CFX_SizeF& size) {
FX_FLOAT fCheckSize = GetCheckButtonSize();
size.x = size.y = fCheckSize;
return CalculateFieldAutoSize(size);
}
bool CXFA_WidgetAcc::CalculatePushButtonAutoSize(CFX_SizeF& size) {
CalcCaptionSize(size);
return CalculateWidgetAutoSize(size);
}
bool CXFA_WidgetAcc::CalculateImageAutoSize(CFX_SizeF& size) {
if (!GetImageImage()) {
LoadImageImage();
}
size.clear();
if (CFX_DIBitmap* pBitmap = GetImageImage()) {
CFX_RectF rtImage, rtFit;
rtImage.Set(0, 0, 0, 0);
rtFit.Set(0, 0, 0, 0);
int32_t iImageXDpi = 0;
int32_t iImageYDpi = 0;
GetImageDpi(iImageXDpi, iImageYDpi);
rtImage.width =
XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi);
rtImage.height =
XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi);
if (GetWidth(rtFit.width)) {
GetWidthWithoutMargin(rtFit.width);
} else {
rtFit.width = rtImage.width;
}
if (GetHeight(rtFit.height)) {
GetHeightWithoutMargin(rtFit.height);
} else {
rtFit.height = rtImage.height;
}
size.x = rtFit.width;
size.y = rtFit.height;
}
return CalculateWidgetAutoSize(size);
}
bool CXFA_WidgetAcc::CalculateImageEditAutoSize(CFX_SizeF& size) {
if (!GetImageEditImage()) {
LoadImageEditImage();
}
size.clear();
if (CFX_DIBitmap* pBitmap = GetImageEditImage()) {
CFX_RectF rtImage, rtFit;
rtImage.Set(0, 0, 0, 0);
rtFit.Set(0, 0, 0, 0);
int32_t iImageXDpi = 0;
int32_t iImageYDpi = 0;
GetImageEditDpi(iImageXDpi, iImageYDpi);
rtImage.width =
XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetWidth(), (FX_FLOAT)iImageXDpi);
rtImage.height =
XFA_UnitPx2Pt((FX_FLOAT)pBitmap->GetHeight(), (FX_FLOAT)iImageYDpi);
if (GetWidth(rtFit.width)) {
GetWidthWithoutMargin(rtFit.width);
} else {
rtFit.width = rtImage.width;
}
if (GetHeight(rtFit.height)) {
GetHeightWithoutMargin(rtFit.height);
} else {
rtFit.height = rtImage.height;
}
size.x = rtFit.width;
size.y = rtFit.height;
}
return CalculateFieldAutoSize(size);
}
bool CXFA_WidgetAcc::LoadImageImage() {
InitLayoutData();
return static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
->LoadImageData(this);
}
bool CXFA_WidgetAcc::LoadImageEditImage() {
InitLayoutData();
return static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
->LoadImageData(this);
}
void CXFA_WidgetAcc::GetImageDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
CXFA_ImageLayoutData* pData =
static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
iImageXDpi = pData->m_iImageXDpi;
iImageYDpi = pData->m_iImageYDpi;
}
void CXFA_WidgetAcc::GetImageEditDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
CXFA_ImageEditData* pData =
static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
iImageXDpi = pData->m_iImageXDpi;
iImageYDpi = pData->m_iImageYDpi;
}
bool CXFA_WidgetAcc::CalculateTextAutoSize(CFX_SizeF& size) {
LoadText();
CXFA_TextLayout* pTextLayout =
static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
if (pTextLayout) {
size.x = pTextLayout->StartLayout(size.x);
size.y = pTextLayout->GetLayoutHeight();
}
return CalculateWidgetAutoSize(size);
}
void CXFA_WidgetAcc::LoadText() {
InitLayoutData();
static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->LoadText(this);
}
FX_FLOAT CXFA_WidgetAcc::CalculateWidgetAutoWidth(FX_FLOAT fWidthCalc) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fLeftInset, fRightInset;
mgWidget.GetLeftInset(fLeftInset);
mgWidget.GetRightInset(fRightInset);
fWidthCalc += fLeftInset + fRightInset;
}
FX_FLOAT fMin = 0, fMax = 0;
if (GetMinWidth(fMin)) {
fWidthCalc = std::max(fWidthCalc, fMin);
}
if (GetMaxWidth(fMax) && fMax > 0) {
fWidthCalc = std::min(fWidthCalc, fMax);
}
return fWidthCalc;
}
FX_FLOAT CXFA_WidgetAcc::GetWidthWithoutMargin(FX_FLOAT fWidthCalc) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fLeftInset, fRightInset;
mgWidget.GetLeftInset(fLeftInset);
mgWidget.GetRightInset(fRightInset);
fWidthCalc -= fLeftInset + fRightInset;
}
return fWidthCalc;
}
FX_FLOAT CXFA_WidgetAcc::CalculateWidgetAutoHeight(FX_FLOAT fHeightCalc) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fTopInset, fBottomInset;
mgWidget.GetTopInset(fTopInset);
mgWidget.GetBottomInset(fBottomInset);
fHeightCalc += fTopInset + fBottomInset;
}
FX_FLOAT fMin = 0, fMax = 0;
if (GetMinHeight(fMin)) {
fHeightCalc = std::max(fHeightCalc, fMin);
}
if (GetMaxHeight(fMax) && fMax > 0) {
fHeightCalc = std::min(fHeightCalc, fMax);
}
return fHeightCalc;
}
FX_FLOAT CXFA_WidgetAcc::GetHeightWithoutMargin(FX_FLOAT fHeightCalc) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
FX_FLOAT fTopInset, fBottomInset;
mgWidget.GetTopInset(fTopInset);
mgWidget.GetBottomInset(fBottomInset);
fHeightCalc -= fTopInset + fBottomInset;
}
return fHeightCalc;
}
void CXFA_WidgetAcc::StartWidgetLayout(FX_FLOAT& fCalcWidth,
FX_FLOAT& fCalcHeight) {
InitLayoutData();
XFA_Element eUIType = GetUIType();
if (eUIType == XFA_Element::Text) {
m_pLayoutData->m_fWidgetHeight = -1;
GetHeight(m_pLayoutData->m_fWidgetHeight);
StartTextLayout(fCalcWidth, fCalcHeight);
return;
}
if (fCalcWidth > 0 && fCalcHeight > 0) {
return;
}
m_pLayoutData->m_fWidgetHeight = -1;
FX_FLOAT fWidth = 0;
if (fCalcWidth > 0 && fCalcHeight < 0) {
if (!GetHeight(fCalcHeight)) {
CalculateAccWidthAndHeight(eUIType, fCalcWidth, fCalcHeight);
}
m_pLayoutData->m_fWidgetHeight = fCalcHeight;
return;
}
if (fCalcWidth < 0 && fCalcHeight < 0) {
if (!GetWidth(fWidth) || !GetHeight(fCalcHeight)) {
CalculateAccWidthAndHeight(eUIType, fWidth, fCalcHeight);
}
fCalcWidth = fWidth;
}
m_pLayoutData->m_fWidgetHeight = fCalcHeight;
}
void CXFA_WidgetAcc::CalculateAccWidthAndHeight(XFA_Element eUIType,
FX_FLOAT& fWidth,
FX_FLOAT& fCalcHeight) {
CFX_SizeF sz(fWidth, m_pLayoutData->m_fWidgetHeight);
switch (eUIType) {
case XFA_Element::Barcode:
case XFA_Element::ChoiceList:
case XFA_Element::Signature:
CalculateFieldAutoSize(sz);
break;
case XFA_Element::ImageEdit:
CalculateImageEditAutoSize(sz);
break;
case XFA_Element::Button:
CalculatePushButtonAutoSize(sz);
break;
case XFA_Element::CheckButton:
CalculateCheckButtonAutoSize(sz);
break;
case XFA_Element::DateTimeEdit:
case XFA_Element::NumericEdit:
case XFA_Element::PasswordEdit:
case XFA_Element::TextEdit:
CalculateTextEditAutoSize(sz);
break;
case XFA_Element::Image:
CalculateImageAutoSize(sz);
break;
case XFA_Element::Arc:
case XFA_Element::Line:
case XFA_Element::Rectangle:
case XFA_Element::Subform:
case XFA_Element::ExclGroup:
CalculateWidgetAutoSize(sz);
break;
default:
break;
}
fWidth = sz.x;
m_pLayoutData->m_fWidgetHeight = sz.y;
fCalcHeight = sz.y;
}
bool CXFA_WidgetAcc::FindSplitPos(int32_t iBlockIndex, FX_FLOAT& fCalcHeight) {
XFA_Element eUIType = GetUIType();
if (eUIType == XFA_Element::Subform) {
return false;
}
if (eUIType != XFA_Element::Text && eUIType != XFA_Element::TextEdit &&
eUIType != XFA_Element::NumericEdit &&
eUIType != XFA_Element::PasswordEdit) {
fCalcHeight = 0;
return true;
}
FX_FLOAT fTopInset = 0;
FX_FLOAT fBottomInset = 0;
if (iBlockIndex == 0) {
CXFA_Margin mgWidget = GetMargin();
if (mgWidget) {
mgWidget.GetTopInset(fTopInset);
mgWidget.GetBottomInset(fBottomInset);
}
CFX_RectF rtUIMargin = GetUIMargin();
fTopInset += rtUIMargin.top;
fBottomInset += rtUIMargin.width;
}
if (eUIType == XFA_Element::Text) {
FX_FLOAT fHeight = fCalcHeight;
if (iBlockIndex == 0) {
fCalcHeight = fCalcHeight - fTopInset;
if (fCalcHeight < 0) {
fCalcHeight = 0;
}
}
CXFA_TextLayout* pTextLayout =
static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
pTextLayout->DoLayout(iBlockIndex, fCalcHeight, fCalcHeight,
m_pLayoutData->m_fWidgetHeight - fTopInset);
if (fCalcHeight != 0) {
if (iBlockIndex == 0) {
fCalcHeight = fCalcHeight + fTopInset;
}
if (fabs(fHeight - fCalcHeight) < XFA_FLOAT_PERCISION) {
return false;
}
}
return true;
}
XFA_ATTRIBUTEENUM iCapPlacement = XFA_ATTRIBUTEENUM_Unknown;
FX_FLOAT fCapReserve = 0;
if (iBlockIndex == 0) {
CXFA_Caption caption = GetCaption();
if (caption && caption.GetPresence() != XFA_ATTRIBUTEENUM_Hidden) {
iCapPlacement = (XFA_ATTRIBUTEENUM)caption.GetPlacementType();
fCapReserve = caption.GetReserve();
}
if (iCapPlacement == XFA_ATTRIBUTEENUM_Top &&
fCalcHeight < fCapReserve + fTopInset) {
fCalcHeight = 0;
return true;
}
if (iCapPlacement == XFA_ATTRIBUTEENUM_Bottom &&
m_pLayoutData->m_fWidgetHeight - fCapReserve - fBottomInset) {
fCalcHeight = 0;
return true;
}
if (iCapPlacement != XFA_ATTRIBUTEENUM_Top) {
fCapReserve = 0;
}
}
CXFA_FieldLayoutData* pFieldData =
static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
int32_t iLinesCount = 0;
FX_FLOAT fHeight = m_pLayoutData->m_fWidgetHeight;
CFX_WideString wsText;
GetValue(wsText, XFA_VALUEPICTURE_Display);
if (wsText.IsEmpty()) {
iLinesCount = 1;
} else {
if (!pFieldData->m_pTextOut) {
FX_FLOAT fWidth = 0;
GetWidth(fWidth);
CalculateAccWidthAndHeight(eUIType, fWidth, fHeight);
}
iLinesCount = pFieldData->m_pTextOut->GetTotalLines();
}
std::vector<FX_FLOAT>* pFieldArray = &pFieldData->m_FieldSplitArray;
int32_t iFieldSplitCount = pdfium::CollectionSize<int32_t>(*pFieldArray);
for (int32_t i = 0; i < iBlockIndex * 3; i += 3) {
iLinesCount -= (int32_t)(*pFieldArray)[i + 1];
fHeight -= (*pFieldArray)[i + 2];
}
if (iLinesCount == 0) {
return false;
}
FX_FLOAT fLineHeight = GetLineHeight();
FX_FLOAT fFontSize = GetFontSize();
FX_FLOAT fTextHeight = iLinesCount * fLineHeight - fLineHeight + fFontSize;
FX_FLOAT fSpaceAbove = 0;
FX_FLOAT fStartOffset = 0;
if (fHeight > 0.1f && iBlockIndex == 0) {
fStartOffset = fTopInset;
fHeight -= (fTopInset + fBottomInset);
if (CXFA_Para para = GetPara()) {
fSpaceAbove = para.GetSpaceAbove();
FX_FLOAT fSpaceBelow = para.GetSpaceBelow();
fHeight -= (fSpaceAbove + fSpaceBelow);
switch (para.GetVerticalAlign()) {
case XFA_ATTRIBUTEENUM_Top:
fStartOffset += fSpaceAbove;
break;
case XFA_ATTRIBUTEENUM_Middle:
fStartOffset += ((fHeight - fTextHeight) / 2 + fSpaceAbove);
break;
case XFA_ATTRIBUTEENUM_Bottom:
fStartOffset += (fHeight - fTextHeight + fSpaceAbove);
break;
}
}
if (fStartOffset < 0.1f)
fStartOffset = 0;
}
for (int32_t i = iBlockIndex - 1; iBlockIndex > 0 && i < iBlockIndex; i++) {
fStartOffset = (*pFieldArray)[i * 3] - (*pFieldArray)[i * 3 + 2];
if (fStartOffset < 0.1f)
fStartOffset = 0;
}
if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
(*pFieldArray)[0] = fStartOffset;
} else {
pFieldArray->push_back(fStartOffset);
}
XFA_VERSION version = GetDoc()->GetXFADoc()->GetCurVersionMode();
bool bCanSplitNoContent = false;
XFA_ATTRIBUTEENUM eLayoutMode;
GetNode()
->GetNodeItem(XFA_NODEITEM_Parent)
->TryEnum(XFA_ATTRIBUTE_Layout, eLayoutMode, true);
if ((eLayoutMode == XFA_ATTRIBUTEENUM_Position ||
eLayoutMode == XFA_ATTRIBUTEENUM_Tb ||
eLayoutMode == XFA_ATTRIBUTEENUM_Row ||
eLayoutMode == XFA_ATTRIBUTEENUM_Table) &&
version > XFA_VERSION_208) {
bCanSplitNoContent = true;
}
if ((eLayoutMode == XFA_ATTRIBUTEENUM_Tb ||
eLayoutMode == XFA_ATTRIBUTEENUM_Row ||
eLayoutMode == XFA_ATTRIBUTEENUM_Table) &&
version <= XFA_VERSION_208) {
if (fStartOffset < fCalcHeight) {
bCanSplitNoContent = true;
} else {
fCalcHeight = 0;
return true;
}
}
if (bCanSplitNoContent) {
if ((fCalcHeight - fTopInset - fSpaceAbove < fLineHeight)) {
fCalcHeight = 0;
return true;
}
if (fStartOffset + XFA_FLOAT_PERCISION >= fCalcHeight) {
if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
(*pFieldArray)[iBlockIndex * 3 + 1] = 0;
(*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
} else {
pFieldArray->push_back(0);
pFieldArray->push_back(fCalcHeight);
}
return false;
}
if (fCalcHeight - fStartOffset < fLineHeight) {
fCalcHeight = fStartOffset;
if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
(*pFieldArray)[iBlockIndex * 3 + 1] = 0;
(*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
} else {
pFieldArray->push_back(0);
pFieldArray->push_back(fCalcHeight);
}
return true;
}
FX_FLOAT fTextNum =
fCalcHeight + XFA_FLOAT_PERCISION - fCapReserve - fStartOffset;
int32_t iLineNum =
(int32_t)((fTextNum + (fLineHeight - fFontSize)) / fLineHeight);
if (iLineNum >= iLinesCount) {
if (fCalcHeight - fStartOffset - fTextHeight >= fFontSize) {
if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
(*pFieldArray)[iBlockIndex * 3 + 1] = (FX_FLOAT)iLinesCount;
(*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
} else {
pFieldArray->push_back((FX_FLOAT)iLinesCount);
pFieldArray->push_back(fCalcHeight);
}
return false;
}
if (fHeight - fStartOffset - fTextHeight < fFontSize) {
iLineNum -= 1;
if (iLineNum == 0) {
fCalcHeight = 0;
return true;
}
} else {
iLineNum = (int32_t)(fTextNum / fLineHeight);
}
}
if (iLineNum > 0) {
FX_FLOAT fSplitHeight =
iLineNum * fLineHeight + fCapReserve + fStartOffset;
if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
(*pFieldArray)[iBlockIndex * 3 + 1] = (FX_FLOAT)iLineNum;
(*pFieldArray)[iBlockIndex * 3 + 2] = fSplitHeight;
} else {
pFieldArray->push_back((FX_FLOAT)iLineNum);
pFieldArray->push_back(fSplitHeight);
}
if (fabs(fSplitHeight - fCalcHeight) < XFA_FLOAT_PERCISION) {
return false;
}
fCalcHeight = fSplitHeight;
return true;
}
}
fCalcHeight = 0;
return true;
}
void CXFA_WidgetAcc::InitLayoutData() {
if (m_pLayoutData) {
return;
}
switch (GetUIType()) {
case XFA_Element::Text:
m_pLayoutData = pdfium::MakeUnique<CXFA_TextLayoutData>();
return;
case XFA_Element::TextEdit:
m_pLayoutData = pdfium::MakeUnique<CXFA_TextEditData>();
return;
case XFA_Element::Image:
m_pLayoutData = pdfium::MakeUnique<CXFA_ImageLayoutData>();
return;
case XFA_Element::ImageEdit:
m_pLayoutData = pdfium::MakeUnique<CXFA_ImageEditData>();
return;
default:
break;
}
if (GetElementType() == XFA_Element::Field) {
m_pLayoutData = pdfium::MakeUnique<CXFA_FieldLayoutData>();
return;
}
m_pLayoutData = pdfium::MakeUnique<CXFA_WidgetLayoutData>();
}
void CXFA_WidgetAcc::StartTextLayout(FX_FLOAT& fCalcWidth,
FX_FLOAT& fCalcHeight) {
LoadText();
CXFA_TextLayout* pTextLayout =
static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
FX_FLOAT fTextHeight = 0;
if (fCalcWidth > 0 && fCalcHeight > 0) {
FX_FLOAT fWidth = GetWidthWithoutMargin(fCalcWidth);
pTextLayout->StartLayout(fWidth);
fTextHeight = fCalcHeight;
fTextHeight = GetHeightWithoutMargin(fTextHeight);
pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
return;
}
if (fCalcWidth > 0 && fCalcHeight < 0) {
FX_FLOAT fWidth = GetWidthWithoutMargin(fCalcWidth);
pTextLayout->StartLayout(fWidth);
}
if (fCalcWidth < 0 && fCalcHeight < 0) {
FX_FLOAT fMaxWidth = -1;
bool bRet = GetWidth(fMaxWidth);
if (bRet) {
FX_FLOAT fWidth = GetWidthWithoutMargin(fMaxWidth);
pTextLayout->StartLayout(fWidth);
} else {
FX_FLOAT fWidth = pTextLayout->StartLayout(fMaxWidth);
fMaxWidth = CalculateWidgetAutoWidth(fWidth);
fWidth = GetWidthWithoutMargin(fMaxWidth);
pTextLayout->StartLayout(fWidth);
}
fCalcWidth = fMaxWidth;
}
if (m_pLayoutData->m_fWidgetHeight < 0) {
m_pLayoutData->m_fWidgetHeight = pTextLayout->GetLayoutHeight();
m_pLayoutData->m_fWidgetHeight =
CalculateWidgetAutoHeight(m_pLayoutData->m_fWidgetHeight);
}
fTextHeight = m_pLayoutData->m_fWidgetHeight;
fTextHeight = GetHeightWithoutMargin(fTextHeight);
pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
fCalcHeight = m_pLayoutData->m_fWidgetHeight;
}
bool CXFA_WidgetAcc::LoadCaption() {
InitLayoutData();
return static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
->LoadCaption(this);
}
CXFA_TextLayout* CXFA_WidgetAcc::GetCaptionTextLayout() {
return m_pLayoutData
? static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
->m_pCapTextLayout.get()
: nullptr;
}
CXFA_TextLayout* CXFA_WidgetAcc::GetTextLayout() {
return m_pLayoutData
? static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())
->GetTextLayout()
: nullptr;
}
CFX_DIBitmap* CXFA_WidgetAcc::GetImageImage() {
return m_pLayoutData
? static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
->m_pDIBitmap
: nullptr;
}
CFX_DIBitmap* CXFA_WidgetAcc::GetImageEditImage() {
return m_pLayoutData
? static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
->m_pDIBitmap
: nullptr;
}
void CXFA_WidgetAcc::SetImageImage(CFX_DIBitmap* newImage) {
CXFA_ImageLayoutData* pData =
static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
if (pData->m_pDIBitmap == newImage)
return;
if (pData->m_pDIBitmap && !pData->m_bNamedImage)
delete pData->m_pDIBitmap;
pData->m_pDIBitmap = newImage;
}
void CXFA_WidgetAcc::SetImageEditImage(CFX_DIBitmap* newImage) {
CXFA_ImageEditData* pData =
static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
if (pData->m_pDIBitmap == newImage)
return;
if (pData->m_pDIBitmap && !pData->m_bNamedImage)
delete pData->m_pDIBitmap;
pData->m_pDIBitmap = newImage;
}
CXFA_WidgetLayoutData* CXFA_WidgetAcc::GetWidgetLayoutData() {
return m_pLayoutData.get();
}
CFX_RetainPtr<CFGAS_GEFont> CXFA_WidgetAcc::GetFDEFont() {
CFX_WideStringC wsFontName = L"Courier";
uint32_t dwFontStyle = 0;
if (CXFA_Font font = GetFont()) {
if (font.IsBold())
dwFontStyle |= FX_FONTSTYLE_Bold;
if (font.IsItalic())
dwFontStyle |= FX_FONTSTYLE_Italic;
font.GetTypeface(wsFontName);
}
auto pDoc = GetDoc();
return pDoc->GetApp()->GetXFAFontMgr()->GetFont(pDoc, wsFontName,
dwFontStyle);
}
FX_FLOAT CXFA_WidgetAcc::GetFontSize() {
FX_FLOAT fFontSize = 10.0f;
if (CXFA_Font font = GetFont()) {
fFontSize = font.GetFontSize();
}
return fFontSize < 0.1f ? 10.0f : fFontSize;
}
FX_FLOAT CXFA_WidgetAcc::GetLineHeight() {
FX_FLOAT fLineHeight = 0;
if (CXFA_Para para = GetPara()) {
fLineHeight = para.GetLineHeight();
}
if (fLineHeight < 1) {
fLineHeight = GetFontSize() * 1.2f;
}
return fLineHeight;
}
FX_ARGB CXFA_WidgetAcc::GetTextColor() {
if (CXFA_Font font = GetFont()) {
return font.GetColor();
}
return 0xFF000000;
}
CXFA_Node* CXFA_TextProvider::GetTextNode(bool& bRichText) {
bRichText = false;
if (m_pTextNode) {
if (m_pTextNode->GetElementType() == XFA_Element::ExData) {
CFX_WideString wsContentType;
m_pTextNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType,
false);
if (wsContentType == L"text/html") {
bRichText = true;
}
}
return m_pTextNode;
}
if (m_eType == XFA_TEXTPROVIDERTYPE_Text) {
CXFA_Node* pElementNode = m_pWidgetAcc->GetNode();
CXFA_Node* pValueNode = pElementNode->GetChild(0, XFA_Element::Value);
if (!pValueNode) {
return nullptr;
}
CXFA_Node* pChildNode = pValueNode->GetNodeItem(XFA_NODEITEM_FirstChild);
if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
CFX_WideString wsContentType;
pChildNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
if (wsContentType == L"text/html") {
bRichText = true;
}
}
return pChildNode;
} else if (m_eType == XFA_TEXTPROVIDERTYPE_Datasets) {
CXFA_Node* pBind = m_pWidgetAcc->GetDatasets();
CFDE_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
ASSERT(pXMLNode);
for (CFDE_XMLNode* pXMLChild =
pXMLNode->GetNodeItem(CFDE_XMLNode::FirstChild);
pXMLChild;
pXMLChild = pXMLChild->GetNodeItem(CFDE_XMLNode::NextSibling)) {
if (pXMLChild->GetType() == FDE_XMLNODE_Element) {
CFDE_XMLElement* pElement = static_cast<CFDE_XMLElement*>(pXMLChild);
if (XFA_RecognizeRichText(pElement)) {
bRichText = true;
}
}
}
return pBind;
} else if (m_eType == XFA_TEXTPROVIDERTYPE_Caption) {
CXFA_Node* pCaptionNode =
m_pWidgetAcc->GetNode()->GetChild(0, XFA_Element::Caption);
if (!pCaptionNode) {
return nullptr;
}
CXFA_Node* pValueNode = pCaptionNode->GetChild(0, XFA_Element::Value);
if (!pValueNode) {
return nullptr;
}
CXFA_Node* pChildNode = pValueNode->GetNodeItem(XFA_NODEITEM_FirstChild);
if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
CFX_WideString wsContentType;
pChildNode->GetAttribute(XFA_ATTRIBUTE_ContentType, wsContentType, false);
if (wsContentType == L"text/html") {
bRichText = true;
}
}
return pChildNode;
}
CXFA_Node* pItemNode =
m_pWidgetAcc->GetNode()->GetChild(0, XFA_Element::Items);
if (!pItemNode) {
return nullptr;
}
CXFA_Node* pNode = pItemNode->GetNodeItem(XFA_NODEITEM_FirstChild);
while (pNode) {
CFX_WideStringC wsName;
pNode->TryCData(XFA_ATTRIBUTE_Name, wsName);
if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover && wsName == L"rollover") {
return pNode;
}
if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName == L"down") {
return pNode;
}
pNode = pNode->GetNodeItem(XFA_NODEITEM_NextSibling);
}
return nullptr;
}
CXFA_Para CXFA_TextProvider::GetParaNode() {
if (m_eType == XFA_TEXTPROVIDERTYPE_Text) {
return m_pWidgetAcc->GetPara();
}
CXFA_Node* pNode = m_pWidgetAcc->GetNode()->GetChild(0, XFA_Element::Caption);
return CXFA_Para(pNode->GetChild(0, XFA_Element::Para));
}
CXFA_Font CXFA_TextProvider::GetFontNode() {
if (m_eType == XFA_TEXTPROVIDERTYPE_Text) {
return m_pWidgetAcc->GetFont();
}
CXFA_Node* pNode = m_pWidgetAcc->GetNode()->GetChild(0, XFA_Element::Caption);
pNode = pNode->GetChild(0, XFA_Element::Font);
if (pNode) {
return CXFA_Font(pNode);
}
return m_pWidgetAcc->GetFont();
}
bool CXFA_TextProvider::IsCheckButtonAndAutoWidth() {
XFA_Element eType = m_pWidgetAcc->GetUIType();
if (eType == XFA_Element::CheckButton) {
FX_FLOAT fWidth = 0;
return !m_pWidgetAcc->GetWidth(fWidth);
}
return false;
}
bool CXFA_TextProvider::GetEmbbedObj(bool bURI,
bool bRaw,
const CFX_WideString& wsAttr,
CFX_WideString& wsValue) {
if (m_eType != XFA_TEXTPROVIDERTYPE_Text) {
return false;
}
if (bURI) {
CXFA_Node* pWidgetNode = m_pWidgetAcc->GetNode();
CXFA_Node* pParent = pWidgetNode->GetNodeItem(XFA_NODEITEM_Parent);
CXFA_Document* pDocument = pWidgetNode->GetDocument();
CXFA_Node* pIDNode = nullptr;
CXFA_WidgetAcc* pEmbAcc = nullptr;
if (pParent) {
pIDNode = pDocument->GetNodeByID(pParent, wsAttr.AsStringC());
}
if (!pIDNode) {
pIDNode = pDocument->GetNodeByID(
ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Form)),
wsAttr.AsStringC());
}
if (pIDNode) {
pEmbAcc = static_cast<CXFA_WidgetAcc*>(pIDNode->GetWidgetData());
}
if (pEmbAcc) {
pEmbAcc->GetValue(wsValue, XFA_VALUEPICTURE_Display);
return true;
}
}
return false;
}