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