// 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/fx_string.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxge/cfx_renderdevice.h"
#include "core/fxge/fx_dib.h"
#include "xfa/fgas/layout/cfx_txtbreak.h"
class CFGAS_GEFont;
struct FDE_TEXTEDITPIECE {
FDE_TEXTEDITPIECE();
FDE_TEXTEDITPIECE(const FDE_TEXTEDITPIECE& that);
~FDE_TEXTEDITPIECE();
CFX_RectF rtPiece;
int32_t nStart = 0;
int32_t nCount = 0;
int32_t nBidiLevel = 0;
uint32_t dwCharStyles = 0;
};
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(size_t nIndex);
size_t FindNextBreakPos(bool bPrev);
bool IsEOF(bool bPrev) const;
private:
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 WideString& prevText) = 0;
virtual void OnSelChanged() = 0;
virtual bool OnValidate(const 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 WideString& text,
RecordOperation add_operation = RecordOperation::kInsertRecord);
WideString Delete(
size_t start_idx,
size_t length,
RecordOperation add_operation = RecordOperation::kInsertRecord);
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(RetainPtr<CFGAS_GEFont> font);
RetainPtr<CFGAS_GEFont> GetFont() const;
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;
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();
// This is not const it can trigger a |Layout|.
size_t GetIndexBefore(size_t pos);
size_t GetIndexLeft(size_t pos) const;
size_t GetIndexRight(size_t pos) const;
size_t GetIndexUp(size_t pos) const;
size_t GetIndexDown(size_t pos) const;
size_t GetIndexAtStartOfLine(size_t pos) const;
size_t GetIndexAtEndOfLine(size_t pos) const;
void SelectAll();
void SetSelection(size_t start_idx, size_t count);
void ClearSelection();
bool HasSelection() const { return has_selection_; }
// Returns <start_idx, count> of the selection.
std::pair<size_t, size_t> GetSelection() const {
return {selection_.start_idx, selection_.count};
}
WideString GetSelectedText() const;
WideString DeleteSelectedText(
RecordOperation add_operation = RecordOperation::kInsertRecord);
void ReplaceSelectedText(const 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, count>
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 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 count;
};
CFX_RectF contents_bounding_box_;
UnownedPtr<Delegate> delegate_;
std::vector<FDE_TEXTEDITPIECE> text_piece_info_;
std::vector<size_t> char_widths_;
CFX_TxtBreak text_break_;
RetainPtr<CFGAS_GEFont> font_;
FX_ARGB font_color_;
float font_size_;
float line_spacing_;
std::vector<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_