// Copyright 2014 The PDFium Authors // 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 "public/fpdf_formfill.h" #include #include #include "constants/form_fields.h" #include "core/fpdfapi/page/cpdf_annotcontext.h" #include "core/fpdfapi/page/cpdf_occontext.h" #include "core/fpdfapi/page/cpdf_page.h" #include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" #include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/render/cpdf_renderoptions.h" #include "core/fpdfdoc/cpdf_formcontrol.h" #include "core/fpdfdoc/cpdf_formfield.h" #include "core/fpdfdoc/cpdf_interactiveform.h" #include "core/fxge/cfx_defaultrenderdevice.h" #include "fpdfsdk/cpdfsdk_annot.h" #include "fpdfsdk/cpdfsdk_formfillenvironment.h" #include "fpdfsdk/cpdfsdk_helpers.h" #include "fpdfsdk/cpdfsdk_interactiveform.h" #include "fpdfsdk/cpdfsdk_pageview.h" #include "public/fpdfview.h" #ifdef PDF_ENABLE_XFA #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h" #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h" static_assert(static_cast(AlertButton::kDefault) == JSPLATFORM_ALERT_BUTTON_DEFAULT, "Default alert button types must match"); static_assert(static_cast(AlertButton::kOK) == JSPLATFORM_ALERT_BUTTON_OK, "OK alert button types must match"); static_assert(static_cast(AlertButton::kOKCancel) == JSPLATFORM_ALERT_BUTTON_OKCANCEL, "OKCancel alert button types must match"); static_assert(static_cast(AlertButton::kYesNo) == JSPLATFORM_ALERT_BUTTON_YESNO, "YesNo alert button types must match"); static_assert(static_cast(AlertButton::kYesNoCancel) == JSPLATFORM_ALERT_BUTTON_YESNOCANCEL, "YesNoCancel alert button types must match"); static_assert(static_cast(AlertIcon::kDefault) == JSPLATFORM_ALERT_ICON_DEFAULT, "Default alert icon types must match"); static_assert(static_cast(AlertIcon::kError) == JSPLATFORM_ALERT_ICON_ERROR, "Error alert icon types must match"); static_assert(static_cast(AlertIcon::kWarning) == JSPLATFORM_ALERT_ICON_WARNING, "Warning alert icon types must match"); static_assert(static_cast(AlertIcon::kQuestion) == JSPLATFORM_ALERT_ICON_QUESTION, "Question alert icon types must match"); static_assert(static_cast(AlertIcon::kStatus) == JSPLATFORM_ALERT_ICON_STATUS, "Status alert icon types must match"); static_assert(static_cast(AlertIcon::kAsterisk) == JSPLATFORM_ALERT_ICON_ASTERISK, "Asterisk alert icon types must match"); static_assert(static_cast(AlertReturn::kOK) == JSPLATFORM_ALERT_RETURN_OK, "OK alert return types must match"); static_assert(static_cast(AlertReturn::kCancel) == JSPLATFORM_ALERT_RETURN_CANCEL, "Cancel alert return types must match"); static_assert(static_cast(AlertReturn::kNo) == JSPLATFORM_ALERT_RETURN_NO, "No alert return types must match"); static_assert(static_cast(AlertReturn::kYes) == JSPLATFORM_ALERT_RETURN_YES, "Yes alert return types must match"); static_assert(static_cast(FormType::kNone) == FORMTYPE_NONE, "None form types must match"); static_assert(static_cast(FormType::kAcroForm) == FORMTYPE_ACRO_FORM, "AcroForm form types must match"); static_assert(static_cast(FormType::kXFAFull) == FORMTYPE_XFA_FULL, "XFA full form types must match"); static_assert(static_cast(FormType::kXFAForeground) == FORMTYPE_XFA_FOREGROUND, "XFA foreground form types must match"); #endif // PDF_ENABLE_XFA static_assert(static_cast(FormFieldType::kUnknown) == FPDF_FORMFIELD_UNKNOWN, "Unknown form field types must match"); static_assert(static_cast(FormFieldType::kPushButton) == FPDF_FORMFIELD_PUSHBUTTON, "PushButton form field types must match"); static_assert(static_cast(FormFieldType::kCheckBox) == FPDF_FORMFIELD_CHECKBOX, "CheckBox form field types must match"); static_assert(static_cast(FormFieldType::kRadioButton) == FPDF_FORMFIELD_RADIOBUTTON, "RadioButton form field types must match"); static_assert(static_cast(FormFieldType::kComboBox) == FPDF_FORMFIELD_COMBOBOX, "ComboBox form field types must match"); static_assert(static_cast(FormFieldType::kListBox) == FPDF_FORMFIELD_LISTBOX, "ListBox form field types must match"); static_assert(static_cast(FormFieldType::kTextField) == FPDF_FORMFIELD_TEXTFIELD, "TextField form field types must match"); static_assert(static_cast(FormFieldType::kSignature) == FPDF_FORMFIELD_SIGNATURE, "Signature form field types must match"); #ifdef PDF_ENABLE_XFA static_assert(static_cast(FormFieldType::kXFA) == FPDF_FORMFIELD_XFA, "XFA form field types must match"); static_assert(static_cast(FormFieldType::kXFA_CheckBox) == FPDF_FORMFIELD_XFA_CHECKBOX, "XFA CheckBox form field types must match"); static_assert(static_cast(FormFieldType::kXFA_ComboBox) == FPDF_FORMFIELD_XFA_COMBOBOX, "XFA ComboBox form field types must match"); static_assert(static_cast(FormFieldType::kXFA_ImageField) == FPDF_FORMFIELD_XFA_IMAGEFIELD, "XFA ImageField form field types must match"); static_assert(static_cast(FormFieldType::kXFA_ListBox) == FPDF_FORMFIELD_XFA_LISTBOX, "XFA ListBox form field types must match"); static_assert(static_cast(FormFieldType::kXFA_PushButton) == FPDF_FORMFIELD_XFA_PUSHBUTTON, "XFA PushButton form field types must match"); static_assert(static_cast(FormFieldType::kXFA_Signature) == FPDF_FORMFIELD_XFA_SIGNATURE, "XFA Signature form field types must match"); static_assert(static_cast(FormFieldType::kXFA_TextField) == FPDF_FORMFIELD_XFA_TEXTFIELD, "XFA TextField form field types must match"); #endif // PDF_ENABLE_XFA static_assert(kFormFieldTypeCount == FPDF_FORMFIELD_COUNT, "Number of form field types must match"); static_assert(static_cast(CPDF_AAction::kCloseDocument) == FPDFDOC_AACTION_WC, "CloseDocument action must match"); static_assert(static_cast(CPDF_AAction::kSaveDocument) == FPDFDOC_AACTION_WS, "SaveDocument action must match"); static_assert(static_cast(CPDF_AAction::kDocumentSaved) == FPDFDOC_AACTION_DS, "DocumentSaved action must match"); static_assert(static_cast(CPDF_AAction::kPrintDocument) == FPDFDOC_AACTION_WP, "PrintDocument action must match"); static_assert(static_cast(CPDF_AAction::kDocumentPrinted) == FPDFDOC_AACTION_DP, "DocumentPrinted action must match"); namespace { CPDFSDK_PageView* FormHandleToPageView(FPDF_FORMHANDLE hHandle, FPDF_PAGE fpdf_page) { IPDF_Page* pPage = IPDFPageFromFPDFPage(fpdf_page); if (!pPage) return nullptr; CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); return pFormFillEnv ? pFormFillEnv->GetOrCreatePageView(pPage) : nullptr; } void FFLCommon(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_RECORDER recorder, FPDF_PAGE fpdf_page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags) { if (!hHandle) return; IPDF_Page* pPage = IPDFPageFromFPDFPage(fpdf_page); if (!pPage) return; CPDF_Document* pPDFDoc = pPage->GetDocument(); CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, fpdf_page); const FX_RECT rect(start_x, start_y, start_x + size_x, start_y + size_y); CFX_Matrix matrix = pPage->GetDisplayMatrix(rect, rotate); auto pDevice = std::make_unique(); #if defined(_SKIA_SUPPORT_) if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) pDevice->AttachRecorder(static_cast(recorder)); #endif RetainPtr holder(CFXDIBitmapFromFPDFBitmap(bitmap)); pDevice->AttachWithRgbByteOrder(holder, !!(flags & FPDF_REVERSE_BYTE_ORDER)); { CFX_RenderDevice::StateRestorer restorer(pDevice.get()); pDevice->SetClip_Rect(rect); CPDF_RenderOptions options; options.GetOptions().bClearType = !!(flags & FPDF_LCD_TEXT); // Grayscale output if (flags & FPDF_GRAYSCALE) options.SetColorMode(CPDF_RenderOptions::kGray); options.SetDrawAnnots(flags & FPDF_ANNOT); options.SetOCContext( pdfium::MakeRetain(pPDFDoc, CPDF_OCContext::kView)); if (pPageView) pPageView->PageView_OnDraw(pDevice.get(), matrix, &options, rect); } } // Returns true if formfill version is correctly set. See |version| in // FPDF_FORMFILLINFO for details regarding correct version. bool CheckFormfillVersion(FPDF_FORMFILLINFO* formInfo) { if (!formInfo || formInfo->version < 1 || formInfo->version > 2) return false; #ifdef PDF_ENABLE_XFA if (formInfo->version != 2) return false; #endif // PDF_ENABLE_XFA return true; } } // namespace FPDF_EXPORT int FPDF_CALLCONV FPDFPage_HasFormFieldAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y) { const CPDF_Page* pPage = CPDFPageFromFPDFPage(page); if (pPage) { CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle); if (!pForm) return -1; const CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm(); const CPDF_FormControl* pFormCtrl = pPDFForm->GetControlAtPoint( pPage, CFX_PointF(static_cast(page_x), static_cast(page_y)), nullptr); if (!pFormCtrl) return -1; const CPDF_FormField* pFormField = pFormCtrl->GetField(); return pFormField ? static_cast(pFormField->GetFieldType()) : -1; } #ifdef PDF_ENABLE_XFA const CPDFXFA_Page* pXFAPage = ToXFAPage(IPDFPageFromFPDFPage(page)); if (pXFAPage) { return pXFAPage->HasFormFieldAtPoint( CFX_PointF(static_cast(page_x), static_cast(page_y))); } #endif // PDF_ENABLE_XFA return -1; } FPDF_EXPORT int FPDF_CALLCONV FPDFPage_FormFieldZOrderAtPoint(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, double page_x, double page_y) { CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle); if (!pForm) return -1; CPDF_Page* pPage = CPDFPageFromFPDFPage(page); if (!pPage) return -1; CPDF_InteractiveForm* pPDFForm = pForm->GetInteractiveForm(); int z_order = -1; pPDFForm->GetControlAtPoint( pPage, CFX_PointF(static_cast(page_x), static_cast(page_y)), &z_order); return z_order; } FPDF_EXPORT FPDF_FORMHANDLE FPDF_CALLCONV FPDFDOC_InitFormFillEnvironment(FPDF_DOCUMENT document, FPDF_FORMFILLINFO* formInfo) { if (!CheckFormfillVersion(formInfo)) return nullptr; auto* pDocument = CPDFDocumentFromFPDFDocument(document); if (!pDocument) return nullptr; #ifdef PDF_ENABLE_XFA CPDFXFA_Context* pContext = nullptr; if (!formInfo->xfa_disabled) { if (!pDocument->GetExtension()) { pDocument->SetExtension(std::make_unique(pDocument)); } // If the CPDFXFA_Context has a FormFillEnvironment already then we've done // this and can just return the old Env. Otherwise, we'll end up setting a // new environment into the XFADocument and, that could get weird. pContext = static_cast(pDocument->GetExtension()); if (pContext->GetFormFillEnv()) { return FPDFFormHandleFromCPDFSDKFormFillEnvironment( pContext->GetFormFillEnv()); } } #endif // PDF_ENABLE_XFA auto pFormFillEnv = std::make_unique(pDocument, formInfo); #ifdef PDF_ENABLE_XFA if (pContext) pContext->SetFormFillEnv(pFormFillEnv.get()); #endif // PDF_ENABLE_XFA ReportUnsupportedXFA(pDocument); return FPDFFormHandleFromCPDFSDKFormFillEnvironment( pFormFillEnv.release()); // Caller takes ownership. } FPDF_EXPORT void FPDF_CALLCONV FPDFDOC_ExitFormFillEnvironment(FPDF_FORMHANDLE hHandle) { if (!hHandle) return; // Take back ownership of the form fill environment. This is the inverse of // FPDFDOC_InitFormFillEnvironment() above. std::unique_ptr pFormFillEnv( CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle)); #ifdef PDF_ENABLE_XFA // Reset the focused annotations and remove the SDK document from the // XFA document. pFormFillEnv->ClearAllFocusedAnnots(); // If the document was closed first, it's possible the XFA document // is now a nullptr. auto* pContext = static_cast(pFormFillEnv->GetDocExtension()); if (pContext) pContext->SetFormFillEnv(nullptr); #endif // PDF_ENABLE_XFA } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseMove(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnMouseMove( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnMouseWheel(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, const FS_POINTF* page_coord, int delta_x, int delta_y) { if (!page_coord) return false; CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnMouseWheel( Mask::FromUnderlyingUnchecked(modifier), CFXPointFFromFSPointF(*page_coord), CFX_Vector(delta_x, delta_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnFocus(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnFocus( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { #ifdef PDF_ENABLE_CLICK_LOGGING fprintf(stderr, "mousedown,left,%d,%d\n", static_cast(round(page_x)), static_cast(round(page_y))); #endif // PDF_ENABLE_CLICK_LOGGING CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnLButtonDown( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { #ifdef PDF_ENABLE_CLICK_LOGGING fprintf(stderr, "mouseup,left,%d,%d\n", static_cast(round(page_x)), static_cast(round(page_y))); #endif // PDF_ENABLE_CLICK_LOGGING CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnLButtonUp( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnLButtonDoubleClick(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { #ifdef PDF_ENABLE_CLICK_LOGGING fprintf(stderr, "mousedown,doubleleft,%d,%d\n", static_cast(round(page_x)), static_cast(round(page_y))); #endif // PDF_ENABLE_CLICK_LOGGING CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnLButtonDblClk( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { #ifdef PDF_ENABLE_CLICK_LOGGING fprintf(stderr, "mousedown,right,%d,%d\n", static_cast(round(page_x)), static_cast(round(page_y))); #endif // PDF_ENABLE_CLICK_LOGGING CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnRButtonDown( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnRButtonUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int modifier, double page_x, double page_y) { #ifdef PDF_ENABLE_CLICK_LOGGING fprintf(stderr, "mouseup,right,%d,%d\n", static_cast(round(page_x)), static_cast(round(page_y))); #endif // PDF_ENABLE_CLICK_LOGGING CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnRButtonUp( Mask::FromUnderlyingUnchecked(modifier), CFX_PointF(page_x, page_y)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyDown(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnKeyDown( static_cast(nKeyCode), Mask::FromUnderlyingUnchecked(modifier)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnKeyUp(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nKeyCode, int modifier) { return false; } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_OnChar(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int nChar, int modifier) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->OnChar( nChar, Mask::FromUnderlyingUnchecked(modifier)); } FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetFocusedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return 0; return Utf16EncodeMaybeCopyAndReturnLength(pPageView->GetFocusedFormText(), buffer, buflen); } FPDF_EXPORT unsigned long FPDF_CALLCONV FORM_GetSelectedText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, void* buffer, unsigned long buflen) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return 0; return Utf16EncodeMaybeCopyAndReturnLength(pPageView->GetSelectedText(), buffer, buflen); } FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceAndKeepSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return; pPageView->ReplaceAndKeepSelection(WideStringFromFPDFWideString(wsText)); } FPDF_EXPORT void FPDF_CALLCONV FORM_ReplaceSelection(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, FPDF_WIDESTRING wsText) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return; pPageView->ReplaceSelection(WideStringFromFPDFWideString(wsText)); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SelectAllText(FPDF_FORMHANDLE hHandle, FPDF_PAGE page) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->SelectAllText(); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanUndo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return false; return pPageView->CanUndo(); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_CanRedo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return false; return pPageView->CanRedo(); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Undo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return false; return pPageView->Undo(); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_Redo(FPDF_FORMHANDLE hHandle, FPDF_PAGE page) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); if (!pPageView) return false; return pPageView->Redo(); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_ForceToKillFocus(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (!pFormFillEnv) return false; return pFormFillEnv->KillFocusAnnot({}); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_GetFocusedAnnot(FPDF_FORMHANDLE handle, int* page_index, FPDF_ANNOTATION* annot) { if (!page_index || !annot) return false; CPDFSDK_FormFillEnvironment* form_fill_env = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(handle); if (!form_fill_env) return false; // Set |page_index| and |annot| to default values. This is returned when there // is no focused annotation. *page_index = -1; *annot = nullptr; CPDFSDK_Annot* cpdfsdk_annot = form_fill_env->GetFocusAnnot(); if (!cpdfsdk_annot) return true; // TODO(crbug.com/pdfium/1482): Handle XFA case. if (cpdfsdk_annot->AsXFAWidget()) return true; CPDFSDK_PageView* page_view = cpdfsdk_annot->GetPageView(); if (!page_view->IsValid()) return true; IPDF_Page* page = cpdfsdk_annot->GetPage(); if (!page) return true; RetainPtr annot_dict = cpdfsdk_annot->GetPDFAnnot()->GetMutableAnnotDict(); auto annot_context = std::make_unique(std::move(annot_dict), page); *page_index = page_view->GetPageIndex(); // Caller takes ownership. *annot = FPDFAnnotationFromCPDFAnnotContext(annot_context.release()); return true; } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetFocusedAnnot(FPDF_FORMHANDLE handle, FPDF_ANNOTATION annot) { CPDFSDK_FormFillEnvironment* form_fill_env = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(handle); if (!form_fill_env) return false; CPDF_AnnotContext* annot_context = CPDFAnnotContextFromFPDFAnnotation(annot); if (!annot_context) return false; CPDFSDK_PageView* page_view = form_fill_env->GetOrCreatePageView(annot_context->GetPage()); if (!page_view->IsValid()) return false; RetainPtr annot_dict = annot_context->GetMutableAnnotDict(); ObservedPtr cpdfsdk_annot( page_view->GetAnnotByDict(annot_dict.Get())); if (!cpdfsdk_annot) return false; return form_fill_env->SetFocusAnnot(cpdfsdk_annot); } FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLDraw(FPDF_FORMHANDLE hHandle, FPDF_BITMAP bitmap, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags) { FFLCommon(hHandle, bitmap, nullptr, page, start_x, start_y, size_x, size_y, rotate, flags); } #if defined(_SKIA_SUPPORT_) FPDF_EXPORT void FPDF_CALLCONV FPDF_FFLRecord(FPDF_FORMHANDLE hHandle, FPDF_RECORDER recorder, FPDF_PAGE page, int start_x, int start_y, int size_x, int size_y, int rotate, int flags) { FFLCommon(hHandle, nullptr, recorder, page, start_x, start_y, size_x, size_y, rotate, flags); } #endif FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightColor(FPDF_FORMHANDLE hHandle, int fieldType, unsigned long color) { CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle); if (!pForm) return; absl::optional cast_input = CPDF_FormField::IntToFormFieldType(fieldType); if (!cast_input.has_value()) return; if (cast_input.value() == FormFieldType::kUnknown) { pForm->SetAllHighlightColors(static_cast(color)); } else { pForm->SetHighlightColor(static_cast(color), cast_input.value()); } } FPDF_EXPORT void FPDF_CALLCONV FPDF_SetFormFieldHighlightAlpha(FPDF_FORMHANDLE hHandle, unsigned char alpha) { if (CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle)) pForm->SetHighlightAlpha(alpha); } FPDF_EXPORT void FPDF_CALLCONV FPDF_RemoveFormFieldHighlight(FPDF_FORMHANDLE hHandle) { if (CPDFSDK_InteractiveForm* pForm = FormHandleToInteractiveForm(hHandle)) pForm->RemoveAllHighLights(); } FPDF_EXPORT void FPDF_CALLCONV FORM_OnAfterLoadPage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle) { if (CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page)) pPageView->SetValid(true); } FPDF_EXPORT void FPDF_CALLCONV FORM_OnBeforeClosePage(FPDF_PAGE page, FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (!pFormFillEnv) return; IPDF_Page* pPage = IPDFPageFromFPDFPage(page); if (!pPage) return; CPDFSDK_PageView* pPageView = pFormFillEnv->GetPageView(pPage); if (pPageView) { pPageView->SetValid(false); // RemovePageView() takes care of the delete for us. pFormFillEnv->RemovePageView(pPage); } } FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentJSAction(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (pFormFillEnv && pFormFillEnv->IsJSPlatformPresent()) pFormFillEnv->ProcJavascriptAction(); } FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentOpenAction(FPDF_FORMHANDLE hHandle) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (pFormFillEnv) pFormFillEnv->ProcOpenAction(); } FPDF_EXPORT void FPDF_CALLCONV FORM_DoDocumentAAction(FPDF_FORMHANDLE hHandle, int aaType) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (!pFormFillEnv) return; CPDF_Document* pDoc = pFormFillEnv->GetPDFDocument(); const CPDF_Dictionary* pDict = pDoc->GetRoot(); if (!pDict) return; CPDF_AAction aa(pDict->GetDictFor(pdfium::form_fields::kAA)); auto type = static_cast(aaType); if (aa.ActionExist(type)) pFormFillEnv->DoActionDocument(aa.GetAction(type), type); } FPDF_EXPORT void FPDF_CALLCONV FORM_DoPageAAction(FPDF_PAGE page, FPDF_FORMHANDLE hHandle, int aaType) { CPDFSDK_FormFillEnvironment* pFormFillEnv = CPDFSDKFormFillEnvironmentFromFPDFFormHandle(hHandle); if (!pFormFillEnv) return; IPDF_Page* pPage = IPDFPageFromFPDFPage(page); CPDF_Page* pPDFPage = CPDFPageFromFPDFPage(page); if (!pPDFPage) return; if (!pFormFillEnv->GetPageView(pPage)) return; CPDF_AAction aa(pPDFPage->GetDict()->GetDictFor(pdfium::form_fields::kAA)); CPDF_AAction::AActionType type = aaType == FPDFPAGE_AACTION_OPEN ? CPDF_AAction::kOpenPage : CPDF_AAction::kClosePage; if (aa.ActionExist(type)) pFormFillEnv->DoActionPage(aa.GetAction(type), type); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_SetIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index, FPDF_BOOL selected) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->SetIndexSelected(index, selected); } FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FORM_IsIndexSelected(FPDF_FORMHANDLE hHandle, FPDF_PAGE page, int index) { CPDFSDK_PageView* pPageView = FormHandleToPageView(hHandle, page); return pPageView && pPageView->IsIndexSelected(index); }