summaryrefslogtreecommitdiff
path: root/xfa/fde/cfde_texteditengine.h
blob: aa8a24381d6921ac3dcbc2f56017f92a6ade1ad6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// Copyright 2017 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#ifndef XFA_FDE_CFDE_TEXTEDITENGINE_H_
#define XFA_FDE_CFDE_TEXTEDITENGINE_H_

#include <memory>
#include <utility>
#include <vector>

#include "core/fxcrt/cfx_retain_ptr.h"
#include "core/fxcrt/fx_string.h"
#include "core/fxge/cfx_renderdevice.h"
#include "core/fxge/fx_dib.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fgas/layout/cfx_txtbreak.h"

struct FDE_TEXTEDITPIECE {
  FDE_TEXTEDITPIECE();
  FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that);
  ~FDE_TEXTEDITPIECE();

  int32_t nStart;
  int32_t nCount;
  int32_t nBidiLevel;
  CFX_RectF rtPiece;
  uint32_t dwCharStyles;
};

inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE() = default;
inline FDE_TEXTEDITPIECE::FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that) =
    default;
inline FDE_TEXTEDITPIECE::~FDE_TEXTEDITPIECE() = default;

class CFDE_TextEditEngine {
 public:
  class Iterator {
   public:
    explicit Iterator(const CFDE_TextEditEngine* engine);
    ~Iterator();

    void Next(bool bPrev);
    wchar_t GetChar() const;
    void SetAt(int32_t nIndex);
    int32_t GetAt() const;
    void FindNextBreakPos(bool bPrev);
    bool IsEOF(bool bTail) const;

   private:
    CFX_UnownedPtr<const CFDE_TextEditEngine> engine_;
    int32_t current_position_;
  };

  class Operation {
   public:
    virtual ~Operation() = default;
    virtual void Redo() const = 0;
    virtual void Undo() const = 0;
  };

  class Delegate {
   public:
    virtual ~Delegate() = default;
    virtual void NotifyTextFull() = 0;
    virtual void OnCaretChanged() = 0;
    virtual void OnTextChanged(const CFX_WideString& prevText) = 0;
    virtual void OnSelChanged() = 0;
    virtual bool OnValidate(const CFX_WideString& wsText) = 0;
    virtual void SetScrollOffset(float fScrollOffset) = 0;
  };

  enum class RecordOperation {
    kInsertRecord,
    kSkipRecord,
  };

  CFDE_TextEditEngine();
  ~CFDE_TextEditEngine();

  void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
  void Clear();

  void Insert(size_t idx,
              const CFX_WideString& text,
              RecordOperation add_operation = RecordOperation::kInsertRecord);
  CFX_WideString Delete(
      size_t start_idx,
      size_t length,
      RecordOperation add_operation = RecordOperation::kInsertRecord);
  CFX_WideString GetText() const;
  size_t GetLength() const;

  // Non-const so we can force a layout.
  CFX_RectF GetContentsBoundingBox();
  void SetAvailableWidth(size_t width);

  void SetFont(CFX_RetainPtr<CFGAS_GEFont> font);
  CFX_RetainPtr<CFGAS_GEFont> GetFont() const { return font_; }
  void SetFontSize(float size);
  float GetFontSize() const { return font_size_; }
  void SetFontColor(FX_ARGB color) { font_color_ = color; }
  FX_ARGB GetFontColor() const { return font_color_; }
  float GetFontAscent() const {
    return (static_cast<float>(font_->GetAscent()) * font_size_) / 1000;
  }

  void SetAlignment(uint32_t alignment);
  float GetLineSpace() const { return line_spacing_; }
  void SetLineSpace(float space) { line_spacing_ = space; }
  void SetAliasChar(wchar_t alias) { password_alias_ = alias; }
  void SetHasCharacterLimit(bool limit);
  void SetCharacterLimit(size_t limit);
  void SetCombText(bool enable);
  void SetTabWidth(float width);
  void SetVisibleLineCount(size_t lines);

  void EnableValidation(bool val) { validation_enabled_ = val; }
  void EnablePasswordMode(bool val) { password_mode_ = val; }
  void EnableMultiLine(bool val);
  void EnableLineWrap(bool val);
  void LimitHorizontalScroll(bool val);
  void LimitVerticalScroll(bool val);

  bool CanUndo() const;
  bool CanRedo() const;
  bool Redo();
  bool Undo();
  void ClearOperationRecords();

  // TODO(dsinclair): Implement ....
  size_t GetIndexBefore(size_t pos) { return 0; }
  size_t GetIndexLeft(size_t pos) { return 0; }
  size_t GetIndexRight(size_t pos) { return 0; }
  size_t GetIndexUp(size_t pos) { return 0; }
  size_t GetIndexDown(size_t pos) { return 0; }
  size_t GetIndexAtStartOfLine(size_t pos) { return 0; }
  size_t GetIndexAtEndOfLine(size_t pos) { return 0; }

  void SelectAll();
  void SetSelection(size_t start_idx, size_t end_idx);
  void ClearSelection();
  bool HasSelection() const { return has_selection_; }
  // Returns <start, end> indices of the selection.
  std::pair<size_t, size_t> GetSelection() const {
    return {selection_.start_idx, selection_.end_idx};
  }
  CFX_WideString GetSelectedText() const;
  CFX_WideString DeleteSelectedText(
      RecordOperation add_operation = RecordOperation::kInsertRecord);
  void ReplaceSelectedText(const CFX_WideString& str);

  void Layout();

  wchar_t GetChar(size_t idx) const;
  // Non-const so we can force a Layout() if needed.
  size_t GetWidthOfChar(size_t idx);
  // Non-const so we can force a Layout() if needed.
  size_t GetIndexForPoint(const CFX_PointF& point);
  // <start_idx, end_idx>
  std::pair<size_t, size_t> BoundsForWordAt(size_t idx) const;

  // Returns <bidi level, character rect>
  std::pair<int32_t, CFX_RectF> GetCharacterInfo(int32_t start_idx);
  std::vector<CFX_RectF> GetCharacterRectsInRange(int32_t start_idx,
                                                  int32_t count);

  CFX_TxtBreak* GetTextBreak() { return &text_break_; }

  const std::vector<FDE_TEXTEDITPIECE>& GetTextPieces() {
    // Force a layout if needed.
    Layout();
    return text_piece_info_;
  }

  std::vector<FXTEXT_CHARPOS> GetDisplayPos(const FDE_TEXTEDITPIECE& info);

  void SetMaxEditOperationsForTesting(size_t max);

 private:
  void SetCombTextWidth();
  void AdjustGap(size_t idx, size_t length);
  void RebuildPieces();
  size_t CountCharsExceedingSize(const CFX_WideString& str,
                                 size_t num_to_check);
  void AddOperationRecord(std::unique_ptr<Operation> op);

  bool IsAlignedRight() const {
    return !!(character_alignment_ & CFX_TxtLineAlignment_Left);
  }

  bool IsAlignedCenter() const {
    return !!(character_alignment_ & CFX_TxtLineAlignment_Center);
  }
  std::vector<CFX_RectF> GetCharRects(const FDE_TEXTEDITPIECE& piece);

  struct Selection {
    size_t start_idx;
    size_t end_idx;
  };

  CFX_RectF contents_bounding_box_;
  CFX_UnownedPtr<Delegate> delegate_;
  std::vector<FDE_TEXTEDITPIECE> text_piece_info_;
  std::vector<size_t> char_widths_;
  CFX_TxtBreak text_break_;
  CFX_RetainPtr<CFGAS_GEFont> font_;
  FX_ARGB font_color_;
  float font_size_;
  float line_spacing_;
  std::vector<CFX_WideString::CharType> content_;
  size_t text_length_;
  size_t gap_position_;
  size_t gap_size_;
  size_t available_width_;
  size_t character_limit_;
  size_t visible_line_count_;
  // Ring buffer of edit operations
  std::vector<std::unique_ptr<Operation>> operation_buffer_;
  // Next edit operation to undo.
  size_t next_operation_index_to_undo_;
  // Next index to insert an edit operation into.
  size_t next_operation_index_to_insert_;
  size_t max_edit_operations_;
  uint32_t character_alignment_;
  bool has_character_limit_;
  bool is_comb_text_;
  bool is_dirty_;
  bool validation_enabled_;
  bool is_multiline_;
  bool is_linewrap_enabled_;
  bool limit_horizontal_area_;
  bool limit_vertical_area_;
  bool password_mode_;
  wchar_t password_alias_;
  bool has_selection_;
  Selection selection_;
};

#endif  // XFA_FDE_CFDE_TEXTEDITENGINE_H_