1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MEDIAPROVIDER_PDF_JNI_PDFCLIENT_FORM_FILLER_H_
18 #define MEDIAPROVIDER_PDF_JNI_PDFCLIENT_FORM_FILLER_H_
19 
20 #include <span>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "cpp/fpdf_scopers.h"
26 #include "form_widget_info.h"
27 #include "fpdf_formfill.h"
28 #include "fpdfview.h"
29 #include "rect.h"
30 
31 namespace pdfClient {
32 
33 class Document;
34 
35 // Handles all interactions with form filling elements including rendering and
36 // editing.
37 class FormFiller : public FPDF_FORMFILLINFO {
38   public:
39     explicit FormFiller(Document* document, FPDF_DOCUMENT fpdf_document);
40 
41     ~FormFiller();
42 
43     // Must be called before this FormFiller is used to complete any form filling
44     // actions on the |page|.
45     void NotifyAfterPageLoad(FPDF_PAGE page);
46 
47     // Must be called before releasing |page| to release resources when no
48     // further form filling actions will be executed on the |page|.
49     void NotifyBeforePageClose(FPDF_PAGE page);
50 
51     // Renders form widget content.
52     bool RenderTile(FPDF_PAGE page, FPDF_BITMAP bitmap, FS_MATRIX transform, FS_RECTF clip,
53                     int render_mode) const;
54 
55     // Obtain information about the form widget at |point| on the page, if any.
56     // |point| is in page coordinates.
57     FormWidgetInfo GetFormWidgetInfo(FPDF_PAGE page, const Point_d point);
58 
59     // Obtain information about the form widget with index |annotation_index| on
60     // the page, if any.
61     FormWidgetInfo GetFormWidgetInfo(FPDF_PAGE page, const int annotation_index);
62 
63     // Obtain form widget information for |annotation|, if any.
64     FormWidgetInfo GetFormWidgetInfo(FPDF_PAGE page, FPDF_ANNOTATION annotation);
65 
66     // Obtain form widget information for all form field annotations on |page|,
67     // optionally restricting by |type_ids| and store in |widget_infos|. See
68     // fpdf_formfill.h for type constants. If |type_ids| is empty all form
69     // widgets on |page| will be added to |widget_infos|, if any.
70     void GetFormWidgetInfos(FPDF_PAGE page, const std::unordered_set<int>& type_ids,
71                             std::vector<FormWidgetInfo>* widget_infos);
72 
73     // Perform a click at |point| on the page. Any focus in the document
74     // resulting from this operation will be killed before returning (i.e. there
75     // will be no "currently selected widget" resulting from the click). No-op if
76     // no widget present at |point| or widget cannot be edited. Returns true if
77     // click was performed. |point| is in page coordinates.
78     bool ClickOnPoint(FPDF_PAGE page, const Point_d point);
79 
80     // Set the value text of the widget at |annotation_index| on |page|. No-op if
81     // no widget present or widget cannot be edited. Returns true if text was
82     // set, false otherwise.
83     bool SetText(FPDF_PAGE page, const int annotation_index, const std::string_view text);
84 
85     // Set the |selected_indices| for the choice widget at |annotation_index| as
86     // selected and deselect all other indices. No-op if no widget present or
87     // widget cannot be edited. Returns true if indices were set, false otherwise.
88     bool SetChoiceSelection(FPDF_PAGE page, const int annotation_index,
89                             std::span<const int> selected_indices);
90 
91   private:
92     // Returns true if the |annotation| is a widget.
93     bool IsWidget(FPDF_ANNOTATION annotation);
94     // Returns the form annotation at |point|, if present. Else nullptr.
95     ScopedFPDFAnnotation GetFormAnnotation(FPDF_PAGE page, Point_d point);
96     // Returns the form annotation at |index|, if present. Else nullptr.
97     ScopedFPDFAnnotation GetFormAnnotation(FPDF_PAGE page, int index);
98 
99     // Return the type of widget at |point|, if present. Else -1.
100     int GetFormFieldType(FPDF_PAGE page, Point_d point);
101     // Return the type of widget the |annotation| is. -1 if not a widget.
102     int GetFormFieldType(FPDF_PAGE page, FPDF_ANNOTATION annotation);
103 
104     // Get the coordinate rectangle that the |annotation| occupies on the page.
105     // Result is in Page Coordinates.
106     Rectangle_i GetAnnotationRect(FPDF_ANNOTATION annotation);
107 
108     // Return the index of the |annotation| on the |page| or -1  if not found.
109     int GetAnnotationIndex(FPDF_PAGE page, FPDF_ANNOTATION annotation);
110 
111     // Returns the number of options the choice |annotation| contains. Returns -1
112     // if annotation is not a choice type.
113     int GetOptionCount(FPDF_ANNOTATION annotation);
114 
115     // Get Options for the choice |annotation|. Returns empty list if the
116     // annotation is not a choice type or does not have options.
117     std::vector<Option> GetOptions(FPDF_PAGE page, FPDF_ANNOTATION annotation);
118 
119     // Get the "MaxLen" value for the annotation. Returns -1 if the MaxLen value
120     // is not present in the annotation dictionary.
121     int GetMaxLen(FPDF_ANNOTATION annotation);
122 
123     // Get the text font size of a widget containing text. Returns 0 if the font
124     // size was not found which indicates that widget text is autosized.
125     float GetFontSize(FPDF_ANNOTATION annotation);
126 
127     // Gets the TU value for the form widget, if any. If TU is not provided will
128     // return the T value, if any. If not provided returns empty string.
129     std::string GetAccessibilityLabel(FPDF_ANNOTATION annotation);
130 
131     // Gets the text value for a read only form widget (i.e. widget for which
132     // pdfium form filling operations are not permitted). Determines the checked
133     // state and returns "true" or "false" for checkboxes and radio buttons.
134     // Obtains the annotation dictionary "V" entry for all other types.
135     std::string GetReadOnlyTextValue(int type, FPDF_ANNOTATION annotation);
136 
137     // Perform a click action on the document in Pdfium.
138     void PerformClick(FPDF_PAGE page, const Point_d point);
139     // Set the text of the field that is currently focused (in Pdfium) to |text|.
140     void SetFieldText(FPDF_PAGE page, std::string_view text);
141     // Set all the text of the field that is currently focused (in Pdfium) as
142     // selected.
143     void SelectAllFieldText(FPDF_PAGE page);
144     // Replace the text that is currently selected in the focused field (in
145     // Pdfium) with |replacement_text|.
146     void ReplaceSelectedText(FPDF_PAGE page, std::string_view replacement_text);
147 
148     // Set Pdfium's focus to the widget at |point|, if any.
149     bool SetFormFocus(FPDF_PAGE page, const Point_d point);
150     // Set Pdfium's focus to the |annotation|.
151     bool SetFormFocus(FPDF_PAGE page, FPDF_ANNOTATION annotation);
152     // Kill all focus held in Pdfium, if any.
153     bool KillFormFocus();
154 
155     // Implementation of method from FPDF_FORMFILLINFO. Pdfium will use this
156     // method to inform FormFiller when a rectangle of |page|'s bitmap has been
157     // invalidated. This occurs following form filling actions.
158     static void Invalidate(FPDF_FORMFILLINFO* pThis, FPDF_PAGE page, double left, double top,
159                            double right, double bottom);
160 
161     Document* document_;  // Not owned.
162     ScopedFPDFFormHandle form_handle_;
163 };
164 
165 }  // namespace pdfClient
166 
167 #endif  // MEDIAPROVIDER_PDF_JNI_PDFCLIENT_FORM_FILLER_H_