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