xref: /aosp_15_r20/external/pdfium/xfa/fde/cfde_texteditengine.h (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #ifndef XFA_FDE_CFDE_TEXTEDITENGINE_H_
8 #define XFA_FDE_CFDE_TEXTEDITENGINE_H_
9 
10 #include <limits>
11 #include <memory>
12 #include <utility>
13 #include <vector>
14 
15 #include "core/fxcrt/retain_ptr.h"
16 #include "core/fxcrt/unowned_ptr.h"
17 #include "core/fxcrt/widestring.h"
18 #include "core/fxge/dib/fx_dib.h"
19 #include "xfa/fgas/layout/cfgas_txtbreak.h"
20 
21 class CFGAS_GEFont;
22 class TextCharPos;
23 
24 struct FDE_TEXTEDITPIECE {
25   FDE_TEXTEDITPIECE();
26   FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that);
27   ~FDE_TEXTEDITPIECE();
28 
29   CFX_RectF rtPiece;
30   int32_t nStart = 0;
31   int32_t nCount = 0;
32   int32_t nBidiLevel = 0;
33   uint32_t dwCharStyles = 0;
34 };
35 
36 inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE() = default;
37 inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that) =
38     default;
39 inline FDE_TEXTEDITPIECE::~FDE_TEXTEDITPIECE() = default;
40 
41 class CFDE_TextEditEngine final : public CFGAS_TxtBreak::Engine {
42  public:
43   class Iterator {
44    public:
45     explicit Iterator(const CFDE_TextEditEngine* engine);
46     ~Iterator();
47 
48     void Next(bool bPrev);
49     wchar_t GetChar() const;
50     void SetAt(size_t nIndex);
51     size_t FindNextBreakPos(bool bPrev);
52     bool IsEOF(bool bPrev) const;
53 
54    private:
55     UnownedPtr<const CFDE_TextEditEngine> const engine_;
56     int32_t current_position_ = -1;
57   };
58 
59   class Operation {
60    public:
61     virtual ~Operation() = default;
62     virtual void Redo() const = 0;
63     virtual void Undo() const = 0;
64   };
65 
66   struct TextChange {
67     WideString text;
68     WideString previous_text;
69     size_t selection_start;
70     size_t selection_end;
71     bool cancelled;
72   };
73 
74   class Delegate {
75    public:
76     virtual ~Delegate() = default;
77     virtual void NotifyTextFull() = 0;
78     virtual void OnCaretChanged() = 0;
79     virtual void OnTextWillChange(TextChange* change) = 0;
80     virtual void OnTextChanged() = 0;
81     virtual void OnSelChanged() = 0;
82     virtual bool OnValidate(const WideString& wsText) = 0;
83     virtual void SetScrollOffset(float fScrollOffset) = 0;
84   };
85 
86   enum class RecordOperation { kInsertRecord, kSkipRecord, kSkipNotify };
87 
88   CFDE_TextEditEngine();
89   ~CFDE_TextEditEngine() override;
90 
91   // CFGAS_TxtBreak::Engine:
92   wchar_t GetChar(size_t idx) const override;
93   int32_t GetWidthOfChar(size_t idx) override;
94 
SetDelegate(Delegate * delegate)95   void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
96   void Clear();
97 
98   void Insert(size_t idx,
99               const WideString& text,
100               RecordOperation add_operation = RecordOperation::kInsertRecord);
101   WideString Delete(
102       size_t start_idx,
103       size_t length,
104       RecordOperation add_operation = RecordOperation::kInsertRecord);
105   WideString GetText() const;
106   size_t GetLength() const;
107 
108   // Non-const so we can force a layout.
109   CFX_RectF GetContentsBoundingBox();
110   void SetAvailableWidth(size_t width);
111 
112   void SetFont(RetainPtr<CFGAS_GEFont> font);
113   RetainPtr<CFGAS_GEFont> GetFont() const;
114   void SetFontSize(float size);
GetFontSize()115   float GetFontSize() const { return font_size_; }
SetFontColor(FX_ARGB color)116   void SetFontColor(FX_ARGB color) { font_color_ = color; }
GetFontColor()117   FX_ARGB GetFontColor() const { return font_color_; }
118 
119   void SetAlignment(uint32_t alignment);
GetLineSpace()120   float GetLineSpace() const { return line_spacing_; }
SetLineSpace(float space)121   void SetLineSpace(float space) { line_spacing_ = space; }
SetAliasChar(wchar_t alias)122   void SetAliasChar(wchar_t alias) { password_alias_ = alias; }
123   void SetHasCharacterLimit(bool limit);
124   void SetCharacterLimit(size_t limit);
125   void SetCombText(bool enable);
126   void SetTabWidth(float width);
127   void SetVisibleLineCount(size_t lines);
128 
EnableValidation(bool val)129   void EnableValidation(bool val) { validation_enabled_ = val; }
EnablePasswordMode(bool val)130   void EnablePasswordMode(bool val) { password_mode_ = val; }
131   void EnableMultiLine(bool val);
132   void EnableLineWrap(bool val);
133   void LimitHorizontalScroll(bool val);
134   void LimitVerticalScroll(bool val);
135 
136   bool CanUndo() const;
137   bool CanRedo() const;
138   bool Redo();
139   bool Undo();
140   void ClearOperationRecords();
141 
142   size_t GetIndexLeft(size_t pos) const;
143   size_t GetIndexRight(size_t pos) const;
144   size_t GetIndexUp(size_t pos) const;
145   size_t GetIndexDown(size_t pos) const;
146   size_t GetIndexAtStartOfLine(size_t pos) const;
147   size_t GetIndexAtEndOfLine(size_t pos) const;
148 
149   void SelectAll();
150   void SetSelection(size_t start_idx, size_t count);
151   void ClearSelection();
HasSelection()152   bool HasSelection() const { return has_selection_; }
153   // Returns <start_idx, count> of the selection.
GetSelection()154   std::pair<size_t, size_t> GetSelection() const {
155     return {selection_.start_idx, selection_.count};
156   }
157   WideString GetSelectedText() const;
158   WideString DeleteSelectedText(
159       RecordOperation add_operation = RecordOperation::kInsertRecord);
160   void ReplaceSelectedText(const WideString& str);
161 
162   void Layout();
163 
164   // Non-const so we can force a Layout() if needed.
165   size_t GetIndexForPoint(const CFX_PointF& point);
166   // <start_idx, count>
167   std::pair<size_t, size_t> BoundsForWordAt(size_t idx) const;
168 
169   // Note that if CanGenerateCharacterInfo() returns false, then
170   // GetCharacterInfo() cannot be called.
CanGenerateCharacterInfo()171   bool CanGenerateCharacterInfo() const { return text_length_ > 0 && font_; }
172 
173   // Returns <bidi level, character rect>
174   std::pair<int32_t, CFX_RectF> GetCharacterInfo(int32_t start_idx);
175   std::vector<CFX_RectF> GetCharacterRectsInRange(int32_t start_idx,
176                                                   int32_t count);
177 
GetTextPieces()178   const std::vector<FDE_TEXTEDITPIECE>& GetTextPieces() {
179     // Force a layout if needed.
180     Layout();
181     return text_piece_info_;
182   }
183 
184   std::vector<TextCharPos> GetDisplayPos(const FDE_TEXTEDITPIECE& info);
185 
186   void SetMaxEditOperationsForTesting(size_t max);
187 
188  private:
189   struct Selection {
190     size_t start_idx;
191     size_t count;
192   };
193 
194   static constexpr size_t kGapSize = 128;
195   static constexpr size_t kMaxEditOperations = 128;
196   static constexpr size_t kPageWidthMax = 0xffff;
197 
198   void SetCombTextWidth();
199   void AdjustGap(size_t idx, size_t length);
200   void RebuildPieces();
201   size_t CountCharsExceedingSize(const WideString& str, size_t num_to_check);
202   void AddOperationRecord(std::unique_ptr<Operation> op);
203 
IsAlignedRight()204   bool IsAlignedRight() const {
205     return !!(character_alignment_ & CFX_TxtLineAlignment_Right);
206   }
207 
IsAlignedCenter()208   bool IsAlignedCenter() const {
209     return !!(character_alignment_ & CFX_TxtLineAlignment_Center);
210   }
211   std::vector<CFX_RectF> GetCharRects(const FDE_TEXTEDITPIECE& piece);
212 
213   CFX_RectF contents_bounding_box_;
214   UnownedPtr<Delegate> delegate_;
215   std::vector<FDE_TEXTEDITPIECE> text_piece_info_;
216   std::vector<int32_t> char_widths_;  // May be negative for combining chars.
217   CFGAS_TxtBreak text_break_;
218   RetainPtr<CFGAS_GEFont> font_;
219   FX_ARGB font_color_ = 0xff000000;
220   float font_size_ = 10.0f;
221   float line_spacing_ = 10.0f;
222   std::vector<WideString::CharType> content_;
223   size_t text_length_ = 0;
224 
225   // See e.g. https://en.wikipedia.org/wiki/Gap_buffer
226   size_t gap_position_ = 0;
227   size_t gap_size_ = kGapSize;
228 
229   size_t available_width_ = kPageWidthMax;
230   size_t character_limit_ = std::numeric_limits<size_t>::max();
231   size_t visible_line_count_ = 1;
232   // Ring buffer of edit operations
233   std::vector<std::unique_ptr<Operation>> operation_buffer_;
234   // Next edit operation to undo.
235   size_t next_operation_index_to_undo_ = kMaxEditOperations - 1;
236   // Next index to insert an edit operation into.
237   size_t next_operation_index_to_insert_ = 0;
238   size_t max_edit_operations_ = kMaxEditOperations;
239   uint32_t character_alignment_ = CFX_TxtLineAlignment_Left;
240   bool has_character_limit_ = false;
241   bool is_comb_text_ = false;
242   bool is_dirty_ = false;
243   bool validation_enabled_ = false;
244   bool is_multiline_ = false;
245   bool is_linewrap_enabled_ = false;
246   bool limit_horizontal_area_ = false;
247   bool limit_vertical_area_ = false;
248   bool password_mode_ = false;
249   wchar_t password_alias_ = L'*';
250   bool has_selection_ = false;
251   Selection selection_{0, 0};
252 };
253 
254 #endif  // XFA_FDE_CFDE_TEXTEDITENGINE_H_
255