// 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 "fpdfsdk/include/fsdk_baseform.h" #include #include #include "fpdfsdk/include/formfiller/FFL_FormFiller.h" #include "fpdfsdk/include/fsdk_actionhandler.h" #include "fpdfsdk/include/fsdk_baseannot.h" #include "fpdfsdk/include/fsdk_define.h" #include "fpdfsdk/include/fsdk_mgr.h" #include "fpdfsdk/include/javascript/IJavaScript.h" #include "fpdfsdk/include/pdfwindow/PWL_Utils.h" #define IsFloatZero(f) ((f) < 0.01 && (f) > -0.01) #define IsFloatBigger(fa, fb) ((fa) > (fb) && !IsFloatZero((fa) - (fb))) #define IsFloatSmaller(fa, fb) ((fa) < (fb) && !IsFloatZero((fa) - (fb))) #define IsFloatEqual(fa, fb) IsFloatZero((fa) - (fb)) CPDFSDK_Widget::CPDFSDK_Widget(CPDF_Annot* pAnnot, CPDFSDK_PageView* pPageView, CPDFSDK_InterForm* pInterForm) : CPDFSDK_BAAnnot(pAnnot, pPageView), m_pInterForm(pInterForm), m_nAppAge(0), m_nValueAge(0) { ASSERT(m_pInterForm); } CPDFSDK_Widget::~CPDFSDK_Widget() {} FX_BOOL CPDFSDK_Widget::IsWidgetAppearanceValid( CPDF_Annot::AppearanceMode mode) { CPDF_Dictionary* pAP = m_pAnnot->GetAnnotDict()->GetDictBy("AP"); if (!pAP) return FALSE; // Choose the right sub-ap const FX_CHAR* ap_entry = "N"; if (mode == CPDF_Annot::Down) ap_entry = "D"; else if (mode == CPDF_Annot::Rollover) ap_entry = "R"; if (!pAP->KeyExist(ap_entry)) ap_entry = "N"; // Get the AP stream or subdirectory CPDF_Object* psub = pAP->GetElementValue(ap_entry); if (!psub) return FALSE; int nFieldType = GetFieldType(); switch (nFieldType) { case FIELDTYPE_PUSHBUTTON: case FIELDTYPE_COMBOBOX: case FIELDTYPE_LISTBOX: case FIELDTYPE_TEXTFIELD: case FIELDTYPE_SIGNATURE: return psub->IsStream(); case FIELDTYPE_CHECKBOX: case FIELDTYPE_RADIOBUTTON: if (CPDF_Dictionary* pSubDict = psub->AsDictionary()) { return pSubDict->GetStreamBy(GetAppState()) != NULL; } return FALSE; } return TRUE; } int CPDFSDK_Widget::GetFieldType() const { return GetFormField()->GetFieldType(); } FX_BOOL CPDFSDK_Widget::IsAppearanceValid() { return CPDFSDK_BAAnnot::IsAppearanceValid(); } int CPDFSDK_Widget::GetFieldFlags() const { CPDF_InterForm* pPDFInterForm = m_pInterForm->GetInterForm(); CPDF_FormControl* pFormControl = pPDFInterForm->GetControlByDict(m_pAnnot->GetAnnotDict()); CPDF_FormField* pFormField = pFormControl->GetField(); return pFormField->GetFieldFlags(); } CFX_ByteString CPDFSDK_Widget::GetSubType() const { int nType = GetFieldType(); if (nType == FIELDTYPE_SIGNATURE) return BFFT_SIGNATURE; return CPDFSDK_Annot::GetSubType(); } CPDF_FormField* CPDFSDK_Widget::GetFormField() const { return GetFormControl()->GetField(); } CPDF_FormControl* CPDFSDK_Widget::GetFormControl() const { CPDF_InterForm* pPDFInterForm = m_pInterForm->GetInterForm(); return pPDFInterForm->GetControlByDict(GetAnnotDict()); } CPDF_FormControl* CPDFSDK_Widget::GetFormControl( CPDF_InterForm* pInterForm, const CPDF_Dictionary* pAnnotDict) { ASSERT(pAnnotDict); return pInterForm->GetControlByDict(pAnnotDict); } int CPDFSDK_Widget::GetRotate() const { CPDF_FormControl* pCtrl = GetFormControl(); return pCtrl->GetRotation() % 360; } FX_BOOL CPDFSDK_Widget::GetFillColor(FX_COLORREF& color) const { CPDF_FormControl* pFormCtrl = GetFormControl(); int iColorType = 0; color = FX_ARGBTOCOLORREF(pFormCtrl->GetBackgroundColor(iColorType)); return iColorType != COLORTYPE_TRANSPARENT; } FX_BOOL CPDFSDK_Widget::GetBorderColor(FX_COLORREF& color) const { CPDF_FormControl* pFormCtrl = GetFormControl(); int iColorType = 0; color = FX_ARGBTOCOLORREF(pFormCtrl->GetBorderColor(iColorType)); return iColorType != COLORTYPE_TRANSPARENT; } FX_BOOL CPDFSDK_Widget::GetTextColor(FX_COLORREF& color) const { CPDF_FormControl* pFormCtrl = GetFormControl(); CPDF_DefaultAppearance da = pFormCtrl->GetDefaultAppearance(); if (da.HasColor()) { FX_ARGB argb; int iColorType = COLORTYPE_TRANSPARENT; da.GetColor(argb, iColorType); color = FX_ARGBTOCOLORREF(argb); return iColorType != COLORTYPE_TRANSPARENT; } return FALSE; } FX_FLOAT CPDFSDK_Widget::GetFontSize() const { CPDF_FormControl* pFormCtrl = GetFormControl(); CPDF_DefaultAppearance pDa = pFormCtrl->GetDefaultAppearance(); CFX_ByteString csFont = ""; FX_FLOAT fFontSize = 0.0f; pDa.GetFont(csFont, fFontSize); return fFontSize; } int CPDFSDK_Widget::GetSelectedIndex(int nIndex) const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetSelectedIndex(nIndex); } CFX_WideString CPDFSDK_Widget::GetValue() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetValue(); } CFX_WideString CPDFSDK_Widget::GetDefaultValue() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetDefaultValue(); } CFX_WideString CPDFSDK_Widget::GetOptionLabel(int nIndex) const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetOptionLabel(nIndex); } int CPDFSDK_Widget::CountOptions() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->CountOptions(); } FX_BOOL CPDFSDK_Widget::IsOptionSelected(int nIndex) const { CPDF_FormField* pFormField = GetFormField(); return pFormField->IsItemSelected(nIndex); } int CPDFSDK_Widget::GetTopVisibleIndex() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetTopVisibleIndex(); } FX_BOOL CPDFSDK_Widget::IsChecked() const { CPDF_FormControl* pFormCtrl = GetFormControl(); return pFormCtrl->IsChecked(); } int CPDFSDK_Widget::GetAlignment() const { CPDF_FormControl* pFormCtrl = GetFormControl(); return pFormCtrl->GetControlAlignment(); } int CPDFSDK_Widget::GetMaxLen() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetMaxLen(); } void CPDFSDK_Widget::SetCheck(FX_BOOL bChecked, FX_BOOL bNotify) { CPDF_FormControl* pFormCtrl = GetFormControl(); CPDF_FormField* pFormField = pFormCtrl->GetField(); pFormField->CheckControl(pFormField->GetControlIndex(pFormCtrl), bChecked, bNotify); } void CPDFSDK_Widget::SetValue(const CFX_WideString& sValue, FX_BOOL bNotify) { CPDF_FormField* pFormField = GetFormField(); pFormField->SetValue(sValue, bNotify); } void CPDFSDK_Widget::SetDefaultValue(const CFX_WideString& sValue) {} void CPDFSDK_Widget::SetOptionSelection(int index, FX_BOOL bSelected, FX_BOOL bNotify) { CPDF_FormField* pFormField = GetFormField(); pFormField->SetItemSelection(index, bSelected, bNotify); } void CPDFSDK_Widget::ClearSelection(FX_BOOL bNotify) { CPDF_FormField* pFormField = GetFormField(); pFormField->ClearSelection(bNotify); } void CPDFSDK_Widget::SetTopVisibleIndex(int index) {} void CPDFSDK_Widget::SetAppModified() { m_bAppModified = TRUE; } void CPDFSDK_Widget::ClearAppModified() { m_bAppModified = FALSE; } FX_BOOL CPDFSDK_Widget::IsAppModified() const { return m_bAppModified; } void CPDFSDK_Widget::ResetAppearance(const FX_WCHAR* sValue, FX_BOOL bValueChanged) { SetAppModified(); m_nAppAge++; if (m_nAppAge > 999999) m_nAppAge = 0; if (bValueChanged) m_nValueAge++; int nFieldType = GetFieldType(); switch (nFieldType) { case FIELDTYPE_PUSHBUTTON: ResetAppearance_PushButton(); break; case FIELDTYPE_CHECKBOX: ResetAppearance_CheckBox(); break; case FIELDTYPE_RADIOBUTTON: ResetAppearance_RadioButton(); break; case FIELDTYPE_COMBOBOX: ResetAppearance_ComboBox(sValue); break; case FIELDTYPE_LISTBOX: ResetAppearance_ListBox(); break; case FIELDTYPE_TEXTFIELD: ResetAppearance_TextField(sValue); break; } m_pAnnot->ClearCachedAP(); } CFX_WideString CPDFSDK_Widget::OnFormat(FX_BOOL& bFormated) { CPDF_FormField* pFormField = GetFormField(); ASSERT(pFormField); return m_pInterForm->OnFormat(pFormField, bFormated); } void CPDFSDK_Widget::ResetFieldAppearance(FX_BOOL bValueChanged) { CPDF_FormField* pFormField = GetFormField(); ASSERT(pFormField); m_pInterForm->ResetFieldAppearance(pFormField, NULL, bValueChanged); } void CPDFSDK_Widget::DrawAppearance(CFX_RenderDevice* pDevice, const CFX_Matrix* pUser2Device, CPDF_Annot::AppearanceMode mode, const CPDF_RenderOptions* pOptions) { int nFieldType = GetFieldType(); if ((nFieldType == FIELDTYPE_CHECKBOX || nFieldType == FIELDTYPE_RADIOBUTTON) && mode == CPDF_Annot::Normal && !IsWidgetAppearanceValid(CPDF_Annot::Normal)) { CFX_PathData pathData; CPDF_Rect rcAnnot = GetRect(); pathData.AppendRect(rcAnnot.left, rcAnnot.bottom, rcAnnot.right, rcAnnot.top); CFX_GraphStateData gsd; gsd.m_LineWidth = 0.0f; pDevice->DrawPath(&pathData, pUser2Device, &gsd, 0, 0xFFAAAAAA, FXFILL_ALTERNATE); } else { CPDFSDK_BAAnnot::DrawAppearance(pDevice, pUser2Device, mode, pOptions); } } void CPDFSDK_Widget::UpdateField() { CPDF_FormField* pFormField = GetFormField(); ASSERT(pFormField); m_pInterForm->UpdateField(pFormField); } void CPDFSDK_Widget::DrawShadow(CFX_RenderDevice* pDevice, CPDFSDK_PageView* pPageView) { int nFieldType = GetFieldType(); if (m_pInterForm->IsNeedHighLight(nFieldType)) { CPDF_Rect rc = GetRect(); FX_COLORREF color = m_pInterForm->GetHighlightColor(nFieldType); uint8_t alpha = m_pInterForm->GetHighlightAlpha(); CFX_FloatRect rcDevice; ASSERT(m_pInterForm->GetDocument()); CPDFDoc_Environment* pEnv = m_pInterForm->GetDocument()->GetEnv(); if (!pEnv) return; CFX_Matrix page2device; pPageView->GetCurrentMatrix(page2device); page2device.Transform(((FX_FLOAT)rc.left), ((FX_FLOAT)rc.bottom), rcDevice.left, rcDevice.bottom); page2device.Transform(((FX_FLOAT)rc.right), ((FX_FLOAT)rc.top), rcDevice.right, rcDevice.top); rcDevice.Normalize(); FX_ARGB argb = ArgbEncode((int)alpha, color); FX_RECT rcDev((int)rcDevice.left, (int)rcDevice.top, (int)rcDevice.right, (int)rcDevice.bottom); pDevice->FillRect(&rcDev, argb); } } void CPDFSDK_Widget::ResetAppearance_PushButton() { CPDF_FormControl* pControl = GetFormControl(); CPDF_Rect rcWindow = GetRotatedRect(); int32_t nLayout = 0; switch (pControl->GetTextPosition()) { case TEXTPOS_ICON: nLayout = PPBL_ICON; break; case TEXTPOS_BELOW: nLayout = PPBL_ICONTOPLABELBOTTOM; break; case TEXTPOS_ABOVE: nLayout = PPBL_LABELTOPICONBOTTOM; break; case TEXTPOS_RIGHT: nLayout = PPBL_ICONLEFTLABELRIGHT; break; case TEXTPOS_LEFT: nLayout = PPBL_LABELLEFTICONRIGHT; break; case TEXTPOS_OVERLAID: nLayout = PPBL_LABELOVERICON; break; default: nLayout = PPBL_LABEL; break; } CPWL_Color crBackground, crBorder; int iColorType; FX_FLOAT fc[4]; pControl->GetOriginalBackgroundColor(iColorType, fc); if (iColorType > 0) crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); pControl->GetOriginalBorderColor(iColorType, fc); if (iColorType > 0) crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth(); int32_t nBorderStyle = 0; CPWL_Dash dsBorder(3, 0, 0); CPWL_Color crLeftTop, crRightBottom; switch (GetBorderStyle()) { case BBS_DASH: nBorderStyle = PBS_DASH; dsBorder = CPWL_Dash(3, 3, 0); break; case BBS_BEVELED: nBorderStyle = PBS_BEVELED; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1); crRightBottom = CPWL_Utils::DevideColor(crBackground, 2); break; case BBS_INSET: nBorderStyle = PBS_INSET; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75); break; case BBS_UNDERLINE: nBorderStyle = PBS_UNDERLINED; break; default: nBorderStyle = PBS_SOLID; break; } CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth); CPWL_Color crText(COLORTYPE_GRAY, 0); FX_FLOAT fFontSize = 12.0f; CFX_ByteString csNameTag; CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); if (da.HasColor()) { da.GetColor(iColorType, fc); crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); } if (da.HasFont()) da.GetFont(csNameTag, fFontSize); CFX_WideString csWCaption; CFX_WideString csNormalCaption, csRolloverCaption, csDownCaption; if (pControl->HasMKEntry("CA")) { csNormalCaption = pControl->GetNormalCaption(); } if (pControl->HasMKEntry("RC")) { csRolloverCaption = pControl->GetRolloverCaption(); } if (pControl->HasMKEntry("AC")) { csDownCaption = pControl->GetDownCaption(); } CPDF_Stream* pNormalIcon = NULL; CPDF_Stream* pRolloverIcon = NULL; CPDF_Stream* pDownIcon = NULL; if (pControl->HasMKEntry("I")) { pNormalIcon = pControl->GetNormalIcon(); } if (pControl->HasMKEntry("RI")) { pRolloverIcon = pControl->GetRolloverIcon(); } if (pControl->HasMKEntry("IX")) { pDownIcon = pControl->GetDownIcon(); } if (pNormalIcon) { if (CPDF_Dictionary* pImageDict = pNormalIcon->GetDict()) { if (pImageDict->GetStringBy("Name").IsEmpty()) pImageDict->SetAtString("Name", "ImgA"); } } if (pRolloverIcon) { if (CPDF_Dictionary* pImageDict = pRolloverIcon->GetDict()) { if (pImageDict->GetStringBy("Name").IsEmpty()) pImageDict->SetAtString("Name", "ImgB"); } } if (pDownIcon) { if (CPDF_Dictionary* pImageDict = pDownIcon->GetDict()) { if (pImageDict->GetStringBy("Name").IsEmpty()) pImageDict->SetAtString("Name", "ImgC"); } } CPDF_IconFit iconFit = pControl->GetIconFit(); CPDFSDK_Document* pDoc = m_pInterForm->GetDocument(); CPDFDoc_Environment* pEnv = pDoc->GetEnv(); CBA_FontMap font_map(this, pEnv->GetSysHandler()); font_map.SetAPType("N"); CFX_ByteString csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder) + CPWL_Utils::GetPushButtonAppStream( iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map, pNormalIcon, iconFit, csNormalCaption, crText, fFontSize, nLayout); WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP); if (pNormalIcon) AddImageToAppearance("N", pNormalIcon); CPDF_FormControl::HighlightingMode eHLM = pControl->GetHighlightingMode(); if (eHLM == CPDF_FormControl::Push || eHLM == CPDF_FormControl::Toggle) { if (csRolloverCaption.IsEmpty() && !pRolloverIcon) { csRolloverCaption = csNormalCaption; pRolloverIcon = pNormalIcon; } font_map.SetAPType("R"); csAP = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder) + CPWL_Utils::GetPushButtonAppStream( iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map, pRolloverIcon, iconFit, csRolloverCaption, crText, fFontSize, nLayout); WriteAppearance("R", GetRotatedRect(), GetMatrix(), csAP); if (pRolloverIcon) AddImageToAppearance("R", pRolloverIcon); if (csDownCaption.IsEmpty() && !pDownIcon) { csDownCaption = csNormalCaption; pDownIcon = pNormalIcon; } switch (nBorderStyle) { case PBS_BEVELED: { CPWL_Color crTemp = crLeftTop; crLeftTop = crRightBottom; crRightBottom = crTemp; } break; case PBS_INSET: crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1); break; } font_map.SetAPType("D"); csAP = CPWL_Utils::GetRectFillAppStream( rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder) + CPWL_Utils::GetPushButtonAppStream( iconFit.GetFittingBounds() ? rcWindow : rcClient, &font_map, pDownIcon, iconFit, csDownCaption, crText, fFontSize, nLayout); WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP); if (pDownIcon) AddImageToAppearance("D", pDownIcon); } else { RemoveAppearance("D"); RemoveAppearance("R"); } } void CPDFSDK_Widget::ResetAppearance_CheckBox() { CPDF_FormControl* pControl = GetFormControl(); CPWL_Color crBackground, crBorder, crText; int iColorType; FX_FLOAT fc[4]; pControl->GetOriginalBackgroundColor(iColorType, fc); if (iColorType > 0) crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); pControl->GetOriginalBorderColor(iColorType, fc); if (iColorType > 0) crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth(); int32_t nBorderStyle = 0; CPWL_Dash dsBorder(3, 0, 0); CPWL_Color crLeftTop, crRightBottom; switch (GetBorderStyle()) { case BBS_DASH: nBorderStyle = PBS_DASH; dsBorder = CPWL_Dash(3, 3, 0); break; case BBS_BEVELED: nBorderStyle = PBS_BEVELED; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1); crRightBottom = CPWL_Utils::DevideColor(crBackground, 2); break; case BBS_INSET: nBorderStyle = PBS_INSET; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75); break; case BBS_UNDERLINE: nBorderStyle = PBS_UNDERLINED; break; default: nBorderStyle = PBS_SOLID; break; } CPDF_Rect rcWindow = GetRotatedRect(); CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth); CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); if (da.HasColor()) { da.GetColor(iColorType, fc); crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); } int32_t nStyle = 0; CFX_WideString csWCaption = pControl->GetNormalCaption(); if (csWCaption.GetLength() > 0) { switch (csWCaption[0]) { case L'l': nStyle = PCS_CIRCLE; break; case L'8': nStyle = PCS_CROSS; break; case L'u': nStyle = PCS_DIAMOND; break; case L'n': nStyle = PCS_SQUARE; break; case L'H': nStyle = PCS_STAR; break; default: // L'4' nStyle = PCS_CHECK; break; } } else { nStyle = PCS_CHECK; } CFX_ByteString csAP_N_ON = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); CFX_ByteString csAP_N_OFF = csAP_N_ON; switch (nBorderStyle) { case PBS_BEVELED: { CPWL_Color crTemp = crLeftTop; crLeftTop = crRightBottom; crRightBottom = crTemp; } break; case PBS_INSET: crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1); break; } CFX_ByteString csAP_D_ON = CPWL_Utils::GetRectFillAppStream( rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); CFX_ByteString csAP_D_OFF = csAP_D_ON; csAP_N_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText); csAP_D_ON += CPWL_Utils::GetCheckBoxAppStream(rcClient, nStyle, crText); WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON, pControl->GetCheckedAPState()); WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off"); WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON, pControl->GetCheckedAPState()); WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off"); CFX_ByteString csAS = GetAppState(); if (csAS.IsEmpty()) SetAppState("Off"); } void CPDFSDK_Widget::ResetAppearance_RadioButton() { CPDF_FormControl* pControl = GetFormControl(); CPWL_Color crBackground, crBorder, crText; int iColorType; FX_FLOAT fc[4]; pControl->GetOriginalBackgroundColor(iColorType, fc); if (iColorType > 0) crBackground = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); pControl->GetOriginalBorderColor(iColorType, fc); if (iColorType > 0) crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth(); int32_t nBorderStyle = 0; CPWL_Dash dsBorder(3, 0, 0); CPWL_Color crLeftTop, crRightBottom; switch (GetBorderStyle()) { case BBS_DASH: nBorderStyle = PBS_DASH; dsBorder = CPWL_Dash(3, 3, 0); break; case BBS_BEVELED: nBorderStyle = PBS_BEVELED; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1); crRightBottom = CPWL_Utils::DevideColor(crBackground, 2); break; case BBS_INSET: nBorderStyle = PBS_INSET; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75); break; case BBS_UNDERLINE: nBorderStyle = PBS_UNDERLINED; break; default: nBorderStyle = PBS_SOLID; break; } CPDF_Rect rcWindow = GetRotatedRect(); CPDF_Rect rcClient = CPWL_Utils::DeflateRect(rcWindow, fBorderWidth); CPDF_DefaultAppearance da = pControl->GetDefaultAppearance(); if (da.HasColor()) { da.GetColor(iColorType, fc); crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); } int32_t nStyle = 0; CFX_WideString csWCaption = pControl->GetNormalCaption(); if (csWCaption.GetLength() > 0) { switch (csWCaption[0]) { default: // L'l': nStyle = PCS_CIRCLE; break; case L'8': nStyle = PCS_CROSS; break; case L'u': nStyle = PCS_DIAMOND; break; case L'n': nStyle = PCS_SQUARE; break; case L'H': nStyle = PCS_STAR; break; case L'4': nStyle = PCS_CHECK; break; } } else { nStyle = PCS_CIRCLE; } CFX_ByteString csAP_N_ON; CPDF_Rect rcCenter = CPWL_Utils::DeflateRect(CPWL_Utils::GetCenterSquare(rcWindow), 1.0f); if (nStyle == PCS_CIRCLE) { if (nBorderStyle == PBS_BEVELED) { crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1); crRightBottom = CPWL_Utils::SubstractColor(crBackground, 0.25f); } else if (nBorderStyle == PBS_INSET) { crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5f); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75f); } csAP_N_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBackground) + CPWL_Utils::GetCircleBorderAppStream( rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); } else { csAP_N_ON = CPWL_Utils::GetRectFillAppStream(rcWindow, crBackground) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); } CFX_ByteString csAP_N_OFF = csAP_N_ON; switch (nBorderStyle) { case PBS_BEVELED: { CPWL_Color crTemp = crLeftTop; crLeftTop = crRightBottom; crRightBottom = crTemp; } break; case PBS_INSET: crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1); break; } CFX_ByteString csAP_D_ON; if (nStyle == PCS_CIRCLE) { CPWL_Color crBK = CPWL_Utils::SubstractColor(crBackground, 0.25f); if (nBorderStyle == PBS_BEVELED) { crLeftTop = CPWL_Utils::SubstractColor(crBackground, 0.25f); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1); crBK = crBackground; } else if (nBorderStyle == PBS_INSET) { crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 1); } csAP_D_ON = CPWL_Utils::GetCircleFillAppStream(rcCenter, crBK) + CPWL_Utils::GetCircleBorderAppStream( rcCenter, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); } else { csAP_D_ON = CPWL_Utils::GetRectFillAppStream( rcWindow, CPWL_Utils::SubstractColor(crBackground, 0.25f)) + CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); } CFX_ByteString csAP_D_OFF = csAP_D_ON; csAP_N_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText); csAP_D_ON += CPWL_Utils::GetRadioButtonAppStream(rcClient, nStyle, crText); WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_ON, pControl->GetCheckedAPState()); WriteAppearance("N", GetRotatedRect(), GetMatrix(), csAP_N_OFF, "Off"); WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_ON, pControl->GetCheckedAPState()); WriteAppearance("D", GetRotatedRect(), GetMatrix(), csAP_D_OFF, "Off"); CFX_ByteString csAS = GetAppState(); if (csAS.IsEmpty()) SetAppState("Off"); } void CPDFSDK_Widget::ResetAppearance_ComboBox(const FX_WCHAR* sValue) { CPDF_FormControl* pControl = GetFormControl(); CPDF_FormField* pField = pControl->GetField(); CFX_ByteTextBuf sBody, sLines; CPDF_Rect rcClient = GetClientRect(); CPDF_Rect rcButton = rcClient; rcButton.left = rcButton.right - 13; rcButton.Normalize(); if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) { pEdit->EnableRefresh(FALSE); CPDFSDK_Document* pDoc = m_pInterForm->GetDocument(); CPDFDoc_Environment* pEnv = pDoc->GetEnv(); CBA_FontMap font_map(this, pEnv->GetSysHandler()); pEdit->SetFontMap(&font_map); CPDF_Rect rcEdit = rcClient; rcEdit.right = rcButton.left; rcEdit.Normalize(); pEdit->SetPlateRect(rcEdit); pEdit->SetAlignmentV(1); FX_FLOAT fFontSize = GetFontSize(); if (IsFloatZero(fFontSize)) pEdit->SetAutoFontSize(TRUE); else pEdit->SetFontSize(fFontSize); pEdit->Initialize(); if (sValue) { pEdit->SetText(sValue); } else { int32_t nCurSel = pField->GetSelectedIndex(0); if (nCurSel < 0) pEdit->SetText(pField->GetValue().c_str()); else pEdit->SetText(pField->GetOptionLabel(nCurSel).c_str()); } CPDF_Rect rcContent = pEdit->GetContentRect(); CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, 0.0f)); if (sEdit.GetLength() > 0) { sBody << "/Tx BMC\n" << "q\n"; if (rcContent.Width() > rcEdit.Width() || rcContent.Height() > rcEdit.Height()) { sBody << rcEdit.left << " " << rcEdit.bottom << " " << rcEdit.Width() << " " << rcEdit.Height() << " re\nW\nn\n"; } CPWL_Color crText = GetTextPWLColor(); sBody << "BT\n" << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n" << "Q\nEMC\n"; } IFX_Edit::DelEdit(pEdit); } sBody << CPWL_Utils::GetDropButtonAppStream(rcButton); CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() + sLines.GetByteString() + sBody.GetByteString(); WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP); } void CPDFSDK_Widget::ResetAppearance_ListBox() { CPDF_FormControl* pControl = GetFormControl(); CPDF_FormField* pField = pControl->GetField(); CPDF_Rect rcClient = GetClientRect(); CFX_ByteTextBuf sBody, sLines; if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) { pEdit->EnableRefresh(FALSE); CPDFSDK_Document* pDoc = m_pInterForm->GetDocument(); CPDFDoc_Environment* pEnv = pDoc->GetEnv(); CBA_FontMap font_map(this, pEnv->GetSysHandler()); pEdit->SetFontMap(&font_map); pEdit->SetPlateRect(CPDF_Rect(rcClient.left, 0.0f, rcClient.right, 0.0f)); FX_FLOAT fFontSize = GetFontSize(); if (IsFloatZero(fFontSize)) pEdit->SetFontSize(12.0f); else pEdit->SetFontSize(fFontSize); pEdit->Initialize(); CFX_ByteTextBuf sList; FX_FLOAT fy = rcClient.top; int32_t nTop = pField->GetTopVisibleIndex(); int32_t nCount = pField->CountOptions(); int32_t nSelCount = pField->CountSelectedItems(); for (int32_t i = nTop; i < nCount; i++) { FX_BOOL bSelected = FALSE; for (int32_t j = 0; j < nSelCount; j++) { if (pField->GetSelectedIndex(j) == i) { bSelected = TRUE; break; } } pEdit->SetText(pField->GetOptionLabel(i).c_str()); CPDF_Rect rcContent = pEdit->GetContentRect(); FX_FLOAT fItemHeight = rcContent.Height(); if (bSelected) { CPDF_Rect rcItem = CPDF_Rect(rcClient.left, fy - fItemHeight, rcClient.right, fy); sList << "q\n" << CPWL_Utils::GetColorAppStream( CPWL_Color(COLORTYPE_RGB, 0, 51.0f / 255.0f, 113.0f / 255.0f), TRUE) << rcItem.left << " " << rcItem.bottom << " " << rcItem.Width() << " " << rcItem.Height() << " re f\n" << "Q\n"; sList << "BT\n" << CPWL_Utils::GetColorAppStream( CPWL_Color(COLORTYPE_GRAY, 1), TRUE) << CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, fy)) << "ET\n"; } else { CPWL_Color crText = GetTextPWLColor(); sList << "BT\n" << CPWL_Utils::GetColorAppStream(crText, TRUE) << CPWL_Utils::GetEditAppStream(pEdit, CPDF_Point(0.0f, fy)) << "ET\n"; } fy -= fItemHeight; } if (sList.GetSize() > 0) { sBody << "/Tx BMC\n" << "q\n" << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n"; sBody << sList << "Q\nEMC\n"; } IFX_Edit::DelEdit(pEdit); } CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() + sLines.GetByteString() + sBody.GetByteString(); WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP); } void CPDFSDK_Widget::ResetAppearance_TextField(const FX_WCHAR* sValue) { CPDF_FormControl* pControl = GetFormControl(); CPDF_FormField* pField = pControl->GetField(); CFX_ByteTextBuf sBody, sLines; if (IFX_Edit* pEdit = IFX_Edit::NewEdit()) { pEdit->EnableRefresh(FALSE); CPDFSDK_Document* pDoc = m_pInterForm->GetDocument(); CPDFDoc_Environment* pEnv = pDoc->GetEnv(); CBA_FontMap font_map(this, pEnv->GetSysHandler()); pEdit->SetFontMap(&font_map); CPDF_Rect rcClient = GetClientRect(); pEdit->SetPlateRect(rcClient); pEdit->SetAlignmentH(pControl->GetControlAlignment()); FX_DWORD dwFieldFlags = pField->GetFieldFlags(); FX_BOOL bMultiLine = (dwFieldFlags >> 12) & 1; if (bMultiLine) { pEdit->SetMultiLine(TRUE); pEdit->SetAutoReturn(TRUE); } else { pEdit->SetAlignmentV(1); } FX_WORD subWord = 0; if ((dwFieldFlags >> 13) & 1) { subWord = '*'; pEdit->SetPasswordChar(subWord); } int nMaxLen = pField->GetMaxLen(); FX_BOOL bCharArray = (dwFieldFlags >> 24) & 1; FX_FLOAT fFontSize = GetFontSize(); if (nMaxLen > 0) { if (bCharArray) { pEdit->SetCharArray(nMaxLen); if (IsFloatZero(fFontSize)) { fFontSize = CPWL_Edit::GetCharArrayAutoFontSize( font_map.GetPDFFont(0), rcClient, nMaxLen); } } else { if (sValue) nMaxLen = wcslen((const wchar_t*)sValue); pEdit->SetLimitChar(nMaxLen); } } if (IsFloatZero(fFontSize)) pEdit->SetAutoFontSize(TRUE); else pEdit->SetFontSize(fFontSize); pEdit->Initialize(); if (sValue) pEdit->SetText(sValue); else pEdit->SetText(pField->GetValue().c_str()); CPDF_Rect rcContent = pEdit->GetContentRect(); CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream( pEdit, CPDF_Point(0.0f, 0.0f), NULL, !bCharArray, subWord); if (sEdit.GetLength() > 0) { sBody << "/Tx BMC\n" << "q\n"; if (rcContent.Width() > rcClient.Width() || rcContent.Height() > rcClient.Height()) { sBody << rcClient.left << " " << rcClient.bottom << " " << rcClient.Width() << " " << rcClient.Height() << " re\nW\nn\n"; } CPWL_Color crText = GetTextPWLColor(); sBody << "BT\n" << CPWL_Utils::GetColorAppStream(crText) << sEdit << "ET\n" << "Q\nEMC\n"; } if (bCharArray) { switch (GetBorderStyle()) { case BBS_SOLID: { CFX_ByteString sColor = CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE); if (sColor.GetLength() > 0) { sLines << "q\n" << GetBorderWidth() << " w\n" << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE) << " 2 J 0 j\n"; for (int32_t i = 1; i < nMaxLen; i++) { sLines << rcClient.left + ((rcClient.right - rcClient.left) / nMaxLen) * i << " " << rcClient.bottom << " m\n" << rcClient.left + ((rcClient.right - rcClient.left) / nMaxLen) * i << " " << rcClient.top << " l S\n"; } sLines << "Q\n"; } } break; case BBS_DASH: { CFX_ByteString sColor = CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE); if (sColor.GetLength() > 0) { CPWL_Dash dsBorder = CPWL_Dash(3, 3, 0); sLines << "q\n" << GetBorderWidth() << " w\n" << CPWL_Utils::GetColorAppStream(GetBorderPWLColor(), FALSE) << "[" << dsBorder.nDash << " " << dsBorder.nGap << "] " << dsBorder.nPhase << " d\n"; for (int32_t i = 1; i < nMaxLen; i++) { sLines << rcClient.left + ((rcClient.right - rcClient.left) / nMaxLen) * i << " " << rcClient.bottom << " m\n" << rcClient.left + ((rcClient.right - rcClient.left) / nMaxLen) * i << " " << rcClient.top << " l S\n"; } sLines << "Q\n"; } } break; } } IFX_Edit::DelEdit(pEdit); } CFX_ByteString sAP = GetBackgroundAppStream() + GetBorderAppStream() + sLines.GetByteString() + sBody.GetByteString(); WriteAppearance("N", GetRotatedRect(), GetMatrix(), sAP); } CPDF_Rect CPDFSDK_Widget::GetClientRect() const { CPDF_Rect rcWindow = GetRotatedRect(); FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth(); switch (GetBorderStyle()) { case BBS_BEVELED: case BBS_INSET: fBorderWidth *= 2.0f; break; } return CPWL_Utils::DeflateRect(rcWindow, fBorderWidth); } CPDF_Rect CPDFSDK_Widget::GetRotatedRect() const { CPDF_Rect rectAnnot = GetRect(); FX_FLOAT fWidth = rectAnnot.right - rectAnnot.left; FX_FLOAT fHeight = rectAnnot.top - rectAnnot.bottom; CPDF_FormControl* pControl = GetFormControl(); CPDF_Rect rcPDFWindow; switch (abs(pControl->GetRotation() % 360)) { case 0: case 180: default: rcPDFWindow = CPDF_Rect(0, 0, fWidth, fHeight); break; case 90: case 270: rcPDFWindow = CPDF_Rect(0, 0, fHeight, fWidth); break; } return rcPDFWindow; } CFX_ByteString CPDFSDK_Widget::GetBackgroundAppStream() const { CPWL_Color crBackground = GetFillPWLColor(); if (crBackground.nColorType != COLORTYPE_TRANSPARENT) { return CPWL_Utils::GetRectFillAppStream(GetRotatedRect(), crBackground); } return ""; } CFX_ByteString CPDFSDK_Widget::GetBorderAppStream() const { CPDF_Rect rcWindow = GetRotatedRect(); CPWL_Color crBorder = GetBorderPWLColor(); CPWL_Color crBackground = GetFillPWLColor(); CPWL_Color crLeftTop, crRightBottom; FX_FLOAT fBorderWidth = (FX_FLOAT)GetBorderWidth(); int32_t nBorderStyle = 0; CPWL_Dash dsBorder(3, 0, 0); switch (GetBorderStyle()) { case BBS_DASH: nBorderStyle = PBS_DASH; dsBorder = CPWL_Dash(3, 3, 0); break; case BBS_BEVELED: nBorderStyle = PBS_BEVELED; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 1); crRightBottom = CPWL_Utils::DevideColor(crBackground, 2); break; case BBS_INSET: nBorderStyle = PBS_INSET; fBorderWidth *= 2; crLeftTop = CPWL_Color(COLORTYPE_GRAY, 0.5); crRightBottom = CPWL_Color(COLORTYPE_GRAY, 0.75); break; case BBS_UNDERLINE: nBorderStyle = PBS_UNDERLINED; break; default: nBorderStyle = PBS_SOLID; break; } return CPWL_Utils::GetBorderAppStream(rcWindow, fBorderWidth, crBorder, crLeftTop, crRightBottom, nBorderStyle, dsBorder); } CFX_Matrix CPDFSDK_Widget::GetMatrix() const { CFX_Matrix mt; CPDF_FormControl* pControl = GetFormControl(); CPDF_Rect rcAnnot = GetRect(); FX_FLOAT fWidth = rcAnnot.right - rcAnnot.left; FX_FLOAT fHeight = rcAnnot.top - rcAnnot.bottom; switch (abs(pControl->GetRotation() % 360)) { case 0: default: mt = CFX_Matrix(1, 0, 0, 1, 0, 0); break; case 90: mt = CFX_Matrix(0, 1, -1, 0, fWidth, 0); break; case 180: mt = CFX_Matrix(-1, 0, 0, -1, fWidth, fHeight); break; case 270: mt = CFX_Matrix(0, -1, 1, 0, 0, fHeight); break; } return mt; } CPWL_Color CPDFSDK_Widget::GetTextPWLColor() const { CPWL_Color crText = CPWL_Color(COLORTYPE_GRAY, 0); CPDF_FormControl* pFormCtrl = GetFormControl(); CPDF_DefaultAppearance da = pFormCtrl->GetDefaultAppearance(); if (da.HasColor()) { int32_t iColorType; FX_FLOAT fc[4]; da.GetColor(iColorType, fc); crText = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); } return crText; } CPWL_Color CPDFSDK_Widget::GetBorderPWLColor() const { CPWL_Color crBorder; CPDF_FormControl* pFormCtrl = GetFormControl(); int32_t iColorType; FX_FLOAT fc[4]; pFormCtrl->GetOriginalBorderColor(iColorType, fc); if (iColorType > 0) crBorder = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); return crBorder; } CPWL_Color CPDFSDK_Widget::GetFillPWLColor() const { CPWL_Color crFill; CPDF_FormControl* pFormCtrl = GetFormControl(); int32_t iColorType; FX_FLOAT fc[4]; pFormCtrl->GetOriginalBackgroundColor(iColorType, fc); if (iColorType > 0) crFill = CPWL_Color(iColorType, fc[0], fc[1], fc[2], fc[3]); return crFill; } void CPDFSDK_Widget::AddImageToAppearance(const CFX_ByteString& sAPType, CPDF_Stream* pImage) { CPDF_Document* pDoc = m_pPageView->GetPDFDocument(); ASSERT(pDoc); CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictBy("AP"); CPDF_Stream* pStream = pAPDict->GetStreamBy(sAPType); CPDF_Dictionary* pStreamDict = pStream->GetDict(); CFX_ByteString sImageAlias = "IMG"; if (CPDF_Dictionary* pImageDict = pImage->GetDict()) { sImageAlias = pImageDict->GetStringBy("Name"); if (sImageAlias.IsEmpty()) sImageAlias = "IMG"; } CPDF_Dictionary* pStreamResList = pStreamDict->GetDictBy("Resources"); if (!pStreamResList) { pStreamResList = new CPDF_Dictionary(); pStreamDict->SetAt("Resources", pStreamResList); } if (pStreamResList) { CPDF_Dictionary* pXObject = new CPDF_Dictionary; pXObject->SetAtReference(sImageAlias, pDoc, pImage); pStreamResList->SetAt("XObject", pXObject); } } void CPDFSDK_Widget::RemoveAppearance(const CFX_ByteString& sAPType) { if (CPDF_Dictionary* pAPDict = m_pAnnot->GetAnnotDict()->GetDictBy("AP")) { pAPDict->RemoveAt(sAPType); } } FX_BOOL CPDFSDK_Widget::OnAAction(CPDF_AAction::AActionType type, PDFSDK_FieldAction& data, CPDFSDK_PageView* pPageView) { CPDFSDK_Document* pDocument = pPageView->GetSDKDocument(); CPDFDoc_Environment* pEnv = pDocument->GetEnv(); CPDF_Action action = GetAAction(type); if (action && action.GetType() != CPDF_Action::Unknown) { CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander(); return pActionHandler->DoAction_Field(action, type, pDocument, GetFormField(), data); } return FALSE; } CPDF_Action CPDFSDK_Widget::GetAAction(CPDF_AAction::AActionType eAAT) { switch (eAAT) { case CPDF_AAction::CursorEnter: case CPDF_AAction::CursorExit: case CPDF_AAction::ButtonDown: case CPDF_AAction::ButtonUp: case CPDF_AAction::GetFocus: case CPDF_AAction::LoseFocus: case CPDF_AAction::PageOpen: case CPDF_AAction::PageClose: case CPDF_AAction::PageVisible: case CPDF_AAction::PageInvisible: return CPDFSDK_BAAnnot::GetAAction(eAAT); case CPDF_AAction::KeyStroke: case CPDF_AAction::Format: case CPDF_AAction::Validate: case CPDF_AAction::Calculate: { CPDF_FormField* pField = GetFormField(); if (CPDF_AAction aa = pField->GetAdditionalAction()) return aa.GetAction(eAAT); return CPDFSDK_BAAnnot::GetAAction(eAAT); } default: break; } return CPDF_Action(); } CFX_WideString CPDFSDK_Widget::GetAlternateName() const { CPDF_FormField* pFormField = GetFormField(); return pFormField->GetAlternateName(); } int32_t CPDFSDK_Widget::GetAppearanceAge() const { return m_nAppAge; } int32_t CPDFSDK_Widget::GetValueAge() const { return m_nValueAge; } FX_BOOL CPDFSDK_Widget::HitTest(FX_FLOAT pageX, FX_FLOAT pageY) { CPDF_Annot* pAnnot = GetPDFAnnot(); CFX_FloatRect annotRect; pAnnot->GetRect(annotRect); if (annotRect.Contains(pageX, pageY)) { if (!IsVisible()) return FALSE; int nFieldFlags = GetFieldFlags(); if ((nFieldFlags & FIELDFLAG_READONLY) == FIELDFLAG_READONLY) return FALSE; return TRUE; } return FALSE; } CPDFSDK_InterForm::CPDFSDK_InterForm(CPDFSDK_Document* pDocument) : m_pDocument(pDocument), m_pInterForm(NULL), m_bCalculate(TRUE), m_bBusy(FALSE) { m_pInterForm = new CPDF_InterForm(m_pDocument->GetPDFDocument(), FALSE); m_pInterForm->SetFormNotify(this); for (int i = 0; i < kNumFieldTypes; ++i) m_bNeedHightlight[i] = FALSE; m_iHighlightAlpha = 0; } CPDFSDK_InterForm::~CPDFSDK_InterForm() { delete m_pInterForm; m_pInterForm = nullptr; m_Map.clear(); } FX_BOOL CPDFSDK_InterForm::HighlightWidgets() { return FALSE; } CPDFSDK_Widget* CPDFSDK_InterForm::GetSibling(CPDFSDK_Widget* pWidget, FX_BOOL bNext) const { std::unique_ptr pIterator( new CBA_AnnotIterator(pWidget->GetPageView(), "Widget", "")); if (bNext) { return (CPDFSDK_Widget*)pIterator->GetNextAnnot(pWidget); } return (CPDFSDK_Widget*)pIterator->GetPrevAnnot(pWidget); } CPDFSDK_Widget* CPDFSDK_InterForm::GetWidget(CPDF_FormControl* pControl) const { if (!pControl || !m_pInterForm) return nullptr; CPDFSDK_Widget* pWidget = nullptr; const auto it = m_Map.find(pControl); if (it != m_Map.end()) pWidget = it->second; if (pWidget) return pWidget; CPDF_Dictionary* pControlDict = pControl->GetWidget(); CPDF_Document* pDocument = m_pDocument->GetPDFDocument(); CPDFSDK_PageView* pPage = nullptr; if (CPDF_Dictionary* pPageDict = pControlDict->GetDictBy("P")) { int nPageIndex = pDocument->GetPageIndex(pPageDict->GetObjNum()); if (nPageIndex >= 0) { pPage = m_pDocument->GetPageView(nPageIndex); } } if (!pPage) { int nPageIndex = GetPageIndexByAnnotDict(pDocument, pControlDict); if (nPageIndex >= 0) { pPage = m_pDocument->GetPageView(nPageIndex); } } if (!pPage) return nullptr; return (CPDFSDK_Widget*)pPage->GetAnnotByDict(pControlDict); } void CPDFSDK_InterForm::GetWidgets( const CFX_WideString& sFieldName, std::vector* widgets) const { for (int i = 0, sz = m_pInterForm->CountFields(sFieldName); i < sz; ++i) { CPDF_FormField* pFormField = m_pInterForm->GetField(i, sFieldName); ASSERT(pFormField); GetWidgets(pFormField, widgets); } } void CPDFSDK_InterForm::GetWidgets( CPDF_FormField* pField, std::vector* widgets) const { for (int i = 0, sz = pField->CountControls(); i < sz; ++i) { CPDF_FormControl* pFormCtrl = pField->GetControl(i); ASSERT(pFormCtrl); CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl); if (pWidget) widgets->push_back(pWidget); } } int CPDFSDK_InterForm::GetPageIndexByAnnotDict( CPDF_Document* pDocument, CPDF_Dictionary* pAnnotDict) const { ASSERT(pAnnotDict); for (int i = 0, sz = pDocument->GetPageCount(); i < sz; i++) { if (CPDF_Dictionary* pPageDict = pDocument->GetPage(i)) { if (CPDF_Array* pAnnots = pPageDict->GetArrayBy("Annots")) { for (int j = 0, jsz = pAnnots->GetCount(); j < jsz; j++) { CPDF_Object* pDict = pAnnots->GetElementValue(j); if (pAnnotDict == pDict) { return i; } } } } } return -1; } void CPDFSDK_InterForm::AddMap(CPDF_FormControl* pControl, CPDFSDK_Widget* pWidget) { m_Map[pControl] = pWidget; } void CPDFSDK_InterForm::RemoveMap(CPDF_FormControl* pControl) { m_Map.erase(pControl); } void CPDFSDK_InterForm::EnableCalculate(FX_BOOL bEnabled) { m_bCalculate = bEnabled; } FX_BOOL CPDFSDK_InterForm::IsCalculateEnabled() const { return m_bCalculate; } void CPDFSDK_InterForm::OnCalculate(CPDF_FormField* pFormField) { CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); ASSERT(pEnv); if (!pEnv->IsJSInitiated()) return; if (m_bBusy) return; m_bBusy = TRUE; if (IsCalculateEnabled()) { IJS_Runtime* pRuntime = m_pDocument->GetJsRuntime(); pRuntime->SetReaderDocument(m_pDocument); int nSize = m_pInterForm->CountFieldsInCalculationOrder(); for (int i = 0; i < nSize; i++) { if (CPDF_FormField* pField = m_pInterForm->GetFieldInCalculationOrder(i)) { int nType = pField->GetFieldType(); if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) { CPDF_AAction aAction = pField->GetAdditionalAction(); if (aAction && aAction.ActionExist(CPDF_AAction::Calculate)) { CPDF_Action action = aAction.GetAction(CPDF_AAction::Calculate); if (action) { CFX_WideString csJS = action.GetJavaScript(); if (!csJS.IsEmpty()) { IJS_Context* pContext = pRuntime->NewContext(); CFX_WideString sOldValue = pField->GetValue(); CFX_WideString sValue = sOldValue; FX_BOOL bRC = TRUE; pContext->OnField_Calculate(pFormField, pField, sValue, bRC); CFX_WideString sInfo; FX_BOOL bRet = pContext->RunScript(csJS, &sInfo); pRuntime->ReleaseContext(pContext); if (bRet) { if (bRC) { if (sValue.Compare(sOldValue) != 0) pField->SetValue(sValue, TRUE); } } } } } } } } } m_bBusy = FALSE; } CFX_WideString CPDFSDK_InterForm::OnFormat(CPDF_FormField* pFormField, FX_BOOL& bFormated) { CFX_WideString sValue = pFormField->GetValue(); CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); ASSERT(pEnv); if (!pEnv->IsJSInitiated()) { bFormated = FALSE; return sValue; } IJS_Runtime* pRuntime = m_pDocument->GetJsRuntime(); pRuntime->SetReaderDocument(m_pDocument); if (pFormField->GetFieldType() == FIELDTYPE_COMBOBOX) { if (pFormField->CountSelectedItems() > 0) { int index = pFormField->GetSelectedIndex(0); if (index >= 0) sValue = pFormField->GetOptionLabel(index); } } bFormated = FALSE; CPDF_AAction aAction = pFormField->GetAdditionalAction(); if (aAction && aAction.ActionExist(CPDF_AAction::Format)) { CPDF_Action action = aAction.GetAction(CPDF_AAction::Format); if (action) { CFX_WideString script = action.GetJavaScript(); if (!script.IsEmpty()) { CFX_WideString Value = sValue; IJS_Context* pContext = pRuntime->NewContext(); pContext->OnField_Format(pFormField, Value, TRUE); CFX_WideString sInfo; FX_BOOL bRet = pContext->RunScript(script, &sInfo); pRuntime->ReleaseContext(pContext); if (bRet) { sValue = Value; bFormated = TRUE; } } } } return sValue; } void CPDFSDK_InterForm::ResetFieldAppearance(CPDF_FormField* pFormField, const FX_WCHAR* sValue, FX_BOOL bValueChanged) { for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) { CPDF_FormControl* pFormCtrl = pFormField->GetControl(i); ASSERT(pFormCtrl); if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl)) pWidget->ResetAppearance(sValue, bValueChanged); } } void CPDFSDK_InterForm::UpdateField(CPDF_FormField* pFormField) { for (int i = 0, sz = pFormField->CountControls(); i < sz; i++) { CPDF_FormControl* pFormCtrl = pFormField->GetControl(i); ASSERT(pFormCtrl); if (CPDFSDK_Widget* pWidget = GetWidget(pFormCtrl)) { CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); CFFL_IFormFiller* pIFormFiller = pEnv->GetIFormFiller(); UnderlyingPageType* pPage = pWidget->GetUnderlyingPage(); CPDFSDK_PageView* pPageView = m_pDocument->GetPageView(pPage, FALSE); FX_RECT rcBBox = pIFormFiller->GetViewBBox(pPageView, pWidget); pEnv->FFI_Invalidate(pPage, rcBBox.left, rcBBox.top, rcBBox.right, rcBBox.bottom); } } } void CPDFSDK_InterForm::OnKeyStrokeCommit(CPDF_FormField* pFormField, CFX_WideString& csValue, FX_BOOL& bRC) { CPDF_AAction aAction = pFormField->GetAdditionalAction(); if (aAction && aAction.ActionExist(CPDF_AAction::KeyStroke)) { CPDF_Action action = aAction.GetAction(CPDF_AAction::KeyStroke); if (action) { CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander(); PDFSDK_FieldAction fa; fa.bModifier = pEnv->FFI_IsCTRLKeyDown(0); fa.bShift = pEnv->FFI_IsSHIFTKeyDown(0); fa.sValue = csValue; pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::KeyStroke, m_pDocument, pFormField, fa); bRC = fa.bRC; } } } void CPDFSDK_InterForm::OnValidate(CPDF_FormField* pFormField, CFX_WideString& csValue, FX_BOOL& bRC) { CPDF_AAction aAction = pFormField->GetAdditionalAction(); if (aAction && aAction.ActionExist(CPDF_AAction::Validate)) { CPDF_Action action = aAction.GetAction(CPDF_AAction::Validate); if (action) { CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); CPDFSDK_ActionHandler* pActionHandler = pEnv->GetActionHander(); PDFSDK_FieldAction fa; fa.bModifier = pEnv->FFI_IsCTRLKeyDown(0); fa.bShift = pEnv->FFI_IsSHIFTKeyDown(0); fa.sValue = csValue; pActionHandler->DoAction_FieldJavaScript(action, CPDF_AAction::Validate, m_pDocument, pFormField, fa); bRC = fa.bRC; } } } FX_BOOL CPDFSDK_InterForm::DoAction_Hide(const CPDF_Action& action) { ASSERT(action); CPDF_ActionFields af = action.GetWidgets(); std::vector fieldObjects = af.GetAllFields(); std::vector fields = GetFieldFromObjects(fieldObjects); FX_BOOL bHide = action.GetHideStatus(); FX_BOOL bChanged = FALSE; for (CPDF_FormField* pField : fields) { for (int i = 0, sz = pField->CountControls(); i < sz; ++i) { CPDF_FormControl* pControl = pField->GetControl(i); ASSERT(pControl); if (CPDFSDK_Widget* pWidget = GetWidget(pControl)) { int nFlags = pWidget->GetFlags(); nFlags &= ~ANNOTFLAG_INVISIBLE; nFlags &= ~ANNOTFLAG_NOVIEW; if (bHide) nFlags |= ANNOTFLAG_HIDDEN; else nFlags &= ~ANNOTFLAG_HIDDEN; pWidget->SetFlags(nFlags); pWidget->GetPageView()->UpdateView(pWidget); bChanged = TRUE; } } } return bChanged; } FX_BOOL CPDFSDK_InterForm::DoAction_SubmitForm(const CPDF_Action& action) { CFX_WideString sDestination = action.GetFilePath(); if (sDestination.IsEmpty()) return FALSE; CPDF_Dictionary* pActionDict = action.GetDict(); if (pActionDict->KeyExist("Fields")) { CPDF_ActionFields af = action.GetWidgets(); FX_DWORD dwFlags = action.GetFlags(); std::vector fieldObjects = af.GetAllFields(); std::vector fields = GetFieldFromObjects(fieldObjects); if (!fields.empty()) { bool bIncludeOrExclude = !(dwFlags & 0x01); if (m_pInterForm->CheckRequiredFields(&fields, bIncludeOrExclude)) return FALSE; return SubmitFields(sDestination, fields, bIncludeOrExclude, FALSE); } } if (m_pInterForm->CheckRequiredFields(nullptr, true)) return FALSE; return SubmitForm(sDestination, FALSE); } FX_BOOL CPDFSDK_InterForm::SubmitFields( const CFX_WideString& csDestination, const std::vector& fields, FX_BOOL bIncludeOrExclude, FX_BOOL bUrlEncoded) { CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); CFX_ByteTextBuf textBuf; ExportFieldsToFDFTextBuf(fields, bIncludeOrExclude, textBuf); uint8_t* pBuffer = textBuf.GetBuffer(); FX_STRSIZE nBufSize = textBuf.GetLength(); if (bUrlEncoded && !FDFToURLEncodedData(pBuffer, nBufSize)) return FALSE; pEnv->JS_docSubmitForm(pBuffer, nBufSize, csDestination.c_str()); return TRUE; } FX_BOOL CPDFSDK_InterForm::FDFToURLEncodedData(CFX_WideString csFDFFile, CFX_WideString csTxtFile) { return TRUE; } FX_BOOL CPDFSDK_InterForm::FDFToURLEncodedData(uint8_t*& pBuf, FX_STRSIZE& nBufSize) { CFDF_Document* pFDF = CFDF_Document::ParseMemory(pBuf, nBufSize); if (pFDF) { CPDF_Dictionary* pMainDict = pFDF->GetRoot()->GetDictBy("FDF"); if (!pMainDict) return FALSE; // Get fields CPDF_Array* pFields = pMainDict->GetArrayBy("Fields"); if (!pFields) return FALSE; CFX_ByteTextBuf fdfEncodedData; for (FX_DWORD i = 0; i < pFields->GetCount(); i++) { CPDF_Dictionary* pField = pFields->GetDictAt(i); if (!pField) continue; CFX_WideString name; name = pField->GetUnicodeTextBy("T"); CFX_ByteString name_b = CFX_ByteString::FromUnicode(name); CFX_ByteString csBValue = pField->GetStringBy("V"); CFX_WideString csWValue = PDF_DecodeText(csBValue); CFX_ByteString csValue_b = CFX_ByteString::FromUnicode(csWValue); fdfEncodedData = fdfEncodedData << name_b.GetBuffer(name_b.GetLength()); name_b.ReleaseBuffer(); fdfEncodedData = fdfEncodedData << "="; fdfEncodedData = fdfEncodedData << csValue_b.GetBuffer(csValue_b.GetLength()); csValue_b.ReleaseBuffer(); if (i != pFields->GetCount() - 1) fdfEncodedData = fdfEncodedData << "&"; } nBufSize = fdfEncodedData.GetLength(); pBuf = FX_Alloc(uint8_t, nBufSize); FXSYS_memcpy(pBuf, fdfEncodedData.GetBuffer(), nBufSize); } return TRUE; } FX_BOOL CPDFSDK_InterForm::ExportFieldsToFDFTextBuf( const std::vector& fields, FX_BOOL bIncludeOrExclude, CFX_ByteTextBuf& textBuf) { std::unique_ptr pFDF(m_pInterForm->ExportToFDF( m_pDocument->GetPath(), fields, bIncludeOrExclude)); return pFDF ? pFDF->WriteBuf(textBuf) : FALSE; } CFX_WideString CPDFSDK_InterForm::GetTemporaryFileName( const CFX_WideString& sFileExt) { CFX_WideString sFileName; return L""; } FX_BOOL CPDFSDK_InterForm::SubmitForm(const CFX_WideString& sDestination, FX_BOOL bUrlEncoded) { if (sDestination.IsEmpty()) return FALSE; if (!m_pDocument || !m_pInterForm) return FALSE; CPDFDoc_Environment* pEnv = m_pDocument->GetEnv(); CFX_WideString wsPDFFilePath = m_pDocument->GetPath(); CFDF_Document* pFDFDoc = m_pInterForm->ExportToFDF(wsPDFFilePath); if (!pFDFDoc) return FALSE; CFX_ByteTextBuf FdfBuffer; FX_BOOL bRet = pFDFDoc->WriteBuf(FdfBuffer); delete pFDFDoc; if (!bRet) return FALSE; uint8_t* pBuffer = FdfBuffer.GetBuffer(); FX_STRSIZE nBufSize = FdfBuffer.GetLength(); if (bUrlEncoded) { if (!FDFToURLEncodedData(pBuffer, nBufSize)) return FALSE; } pEnv->JS_docSubmitForm(pBuffer, nBufSize, sDestination.c_str()); if (bUrlEncoded) { FX_Free(pBuffer); pBuffer = NULL; } return TRUE; } FX_BOOL CPDFSDK_InterForm::ExportFormToFDFTextBuf(CFX_ByteTextBuf& textBuf) { CFDF_Document* pFDF = m_pInterForm->ExportToFDF(m_pDocument->GetPath()); if (!pFDF) return FALSE; FX_BOOL bRet = pFDF->WriteBuf(textBuf); delete pFDF; return bRet; } FX_BOOL CPDFSDK_InterForm::DoAction_ResetForm(const CPDF_Action& action) { ASSERT(action); CPDF_Dictionary* pActionDict = action.GetDict(); if (!pActionDict->KeyExist("Fields")) return m_pInterForm->ResetForm(true); CPDF_ActionFields af = action.GetWidgets(); FX_DWORD dwFlags = action.GetFlags(); std::vector fieldObjects = af.GetAllFields(); std::vector fields = GetFieldFromObjects(fieldObjects); return m_pInterForm->ResetForm(fields, !(dwFlags & 0x01), true); } FX_BOOL CPDFSDK_InterForm::DoAction_ImportData(const CPDF_Action& action) { return FALSE; } std::vector CPDFSDK_InterForm::GetFieldFromObjects( const std::vector& objects) const { std::vector fields; for (CPDF_Object* pObject : objects) { if (pObject && pObject->IsString()) { CFX_WideString csName = pObject->GetUnicodeText(); CPDF_FormField* pField = m_pInterForm->GetField(0, csName); if (pField) fields.push_back(pField); } } return fields; } int CPDFSDK_InterForm::BeforeValueChange(const CPDF_FormField* pField, CFX_WideString& csValue) { CPDF_FormField* pFormField = (CPDF_FormField*)pField; int nType = pFormField->GetFieldType(); if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) { FX_BOOL bRC = TRUE; OnKeyStrokeCommit(pFormField, csValue, bRC); if (bRC) { OnValidate(pFormField, csValue, bRC); return bRC ? 1 : -1; } return -1; } return 0; } int CPDFSDK_InterForm::AfterValueChange(const CPDF_FormField* pField) { CPDF_FormField* pFormField = (CPDF_FormField*)pField; int nType = pFormField->GetFieldType(); if (nType == FIELDTYPE_COMBOBOX || nType == FIELDTYPE_TEXTFIELD) { OnCalculate(pFormField); FX_BOOL bFormated = FALSE; CFX_WideString sValue = OnFormat(pFormField, bFormated); if (bFormated) ResetFieldAppearance(pFormField, sValue.c_str(), TRUE); else ResetFieldAppearance(pFormField, NULL, TRUE); UpdateField(pFormField); } return 0; } int CPDFSDK_InterForm::BeforeSelectionChange(const CPDF_FormField* pField, CFX_WideString& csValue) { CPDF_FormField* pFormField = (CPDF_FormField*)pField; if (pFormField->GetFieldType() != FIELDTYPE_LISTBOX) return 0; FX_BOOL bRC = TRUE; OnKeyStrokeCommit(pFormField, csValue, bRC); if (!bRC) return -1; OnValidate(pFormField, csValue, bRC); if (!bRC) return -1; return 1; } int CPDFSDK_InterForm::AfterSelectionChange(const CPDF_FormField* pField) { CPDF_FormField* pFormField = (CPDF_FormField*)pField; if (pFormField->GetFieldType() == FIELDTYPE_LISTBOX) { OnCalculate(pFormField); ResetFieldAppearance(pFormField, NULL, TRUE); UpdateField(pFormField); } return 0; } void CPDFSDK_InterForm::AfterCheckedStatusChange(CPDF_FormField* pField) { int nType = pField->GetFieldType(); if (nType == FIELDTYPE_CHECKBOX || nType == FIELDTYPE_RADIOBUTTON) { OnCalculate(pField); UpdateField(pField); } } int CPDFSDK_InterForm::BeforeFormReset(const CPDF_InterForm* pForm) { return 0; } int CPDFSDK_InterForm::AfterFormReset(const CPDF_InterForm* pForm) { OnCalculate(nullptr); return 0; } int CPDFSDK_InterForm::BeforeFormImportData(const CPDF_InterForm* pForm) { return 0; } int CPDFSDK_InterForm::AfterFormImportData(const CPDF_InterForm* pForm) { OnCalculate(nullptr); return 0; } FX_BOOL CPDFSDK_InterForm::IsNeedHighLight(int nFieldType) { if (nFieldType < 1 || nFieldType > kNumFieldTypes) return FALSE; return m_bNeedHightlight[nFieldType - 1]; } void CPDFSDK_InterForm::RemoveAllHighLight() { for (int i = 0; i < kNumFieldTypes; ++i) m_bNeedHightlight[i] = FALSE; } void CPDFSDK_InterForm::SetHighlightColor(FX_COLORREF clr, int nFieldType) { if (nFieldType < 0 || nFieldType > kNumFieldTypes) return; switch (nFieldType) { case 0: { for (int i = 0; i < kNumFieldTypes; ++i) { m_aHighlightColor[i] = clr; m_bNeedHightlight[i] = TRUE; } break; } default: { m_aHighlightColor[nFieldType - 1] = clr; m_bNeedHightlight[nFieldType - 1] = TRUE; break; } } } FX_COLORREF CPDFSDK_InterForm::GetHighlightColor(int nFieldType) { if (nFieldType < 0 || nFieldType > kNumFieldTypes) return FXSYS_RGB(255, 255, 255); if (nFieldType == 0) return m_aHighlightColor[0]; return m_aHighlightColor[nFieldType - 1]; } CBA_AnnotIterator::CBA_AnnotIterator(CPDFSDK_PageView* pPageView, const CFX_ByteString& sType, const CFX_ByteString& sSubType) : m_eTabOrder(STRUCTURE), m_pPageView(pPageView), m_sType(sType), m_sSubType(sSubType) { CPDF_Page* pPDFPage = m_pPageView->GetPDFPage(); CFX_ByteString sTabs = pPDFPage->m_pFormDict->GetStringBy("Tabs"); if (sTabs == "R") m_eTabOrder = ROW; else if (sTabs == "C") m_eTabOrder = COLUMN; GenerateResults(); } CBA_AnnotIterator::~CBA_AnnotIterator() { } CPDFSDK_Annot* CBA_AnnotIterator::GetFirstAnnot() { return m_Annots.empty() ? nullptr : m_Annots.front(); } CPDFSDK_Annot* CBA_AnnotIterator::GetLastAnnot() { return m_Annots.empty() ? nullptr : m_Annots.back(); } CPDFSDK_Annot* CBA_AnnotIterator::GetNextAnnot(CPDFSDK_Annot* pAnnot) { auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot); if (iter == m_Annots.end()) return nullptr; ++iter; if (iter == m_Annots.end()) iter = m_Annots.begin(); return *iter; } CPDFSDK_Annot* CBA_AnnotIterator::GetPrevAnnot(CPDFSDK_Annot* pAnnot) { auto iter = std::find(m_Annots.begin(), m_Annots.end(), pAnnot); if (iter == m_Annots.end()) return nullptr; if (iter == m_Annots.begin()) iter = m_Annots.end(); return *(--iter); } // static bool CBA_AnnotIterator::CompareByLeftAscending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) { return GetAnnotRect(p1).left < GetAnnotRect(p2).left; } // static bool CBA_AnnotIterator::CompareByTopDescending(const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) { return GetAnnotRect(p1).top > GetAnnotRect(p2).top; } void CBA_AnnotIterator::GenerateResults() { switch (m_eTabOrder) { case STRUCTURE: { for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) { CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i); if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType) m_Annots.push_back(pAnnot); } } break; case ROW: { std::vector sa; for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) { CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i); if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType) sa.push_back(pAnnot); } std::sort(sa.begin(), sa.end(), CompareByLeftAscending); while (!sa.empty()) { int nLeftTopIndex = -1; FX_FLOAT fTop = 0.0f; for (int i = sa.size() - 1; i >= 0; i--) { CPDF_Rect rcAnnot = GetAnnotRect(sa[i]); if (rcAnnot.top > fTop) { nLeftTopIndex = i; fTop = rcAnnot.top; } } if (nLeftTopIndex >= 0) { CPDFSDK_Annot* pLeftTopAnnot = sa[nLeftTopIndex]; CPDF_Rect rcLeftTop = GetAnnotRect(pLeftTopAnnot); m_Annots.push_back(pLeftTopAnnot); sa.erase(sa.begin() + nLeftTopIndex); std::vector aSelect; for (int i = 0; i < sa.size(); ++i) { CPDF_Rect rcAnnot = GetAnnotRect(sa[i]); FX_FLOAT fCenterY = (rcAnnot.top + rcAnnot.bottom) / 2.0f; if (fCenterY > rcLeftTop.bottom && fCenterY < rcLeftTop.top) aSelect.push_back(i); } for (int i = 0; i < aSelect.size(); ++i) m_Annots.push_back(sa[aSelect[i]]); for (int i = aSelect.size() - 1; i >= 0; --i) sa.erase(sa.begin() + aSelect[i]); } } } break; case COLUMN: { std::vector sa; for (size_t i = 0; i < m_pPageView->CountAnnots(); ++i) { CPDFSDK_Annot* pAnnot = m_pPageView->GetAnnot(i); if (pAnnot->GetType() == m_sType && pAnnot->GetSubType() == m_sSubType) sa.push_back(pAnnot); } std::sort(sa.begin(), sa.end(), CompareByTopDescending); while (!sa.empty()) { int nLeftTopIndex = -1; FX_FLOAT fLeft = -1.0f; for (int i = sa.size() - 1; i >= 0; --i) { CPDF_Rect rcAnnot = GetAnnotRect(sa[i]); if (fLeft < 0) { nLeftTopIndex = 0; fLeft = rcAnnot.left; } else if (rcAnnot.left < fLeft) { nLeftTopIndex = i; fLeft = rcAnnot.left; } } if (nLeftTopIndex >= 0) { CPDFSDK_Annot* pLeftTopAnnot = sa[nLeftTopIndex]; CPDF_Rect rcLeftTop = GetAnnotRect(pLeftTopAnnot); m_Annots.push_back(pLeftTopAnnot); sa.erase(sa.begin() + nLeftTopIndex); std::vector aSelect; for (int i = 0; i < sa.size(); ++i) { CPDF_Rect rcAnnot = GetAnnotRect(sa[i]); FX_FLOAT fCenterX = (rcAnnot.left + rcAnnot.right) / 2.0f; if (fCenterX > rcLeftTop.left && fCenterX < rcLeftTop.right) aSelect.push_back(i); } for (int i = 0; i < aSelect.size(); ++i) m_Annots.push_back(sa[aSelect[i]]); for (int i = aSelect.size() - 1; i >= 0; --i) sa.erase(sa.begin() + aSelect[i]); } } break; } } } CPDF_Rect CBA_AnnotIterator::GetAnnotRect(const CPDFSDK_Annot* pAnnot) { CPDF_Rect rcAnnot; pAnnot->GetPDFAnnot()->GetRect(rcAnnot); return rcAnnot; }