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