summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2017-08-30 12:16:16 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-08-30 16:26:12 +0000
commit68eefa6a6f6bbab73000a29e2cac3e104be1cc81 (patch)
treeb48dbf0932022bc551ae06e2400262c203856942
parentaa3a9cd82df9dff1ef136797259e606a39c18b75 (diff)
downloadpdfium-68eefa6a6f6bbab73000a29e2cac3e104be1cc81.tar.xz
Rebuild CFDE_TextEditEngine.
This CL rebuilds the text edit engine in a simpler fashion. Instead of depending on multiple pages, paragraphs and buffer fields there is a single text edit engine which contains a gap buffer. This makes the code easier to understand and follow. Change-Id: I10fe85603fa9ed15a647eaac2d931f113cd0c7b0 Reviewed-on: https://pdfium-review.googlesource.com/11990 Commit-Queue: dsinclair <dsinclair@chromium.org> Reviewed-by: Henrique Nakashima <hnakashima@chromium.org> Reviewed-by: Ryan Harrison <rharrison@chromium.org>
-rw-r--r--BUILD.gn16
-rw-r--r--DEPS2
-rw-r--r--xfa/fde/cfde_texteditengine.cpp972
-rw-r--r--xfa/fde/cfde_texteditengine.h241
-rw-r--r--xfa/fde/cfde_texteditengine_unittest.cpp418
-rw-r--r--xfa/fde/cfde_txtedtbuf.cpp316
-rw-r--r--xfa/fde/cfde_txtedtbuf.h76
-rw-r--r--xfa/fde/cfde_txtedtbuf_unittest.cpp188
-rw-r--r--xfa/fde/cfde_txtedtengine.cpp1234
-rw-r--r--xfa/fde/cfde_txtedtengine.h223
-rw-r--r--xfa/fde/cfde_txtedtpage.cpp398
-rw-r--r--xfa/fde/cfde_txtedtpage.h94
-rw-r--r--xfa/fde/cfde_txtedtparag.cpp153
-rw-r--r--xfa/fde/cfde_txtedtparag.h45
-rw-r--r--xfa/fde/cfde_txtedttextset.cpp60
-rw-r--r--xfa/fde/cfde_txtedttextset.h33
-rw-r--r--xfa/fde/ifde_txtedtdorecord.h20
-rw-r--r--xfa/fgas/layout/cfx_break.h1
-rw-r--r--xfa/fgas/layout/cfx_txtbreak.cpp88
-rw-r--r--xfa/fgas/layout/cfx_txtbreak.h4
-rw-r--r--xfa/fwl/cfwl_combobox.cpp2
-rw-r--r--xfa/fwl/cfwl_combobox.h6
-rw-r--r--xfa/fwl/cfwl_comboedit.cpp10
-rw-r--r--xfa/fwl/cfwl_datetimepicker.h8
-rw-r--r--xfa/fwl/cfwl_edit.cpp631
-rw-r--r--xfa/fwl/cfwl_edit.h50
-rw-r--r--xfa/fxfa/cxfa_ffcombobox.cpp3
-rw-r--r--xfa/fxfa/cxfa_ffdatetimeedit.cpp2
-rw-r--r--xfa/fxfa/cxfa_ffnumericedit.cpp3
-rw-r--r--xfa/fxfa/cxfa_ffpasswordedit.cpp6
-rw-r--r--xfa/fxfa/cxfa_fftextedit.cpp17
31 files changed, 2010 insertions, 3310 deletions
diff --git a/BUILD.gn b/BUILD.gn
index e498e2f614..1a08382bf6 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1467,20 +1467,10 @@ if (pdf_enable_xfa) {
static_library("xfa") {
sources = [
+ "xfa/fde/cfde_texteditengine.cpp",
+ "xfa/fde/cfde_texteditengine.h",
"xfa/fde/cfde_textout.cpp",
"xfa/fde/cfde_textout.h",
- "xfa/fde/cfde_txtedtbuf.cpp",
- "xfa/fde/cfde_txtedtbuf.h",
- "xfa/fde/cfde_txtedtengine.cpp",
- "xfa/fde/cfde_txtedtengine.h",
- "xfa/fde/cfde_txtedtpage.cpp",
- "xfa/fde/cfde_txtedtpage.h",
- "xfa/fde/cfde_txtedtparag.cpp",
- "xfa/fde/cfde_txtedtparag.h",
- "xfa/fde/cfde_txtedttextset.cpp",
- "xfa/fde/cfde_txtedttextset.h",
- "xfa/fde/ifde_txtedtdorecord.h",
- "xfa/fde/ifde_txtedtpage.h",
"xfa/fgas/crt/cfgas_formatstring.cpp",
"xfa/fgas/crt/cfgas_formatstring.h",
"xfa/fgas/font/cfgas_fontmgr.cpp",
@@ -1956,7 +1946,7 @@ test("pdfium_unittests") {
"core/fxcrt/xml/cfx_xmlsyntaxparser_unittest.cpp",
"fxbarcode/oned/BC_OnedCode128Writer_unittest.cpp",
"fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp",
- "xfa/fde/cfde_txtedtbuf_unittest.cpp",
+ "xfa/fde/cfde_texteditengine_unittest.cpp",
"xfa/fgas/crt/cfgas_formatstring_unittest.cpp",
"xfa/fgas/layout/cfx_rtfbreak_unittest.cpp",
"xfa/fwl/cfx_barcode_unittest.cpp",
diff --git a/DEPS b/DEPS
index b8769b89f4..b7bc444da3 100644
--- a/DEPS
+++ b/DEPS
@@ -18,7 +18,7 @@ vars = {
'jinja2_revision': 'd34383206fa42d52faa10bb9931d6d538f3a57e0',
'jpeg_turbo_revision': '7260e4d8b8e1e40b17f03fafdf1cd83296900f76',
'markupsafe_revision': '8f45f5cfa0009d2a70589bcda0349b8cb2b72783',
- 'pdfium_tests_revision': '056a182ccff4c6f21e80f70a5601706dece34d84',
+ 'pdfium_tests_revision': '14606ac642de57bea9aae0d07aa76f5e0ac50dba',
'skia_revision': 'e0e20755f6c09b71038ced2bf4a00b4c4593f504',
'tools_memory_revision': '427f10475e1a8d72424c29d00bf689122b738e5d',
'trace_event_revision': '06294c8a4a6f744ef284cd63cfe54dbf61eea290',
diff --git a/xfa/fde/cfde_texteditengine.cpp b/xfa/fde/cfde_texteditengine.cpp
new file mode 100644
index 0000000000..e92897ea7d
--- /dev/null
+++ b/xfa/fde/cfde_texteditengine.cpp
@@ -0,0 +1,972 @@
+// 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
+
+#include "xfa/fde/cfde_texteditengine.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "xfa/fde/cfde_textout.h"
+
+namespace {
+
+constexpr size_t kMaxEditOperations = 128;
+constexpr size_t kGapSize = 128;
+constexpr size_t kPageWidthMax = 0xffff;
+
+class InsertOperation : public CFDE_TextEditEngine::Operation {
+ public:
+ InsertOperation(CFDE_TextEditEngine* engine,
+ size_t start_idx,
+ const CFX_WideString& added_text)
+ : engine_(engine), start_idx_(start_idx), added_text_(added_text) {}
+
+ ~InsertOperation() override {}
+
+ void Redo() const override {
+ engine_->Insert(start_idx_, added_text_,
+ CFDE_TextEditEngine::RecordOperation::kSkipRecord);
+ }
+
+ void Undo() const override {
+ engine_->Delete(start_idx_, added_text_.GetLength(),
+ CFDE_TextEditEngine::RecordOperation::kSkipRecord);
+ }
+
+ private:
+ CFX_UnownedPtr<CFDE_TextEditEngine> engine_;
+ size_t start_idx_;
+ CFX_WideString added_text_;
+};
+
+class DeleteOperation : public CFDE_TextEditEngine::Operation {
+ public:
+ DeleteOperation(CFDE_TextEditEngine* engine,
+ size_t start_idx,
+ const CFX_WideString& removed_text)
+ : engine_(engine), start_idx_(start_idx), removed_text_(removed_text) {}
+
+ ~DeleteOperation() override {}
+
+ void Redo() const override {
+ engine_->Delete(start_idx_, removed_text_.GetLength(),
+ CFDE_TextEditEngine::RecordOperation::kSkipRecord);
+ }
+
+ void Undo() const override {
+ engine_->Insert(start_idx_, removed_text_,
+ CFDE_TextEditEngine::RecordOperation::kSkipRecord);
+ }
+
+ private:
+ CFX_UnownedPtr<CFDE_TextEditEngine> engine_;
+ size_t start_idx_;
+ CFX_WideString removed_text_;
+};
+
+class ReplaceOperation : public CFDE_TextEditEngine::Operation {
+ public:
+ ReplaceOperation(CFDE_TextEditEngine* engine,
+ size_t start_idx,
+ const CFX_WideString& removed_text,
+ const CFX_WideString& added_text)
+ : insert_op_(engine, start_idx, added_text),
+ delete_op_(engine, start_idx, removed_text) {}
+
+ ~ReplaceOperation() override {}
+
+ void Redo() const override {
+ delete_op_.Redo();
+ insert_op_.Redo();
+ }
+
+ void Undo() const override {
+ insert_op_.Undo();
+ delete_op_.Undo();
+ }
+
+ private:
+ InsertOperation insert_op_;
+ DeleteOperation delete_op_;
+};
+
+} // namespace
+
+CFDE_TextEditEngine::CFDE_TextEditEngine()
+ : font_color_(0xff000000),
+ font_size_(10.0f),
+ line_spacing_(10.0f),
+ text_length_(0),
+ gap_position_(0),
+ gap_size_(kGapSize),
+ available_width_(kPageWidthMax),
+ character_limit_(std::numeric_limits<size_t>::max()),
+ visible_line_count_(1),
+ next_operation_index_to_undo_(kMaxEditOperations - 1),
+ next_operation_index_to_insert_(0),
+ max_edit_operations_(kMaxEditOperations),
+ character_alignment_(CFX_TxtLineAlignment_Left),
+ has_character_limit_(false),
+ is_comb_text_(false),
+ is_dirty_(false),
+ validation_enabled_(false),
+ is_multiline_(false),
+ is_linewrap_enabled_(false),
+ limit_horizontal_area_(false),
+ limit_vertical_area_(false),
+ password_mode_(false),
+ password_alias_(L'*'),
+ has_selection_(false),
+ selection_({0, 0}) {
+ content_.resize(gap_size_);
+ operation_buffer_.resize(max_edit_operations_);
+
+ text_break_.SetFontSize(font_size_);
+ text_break_.SetLineBreakTolerance(2.0f);
+ text_break_.SetTabWidth(36);
+}
+
+CFDE_TextEditEngine::~CFDE_TextEditEngine() {}
+
+void CFDE_TextEditEngine::Clear() {
+ text_length_ = 0;
+ gap_position_ = 0;
+ gap_size_ = kGapSize;
+
+ content_.clear();
+ content_.resize(gap_size_);
+
+ ClearSelection();
+ ClearOperationRecords();
+}
+
+void CFDE_TextEditEngine::SetMaxEditOperationsForTesting(size_t max) {
+ max_edit_operations_ = max;
+ operation_buffer_.resize(max);
+
+ ClearOperationRecords();
+}
+
+void CFDE_TextEditEngine::AdjustGap(size_t idx, size_t length) {
+ static const size_t char_size = sizeof(CFX_WideString::CharType);
+
+ // Move the gap, if necessary.
+ if (idx < gap_position_) {
+ memmove(content_.data() + idx + gap_size_, content_.data() + idx,
+ (gap_position_ - idx) * char_size);
+ gap_position_ = idx;
+ } else if (idx > gap_position_) {
+ memmove(content_.data() + gap_position_,
+ content_.data() + gap_position_ + gap_size_,
+ (idx - gap_position_) * char_size);
+ gap_position_ = idx;
+ }
+
+ // If the gap is too small, make it bigger.
+ if (length >= gap_size_) {
+ size_t new_gap_size = length + kGapSize;
+ content_.resize(text_length_ + new_gap_size);
+
+ memmove(content_.data() + gap_position_ + new_gap_size,
+ content_.data() + gap_position_ + gap_size_,
+ (text_length_ - gap_position_) * char_size);
+
+ gap_size_ = new_gap_size;
+ }
+}
+
+size_t CFDE_TextEditEngine::CountCharsExceedingSize(const CFX_WideString& text,
+ size_t num_to_check) {
+ if (!limit_horizontal_area_ && !limit_vertical_area_)
+ return 0;
+
+ auto text_out = pdfium::MakeUnique<CFDE_TextOut>();
+ text_out->SetLineSpace(line_spacing_);
+ text_out->SetFont(font_);
+ text_out->SetFontSize(font_size_);
+
+ FDE_TextStyle style;
+ style.single_line_ = !is_multiline_;
+
+ CFX_RectF text_rect;
+ if (is_linewrap_enabled_) {
+ style.line_wrap_ = true;
+ text_rect.width = available_width_;
+ } else {
+ text_rect.width = kPageWidthMax;
+ }
+ text_out->SetStyles(style);
+
+ size_t length = text.GetLength();
+ CFX_WideStringC temp(text.c_str(), length);
+
+ float vertical_height = line_spacing_ * visible_line_count_;
+ size_t chars_exceeding_size = 0;
+ // TODO(dsinclair): Can this get changed to a binary search?
+ for (size_t i = 0; i < num_to_check; i++) {
+ // This does a lot of string copying ....
+ // TODO(dsinclair): make CalcLogicSize take a WideStringC instead.
+ text_out->CalcLogicSize(CFX_WideString(temp), text_rect);
+
+ if (limit_horizontal_area_ && text_rect.width <= available_width_)
+ break;
+ if (limit_vertical_area_ && text_rect.height <= vertical_height)
+ break;
+
+ --length;
+ temp = temp.Mid(0, length);
+ ++chars_exceeding_size;
+ }
+
+ return chars_exceeding_size;
+}
+
+void CFDE_TextEditEngine::Insert(size_t idx,
+ const CFX_WideString& text,
+ RecordOperation add_operation) {
+ if (idx > text_length_)
+ idx = text_length_;
+
+ size_t length = text.GetLength();
+ if (length == 0)
+ return;
+
+ // If we're going to be too big we insert what we can and notify the
+ // delegate we've filled the text after the insert is done.
+ bool exceeded_limit = false;
+ if (has_character_limit_ && text_length_ + length > character_limit_) {
+ exceeded_limit = true;
+ length = character_limit_ - text_length_;
+ }
+
+ AdjustGap(idx, length);
+
+ if (validation_enabled_ || limit_horizontal_area_ || limit_vertical_area_) {
+ CFX_WideString str;
+ if (gap_position_ > 0)
+ str += CFX_WideStringC(content_.data(), gap_position_);
+
+ str += text;
+
+ if (text_length_ - gap_position_ > 0) {
+ str += CFX_WideStringC(content_.data() + gap_position_ + gap_size_,
+ text_length_ - gap_position_);
+ }
+
+ if (validation_enabled_ && delegate_ && !delegate_->OnValidate(str)) {
+ // TODO(dsinclair): Notify delegate of validation failure?
+ return;
+ }
+
+ // Check if we've limited the horizontal/vertical area, and if so determine
+ // how many of our characters would be outside the area.
+ size_t chars_exceeding = CountCharsExceedingSize(str, length);
+ if (chars_exceeding > 0) {
+ // If none of the characters will fit, notify and exit.
+ if (chars_exceeding == length) {
+ if (delegate_)
+ delegate_->NotifyTextFull();
+ return;
+ }
+
+ // Some, but not all, chars will fit, insert them and then notify
+ // we're full.
+ exceeded_limit = true;
+ length -= chars_exceeding;
+ }
+ }
+
+ if (add_operation == RecordOperation::kInsertRecord) {
+ AddOperationRecord(
+ pdfium::MakeUnique<InsertOperation>(this, gap_position_, text));
+ }
+
+ CFX_WideString previous_text;
+ if (delegate_)
+ previous_text = GetText();
+
+ // Copy the new text into the gap.
+ static const size_t char_size = sizeof(CFX_WideString::CharType);
+ memcpy(content_.data() + gap_position_, text.c_str(), length * char_size);
+ gap_position_ += length;
+ gap_size_ -= length;
+ text_length_ += length;
+
+ is_dirty_ = true;
+
+ // Inserting text resets the selection.
+ ClearSelection();
+
+ if (delegate_) {
+ if (exceeded_limit)
+ delegate_->NotifyTextFull();
+
+ delegate_->OnTextChanged(previous_text);
+ }
+}
+
+void CFDE_TextEditEngine::AddOperationRecord(std::unique_ptr<Operation> op) {
+ size_t last_insert_position = next_operation_index_to_insert_ == 0
+ ? max_edit_operations_ - 1
+ : next_operation_index_to_insert_ - 1;
+
+ // If our undo record is not the last thing we inserted then we need to
+ // remove all the undo records between our insert position and the undo marker
+ // and make that our new insert position.
+ if (next_operation_index_to_undo_ != last_insert_position) {
+ if (next_operation_index_to_undo_ > last_insert_position) {
+ // Our Undo position is ahead of us, which means we need to clear out the
+ // head of the queue.
+ while (last_insert_position != 0) {
+ operation_buffer_[last_insert_position].reset();
+ --last_insert_position;
+ }
+ operation_buffer_[0].reset();
+
+ // Moving this will let us then clear out the end, setting the undo
+ // position to before the insert position.
+ last_insert_position = max_edit_operations_ - 1;
+ }
+
+ // Clear out the vector from undo position to our set insert position.
+ while (next_operation_index_to_undo_ != last_insert_position) {
+ operation_buffer_[last_insert_position].reset();
+ --last_insert_position;
+ }
+ }
+
+ // We're now pointing at the next thing we want to Undo, so insert at the
+ // next position in the queue.
+ ++last_insert_position;
+ if (last_insert_position >= max_edit_operations_)
+ last_insert_position = 0;
+
+ operation_buffer_[last_insert_position] = std::move(op);
+ next_operation_index_to_insert_ =
+ (last_insert_position + 1) % max_edit_operations_;
+ next_operation_index_to_undo_ = last_insert_position;
+}
+
+void CFDE_TextEditEngine::ClearOperationRecords() {
+ for (auto& record : operation_buffer_)
+ record.reset();
+
+ next_operation_index_to_undo_ = max_edit_operations_ - 1;
+ next_operation_index_to_insert_ = 0;
+}
+
+void CFDE_TextEditEngine::LimitHorizontalScroll(bool val) {
+ ClearOperationRecords();
+ limit_horizontal_area_ = val;
+}
+void CFDE_TextEditEngine::LimitVerticalScroll(bool val) {
+ ClearOperationRecords();
+ limit_vertical_area_ = val;
+}
+
+bool CFDE_TextEditEngine::CanUndo() const {
+ return operation_buffer_[next_operation_index_to_undo_] != nullptr &&
+ next_operation_index_to_undo_ != next_operation_index_to_insert_;
+}
+
+bool CFDE_TextEditEngine::CanRedo() const {
+ size_t idx = (next_operation_index_to_undo_ + 1) % max_edit_operations_;
+ return idx != next_operation_index_to_insert_ &&
+ operation_buffer_[idx] != nullptr;
+}
+
+bool CFDE_TextEditEngine::Redo() {
+ if (!CanRedo())
+ return false;
+
+ next_operation_index_to_undo_ =
+ (next_operation_index_to_undo_ + 1) % max_edit_operations_;
+ operation_buffer_[next_operation_index_to_undo_]->Redo();
+ return true;
+}
+
+bool CFDE_TextEditEngine::Undo() {
+ if (!CanUndo())
+ return false;
+
+ operation_buffer_[next_operation_index_to_undo_]->Undo();
+ next_operation_index_to_undo_ = next_operation_index_to_undo_ == 0
+ ? max_edit_operations_ - 1
+ : next_operation_index_to_undo_ - 1;
+ return true;
+}
+
+void CFDE_TextEditEngine::Layout() {
+ if (!is_dirty_)
+ return;
+
+ is_dirty_ = false;
+ RebuildPieces();
+}
+
+CFX_RectF CFDE_TextEditEngine::GetContentsBoundingBox() {
+ // Layout if necessary.
+ Layout();
+ return contents_bounding_box_;
+}
+
+void CFDE_TextEditEngine::SetAvailableWidth(size_t width) {
+ if (width == available_width_)
+ return;
+
+ ClearOperationRecords();
+
+ available_width_ = width;
+ if (is_linewrap_enabled_)
+ text_break_.SetLineWidth(width);
+ if (is_comb_text_)
+ SetCombTextWidth();
+
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetHasCharacterLimit(bool limit) {
+ if (has_character_limit_ == limit)
+ return;
+
+ has_character_limit_ = limit;
+ if (is_comb_text_)
+ SetCombTextWidth();
+
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetCharacterLimit(size_t limit) {
+ if (character_limit_ == limit)
+ return;
+
+ ClearOperationRecords();
+
+ character_limit_ = limit;
+ if (is_comb_text_)
+ SetCombTextWidth();
+
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetFont(CFX_RetainPtr<CFGAS_GEFont> font) {
+ if (font_ == font)
+ return;
+
+ font_ = font;
+ text_break_.SetFont(font_);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetFontSize(float size) {
+ if (font_size_ == size)
+ return;
+
+ font_size_ = size;
+ text_break_.SetFontSize(font_size_);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetTabWidth(float width) {
+ int32_t old_tab_width = text_break_.GetTabWidth();
+ text_break_.SetTabWidth(width);
+ if (old_tab_width == text_break_.GetTabWidth())
+ return;
+
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetAlignment(uint32_t alignment) {
+ if (alignment == character_alignment_)
+ return;
+
+ character_alignment_ = alignment;
+ text_break_.SetAlignment(alignment);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetVisibleLineCount(size_t count) {
+ if (visible_line_count_ == count)
+ return;
+
+ visible_line_count_ = std::max(static_cast<size_t>(1), count);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::EnableMultiLine(bool val) {
+ if (is_multiline_ == val)
+ return;
+
+ is_multiline_ = true;
+
+ uint32_t style = text_break_.GetLayoutStyles();
+ if (is_multiline_)
+ style &= ~FX_LAYOUTSTYLE_SingleLine;
+ else
+ style |= FX_LAYOUTSTYLE_SingleLine;
+ text_break_.SetLayoutStyles(style);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::EnableLineWrap(bool val) {
+ if (is_linewrap_enabled_ == val)
+ return;
+
+ is_linewrap_enabled_ = val;
+ text_break_.SetLineWidth(is_linewrap_enabled_ ? available_width_
+ : kPageWidthMax);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetCombText(bool enable) {
+ if (is_comb_text_ == enable)
+ return;
+
+ is_comb_text_ = enable;
+
+ uint32_t style = text_break_.GetLayoutStyles();
+ if (enable) {
+ style |= FX_LAYOUTSTYLE_CombText;
+ SetCombTextWidth();
+ } else {
+ style &= ~FX_LAYOUTSTYLE_CombText;
+ }
+ text_break_.SetLayoutStyles(style);
+ is_dirty_ = true;
+}
+
+void CFDE_TextEditEngine::SetCombTextWidth() {
+ size_t width = available_width_;
+ if (has_character_limit_)
+ width /= character_limit_;
+
+ text_break_.SetCombWidth(width);
+}
+
+void CFDE_TextEditEngine::SelectAll() {
+ if (text_length_ == 0)
+ return;
+
+ has_selection_ = true;
+ selection_.start_idx = 0;
+ selection_.end_idx = text_length_ - 1;
+}
+
+void CFDE_TextEditEngine::ClearSelection() {
+ has_selection_ = false;
+ selection_.start_idx = 0;
+ selection_.end_idx = 0;
+}
+
+void CFDE_TextEditEngine::SetSelection(size_t start_idx, size_t end_idx) {
+ // If the points are the same, then we pretend the selection doesn't exist
+ // anymore.
+ if (start_idx == end_idx) {
+ ClearSelection();
+ return;
+ }
+
+ if (start_idx > text_length_)
+ return;
+ if (end_idx > text_length_)
+ end_idx = text_length_ - 1;
+
+ has_selection_ = true;
+ selection_.start_idx = start_idx;
+ selection_.end_idx = end_idx;
+}
+
+CFX_WideString CFDE_TextEditEngine::GetSelectedText() const {
+ if (!has_selection_)
+ return L"";
+
+ CFX_WideString text;
+ if (selection_.start_idx < gap_position_) {
+ if (selection_.end_idx < gap_position_) {
+ text += CFX_WideStringC(content_.data() + selection_.start_idx,
+ selection_.end_idx - selection_.start_idx + 1);
+ return text;
+ }
+
+ text += CFX_WideStringC(content_.data() + selection_.start_idx,
+ gap_position_ - selection_.start_idx);
+ text += CFX_WideStringC(
+ content_.data() + gap_position_ + gap_size_,
+ selection_.end_idx - (gap_position_ - selection_.start_idx) + 1);
+ return text;
+ }
+
+ text += CFX_WideStringC(content_.data() + gap_size_ + selection_.start_idx,
+ selection_.end_idx - selection_.start_idx + 1);
+ return text;
+}
+
+CFX_WideString CFDE_TextEditEngine::DeleteSelectedText(
+ RecordOperation add_operation) {
+ if (!has_selection_)
+ return L"";
+
+ return Delete(selection_.start_idx,
+ selection_.end_idx - selection_.start_idx + 1, add_operation);
+}
+
+CFX_WideString CFDE_TextEditEngine::Delete(size_t start_idx,
+ size_t length,
+ RecordOperation add_operation) {
+ if (start_idx >= text_length_)
+ return L"";
+
+ length = std::min(length, text_length_ - start_idx);
+ AdjustGap(start_idx + length, 0);
+
+ CFX_WideString ret;
+ ret += CFX_WideStringC(content_.data() + start_idx, length);
+
+ if (add_operation == RecordOperation::kInsertRecord) {
+ AddOperationRecord(
+ pdfium::MakeUnique<DeleteOperation>(this, start_idx, ret));
+ }
+
+ CFX_WideString previous_text = GetText();
+
+ gap_position_ = start_idx;
+ gap_size_ += length;
+
+ text_length_ -= length;
+ ClearSelection();
+
+ if (delegate_)
+ delegate_->OnTextChanged(previous_text);
+
+ return ret;
+}
+
+void CFDE_TextEditEngine::ReplaceSelectedText(const CFX_WideString& rep) {
+ size_t start_idx = selection_.start_idx;
+
+ CFX_WideString txt = DeleteSelectedText(RecordOperation::kSkipRecord);
+ Insert(gap_position_, rep, RecordOperation::kSkipRecord);
+
+ AddOperationRecord(
+ pdfium::MakeUnique<ReplaceOperation>(this, start_idx, txt, rep));
+}
+
+CFX_WideString CFDE_TextEditEngine::GetText() const {
+ CFX_WideString str;
+ if (gap_position_ > 0)
+ str += CFX_WideStringC(content_.data(), gap_position_);
+ if (text_length_ - gap_position_ > 0) {
+ str += CFX_WideStringC(content_.data() + gap_position_ + gap_size_,
+ text_length_ - gap_position_);
+ }
+ return str;
+}
+
+size_t CFDE_TextEditEngine::GetLength() const {
+ return text_length_;
+}
+
+wchar_t CFDE_TextEditEngine::GetChar(size_t idx) const {
+ if (idx >= text_length_)
+ return L'\0';
+ if (password_mode_)
+ return password_alias_;
+
+ return idx < gap_position_
+ ? content_[idx]
+ : content_[gap_position_ + gap_size_ + (idx - gap_position_)];
+}
+
+size_t CFDE_TextEditEngine::GetWidthOfChar(size_t idx) {
+ // Recalculate the widths if necessary.
+ Layout();
+ return idx < char_widths_.size() ? char_widths_[idx] : 0;
+}
+
+size_t CFDE_TextEditEngine::GetIndexForPoint(const CFX_PointF& point) {
+ // Recalculate the widths if necessary.
+ Layout();
+
+ auto start_it = text_piece_info_.begin();
+ for (; start_it < text_piece_info_.end(); ++start_it) {
+ if (start_it->rtPiece.top <= point.y &&
+ point.y < start_it->rtPiece.bottom())
+ break;
+ }
+ // We didn't find the point before getting to the end of the text, return
+ // end of text.
+ if (start_it == text_piece_info_.end())
+ return text_length_;
+
+ auto end_it = start_it;
+ for (; end_it < text_piece_info_.end(); ++end_it) {
+ // We've moved past where the point should be and didn't find anything.
+ // Return the start of the current piece as the location.
+ if (end_it->rtPiece.bottom() <= point.y || point.y < end_it->rtPiece.top)
+ break;
+ }
+ // Make sure the end iterator is pointing to our text pieces.
+ if (end_it == text_piece_info_.end())
+ --end_it;
+
+ size_t start_it_idx = start_it->nStart;
+ for (; start_it <= end_it; ++start_it) {
+ if (!start_it->rtPiece.Contains(point))
+ continue;
+
+ std::vector<CFX_RectF> rects = GetCharRects(*start_it);
+ for (size_t i = 0; i < rects.size(); ++i) {
+ if (!rects[i].Contains(point))
+ continue;
+ size_t pos = start_it->nStart + i;
+ if (pos >= text_length_)
+ return text_length_;
+
+ wchar_t wch = GetChar(pos);
+ if (wch == L'\n' || wch == L'\r') {
+ if (wch == L'\n' && pos > 0 && GetChar(pos - 1) == L'\r')
+ --pos;
+ return pos;
+ }
+
+ // TODO(dsinclair): Old code had a before flag set based on bidi?
+ return pos;
+ }
+ }
+
+ if (start_it == text_piece_info_.end())
+ return start_it_idx;
+ if (start_it == end_it)
+ return start_it->nStart;
+
+ // We didn't find the point before going over all of the pieces, we want to
+ // return the start of the piece after the point.
+ return end_it->nStart;
+}
+
+std::vector<CFX_RectF> CFDE_TextEditEngine::GetCharRects(
+ const FDE_TEXTEDITPIECE& piece) {
+ if (piece.nCount < 1)
+ return {};
+
+ FX_TXTRUN tr;
+ tr.pEdtEngine = this;
+ tr.pIdentity = &piece;
+ tr.iLength = piece.nCount;
+ tr.pFont = font_;
+ tr.fFontSize = font_size_;
+ tr.dwStyles = text_break_.GetLayoutStyles();
+ tr.dwCharStyles = piece.dwCharStyles;
+ tr.pRect = &piece.rtPiece;
+ return text_break_.GetCharRects(&tr, false);
+}
+
+std::vector<FXTEXT_CHARPOS> CFDE_TextEditEngine::GetDisplayPos(
+ const FDE_TEXTEDITPIECE& piece) {
+ if (piece.nCount < 1)
+ return std::vector<FXTEXT_CHARPOS>();
+
+ FX_TXTRUN tr;
+ tr.pEdtEngine = this;
+ tr.pIdentity = &piece;
+ tr.iLength = piece.nCount;
+ tr.pFont = font_;
+ tr.fFontSize = font_size_;
+ tr.dwStyles = text_break_.GetLayoutStyles();
+ tr.dwCharStyles = piece.dwCharStyles;
+ tr.pRect = &piece.rtPiece;
+
+ std::vector<FXTEXT_CHARPOS> data(text_break_.GetDisplayPos(&tr, nullptr));
+ text_break_.GetDisplayPos(&tr, data.data());
+ return data;
+}
+
+void CFDE_TextEditEngine::RebuildPieces() {
+ text_break_.EndBreak(CFX_BreakType::Paragraph);
+ text_break_.ClearBreakPieces();
+
+ char_widths_.clear();
+ text_piece_info_.clear();
+
+ // Must have a font set in order to break the text.
+ if (text_length_ == 0 || !font_)
+ return;
+
+ bool initialized_bounding_box = false;
+ contents_bounding_box_ = CFX_RectF();
+
+ auto iter = pdfium::MakeUnique<CFDE_TextEditEngine::Iterator>(this);
+ while (!iter->IsEOF(true)) {
+ iter->Next(false);
+
+ CFX_BreakType break_status = text_break_.AppendChar(
+ password_mode_ ? password_alias_ : iter->GetChar());
+ if (iter->IsEOF(true) && CFX_BreakTypeNoneOrPiece(break_status))
+ break_status = text_break_.EndBreak(CFX_BreakType::Paragraph);
+
+ if (CFX_BreakTypeNoneOrPiece(break_status))
+ continue;
+
+ size_t current_piece_start = 0;
+ float current_line_start = 0;
+ int32_t piece_count = text_break_.CountBreakPieces();
+ for (int32_t i = 0; i < piece_count; ++i) {
+ const CFX_BreakPiece* piece = text_break_.GetBreakPieceUnstable(i);
+
+ FDE_TEXTEDITPIECE txtEdtPiece;
+ memset(&txtEdtPiece, 0, sizeof(FDE_TEXTEDITPIECE));
+
+ txtEdtPiece.nBidiLevel = piece->m_iBidiLevel;
+ txtEdtPiece.nCount = piece->GetLength();
+ txtEdtPiece.nStart = current_piece_start;
+ txtEdtPiece.dwCharStyles = piece->m_dwCharStyles;
+ if (FX_IsOdd(piece->m_iBidiLevel))
+ txtEdtPiece.dwCharStyles |= FX_TXTCHARSTYLE_OddBidiLevel;
+
+ txtEdtPiece.rtPiece.left = piece->m_iStartPos / 20000.0f;
+ txtEdtPiece.rtPiece.top = current_line_start;
+ txtEdtPiece.rtPiece.width = piece->m_iWidth / 20000.0f;
+ txtEdtPiece.rtPiece.height = line_spacing_;
+ text_piece_info_.push_back(txtEdtPiece);
+
+ if (initialized_bounding_box) {
+ contents_bounding_box_.Union(txtEdtPiece.rtPiece);
+ } else {
+ contents_bounding_box_ = txtEdtPiece.rtPiece;
+ initialized_bounding_box = true;
+ }
+
+ current_piece_start += txtEdtPiece.nCount;
+ for (int32_t k = 0; k < txtEdtPiece.nCount; ++k)
+ char_widths_.push_back(piece->GetChar(k)->m_iCharWidth);
+ }
+
+ current_line_start += line_spacing_;
+ text_break_.ClearBreakPieces();
+ }
+
+ float delta = 0.0;
+ bool bounds_smaller = contents_bounding_box_.width < available_width_;
+ if (IsAlignedRight() && bounds_smaller) {
+ delta = available_width_ - contents_bounding_box_.width;
+ } else if (IsAlignedCenter() && bounds_smaller) {
+ // TODO(dsinclair): Old code used CombText here and set the space to
+ // something unrelated to the available width .... Figure out if this is
+ // needed and what it should do.
+ // if (is_comb_text_) {
+ // } else {
+ delta = (available_width_ - contents_bounding_box_.width) / 2.0f;
+ // }
+ }
+
+ if (delta != 0.0) {
+ float offset = delta - contents_bounding_box_.left;
+ for (auto& info : text_piece_info_)
+ info.rtPiece.Offset(offset, 0.0f);
+ contents_bounding_box_.Offset(offset, 0.0f);
+ }
+
+ // Shrink the last piece down to the font_size.
+ contents_bounding_box_.height -= line_spacing_ - font_size_;
+ text_piece_info_.back().rtPiece.height = font_size_;
+}
+
+std::pair<int32_t, CFX_RectF> CFDE_TextEditEngine::GetCharacterInfo(
+ int32_t start_idx) {
+ ASSERT(start_idx >= 0);
+ ASSERT(static_cast<size_t>(start_idx) <= text_length_);
+
+ // Make sure the current available data is fresh.
+ Layout();
+
+ auto it = text_piece_info_.begin();
+ for (; it != text_piece_info_.end(); ++it) {
+ if (it->nStart <= start_idx && start_idx < it->nStart + it->nCount)
+ break;
+ }
+ if (it == text_piece_info_.end()) {
+ NOTREACHED();
+ return {0, CFX_RectF()};
+ }
+
+ return {it->nBidiLevel, GetCharRects(*it)[start_idx - it->nStart]};
+}
+
+std::vector<CFX_RectF> CFDE_TextEditEngine::GetCharacterRectsInRange(
+ int32_t start_idx,
+ int32_t count) {
+ // Make sure the current available data is fresh.
+ Layout();
+
+ auto it = text_piece_info_.begin();
+ for (; it != text_piece_info_.end(); ++it) {
+ if (it->nStart <= start_idx && start_idx < it->nStart + it->nCount)
+ break;
+ }
+ if (it == text_piece_info_.end())
+ return {};
+
+ int32_t end_idx = start_idx + count - 1;
+ std::vector<CFX_RectF> rects;
+ while (it != text_piece_info_.end()) {
+ // If we end inside the current piece, extract what we need and we're done.
+ if (it->nStart <= end_idx && end_idx < it->nStart + it->nCount) {
+ std::vector<CFX_RectF> arr = GetCharRects(*it);
+ CFX_RectF piece = arr[0];
+ piece.Union(arr[end_idx - it->nStart]);
+ rects.push_back(piece);
+ break;
+ }
+ rects.push_back(it->rtPiece);
+ ++it;
+ }
+
+ return rects;
+}
+
+CFDE_TextEditEngine::Iterator::Iterator(CFDE_TextEditEngine* engine)
+ : engine_(engine), current_position_(-1) {}
+
+CFDE_TextEditEngine::Iterator::~Iterator() {}
+
+bool CFDE_TextEditEngine::Iterator::Next(bool bPrev) {
+ if (bPrev && current_position_ == -1)
+ return false;
+ if (!bPrev && current_position_ > -1 &&
+ static_cast<size_t>(current_position_) == engine_->GetLength())
+ return false;
+
+ if (bPrev)
+ --current_position_;
+ else
+ ++current_position_;
+
+ return true;
+}
+
+wchar_t CFDE_TextEditEngine::Iterator::GetChar() const {
+ return engine_->GetChar(current_position_);
+}
+
+void CFDE_TextEditEngine::Iterator::SetAt(int32_t nIndex) {
+ NOTREACHED();
+}
+
+int32_t CFDE_TextEditEngine::Iterator::GetAt() const {
+ return current_position_;
+}
+
+bool CFDE_TextEditEngine::Iterator::IsEOF(bool bTail) const {
+ return bTail ? current_position_ > -1 &&
+ static_cast<size_t>(current_position_) ==
+ engine_->GetLength()
+ : current_position_ == -1;
+}
+
+std::unique_ptr<IFX_CharIter> CFDE_TextEditEngine::Iterator::Clone() const {
+ NOTREACHED();
+ return pdfium::MakeUnique<CFDE_TextEditEngine::Iterator>(engine_.Get());
+}
diff --git a/xfa/fde/cfde_texteditengine.h b/xfa/fde/cfde_texteditengine.h
new file mode 100644
index 0000000000..35d9664f99
--- /dev/null
+++ b/xfa/fde/cfde_texteditengine.h
@@ -0,0 +1,241 @@
+// 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/fxcrt/ifx_chariter.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 IFX_CharIter {
+ public:
+ explicit Iterator(CFDE_TextEditEngine* engine);
+ ~Iterator() override;
+
+ bool Next(bool bPrev = false) override;
+ wchar_t GetChar() const override;
+ void SetAt(int32_t nIndex) override;
+ int32_t GetAt() const override;
+ bool IsEOF(bool bTail = true) const override;
+ std::unique_ptr<IFX_CharIter> Clone() const override;
+
+ private:
+ CFX_UnownedPtr<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 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);
+
+ // 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_
diff --git a/xfa/fde/cfde_texteditengine_unittest.cpp b/xfa/fde/cfde_texteditengine_unittest.cpp
new file mode 100644
index 0000000000..da11e46daa
--- /dev/null
+++ b/xfa/fde/cfde_texteditengine_unittest.cpp
@@ -0,0 +1,418 @@
+// 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.
+
+#include "xfa/fde/cfde_texteditengine.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/test_support.h"
+#include "third_party/base/ptr_util.h"
+
+class CFDE_TextEditEngineTest : public testing::Test {
+ public:
+ class Delegate : public CFDE_TextEditEngine::Delegate {
+ public:
+ void Reset() {
+ text_is_full = false;
+ fail_validation = false;
+ }
+
+ void NotifyTextFull() override { text_is_full = true; }
+
+ void OnCaretChanged() override {}
+ void OnTextChanged(const CFX_WideString& prevText) override {}
+ void OnSelChanged() override {}
+ bool OnValidate(const CFX_WideString& wsText) override {
+ return !fail_validation;
+ }
+ void SetScrollOffset(float fScrollOffset) override {}
+
+ bool fail_validation = false;
+ bool text_is_full = false;
+ };
+
+ CFDE_TextEditEngineTest() {}
+ ~CFDE_TextEditEngineTest() override {}
+
+ void SetUp() override {
+ font_ =
+ CFGAS_GEFont::LoadFont(L"Arial Black", 0, 0, GetGlobalFontManager());
+ ASSERT(font_.Get() != nullptr);
+
+ engine_ = pdfium::MakeUnique<CFDE_TextEditEngine>();
+ engine_->SetFont(font_);
+ engine_->SetFontSize(12.0f);
+ }
+
+ void TearDown() override { engine_.reset(); }
+
+ CFDE_TextEditEngine* engine() const { return engine_.get(); }
+
+ private:
+ CFX_RetainPtr<CFGAS_GEFont> font_;
+ std::unique_ptr<CFDE_TextEditEngine> engine_;
+};
+
+TEST_F(CFDE_TextEditEngineTest, Insert) {
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+
+ engine()->Insert(0, L"");
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+ EXPECT_EQ(0U, engine()->GetLength());
+
+ engine()->Insert(0, L"Hello");
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+ EXPECT_EQ(5U, engine()->GetLength());
+
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ EXPECT_EQ(11U, engine()->GetLength());
+
+ engine()->Insert(5, L" New");
+ EXPECT_STREQ(L"Hello New World", engine()->GetText().c_str());
+
+ engine()->Insert(100, L" Cat");
+ EXPECT_STREQ(L"Hello New World Cat", engine()->GetText().c_str());
+
+ engine()->Clear();
+
+ engine()->SetHasCharacterLimit(true);
+ engine()->SetCharacterLimit(5);
+ engine()->Insert(0, L"Hello");
+
+ // No delegate
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+
+ engine()->SetCharacterLimit(8);
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str());
+
+ engine()->Clear();
+
+ // With Delegate
+ auto delegate = pdfium::MakeUnique<CFDE_TextEditEngineTest::Delegate>();
+ engine()->SetDelegate(delegate.get());
+
+ engine()->SetCharacterLimit(5);
+ engine()->Insert(0, L"Hello");
+
+ // Insert when full.
+ engine()->Insert(5, L" World");
+ EXPECT_TRUE(delegate->text_is_full);
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+ delegate->Reset();
+
+ engine()->SetCharacterLimit(8);
+ engine()->Insert(5, L" World");
+ EXPECT_TRUE(delegate->text_is_full);
+ EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str());
+ delegate->Reset();
+ engine()->SetHasCharacterLimit(false);
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello");
+
+ // Insert Invalid text
+ delegate->fail_validation = true;
+ engine()->EnableValidation(true);
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+
+ delegate->fail_validation = false;
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ engine()->EnableValidation(false);
+
+ engine()->Clear();
+
+ engine()->Insert(0, L"Hello\nWorld");
+ EXPECT_FALSE(delegate->text_is_full);
+ EXPECT_STREQ(L"Hello\nWorld", engine()->GetText().c_str());
+ delegate->Reset();
+ engine()->Clear();
+
+ // Insert with limited area and over-fill
+ engine()->LimitHorizontalScroll(true);
+ engine()->SetAvailableWidth(60.0f); // Fits 'Hello Wo'.
+ engine()->Insert(0, L"Hello");
+ EXPECT_FALSE(delegate->text_is_full);
+ engine()->Insert(5, L" World");
+ EXPECT_TRUE(delegate->text_is_full);
+ EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str());
+ engine()->LimitHorizontalScroll(false);
+
+ delegate->Reset();
+ engine()->Clear();
+
+ engine()->SetLineSpace(12.0f);
+ engine()->LimitVerticalScroll(true);
+ // Default is one line of text.
+ engine()->Insert(0, L"Hello");
+ EXPECT_FALSE(delegate->text_is_full);
+ engine()->Insert(5, L" Wo\nrld");
+ EXPECT_TRUE(delegate->text_is_full);
+ EXPECT_STREQ(L"Hello Wo\n", engine()->GetText().c_str());
+ engine()->LimitVerticalScroll(false);
+
+ engine()->SetDelegate(nullptr);
+}
+
+TEST_F(CFDE_TextEditEngineTest, Delete) {
+ EXPECT_STREQ(L"", engine()->Delete(0, 50).c_str());
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+
+ engine()->Insert(0, L"Hello World");
+ EXPECT_STREQ(L" World", engine()->Delete(5, 6).c_str());
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello World");
+ EXPECT_STREQ(L" ", engine()->Delete(5, 1).c_str());
+ EXPECT_STREQ(L"HelloWorld", engine()->GetText().c_str());
+
+ EXPECT_STREQ(L"elloWorld", engine()->Delete(1, 50).c_str());
+ EXPECT_STREQ(L"H", engine()->GetText().c_str());
+}
+
+TEST_F(CFDE_TextEditEngineTest, Clear) {
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+
+ engine()->Clear();
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+
+ engine()->Insert(0, L"Hello World");
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+ engine()->Clear();
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+ EXPECT_EQ(0U, engine()->GetLength());
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetChar) {
+ // Out of bounds.
+ EXPECT_EQ(L'\0', engine()->GetChar(0));
+
+ engine()->Insert(0, L"Hello World");
+ EXPECT_EQ(L'H', engine()->GetChar(0));
+ EXPECT_EQ(L'd', engine()->GetChar(engine()->GetLength() - 1));
+ EXPECT_EQ(L' ', engine()->GetChar(5));
+
+ engine()->Insert(5, L" A");
+ EXPECT_STREQ(L"Hello A World", engine()->GetText().c_str());
+ EXPECT_EQ(L'W', engine()->GetChar(8));
+
+ engine()->EnablePasswordMode(true);
+ EXPECT_EQ(L'*', engine()->GetChar(8));
+
+ engine()->SetAliasChar(L'+');
+ EXPECT_EQ(L'+', engine()->GetChar(8));
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetWidthOfChar) {
+ // Out of Bounds.
+ EXPECT_EQ(0U, engine()->GetWidthOfChar(0));
+
+ engine()->Insert(0, L"Hello World");
+ EXPECT_EQ(199920U, engine()->GetWidthOfChar(0));
+ EXPECT_EQ(159840U, engine()->GetWidthOfChar(1));
+
+ engine()->Insert(0, L"\t");
+ EXPECT_EQ(0U, engine()->GetWidthOfChar(0));
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetDisplayPos) {
+ EXPECT_EQ(0U, engine()->GetDisplayPos(FDE_TEXTEDITPIECE()).size());
+}
+
+TEST_F(CFDE_TextEditEngineTest, Selection) {
+ EXPECT_FALSE(engine()->HasSelection());
+ engine()->SelectAll();
+ EXPECT_FALSE(engine()->HasSelection());
+
+ engine()->Insert(0, L"Hello World");
+ EXPECT_STREQ(L"", engine()->DeleteSelectedText().c_str());
+
+ EXPECT_FALSE(engine()->HasSelection());
+ engine()->SelectAll();
+ EXPECT_TRUE(engine()->HasSelection());
+ EXPECT_STREQ(L"Hello World", engine()->GetSelectedText().c_str());
+
+ engine()->ClearSelection();
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ engine()->SelectAll();
+ size_t start_idx;
+ size_t end_idx;
+ std::tie(start_idx, end_idx) = engine()->GetSelection();
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(10U, end_idx);
+
+ // Selection before gap.
+ EXPECT_STREQ(L"Hello World", engine()->GetSelectedText().c_str());
+ EXPECT_TRUE(engine()->HasSelection());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+ engine()->Insert(5, L" A");
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ // Selection over the gap.
+ engine()->SelectAll();
+ EXPECT_TRUE(engine()->HasSelection());
+ EXPECT_STREQ(L"Hello A World", engine()->GetSelectedText().c_str());
+ engine()->Clear();
+
+ engine()->Insert(0, L"Hello World");
+ engine()->SelectAll();
+
+ EXPECT_STREQ(L"Hello World", engine()->DeleteSelectedText().c_str());
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+
+ engine()->Insert(0, L"Hello World");
+ engine()->SetSelection(5, 9);
+ EXPECT_STREQ(L" Worl", engine()->DeleteSelectedText().c_str());
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"Hellod", engine()->GetText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello World");
+ engine()->SelectAll();
+ engine()->ReplaceSelectedText(L"Goodbye Everybody");
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"Goodbye Everybody", engine()->GetText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello World");
+ engine()->SetSelection(1, 4);
+ engine()->ReplaceSelectedText(L"i,");
+ EXPECT_FALSE(engine()->HasSelection());
+ EXPECT_STREQ(L"Hi, World", engine()->GetText().c_str());
+
+ // Selection fully after gap.
+ engine()->Clear();
+ engine()->Insert(0, L"Hello");
+ engine()->Insert(0, L"A ");
+ engine()->SetSelection(3, 6);
+ EXPECT_STREQ(L"ello", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello World");
+ engine()->ClearSelection();
+ engine()->DeleteSelectedText();
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+}
+
+TEST_F(CFDE_TextEditEngineTest, UndoRedo) {
+ EXPECT_FALSE(engine()->CanUndo());
+ EXPECT_FALSE(engine()->CanRedo());
+ EXPECT_FALSE(engine()->Undo());
+ EXPECT_FALSE(engine()->Redo());
+
+ engine()->Insert(0, L"Hello");
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_FALSE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+ EXPECT_FALSE(engine()->CanUndo());
+ EXPECT_TRUE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_FALSE(engine()->CanRedo());
+
+ engine()->Clear();
+ EXPECT_FALSE(engine()->CanUndo());
+ EXPECT_FALSE(engine()->CanRedo());
+
+ engine()->Insert(0, L"Hello World");
+ engine()->SelectAll();
+ engine()->DeleteSelectedText();
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_STREQ(L"", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_FALSE(engine()->CanRedo());
+
+ engine()->Insert(0, L"Hello World");
+ engine()->SelectAll();
+ engine()->ReplaceSelectedText(L"Goodbye Friend");
+ EXPECT_STREQ(L"Goodbye Friend", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_STREQ(L"Goodbye Friend", engine()->GetText().c_str());
+
+ engine()->Clear();
+ engine()->SetMaxEditOperationsForTesting(3);
+ engine()->Insert(0, L"First ");
+ engine()->Insert(engine()->GetLength(), L"Second ");
+ engine()->Insert(engine()->GetLength(), L"Third");
+
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"First Second ", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->CanUndo());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_FALSE(
+ engine()->CanUndo()); // Can't undo First; undo buffer too small.
+ EXPECT_STREQ(L"First ", engine()->GetText().c_str());
+
+ EXPECT_TRUE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_TRUE(engine()->CanRedo());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_FALSE(engine()->CanRedo());
+ EXPECT_STREQ(L"First Second Third", engine()->GetText().c_str());
+
+ engine()->Clear();
+
+ engine()->SetMaxEditOperationsForTesting(4);
+
+ // Go beyond the max operations limit.
+ engine()->Insert(0, L"H");
+ engine()->Insert(1, L"e");
+ engine()->Insert(2, L"l");
+ engine()->Insert(3, L"l");
+ engine()->Insert(4, L"o");
+ engine()->Insert(5, L" World");
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+
+ // Do A, undo. Do B, undo. Redo should cause B.
+ engine()->Delete(4, 3);
+ EXPECT_STREQ(L"Hellorld", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ engine()->Delete(5, 6);
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->Redo());
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+
+ // Undo down to the limit.
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello World", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hello", engine()->GetText().c_str());
+ EXPECT_TRUE(engine()->Undo());
+ EXPECT_STREQ(L"Hell", engine()->GetText().c_str());
+ EXPECT_FALSE(engine()->Undo());
+ EXPECT_STREQ(L"Hell", engine()->GetText().c_str());
+}
+
+TEST_F(CFDE_TextEditEngineTest, GetIndexForPoint) {
+ engine()->SetFontSize(10.0f);
+ engine()->Insert(0, L"Hello World");
+ EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f}));
+ EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
+ EXPECT_EQ(1U, engine()->GetIndexForPoint({10.0f, 5.0f}));
+}
diff --git a/xfa/fde/cfde_txtedtbuf.cpp b/xfa/fde/cfde_txtedtbuf.cpp
deleted file mode 100644
index caa223c697..0000000000
--- a/xfa/fde/cfde_txtedtbuf.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fde/cfde_txtedtbuf.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-
-namespace {
-
-const int32_t kDefaultChunkSize = 1024;
-
-} // namespace
-
-CFDE_TxtEdtBuf::CFDE_TxtEdtBuf() : m_chunkSize(kDefaultChunkSize), m_nTotal(0) {
- m_chunks.push_back(pdfium::MakeUnique<ChunkHeader>(m_chunkSize));
-}
-
-CFDE_TxtEdtBuf::~CFDE_TxtEdtBuf() {}
-
-void CFDE_TxtEdtBuf::SetText(const CFX_WideString& wsText) {
- ASSERT(!wsText.IsEmpty());
-
- Clear();
-
- int32_t nTextLength = wsText.GetLength();
- int32_t nNeedCount = ((nTextLength - 1) / m_chunkSize + 1) -
- pdfium::CollectionSize<int32_t>(m_chunks);
- for (int32_t i = 0; i < nNeedCount; ++i)
- m_chunks.push_back(pdfium::MakeUnique<ChunkHeader>(m_chunkSize));
-
- const wchar_t* lpSrcBuf = wsText.c_str();
- int32_t nLeave = nTextLength;
- int32_t nCopyedLength = m_chunkSize;
- for (size_t i = 0; i < m_chunks.size() && nLeave > 0; ++i) {
- if (nLeave < nCopyedLength)
- nCopyedLength = nLeave;
-
- ChunkHeader* chunk = m_chunks[i].get();
- memcpy(chunk->wChars.data(), lpSrcBuf, nCopyedLength * sizeof(wchar_t));
- nLeave -= nCopyedLength;
- lpSrcBuf += nCopyedLength;
- chunk->nUsed = nCopyedLength;
- }
- m_nTotal = nTextLength;
-}
-
-wchar_t CFDE_TxtEdtBuf::GetCharByIndex(int32_t nIndex) const {
- ASSERT(nIndex >= 0 && nIndex < GetTextLength());
-
- ChunkHeader* pChunkHeader = nullptr;
- int32_t nTotal = 0;
- for (const auto& chunk : m_chunks) {
- pChunkHeader = chunk.get();
- nTotal += pChunkHeader->nUsed;
- if (nTotal > nIndex)
- break;
- }
- ASSERT(pChunkHeader);
-
- return pChunkHeader->wChars[pChunkHeader->nUsed - (nTotal - nIndex)];
-}
-
-CFX_WideString CFDE_TxtEdtBuf::GetRange(int32_t nBegin, int32_t nLength) const {
- if (nLength == 0 || GetTextLength() == 0)
- return CFX_WideString();
-
- ASSERT(nBegin >= 0 && nLength > 0 && nBegin < GetTextLength() &&
- nBegin + nLength <= GetTextLength());
-
- int32_t chunkIndex = 0;
- int32_t charIndex = 0;
- std::tie(chunkIndex, charIndex) = Index2CP(nBegin);
-
- int32_t nLeave = nLength;
- CFX_WideString wsText;
-
- int32_t nCopyLength = m_chunks[chunkIndex]->nUsed - charIndex;
- wchar_t* lpSrcBuf = m_chunks[chunkIndex]->wChars.data() + charIndex;
- while (nLeave > 0) {
- if (nLeave <= nCopyLength)
- nCopyLength = nLeave;
-
- wsText += CFX_WideStringC(lpSrcBuf, nCopyLength);
-
- ++chunkIndex;
- if (chunkIndex >= pdfium::CollectionSize<int32_t>(m_chunks))
- break;
-
- lpSrcBuf = m_chunks[chunkIndex]->wChars.data();
- nLeave -= nCopyLength;
- nCopyLength = m_chunks[chunkIndex]->nUsed;
- }
- return wsText;
-}
-
-void CFDE_TxtEdtBuf::Insert(int32_t nPos, const CFX_WideString& wsText) {
- ASSERT(nPos >= 0 && nPos <= m_nTotal);
-
- int32_t nLength = wsText.GetLength();
- ASSERT(nLength > 0);
-
- int32_t chunkIndex = 0;
- int32_t charIndex = 0;
- std::tie(chunkIndex, charIndex) = Index2CP(nPos);
-
- if (charIndex != 0) {
- auto newChunk = pdfium::MakeUnique<ChunkHeader>(m_chunkSize);
-
- ChunkHeader* chunk = m_chunks[chunkIndex].get();
- int32_t nCopy = chunk->nUsed - charIndex;
-
- memcpy(newChunk->wChars.data(), chunk->wChars.data() + charIndex,
- nCopy * sizeof(wchar_t));
- chunk->nUsed -= nCopy;
- ++chunkIndex;
-
- newChunk->nUsed = nCopy;
- m_chunks.insert(m_chunks.begin() + chunkIndex, std::move(newChunk));
- charIndex = 0;
- }
-
- const wchar_t* lpText = wsText.c_str();
- if (chunkIndex != 0) {
- ChunkHeader* chunk = m_chunks[chunkIndex - 1].get();
- if (chunk->nUsed != m_chunkSize) {
- chunkIndex--;
- int32_t nCopy = std::min(nLength, m_chunkSize - chunk->nUsed);
- memcpy(chunk->wChars.data() + chunk->nUsed, lpText,
- nCopy * sizeof(wchar_t));
- lpText += nCopy;
- nLength -= nCopy;
- chunk->nUsed += nCopy;
- ++chunkIndex;
- }
- }
-
- while (nLength > 0) {
- auto chunk = pdfium::MakeUnique<ChunkHeader>(m_chunkSize);
-
- int32_t nCopy = std::min(nLength, m_chunkSize);
- memcpy(chunk->wChars.data(), lpText, nCopy * sizeof(wchar_t));
- lpText += nCopy;
- nLength -= nCopy;
- chunk->nUsed = nCopy;
- m_chunks.insert(m_chunks.begin() + chunkIndex, std::move(chunk));
- ++chunkIndex;
- }
-
- m_nTotal += wsText.GetLength();
-}
-
-void CFDE_TxtEdtBuf::Delete(int32_t nIndex, int32_t nLength) {
- ASSERT(nLength > 0 && nIndex >= 0 && nIndex + nLength <= m_nTotal);
-
- int32_t endChunkIndex = 0;
- int32_t endCharIndex = 0;
- std::tie(endChunkIndex, endCharIndex) = Index2CP(nIndex + nLength - 1);
- m_nTotal -= nLength;
-
- int32_t nFirstPart = endCharIndex + 1;
- int32_t nMovePart = m_chunks[endChunkIndex]->nUsed - nFirstPart;
- if (nMovePart != 0) {
- int32_t nDelete = std::min(nFirstPart, nLength);
- memmove(m_chunks[endChunkIndex]->wChars.data() + nFirstPart - nDelete,
- m_chunks[endChunkIndex]->wChars.data() + nFirstPart,
- nMovePart * sizeof(wchar_t));
- m_chunks[endChunkIndex]->nUsed -= nDelete;
- nLength -= nDelete;
- --endChunkIndex;
- }
-
- while (nLength > 0) {
- int32_t nDeleted = std::min(m_chunks[endChunkIndex]->nUsed, nLength);
- m_chunks[endChunkIndex]->nUsed -= nDeleted;
- if (m_chunks[endChunkIndex]->nUsed == 0)
- m_chunks.erase(m_chunks.begin() + endChunkIndex);
-
- nLength -= nDeleted;
- --endChunkIndex;
- }
-}
-
-void CFDE_TxtEdtBuf::Clear() {
- for (auto& chunk : m_chunks)
- chunk->nUsed = 0;
- m_nTotal = 0;
-}
-
-void CFDE_TxtEdtBuf::SetChunkSizeForTesting(size_t size) {
- ASSERT(size > 0);
-
- m_chunkSize = size;
- m_chunks.clear();
- m_chunks.push_back(pdfium::MakeUnique<ChunkHeader>(m_chunkSize));
-}
-
-std::pair<int32_t, int32_t> CFDE_TxtEdtBuf::Index2CP(int32_t nIndex) const {
- ASSERT(nIndex <= GetTextLength());
-
- if (nIndex == m_nTotal)
- return {m_chunks.size() - 1, m_chunks.back()->nUsed};
-
- int32_t chunkIndex = 0;
- int32_t nTotal = 0;
- for (auto& chunk : m_chunks) {
- nTotal += chunk->nUsed;
- if (nTotal > nIndex)
- break;
-
- ++chunkIndex;
- }
-
- return {chunkIndex, m_chunks[chunkIndex]->nUsed - (nTotal - nIndex)};
-}
-
-CFDE_TxtEdtBuf::ChunkHeader::ChunkHeader(int32_t chunkSize) : nUsed(0) {
- wChars.resize(chunkSize);
-}
-
-CFDE_TxtEdtBuf::ChunkHeader::~ChunkHeader() {}
-
-CFDE_TxtEdtBuf::Iterator::Iterator(CFDE_TxtEdtBuf* pBuf, wchar_t wcAlias)
- : m_pBuf(pBuf),
- m_nCurChunk(0),
- m_nCurIndex(0),
- m_nIndex(0),
- m_Alias(wcAlias) {
- ASSERT(m_pBuf);
-}
-
-CFDE_TxtEdtBuf::Iterator::~Iterator() {}
-
-bool CFDE_TxtEdtBuf::Iterator::Next(bool bPrev) {
- if (bPrev) {
- if (m_nIndex == 0)
- return false;
-
- ASSERT(m_nCurChunk < pdfium::CollectionSize<int32_t>(m_pBuf->m_chunks));
-
- if (m_nCurIndex > 0) {
- --m_nCurIndex;
- } else {
- while (m_nCurChunk > 0) {
- --m_nCurChunk;
- ChunkHeader* chunk = m_pBuf->m_chunks[m_nCurChunk].get();
- if (chunk->nUsed > 0) {
- m_nCurIndex = chunk->nUsed - 1;
- break;
- }
- }
- }
- ASSERT(m_nCurChunk >= 0);
-
- --m_nIndex;
- return true;
- }
-
- if (m_nIndex >= (m_pBuf->m_nTotal - 1))
- return false;
-
- ASSERT(m_nCurChunk < pdfium::CollectionSize<int32_t>(m_pBuf->m_chunks));
-
- if (m_pBuf->m_chunks[m_nCurChunk]->nUsed != (m_nCurIndex + 1)) {
- ++m_nCurIndex;
- } else {
- while (m_nCurChunk <
- pdfium::CollectionSize<int32_t>(m_pBuf->m_chunks) - 1) {
- ++m_nCurChunk;
- if (m_pBuf->m_chunks[m_nCurChunk]->nUsed > 0) {
- m_nCurIndex = 0;
- break;
- }
- }
- }
- ++m_nIndex;
- return true;
-}
-
-void CFDE_TxtEdtBuf::Iterator::SetAt(int32_t nIndex) {
- ASSERT(nIndex >= 0 && nIndex < m_pBuf->m_nTotal);
-
- std::tie(m_nCurChunk, m_nCurIndex) = m_pBuf->Index2CP(nIndex);
- m_nIndex = nIndex;
-}
-
-int32_t CFDE_TxtEdtBuf::Iterator::GetAt() const {
- return m_nIndex;
-}
-
-wchar_t CFDE_TxtEdtBuf::Iterator::GetChar() const {
- ASSERT(m_nIndex >= 0 && m_nIndex < m_pBuf->m_nTotal);
-
- if (m_Alias != 0 && m_nIndex != (m_pBuf->m_nTotal - 1))
- return m_Alias;
- return m_pBuf->m_chunks[m_nCurChunk]->wChars[m_nCurIndex];
-}
-
-bool CFDE_TxtEdtBuf::Iterator::IsEOF(bool bTail) const {
- return bTail ? m_nIndex == (m_pBuf->GetTextLength() - 2) : m_nIndex == 0;
-}
-
-std::unique_ptr<IFX_CharIter> CFDE_TxtEdtBuf::Iterator::Clone() const {
- auto pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(m_pBuf, 0);
- pIter->m_nCurChunk = m_nCurChunk;
- pIter->m_nCurIndex = m_nCurIndex;
- pIter->m_nIndex = m_nIndex;
- pIter->m_Alias = m_Alias;
- return pIter;
-}
diff --git a/xfa/fde/cfde_txtedtbuf.h b/xfa/fde/cfde_txtedtbuf.h
deleted file mode 100644
index e8293d0240..0000000000
--- a/xfa/fde/cfde_txtedtbuf.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 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_TXTEDTBUF_H_
-#define XFA_FDE_CFDE_TXTEDTBUF_H_
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "core/fxcrt/fx_basic.h"
-#include "core/fxcrt/fx_system.h"
-#include "core/fxcrt/ifx_chariter.h"
-
-class CFDE_TxtEdtBuf {
- public:
- class Iterator : public IFX_CharIter {
- public:
- Iterator(CFDE_TxtEdtBuf* pBuf, wchar_t wcAlias);
- ~Iterator() override;
-
- bool Next(bool bPrev = false) override;
- wchar_t GetChar() const override;
-
- void SetAt(int32_t nIndex) override;
- int32_t GetAt() const override;
-
- bool IsEOF(bool bTail = true) const override;
- std::unique_ptr<IFX_CharIter> Clone() const override;
-
- private:
- CFDE_TxtEdtBuf* m_pBuf;
- int32_t m_nCurChunk;
- int32_t m_nCurIndex;
- int32_t m_nIndex;
- wchar_t m_Alias;
- };
-
- CFDE_TxtEdtBuf();
- ~CFDE_TxtEdtBuf();
-
- int32_t GetTextLength() const { return m_nTotal; }
- void SetText(const CFX_WideString& wsText);
- CFX_WideString GetText() const { return GetRange(0, m_nTotal); }
-
- wchar_t GetCharByIndex(int32_t nIndex) const;
- CFX_WideString GetRange(int32_t nBegin, int32_t nCount) const;
-
- void Insert(int32_t nPos, const CFX_WideString& wsText);
- void Delete(int32_t nIndex, int32_t nLength);
- void Clear();
-
- void SetChunkSizeForTesting(size_t size);
- size_t GetChunkCountForTesting() const { return m_chunks.size(); }
-
- private:
- class ChunkHeader {
- public:
- explicit ChunkHeader(int32_t chunkSize);
- ~ChunkHeader();
-
- int32_t nUsed;
- std::vector<wchar_t> wChars;
- };
-
- std::pair<int32_t, int32_t> Index2CP(int32_t nIndex) const;
-
- int32_t m_chunkSize;
- int32_t m_nTotal;
- std::vector<std::unique_ptr<ChunkHeader>> m_chunks;
-};
-
-#endif // XFA_FDE_CFDE_TXTEDTBUF_H_
diff --git a/xfa/fde/cfde_txtedtbuf_unittest.cpp b/xfa/fde/cfde_txtedtbuf_unittest.cpp
deleted file mode 100644
index 8c112f19e2..0000000000
--- a/xfa/fde/cfde_txtedtbuf_unittest.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-// 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.
-
-#include "xfa/fde/cfde_txtedtbuf.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/test_support.h"
-#include "third_party/base/ptr_util.h"
-
-class CFDE_TxtEdtBufTest : public testing::Test {
- public:
- void SetUp() override {
- buf_ = pdfium::MakeUnique<CFDE_TxtEdtBuf>();
- buf_->SetChunkSizeForTesting(5);
- }
-
- size_t ChunkCount() const { return buf_->GetChunkCountForTesting(); }
-
- std::unique_ptr<CFDE_TxtEdtBuf> buf_;
-};
-
-TEST_F(CFDE_TxtEdtBufTest, SetTextLessThenChunkSize) {
- buf_->SetText(L"Hi");
- EXPECT_EQ(1UL, ChunkCount());
- EXPECT_EQ(2, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(2, res.GetLength());
- EXPECT_EQ(L"Hi", res);
-}
-
-TEST_F(CFDE_TxtEdtBufTest, InsertAppendChunk) {
- buf_->SetText(L"Hi");
-
- CFX_WideString end = L" World";
- buf_->Insert(2, end);
- EXPECT_EQ(3UL, ChunkCount());
- EXPECT_EQ(8, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(8, res.GetLength());
- EXPECT_EQ(L"Hi World", res);
-}
-
-TEST_F(CFDE_TxtEdtBufTest, InsertPrependChunk) {
- buf_->SetText(L"Hi");
-
- CFX_WideString end = L"World ";
- buf_->Insert(0, end);
- EXPECT_EQ(3UL, ChunkCount());
- EXPECT_EQ(8, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"World Hi", res);
- EXPECT_EQ(8, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, InsertBetweenChunks) {
- buf_->SetText(L"Hello World");
- EXPECT_EQ(3UL, ChunkCount());
-
- CFX_WideString inst = L"there ";
- buf_->Insert(6, inst);
- EXPECT_EQ(5UL, ChunkCount());
- EXPECT_EQ(17, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"Hello there World", res);
- EXPECT_EQ(17, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, SetText) {
- buf_->SetText(L"Hello World");
- EXPECT_EQ(11, buf_->GetTextLength());
-
- buf_->SetText(L"Hi");
- // Don't remove chunks on setting shorter text.
- EXPECT_EQ(3UL, ChunkCount());
- EXPECT_EQ(2, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"Hi", res);
- EXPECT_EQ(2, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, DeleteMiddleText) {
- buf_->SetText(L"Hello there World");
- buf_->Delete(6, 6);
- EXPECT_EQ(4UL, ChunkCount());
- EXPECT_EQ(11, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"Hello World", res);
- EXPECT_EQ(11, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, DeleteEndText) {
- buf_->SetText(L"Hello World");
- buf_->Delete(5, 6);
- EXPECT_EQ(1UL, ChunkCount());
- EXPECT_EQ(5, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"Hello", res);
- EXPECT_EQ(5, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, DeleteStartText) {
- buf_->SetText(L"Hello World");
- buf_->Delete(0, 6);
- EXPECT_EQ(2UL, ChunkCount());
- EXPECT_EQ(5, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"World", res);
- EXPECT_EQ(5, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, DeleteAllText) {
- buf_->SetText(L"Hello World");
- buf_->Delete(0, 11);
- EXPECT_EQ(0UL, ChunkCount());
- EXPECT_EQ(0, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"", res);
- EXPECT_EQ(0, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, Clear) {
- buf_->SetText(L"Hello World");
- buf_->Clear();
- EXPECT_EQ(3UL, ChunkCount());
- EXPECT_EQ(0, buf_->GetTextLength());
-
- CFX_WideString res = buf_->GetText();
- EXPECT_EQ(L"", res);
- EXPECT_EQ(0, res.GetLength());
-}
-
-TEST_F(CFDE_TxtEdtBufTest, GetCharByIndex) {
- buf_->SetText(L"Hello world");
- EXPECT_EQ(L"e", CFX_WideString(buf_->GetCharByIndex(1)));
- EXPECT_EQ(L"o", CFX_WideString(buf_->GetCharByIndex(7)));
-}
-
-TEST_F(CFDE_TxtEdtBufTest, GetRange) {
- buf_->SetText(L"Hello World");
- EXPECT_EQ(L"", buf_->GetRange(1, 0));
- EXPECT_EQ(L"ello", buf_->GetRange(1, 4));
- EXPECT_EQ(L"lo Wo", buf_->GetRange(3, 5));
-}
-
-#ifndef NDEBUG
-using CFDE_TxtEdtBufTestDeathTest = CFDE_TxtEdtBufTest;
-
-TEST_F(CFDE_TxtEdtBufTestDeathTest, InsertBadIndexes) {
- CFX_WideString inst = L"there ";
-
- buf_->SetText(L"Hi");
- EXPECT_DEATH(buf_->Insert(-4, inst), "Assertion");
- EXPECT_DEATH(buf_->Insert(9999, inst), "Assertion");
-}
-
-TEST_F(CFDE_TxtEdtBufTestDeathTest, DeleteWithBadIdx) {
- buf_->SetText(L"Hi");
- EXPECT_DEATH(buf_->Delete(-10, 4), "Assertion");
- EXPECT_DEATH(buf_->Delete(1, -5), "Assertion");
- EXPECT_DEATH(buf_->Delete(5, 1), "Assertion");
- EXPECT_DEATH(buf_->Delete(0, 10000), "Assertion");
-}
-
-TEST_F(CFDE_TxtEdtBufTestDeathTest, GetCharByIndex) {
- buf_->SetText(L"Hi");
- EXPECT_DEATH(buf_->GetCharByIndex(-1), "Assertion");
- EXPECT_DEATH(buf_->GetCharByIndex(100), "Assertion");
-}
-
-TEST_F(CFDE_TxtEdtBufTestDeathTest, GetRange) {
- buf_->SetText(L"Hi");
- EXPECT_DEATH(buf_->GetRange(1, -1), "Assertion");
- EXPECT_DEATH(buf_->GetRange(-1, 1), "Assertion");
- EXPECT_DEATH(buf_->GetRange(10, 1), "Assertion");
- EXPECT_DEATH(buf_->GetRange(1, 100), "Assertion");
-}
-
-#endif // NDEBUG
diff --git a/xfa/fde/cfde_txtedtengine.cpp b/xfa/fde/cfde_txtedtengine.cpp
deleted file mode 100644
index e3815e7de4..0000000000
--- a/xfa/fde/cfde_txtedtengine.cpp
+++ /dev/null
@@ -1,1234 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fde/cfde_txtedtengine.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "core/fxcrt/ifx_chariter.h"
-#include "third_party/base/ptr_util.h"
-#include "xfa/fde/cfde_textout.h"
-#include "xfa/fde/cfde_txtedtbuf.h"
-#include "xfa/fde/cfde_txtedtpage.h"
-#include "xfa/fde/cfde_txtedtparag.h"
-#include "xfa/fwl/cfwl_edit.h"
-
-namespace {
-
-const uint32_t kPageWidthMax = 0xffff;
-
-class InsertOperation : public IFDE_TxtEdtDoRecord {
- public:
- InsertOperation(CFDE_TxtEdtEngine* pEngine,
- int32_t nCaret,
- const CFX_WideString& str)
- : m_pEngine(pEngine), m_nCaret(nCaret), m_wsInsert(str) {
- ASSERT(m_pEngine);
- }
-
- ~InsertOperation() override {}
-
- void Undo() const override {
- CFX_WideString prev = m_pEngine->GetText(0, -1);
-
- if (m_pEngine->IsSelect())
- m_pEngine->ClearSelection();
-
- m_pEngine->Inner_DeleteRange(m_nCaret, m_wsInsert.GetLength());
- m_pEngine->GetParams()->pEventSink->OnTextChanged(prev);
- m_pEngine->SetCaretPos(m_nCaret, true);
- }
-
- void Redo() const override {
- CFX_WideString prev = m_pEngine->GetText(0, -1);
- m_pEngine->Inner_Insert(m_nCaret, m_wsInsert);
- m_pEngine->GetParams()->pEventSink->OnTextChanged(prev);
- m_pEngine->SetCaretPos(m_nCaret, false);
- }
-
- private:
- CFDE_TxtEdtEngine* m_pEngine;
- int32_t m_nCaret;
- CFX_WideString m_wsInsert;
-};
-
-class DeleteOperation : public IFDE_TxtEdtDoRecord {
- public:
- DeleteOperation(CFDE_TxtEdtEngine* pEngine,
- int32_t nIndex,
- int32_t nCaret,
- const CFX_WideString& wsRange,
- bool bSel)
- : m_pEngine(pEngine),
- m_bSel(bSel),
- m_nIndex(nIndex),
- m_nCaret(nCaret),
- m_wsRange(wsRange) {
- ASSERT(m_pEngine);
- }
-
- ~DeleteOperation() override {}
-
- void Undo() const override {
- CFX_WideString prev = m_pEngine->GetText(0, -1);
- if (m_pEngine->IsSelect())
- m_pEngine->ClearSelection();
-
- m_pEngine->Inner_Insert(m_nIndex, m_wsRange);
- if (m_bSel)
- m_pEngine->AddSelRange(m_nIndex, m_wsRange.GetLength());
-
- m_pEngine->GetParams()->pEventSink->OnTextChanged(prev);
- m_pEngine->SetCaretPos(m_nCaret, true);
- }
-
- void Redo() const override {
- CFX_WideString prev = m_pEngine->GetText(0, -1);
- m_pEngine->Inner_DeleteRange(m_nIndex, m_wsRange.GetLength());
- if (m_bSel)
- m_pEngine->RemoveSelRange(m_nIndex, m_wsRange.GetLength());
-
- m_pEngine->GetParams()->pEventSink->OnTextChanged(prev);
- m_pEngine->SetCaretPos(m_nIndex, true);
- }
-
- private:
- CFDE_TxtEdtEngine* m_pEngine;
- bool m_bSel;
- int32_t m_nIndex;
- int32_t m_nCaret;
- CFX_WideString m_wsRange;
-};
-
-} // namespace
-
-FDE_TXTEDTPARAMS::FDE_TXTEDTPARAMS()
- : fPlateWidth(0),
- fPlateHeight(0),
- nLineCount(0),
- dwLayoutStyles(0),
- dwAlignment(0),
- dwMode(0),
- fFontSize(10.0f),
- dwFontColor(0xff000000),
- fLineSpace(10.0f),
- fTabWidth(36),
- pEventSink(nullptr) {}
-
-FDE_TXTEDTPARAMS::~FDE_TXTEDTPARAMS() {}
-
-CFDE_TxtEdtEngine::CFDE_TxtEdtEngine()
- : m_pTxtBuf(pdfium::MakeUnique<CFDE_TxtEdtBuf>()),
- m_nPageLineCount(20),
- m_nLineCount(0),
- m_nAnchorPos(-1),
- m_fCaretPosReserve(0.0),
- m_nCaret(0),
- m_nCaretPage(0),
- m_nLimit(0),
- m_wcAliasChar(L'*'),
- m_FirstLineEnding(LineEnding::kAuto),
- m_bBefore(true),
- m_bLock(false),
- m_bAutoLineEnd(true) {}
-
-CFDE_TxtEdtEngine::~CFDE_TxtEdtEngine() {
- RemoveAllParags();
- RemoveAllPages();
- m_Param.pEventSink = nullptr;
- ClearSelection();
-}
-
-void CFDE_TxtEdtEngine::SetEditParams(const FDE_TXTEDTPARAMS& params) {
- m_Param = params;
- m_bAutoLineEnd = true;
- UpdateTxtBreak();
-}
-
-CFDE_TxtEdtPage* CFDE_TxtEdtEngine::GetPage(int32_t nIndex) {
- if (!pdfium::IndexInBounds(m_PagePtrArray, nIndex))
- return nullptr;
- return m_PagePtrArray[nIndex].get();
-}
-
-void CFDE_TxtEdtEngine::SetText(const CFX_WideString& wsText) {
- ResetEngine();
- int32_t nLength = wsText.GetLength();
- if (nLength > 0) {
- CFX_WideString wsTemp;
- wchar_t* lpBuffer = wsTemp.GetBuffer(nLength);
- memcpy(lpBuffer, wsText.c_str(), nLength * sizeof(wchar_t));
- ReplaceParagEnd(lpBuffer, nLength, false);
- wsTemp.ReleaseBuffer(nLength);
- if (m_nLimit > 0 && nLength > m_nLimit) {
- wsTemp.Delete(m_nLimit, nLength - m_nLimit);
- nLength = m_nLimit;
- }
- m_pTxtBuf->SetText(wsTemp);
- }
- m_pTxtBuf->Insert(nLength, L"\n");
- RebuildParagraphs();
-}
-
-CFX_WideString CFDE_TxtEdtEngine::GetText(int32_t nStart,
- int32_t nCount) const {
- int32_t nTextBufLength = GetTextLength();
- if (nCount == -1)
- nCount = nTextBufLength - nStart;
-
- CFX_WideString wsText = m_pTxtBuf->GetRange(nStart, nCount);
- RecoverParagEnd(wsText);
- return wsText;
-}
-
-void CFDE_TxtEdtEngine::ClearText() {
- if (IsLocked())
- return;
-
- int32_t len = GetTextLength();
- if (len == 0)
- return;
- if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
- // This doesn't really make sense, if the cleared text isn't valid we
- // don't clear it? But what if you want to clear and start again? Should
- // this validation check be removed?
- CFX_WideString wsText = GetText(0, GetTextLength());
- wsText.Delete(0, len);
- if (!m_Param.pEventSink->OnValidate(wsText))
- return;
- }
-
- CFX_WideString prev = GetText(0, -1);
-
- DeleteRange_DoRecord(0, len, false);
- m_Param.pEventSink->OnTextChanged(prev);
- SetCaretPos(0, true);
-}
-
-int32_t CFDE_TxtEdtEngine::SetCaretPos(int32_t nIndex, bool bBefore) {
- if (IsLocked())
- return 0;
-
- ASSERT(nIndex >= 0 && nIndex <= GetTextLength());
- if (!pdfium::IndexInBounds(m_PagePtrArray, m_nCaretPage))
- return 0;
-
- m_bBefore = bBefore;
- m_nCaret = nIndex;
- MovePage2Char(m_nCaret);
- GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
- if (!m_bBefore) {
- m_nCaret++;
- m_bBefore = true;
- }
- m_fCaretPosReserve = m_rtCaret.left;
- m_Param.pEventSink->OnCaretChanged();
- m_nAnchorPos = -1;
- return m_nCaret;
-}
-
-int32_t CFDE_TxtEdtEngine::MoveCaretPos(FDE_CaretMove eMoveCaret, bool bShift) {
- if (IsLocked() || !pdfium::IndexInBounds(m_PagePtrArray, m_nCaretPage))
- return 0;
-
- bool bSelChange = false;
- if (IsSelect()) {
- ClearSelection();
- bSelChange = true;
- }
- if (bShift) {
- if (m_nAnchorPos == -1)
- m_nAnchorPos = m_nCaret;
- } else {
- m_nAnchorPos = -1;
- }
-
- switch (eMoveCaret) {
- case FDE_CaretMove::Left: {
- bool bBefore = true;
- int32_t nIndex = MoveBackward(bBefore);
- if (nIndex >= 0)
- UpdateCaretRect(nIndex, bBefore);
- break;
- }
- case FDE_CaretMove::Right: {
- bool bBefore = true;
- int32_t nIndex = MoveForward(bBefore);
- if (nIndex >= 0)
- UpdateCaretRect(nIndex, bBefore);
- break;
- }
- case FDE_CaretMove::Up: {
- CFX_PointF ptCaret;
- if (MoveUp(ptCaret))
- UpdateCaretIndex(ptCaret);
- break;
- }
- case FDE_CaretMove::Down: {
- CFX_PointF ptCaret;
- if (MoveDown(ptCaret))
- UpdateCaretIndex(ptCaret);
- break;
- }
- case FDE_CaretMove::LineStart:
- MoveLineStart();
- break;
- case FDE_CaretMove::LineEnd:
- MoveLineEnd();
- break;
- case FDE_CaretMove::Home:
- MoveHome();
- break;
- case FDE_CaretMove::End:
- MoveEnd();
- break;
- }
- if (bShift && m_nAnchorPos != -1 && (m_nAnchorPos != m_nCaret)) {
- AddSelRange(std::min(m_nAnchorPos, m_nCaret), abs(m_nAnchorPos - m_nCaret));
- m_Param.pEventSink->OnSelChanged();
- }
- if (bSelChange)
- m_Param.pEventSink->OnSelChanged();
-
- return m_nCaret;
-}
-
-FDE_EditResult CFDE_TxtEdtEngine::Insert(const CFX_WideString& str) {
- if (IsLocked())
- return FDE_EditResult::kLocked;
-
- int32_t nLength = str.GetLength();
- CFX_WideString wsTemp;
- wchar_t* lpBuffer = wsTemp.GetBuffer(nLength);
- memcpy(lpBuffer, str.c_str(), nLength * sizeof(wchar_t));
- ReplaceParagEnd(lpBuffer, nLength, false);
- wsTemp.ReleaseBuffer(nLength);
-
- if (m_nLimit > 0) {
- int32_t nTotalLength = GetTextLength();
- for (const auto& lpSelRange : m_SelRangePtrArr)
- nTotalLength -= lpSelRange->nCount;
-
- int32_t nExpectLength = nTotalLength + nLength;
- if (nTotalLength == m_nLimit)
- return FDE_EditResult::kFull;
-
- if (nExpectLength > m_nLimit)
- nLength -= (nExpectLength - m_nLimit);
- }
- if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) ||
- (m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz)) {
- if (m_Param.dwMode & FDE_TEXTEDITMODE_Password) {
- while (nLength > 0) {
- CFX_WideString wsText = InsertIntoTextCopy(m_nCaret, lpBuffer, nLength);
- int32_t nTotal = wsText.GetLength();
- wchar_t* lpBuf = wsText.GetBuffer(nTotal);
- for (int32_t i = 0; i < nTotal; i++) {
- lpBuf[i] = m_wcAliasChar;
- }
- wsText.ReleaseBuffer(nTotal);
- if (IsFitArea(wsText)) {
- break;
- }
- nLength--;
- }
- } else {
- while (nLength > 0) {
- CFX_WideString wsText = InsertIntoTextCopy(m_nCaret, lpBuffer, nLength);
- if (IsFitArea(wsText))
- break;
-
- nLength--;
- }
- }
- if (nLength == 0)
- return FDE_EditResult::kFull;
- }
- if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
- CFX_WideString wsText = InsertIntoTextCopy(m_nCaret, lpBuffer, nLength);
- if (!m_Param.pEventSink->OnValidate(wsText))
- return FDE_EditResult::kInvalidate;
- }
- if (IsSelect()) {
- DeleteSelect();
- }
- m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<InsertOperation>(
- this, m_nCaret, CFX_WideString(lpBuffer, nLength)));
-
- CFX_WideString prev = GetText(0, -1);
- Inner_Insert(m_nCaret, CFX_WideString(lpBuffer, nLength));
-
- int32_t nStart = m_nCaret;
- nStart += nLength;
- wchar_t wChar = m_pTxtBuf->GetCharByIndex(nStart - 1);
- bool bBefore = true;
- if (wChar != L'\n' && wChar != L'\r') {
- nStart--;
- bBefore = false;
- }
- SetCaretPos(nStart, bBefore);
- m_Param.pEventSink->OnTextChanged(prev);
- return FDE_EditResult::kSuccess;
-}
-
-void CFDE_TxtEdtEngine::Delete(bool bBackspace) {
- if (IsLocked())
- return;
- if (IsSelect()) {
- DeleteSelect();
- return;
- }
-
- int32_t nCount = 1;
- int32_t nStart = m_nCaret;
- if (bBackspace) {
- if (nStart == 0)
- return;
-
- if (nStart > 2 && m_pTxtBuf->GetCharByIndex(nStart - 1) == L'\n' &&
- m_pTxtBuf->GetCharByIndex(nStart - 2) == L'\r') {
- nStart--;
- nCount++;
- }
- nStart--;
- } else {
- if (nStart == GetTextLength())
- return;
-
- if ((nStart + 1 < GetTextLength()) &&
- (m_pTxtBuf->GetCharByIndex(nStart) == L'\r') &&
- (m_pTxtBuf->GetCharByIndex(nStart + 1) == L'\n')) {
- nCount++;
- }
- }
- if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
- // This doesn't really make sense, if the text with the character removed
- // isn't valid we disallow the removal? Is that even possible as the string
- // must have been valid in order to type the character in before hand?
- // Should this check be removed?
- CFX_WideString wsText = GetText(0, GetTextLength());
- wsText.Delete(nStart, nCount);
- if (!m_Param.pEventSink->OnValidate(wsText))
- return;
- }
-
- CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
- m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<DeleteOperation>(
- this, nStart, m_nCaret, wsRange, false));
-
- CFX_WideString prev = GetText(0, -1);
- Inner_DeleteRange(nStart, nCount);
- SetCaretPos(nStart + ((!bBackspace && nStart > 0) ? -1 : 0),
- (bBackspace || nStart == 0));
- m_Param.pEventSink->OnTextChanged(prev);
-}
-
-void CFDE_TxtEdtEngine::RemoveSelRange(int32_t nStart, int32_t nCount) {
- int32_t nRangeCount = pdfium::CollectionSize<int32_t>(m_SelRangePtrArr);
- for (int32_t i = 0; i < nRangeCount; i++) {
- FDE_TXTEDTSELRANGE* lpTemp = m_SelRangePtrArr[i].get();
- if (lpTemp->nStart == nStart && lpTemp->nCount == nCount) {
- m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + i);
- return;
- }
- }
-}
-
-void CFDE_TxtEdtEngine::AddSelRange(int32_t nStart, int32_t nCount) {
- if (nCount == -1)
- nCount = GetTextLength() - nStart;
-
- if (m_SelRangePtrArr.empty()) {
- auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
- lpSelRange->nStart = nStart;
- lpSelRange->nCount = nCount;
- m_SelRangePtrArr.push_back(std::move(lpSelRange));
- m_Param.pEventSink->OnSelChanged();
- return;
- }
- auto* lpTemp = m_SelRangePtrArr.back().get();
- if (nStart >= lpTemp->nStart + lpTemp->nCount) {
- auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
- lpSelRange->nStart = nStart;
- lpSelRange->nCount = nCount;
- m_SelRangePtrArr.push_back(std::move(lpSelRange));
- m_Param.pEventSink->OnSelChanged();
- return;
- }
- int32_t nEnd = nStart + nCount - 1;
- bool bBegin = false;
- int32_t nRangeBgn = 0;
- int32_t nRangeCnt = 0;
- for (int32_t i = 0, nSize = pdfium::CollectionSize<int32_t>(m_SelRangePtrArr);
- i < nSize; i++) {
- lpTemp = m_SelRangePtrArr[i].get();
- int32_t nTempBgn = lpTemp->nStart;
- int32_t nTempEnd = nTempBgn + lpTemp->nCount - 1;
- if (bBegin) {
- if (nEnd < nTempBgn) {
- break;
- } else if (nStart >= nTempBgn && nStart <= nTempEnd) {
- nRangeCnt++;
- break;
- }
- nRangeCnt++;
- } else {
- if (nStart <= nTempEnd) {
- nRangeBgn = i;
- if (nEnd < nTempBgn) {
- break;
- }
- nRangeCnt = 1;
- bBegin = true;
- }
- }
- }
- if (nRangeCnt == 0) {
- auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
- lpSelRange->nStart = nStart;
- lpSelRange->nCount = nCount;
- m_SelRangePtrArr.insert(m_SelRangePtrArr.begin() + nRangeBgn,
- std::move(lpSelRange));
- } else {
- lpTemp = m_SelRangePtrArr[nRangeBgn].get();
- lpTemp->nStart = nStart;
- lpTemp->nCount = nCount;
- nRangeCnt--;
- nRangeBgn++;
- m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + nRangeBgn,
- m_SelRangePtrArr.begin() + nRangeBgn + nRangeCnt);
- }
- m_Param.pEventSink->OnSelChanged();
-}
-
-int32_t CFDE_TxtEdtEngine::GetSelRange(int32_t nIndex, int32_t* nStart) const {
- if (nStart)
- *nStart = m_SelRangePtrArr[nIndex]->nStart;
- return m_SelRangePtrArr[nIndex]->nCount;
-}
-
-void CFDE_TxtEdtEngine::ClearSelection() {
- if (m_SelRangePtrArr.empty())
- return;
- m_SelRangePtrArr.clear();
- if (m_Param.pEventSink)
- m_Param.pEventSink->OnSelChanged();
-}
-
-bool CFDE_TxtEdtEngine::Redo(const IFDE_TxtEdtDoRecord* pDoRecord) {
- if (IsLocked())
- return false;
- pDoRecord->Redo();
- return true;
-}
-
-bool CFDE_TxtEdtEngine::Undo(const IFDE_TxtEdtDoRecord* pDoRecord) {
- if (IsLocked())
- return false;
- pDoRecord->Undo();
- return true;
-}
-
-void CFDE_TxtEdtEngine::Layout() {
- CFX_AutoRestorer<bool> lock(&m_bLock);
- m_bLock = true;
-
- RemoveAllPages();
- UpdateLineCounts();
- UpdatePages();
-
- m_nCaret = std::min(m_nCaret, GetTextLength());
- m_rtCaret = CFX_RectF(0, 0, 1, m_Param.fFontSize);
-}
-
-int32_t CFDE_TxtEdtEngine::Line2Parag(int32_t nStartParag,
- int32_t nStartLineofParag,
- int32_t nLineIndex,
- int32_t& nStartLine) const {
- int32_t nLineTotal = nStartLineofParag;
- int32_t nCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
- CFDE_TxtEdtParag* pParag = nullptr;
- int32_t i = nStartParag;
- for (; i < nCount; i++) {
- pParag = m_ParagPtrArray[i].get();
- nLineTotal += pParag->GetLineCount();
- if (nLineTotal > nLineIndex) {
- break;
- }
- }
- nStartLine = nLineTotal - pParag->GetLineCount();
- return i;
-}
-
-CFX_WideString CFDE_TxtEdtEngine::InsertIntoTextCopy(int32_t nIndex,
- const wchar_t* lpText,
- int32_t nLength) {
- CFX_WideString wsText = GetText(0, GetTextLength());
- int32_t nSelIndex = 0;
- int32_t nSelLength = 0;
- int32_t nSelCount = CountSelRanges();
- while (nSelCount--) {
- nSelLength = GetSelRange(nSelCount, &nSelIndex);
- wsText.Delete(nSelIndex, nSelLength);
- nIndex = nSelIndex;
- }
- CFX_WideString wsTemp;
- int32_t nOldLength = wsText.GetLength();
- const wchar_t* pOldBuffer = wsText.c_str();
- wchar_t* lpBuffer = wsTemp.GetBuffer(nOldLength + nLength);
- memcpy(lpBuffer, pOldBuffer, (nIndex) * sizeof(wchar_t));
- memcpy(lpBuffer + nIndex, lpText, nLength * sizeof(wchar_t));
- memcpy(lpBuffer + nIndex + nLength, pOldBuffer + nIndex,
- (nOldLength - nIndex) * sizeof(wchar_t));
- wsTemp.ReleaseBuffer(nOldLength + nLength);
- wsText = wsTemp;
- return wsText;
-}
-
-void CFDE_TxtEdtEngine::Inner_Insert(int32_t nStart,
- const CFX_WideString& wsText) {
- const int32_t nLength = wsText.GetLength();
- ASSERT(nLength > 0);
- FDE_TXTEDTPARAGPOS ParagPos;
- TextPos2ParagPos(nStart, ParagPos);
-
- GetPage(m_nCaretPage)->UnloadPage();
-
- int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
- for (int32_t i = ParagPos.nParagIndex + 1; i < nParagCount; i++)
- m_ParagPtrArray[i]->IncrementStartIndex(nLength);
-
- CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
- int32_t nReserveLineCount = pParag->GetLineCount();
- int32_t nReserveCharStart = pParag->GetStartIndex();
- int32_t nLeavePart = ParagPos.nCharIndex;
- int32_t nCutPart = pParag->GetTextLength() - ParagPos.nCharIndex;
- int32_t nTextStart = 0;
- int32_t nCur = 0;
- bool bFirst = true;
- int32_t nParagIndex = ParagPos.nParagIndex;
- for (const auto& wCurChar : wsText) {
- ++nCur;
- if (wCurChar == L'\n') {
- if (bFirst) {
- pParag->SetTextLength(nLeavePart + (nCur - nTextStart + 1));
- pParag->SetLineCount(-1);
- nReserveCharStart += pParag->GetTextLength();
- bFirst = false;
- } else {
- auto pParag2 = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
- pParag2->SetLineCount(-1);
- pParag2->SetTextLength(nCur - nTextStart + 1);
- pParag2->SetStartIndex(nReserveCharStart);
- nReserveCharStart += pParag2->GetTextLength();
- m_ParagPtrArray.insert(m_ParagPtrArray.begin() + ++nParagIndex,
- std::move(pParag2));
- }
- nTextStart = nCur + 1;
- }
- }
- if (bFirst) {
- pParag->IncrementTextLength(nLength);
- pParag->SetLineCount(-1);
- bFirst = false;
- } else {
- auto pParag2 = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
- pParag2->SetLineCount(-1);
- pParag2->SetTextLength(nLength - nTextStart + nCutPart);
- pParag2->SetStartIndex(nReserveCharStart);
- m_ParagPtrArray.insert(m_ParagPtrArray.begin() + ++nParagIndex,
- std::move(pParag2));
- }
- m_pTxtBuf->Insert(nStart, wsText);
- int32_t nTotalLineCount = 0;
- for (int32_t i = ParagPos.nParagIndex; i <= nParagIndex; i++) {
- pParag = m_ParagPtrArray[i].get();
- pParag->CalcLines();
- nTotalLineCount += pParag->GetLineCount();
- }
- m_nLineCount += nTotalLineCount - nReserveLineCount;
-
- GetPage(m_nCaretPage)->LoadPage();
- UpdatePages();
-}
-
-void CFDE_TxtEdtEngine::Inner_DeleteRange(int32_t nStart, int32_t nCount) {
- if (nCount == -1) {
- nCount = m_pTxtBuf->GetTextLength() - nStart;
- }
- int32_t nEnd = nStart + nCount - 1;
- ASSERT(nStart >= 0 && nEnd < m_pTxtBuf->GetTextLength());
-
- GetPage(m_nCaretPage)->UnloadPage();
-
- FDE_TXTEDTPARAGPOS ParagPosBgn, ParagPosEnd;
- TextPos2ParagPos(nStart, ParagPosBgn);
- TextPos2ParagPos(nEnd, ParagPosEnd);
- CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPosEnd.nParagIndex].get();
- bool bLastParag = false;
- if (ParagPosEnd.nCharIndex == pParag->GetTextLength() - 1) {
- if (ParagPosEnd.nParagIndex <
- pdfium::CollectionSize<int32_t>(m_ParagPtrArray) - 1) {
- ParagPosEnd.nParagIndex++;
- } else {
- bLastParag = true;
- }
- }
- int32_t nTotalLineCount = 0;
- int32_t nTotalCharCount = 0;
- int32_t i = 0;
- for (i = ParagPosBgn.nParagIndex; i <= ParagPosEnd.nParagIndex; i++) {
- CFDE_TxtEdtParag* pTextParag = m_ParagPtrArray[i].get();
- pTextParag->CalcLines();
- nTotalLineCount += pTextParag->GetLineCount();
- nTotalCharCount += pTextParag->GetTextLength();
- }
- m_pTxtBuf->Delete(nStart, nCount);
- int32_t nNextParagIndex = (ParagPosBgn.nCharIndex == 0 && bLastParag)
- ? ParagPosBgn.nParagIndex
- : (ParagPosBgn.nParagIndex + 1);
- m_ParagPtrArray.erase(m_ParagPtrArray.begin() + nNextParagIndex,
- m_ParagPtrArray.begin() + ParagPosEnd.nParagIndex + 1);
-
- if (!(bLastParag && ParagPosBgn.nCharIndex == 0)) {
- pParag = m_ParagPtrArray[ParagPosBgn.nParagIndex].get();
- pParag->SetTextLength(nTotalCharCount - nCount);
- pParag->CalcLines();
- nTotalLineCount -= pParag->GetLineCount();
- }
- int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
- for (i = nNextParagIndex; i < nParagCount; i++)
- m_ParagPtrArray[i]->DecrementStartIndex(nCount);
-
- m_nLineCount -= nTotalLineCount;
- UpdatePages();
- int32_t nPageCount = CountPages();
- if (m_nCaretPage >= nPageCount) {
- m_nCaretPage = nPageCount - 1;
- }
-
- GetPage(m_nCaret)->LoadPage();
-}
-
-void CFDE_TxtEdtEngine::DeleteRange_DoRecord(int32_t nStart,
- int32_t nCount,
- bool bSel) {
- ASSERT(nStart >= 0);
- if (nCount == -1) {
- nCount = GetTextLength() - nStart;
- }
- ASSERT((nStart + nCount) <= m_pTxtBuf->GetTextLength());
-
- CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
- m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<DeleteOperation>(
- this, nStart, m_nCaret, wsRange, bSel));
-
- Inner_DeleteRange(nStart, nCount);
-}
-
-void CFDE_TxtEdtEngine::ResetEngine() {
- RemoveAllPages();
- RemoveAllParags();
- ClearSelection();
- m_nCaret = 0;
- m_pTxtBuf->Clear();
- m_nCaret = 0;
-}
-
-void CFDE_TxtEdtEngine::RebuildParagraphs() {
- RemoveAllParags();
- wchar_t wChar = L' ';
- int32_t nParagStart = 0;
- int32_t nIndex = 0;
- auto pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(m_pTxtBuf.get(), 0);
- pIter->SetAt(0);
- do {
- wChar = pIter->GetChar();
- nIndex = pIter->GetAt();
- if (wChar == L'\n') {
- auto pParag = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
- pParag->SetStartIndex(nParagStart);
- pParag->SetTextLength(nIndex - nParagStart + 1);
- pParag->SetLineCount(-1);
- m_ParagPtrArray.push_back(std::move(pParag));
- nParagStart = nIndex + 1;
- }
- } while (pIter->Next());
-}
-
-void CFDE_TxtEdtEngine::UpdateLineCounts() {
- if (m_ParagPtrArray.empty())
- return;
-
- int32_t nLineCount = 0;
- for (auto& pParag : m_ParagPtrArray) {
- pParag->CalcLines();
- nLineCount += pParag->GetLineCount();
- }
- m_nLineCount = nLineCount;
-}
-
-void CFDE_TxtEdtEngine::UpdatePages() {
- if (m_nLineCount == 0)
- return;
-
- int32_t nPageCount = (m_nLineCount - 1) / (m_nPageLineCount) + 1;
- int32_t nSize = pdfium::CollectionSize<int32_t>(m_PagePtrArray);
- if (nSize == nPageCount)
- return;
-
- if (nSize > nPageCount) {
- m_PagePtrArray.erase(m_PagePtrArray.begin() + nPageCount,
- m_PagePtrArray.end());
- return;
- }
- for (int32_t i = nSize; i < nPageCount; i++)
- m_PagePtrArray.push_back(pdfium::MakeUnique<CFDE_TxtEdtPage>(this, i));
-}
-
-void CFDE_TxtEdtEngine::UpdateTxtBreak() {
- uint32_t dwStyle = m_TextBreak.GetLayoutStyles();
- if (m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines)
- dwStyle &= ~FX_LAYOUTSTYLE_SingleLine;
- else
- dwStyle |= FX_LAYOUTSTYLE_SingleLine;
-
- if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText)
- dwStyle |= FX_LAYOUTSTYLE_CombText;
- else
- dwStyle &= ~FX_LAYOUTSTYLE_CombText;
-
- m_TextBreak.SetLayoutStyles(dwStyle);
- uint32_t dwAligment = 0;
- if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Justified)
- dwAligment |= CFX_TxtLineAlignment_Justified;
-
- if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Center)
- dwAligment |= CFX_TxtLineAlignment_Center;
- else if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Right)
- dwAligment |= CFX_TxtLineAlignment_Right;
-
- m_TextBreak.SetAlignment(dwAligment);
-
- if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap)
- m_TextBreak.SetLineWidth(m_Param.fPlateWidth);
- else
- m_TextBreak.SetLineWidth(kPageWidthMax);
-
- m_nPageLineCount = m_Param.nLineCount;
- if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) {
- float fCombWidth = m_Param.fPlateWidth;
- if (m_nLimit > 0)
- fCombWidth /= m_nLimit;
-
- m_TextBreak.SetCombWidth(fCombWidth);
- }
- m_TextBreak.SetFont(m_Param.pFont);
- m_TextBreak.SetFontSize(m_Param.fFontSize);
- m_TextBreak.SetTabWidth(m_Param.fTabWidth);
- m_TextBreak.SetDefaultChar(0xFEFF);
- m_TextBreak.SetParagraphBreakChar(L'\n');
- m_TextBreak.SetLineBreakTolerance(m_Param.fFontSize * 0.2f);
- m_TextBreak.SetHorizontalScale(100);
- m_TextBreak.SetCharSpace(0);
-}
-
-bool CFDE_TxtEdtEngine::ReplaceParagEnd(wchar_t*& lpText,
- int32_t& nLength,
- bool bPreIsCR) {
- for (int32_t i = 0; i < nLength; i++) {
- wchar_t wc = lpText[i];
- switch (wc) {
- case L'\r': {
- lpText[i] = L'\n';
- bPreIsCR = true;
- } break;
- case L'\n': {
- if (bPreIsCR == true) {
- int32_t nNext = i + 1;
- if (nNext < nLength) {
- memmove(lpText + i, lpText + nNext,
- (nLength - nNext) * sizeof(wchar_t));
- }
- i--;
- nLength--;
- bPreIsCR = false;
- if (m_bAutoLineEnd) {
- m_FirstLineEnding = LineEnding::kCRLF;
- m_bAutoLineEnd = false;
- }
- } else {
- lpText[i] = L'\n';
- if (m_bAutoLineEnd) {
- m_FirstLineEnding = LineEnding::kLF;
- m_bAutoLineEnd = false;
- }
- }
- } break;
- default: {
- if (bPreIsCR && m_bAutoLineEnd) {
- m_FirstLineEnding = LineEnding::kCR;
- m_bAutoLineEnd = false;
- }
- bPreIsCR = false;
- } break;
- }
- }
- return bPreIsCR;
-}
-
-void CFDE_TxtEdtEngine::RecoverParagEnd(CFX_WideString& wsText) const {
- if (m_FirstLineEnding == LineEnding::kCR)
- return;
-
- if (m_FirstLineEnding == LineEnding::kCRLF) {
- std::vector<int32_t> PosArr;
- int32_t nLength = wsText.GetLength();
- wchar_t* lpPos = const_cast<wchar_t*>(wsText.c_str());
- for (int32_t i = 0; i < nLength; i++, lpPos++) {
- if (*lpPos == L'\n') {
- *lpPos = L'\r';
- PosArr.push_back(i);
- }
- }
- const wchar_t* lpSrcBuf = wsText.c_str();
- CFX_WideString wsTemp;
- int32_t nCount = pdfium::CollectionSize<int32_t>(PosArr);
- wchar_t* lpDstBuf = wsTemp.GetBuffer(nLength + nCount);
- int32_t nDstPos = 0;
- int32_t nSrcPos = 0;
- for (int32_t i = 0; i < nCount; i++) {
- int32_t nPos = PosArr[i];
- int32_t nCopyLen = nPos - nSrcPos + 1;
- memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
- nCopyLen * sizeof(wchar_t));
- nDstPos += nCopyLen;
- nSrcPos += nCopyLen;
- lpDstBuf[nDstPos] = L'\n';
- nDstPos++;
- }
- if (nSrcPos < nLength) {
- memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
- (nLength - nSrcPos) * sizeof(wchar_t));
- }
- wsTemp.ReleaseBuffer(nLength + nCount);
- wsText = wsTemp;
- return;
- }
-
- int32_t nLength = wsText.GetLength();
- wchar_t* lpBuf = const_cast<wchar_t*>(wsText.c_str());
- for (int32_t i = 0; i < nLength; i++, lpBuf++) {
- if (*lpBuf == L'\n')
- *lpBuf = L'\r';
- }
-}
-
-int32_t CFDE_TxtEdtEngine::MovePage2Char(int32_t nIndex) {
- ASSERT(nIndex >= 0);
- ASSERT(nIndex <= m_pTxtBuf->GetTextLength());
- if (m_nCaretPage >= 0) {
- CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
- pPage->LoadPage();
-
- int32_t nPageCharStart = pPage->GetCharStart();
- int32_t nPageCharCount = pPage->GetCharCount();
-
- pPage->UnloadPage();
- if (nIndex >= nPageCharStart && nIndex < nPageCharStart + nPageCharCount)
- return m_nCaretPage;
- }
-
- CFDE_TxtEdtParag* pParag = nullptr;
- int32_t nLineCount = 0;
- int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
- int32_t i = 0;
- for (i = 0; i < nParagCount; i++) {
- pParag = m_ParagPtrArray[i].get();
- if (pParag->GetStartIndex() <= nIndex &&
- nIndex < (pParag->GetStartIndex() + pParag->GetTextLength())) {
- break;
- }
- nLineCount += pParag->GetLineCount();
- }
- pParag->LoadParag();
- int32_t nLineStart = -1;
- int32_t nLineCharCount = -1;
- for (i = 0; i < pParag->GetLineCount(); i++) {
- pParag->GetLineRange(i, nLineStart, nLineCharCount);
- if (nLineStart <= nIndex && nIndex < (nLineStart + nLineCharCount))
- break;
- }
- ASSERT(i < pParag->GetLineCount());
- nLineCount += (i + 1);
- m_nCaretPage = (nLineCount - 1) / m_nPageLineCount + 1 - 1;
- pParag->UnloadParag();
- return m_nCaretPage;
-}
-
-void CFDE_TxtEdtEngine::TextPos2ParagPos(int32_t nIndex,
- FDE_TXTEDTPARAGPOS& ParagPos) const {
- ASSERT(nIndex >= 0 && nIndex < m_pTxtBuf->GetTextLength());
- int32_t nCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
- int32_t nBgn = 0;
- int32_t nMid = 0;
- int32_t nEnd = nCount - 1;
- while (nEnd > nBgn) {
- nMid = (nBgn + nEnd) / 2;
- CFDE_TxtEdtParag* pParag = m_ParagPtrArray[nMid].get();
- if (nIndex < pParag->GetStartIndex())
- nEnd = nMid - 1;
- else if (nIndex >= (pParag->GetStartIndex() + pParag->GetTextLength()))
- nBgn = nMid + 1;
- else
- break;
- }
- if (nBgn == nEnd)
- nMid = nBgn;
-
- ASSERT(nIndex >= m_ParagPtrArray[nMid]->GetStartIndex() &&
- (nIndex < m_ParagPtrArray[nMid]->GetStartIndex() +
- m_ParagPtrArray[nMid]->GetTextLength()));
- ParagPos.nParagIndex = nMid;
- ParagPos.nCharIndex = nIndex - m_ParagPtrArray[nMid]->GetStartIndex();
-}
-
-int32_t CFDE_TxtEdtEngine::MoveForward(bool& bBefore) {
- if (m_nCaret == m_pTxtBuf->GetTextLength() - 1)
- return -1;
-
- int32_t nCaret = m_nCaret;
- if ((nCaret + 1 < m_pTxtBuf->GetTextLength()) &&
- (m_pTxtBuf->GetCharByIndex(nCaret) == L'\r') &&
- (m_pTxtBuf->GetCharByIndex(nCaret + 1) == L'\n')) {
- nCaret++;
- }
- nCaret++;
- bBefore = true;
- return nCaret;
-}
-
-int32_t CFDE_TxtEdtEngine::MoveBackward(bool& bBefore) {
- if (m_nCaret == 0)
- return false;
-
- int32_t nCaret = m_nCaret;
- if (nCaret > 2 && m_pTxtBuf->GetCharByIndex(nCaret - 1) == L'\n' &&
- m_pTxtBuf->GetCharByIndex(nCaret - 2) == L'\r') {
- nCaret--;
- }
- nCaret--;
- bBefore = true;
- return nCaret;
-}
-
-bool CFDE_TxtEdtEngine::MoveUp(CFX_PointF& ptCaret) {
- CFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
- const CFX_RectF& rtContent = pPage->GetContentsBox();
- ptCaret.x = m_fCaretPosReserve;
- ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 - m_Param.fLineSpace;
- if (ptCaret.y < rtContent.top) {
- if (m_nCaretPage == 0) {
- return false;
- }
- ptCaret.y -= rtContent.top;
- m_nCaretPage--;
- CFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
- ptCaret.y += pCurPage->GetContentsBox().bottom();
- }
-
- return true;
-}
-
-bool CFDE_TxtEdtEngine::MoveDown(CFX_PointF& ptCaret) {
- CFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
- const CFX_RectF& rtContent = pPage->GetContentsBox();
- ptCaret.x = m_fCaretPosReserve;
- ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 + m_Param.fLineSpace;
- if (ptCaret.y >= rtContent.bottom()) {
- if (m_nCaretPage == CountPages() - 1) {
- return false;
- }
- ptCaret.y -= rtContent.bottom();
- m_nCaretPage++;
- CFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
- ptCaret.y += pCurPage->GetContentsBox().top;
- }
- return true;
-}
-
-bool CFDE_TxtEdtEngine::MoveLineStart() {
- int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
- FDE_TXTEDTPARAGPOS ParagPos;
- TextPos2ParagPos(nIndex, ParagPos);
- CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
- pParag->LoadParag();
- int32_t nLineCount = pParag->GetLineCount();
- int32_t i = 0;
- int32_t nStart = 0;
- int32_t nCount = 0;
- for (; i < nLineCount; i++) {
- pParag->GetLineRange(i, nStart, nCount);
- if (nIndex >= nStart && nIndex < nStart + nCount) {
- break;
- }
- }
- UpdateCaretRect(nStart, true);
- pParag->UnloadParag();
- return true;
-}
-
-bool CFDE_TxtEdtEngine::MoveLineEnd() {
- int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
- FDE_TXTEDTPARAGPOS ParagPos;
- TextPos2ParagPos(nIndex, ParagPos);
- CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
- pParag->LoadParag();
- int32_t nLineCount = pParag->GetLineCount();
- int32_t i = 0;
- int32_t nStart = 0;
- int32_t nCount = 0;
- for (; i < nLineCount; i++) {
- pParag->GetLineRange(i, nStart, nCount);
- if (nIndex >= nStart && nIndex < nStart + nCount) {
- break;
- }
- }
- nIndex = nStart + nCount - 1;
- ASSERT(nIndex <= GetTextLength());
- wchar_t wChar = m_pTxtBuf->GetCharByIndex(nIndex);
- bool bBefore = false;
- if (nIndex <= GetTextLength()) {
- if (wChar == L'\r') {
- bBefore = true;
- } else if (wChar == L'\n' && nIndex > nStart) {
- bBefore = true;
- nIndex--;
- wChar = m_pTxtBuf->GetCharByIndex(nIndex);
- if (wChar != L'\r') {
- nIndex++;
- }
- }
- }
- UpdateCaretRect(nIndex, bBefore);
- pParag->UnloadParag();
- return true;
-}
-
-bool CFDE_TxtEdtEngine::MoveHome() {
- UpdateCaretRect(0, true);
- return true;
-}
-
-bool CFDE_TxtEdtEngine::MoveEnd() {
- UpdateCaretRect(GetTextLength(), true);
- return true;
-}
-
-bool CFDE_TxtEdtEngine::IsFitArea(CFX_WideString& wsText) {
- auto pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
- pTextOut->SetLineSpace(m_Param.fLineSpace);
- pTextOut->SetFont(m_Param.pFont);
- pTextOut->SetFontSize(m_Param.fFontSize);
-
- FDE_TextStyle dwStyle;
- if (!(m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines))
- dwStyle.single_line_ = true;
-
- CFX_RectF rcText;
- if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap) {
- dwStyle.line_wrap_ = true;
- rcText.width = m_Param.fPlateWidth;
- } else {
- rcText.width = 65535;
- }
- pTextOut->SetStyles(dwStyle);
- wsText += L"\n";
- pTextOut->CalcLogicSize(wsText, rcText);
- wsText.Delete(wsText.GetLength() - 1);
- if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz) &&
- (rcText.width > m_Param.fPlateWidth)) {
- return false;
- }
- if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) &&
- (rcText.height > m_Param.fLineSpace * m_Param.nLineCount)) {
- return false;
- }
- return true;
-}
-
-void CFDE_TxtEdtEngine::UpdateCaretRect(int32_t nIndex, bool bBefore) {
- MovePage2Char(nIndex);
- GetCaretRect(m_rtCaret, m_nCaretPage, nIndex, bBefore);
- m_nCaret = nIndex;
- m_bBefore = bBefore;
- if (!m_bBefore) {
- m_nCaret++;
- m_bBefore = true;
- }
- m_fCaretPosReserve = m_rtCaret.left;
- m_Param.pEventSink->OnCaretChanged();
-}
-
-void CFDE_TxtEdtEngine::GetCaretRect(CFX_RectF& rtCaret,
- int32_t nPageIndex,
- int32_t nCaret,
- bool bBefore) {
- CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
- pPage->LoadPage();
-
- bool bCombText = !!(m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText);
- int32_t nIndexInpage = nCaret - pPage->GetCharStart();
- if (bBefore && bCombText && nIndexInpage > 0) {
- nIndexInpage--;
- bBefore = false;
- }
- int32_t nBIDILevel = pPage->GetCharRect(nIndexInpage, rtCaret, bCombText);
- if ((!FX_IsOdd(nBIDILevel) && !bBefore) ||
- (FX_IsOdd(nBIDILevel) && bBefore)) {
- rtCaret.Offset(rtCaret.width - 1.0f, 0);
- }
- if (rtCaret.width == 0 && rtCaret.left > 1.0f)
- rtCaret.left -= 1.0f;
-
- rtCaret.width = 1.0f;
-
- GetPage(m_nCaretPage)->UnloadPage();
-}
-
-void CFDE_TxtEdtEngine::UpdateCaretIndex(const CFX_PointF& ptCaret) {
- CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
- pPage->LoadPage();
-
- m_nCaret = pPage->GetCharIndex(ptCaret, m_bBefore);
- GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
- if (!m_bBefore) {
- m_nCaret++;
- m_bBefore = true;
- }
- m_Param.pEventSink->OnCaretChanged();
- GetPage(m_nCaretPage)->UnloadPage();
-}
-
-void CFDE_TxtEdtEngine::DeleteSelect() {
- int32_t nCountRange = CountSelRanges();
- if (nCountRange <= 0)
- return;
-
- CFX_WideString prev = GetText(0, -1);
-
- int32_t nSelStart = 0;
- while (nCountRange > 0) {
- int32_t nSelCount = GetSelRange(--nCountRange, &nSelStart);
- m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + nCountRange);
- DeleteRange_DoRecord(nSelStart, nSelCount, true);
- }
- ClearSelection();
- m_Param.pEventSink->OnTextChanged(prev);
- m_Param.pEventSink->OnSelChanged();
- SetCaretPos(nSelStart, true);
-}
diff --git a/xfa/fde/cfde_txtedtengine.h b/xfa/fde/cfde_txtedtengine.h
deleted file mode 100644
index f2bc62cd42..0000000000
--- a/xfa/fde/cfde_txtedtengine.h
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright 2014 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_TXTEDTENGINE_H_
-#define XFA_FDE_CFDE_TXTEDTENGINE_H_
-
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/cfx_retain_ptr.h"
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxge/fx_dib.h"
-#include "xfa/fde/cfde_txtedtbuf.h"
-#include "xfa/fde/cfde_txtedtpage.h"
-#include "xfa/fde/cfde_txtedtparag.h"
-#include "xfa/fgas/layout/cfx_txtbreak.h"
-
-class CFGAS_GEFont;
-class CFWL_Edit;
-class IFDE_TxtEdtDoRecord;
-class IFX_CharIter;
-
-#define FDE_TEXTEDITMODE_MultiLines (1L << 0)
-#define FDE_TEXTEDITMODE_AutoLineWrap (1L << 1)
-#define FDE_TEXTEDITMODE_LimitArea_Vert (1L << 3)
-#define FDE_TEXTEDITMODE_LimitArea_Horz (1L << 4)
-#define FDE_TEXTEDITMODE_Validate (1L << 8)
-#define FDE_TEXTEDITMODE_Password (1L << 9)
-
-#define FDE_TEXTEDITALIGN_Left 0
-#define FDE_TEXTEDITALIGN_Center (1L << 0)
-#define FDE_TEXTEDITALIGN_Right (1L << 1)
-#define FDE_TEXTEDITALIGN_Justified (1L << 4)
-
-#define FDE_TEXTEDITLAYOUT_CombText (1L << 4)
-#define FDE_TEXTEDITLAYOUT_LastLineHeight (1L << 8)
-
-enum class FDE_CaretMove {
- Left,
- Right,
- Up,
- Down,
- LineStart,
- LineEnd,
- Home,
- End,
-};
-
-enum class FDE_EditResult {
- kLocked = -5,
- kInvalidate = -4,
- kFull = -2,
- kSuccess = 0,
-};
-
-struct FDE_TXTEDTPARAMS {
- FDE_TXTEDTPARAMS();
- ~FDE_TXTEDTPARAMS();
-
- float fPlateWidth;
- float fPlateHeight;
-
- int32_t nLineCount;
- uint32_t dwLayoutStyles;
- uint32_t dwAlignment;
- uint32_t dwMode;
-
- CFX_RetainPtr<CFGAS_GEFont> pFont;
- float fFontSize;
- FX_ARGB dwFontColor;
-
- float fLineSpace;
- float fTabWidth;
-
- CFWL_Edit* pEventSink;
-};
-
-class CFDE_TxtEdtEngine {
- public:
- CFDE_TxtEdtEngine();
- ~CFDE_TxtEdtEngine();
-
- void SetEditParams(const FDE_TXTEDTPARAMS& params);
- FDE_TXTEDTPARAMS* GetEditParams() { return &m_Param; }
-
- CFDE_TxtEdtPage* GetPage(int32_t nIndex);
-
- void SetText(const CFX_WideString& wsText);
- int32_t GetTextLength() const { return m_pTxtBuf->GetTextLength() - 1; }
- CFX_WideString GetText(int32_t nStart, int32_t nCount) const;
- void ClearText();
-
- CFX_RectF GetCaretRect() const { return m_rtCaret; }
- int32_t GetCaretPos() const {
- return IsLocked() ? 0 : m_nCaret + (m_bBefore ? 0 : 1);
- }
- int32_t SetCaretPos(int32_t nIndex, bool bBefore);
- int32_t MoveCaretPos(FDE_CaretMove eMoveCaret, bool bShift);
-
- FDE_EditResult Insert(const CFX_WideString& str);
- void Delete(bool bBackspace);
-
- void SetLimit(int32_t nLimit) { m_nLimit = nLimit; }
- int32_t GetLimit() const { return m_nLimit; }
- void SetAliasChar(wchar_t wcAlias) { m_wcAliasChar = wcAlias; }
-
- void RemoveSelRange(int32_t nStart, int32_t nCount);
- void AddSelRange(int32_t nStart, int32_t nCount);
- int32_t CountSelRanges() const {
- return pdfium::CollectionSize<int32_t>(m_SelRangePtrArr);
- }
- int32_t GetSelRange(int32_t nIndex, int32_t* nStart) const;
- void ClearSelection();
-
- bool Redo(const IFDE_TxtEdtDoRecord* pRecord);
- bool Undo(const IFDE_TxtEdtDoRecord* pRecord);
-
- void Layout();
-
- CFDE_TxtEdtParag* GetParag(int32_t nParagIndex) const {
- return m_ParagPtrArray[nParagIndex].get();
- }
- CFDE_TxtEdtBuf* GetTextBuf() const { return m_pTxtBuf.get(); }
-
- CFX_TxtBreak* GetTextBreak() { return &m_TextBreak; }
- int32_t GetLineCount() const { return m_nLineCount; }
- int32_t GetPageLineCount() const { return m_nPageLineCount; }
-
- int32_t Line2Parag(int32_t nStartParag,
- int32_t nStartLineofParag,
- int32_t nLineIndex,
- int32_t& nStartLine) const;
- wchar_t GetAliasChar() const { return m_wcAliasChar; }
-
- bool IsSelect() const { return !m_SelRangePtrArr.empty(); }
- void Inner_DeleteRange(int32_t nStart, int32_t nCount);
- void Inner_Insert(int32_t nStart, const CFX_WideString& wsText);
- const FDE_TXTEDTPARAMS* GetParams() const { return &m_Param; }
-
- private:
- struct FDE_TXTEDTSELRANGE {
- int32_t nStart;
- int32_t nCount;
- };
-
- struct FDE_TXTEDTPARAGPOS {
- int32_t nParagIndex;
- int32_t nCharIndex;
- };
-
- enum class LineEnding : uint8_t {
- kAuto,
- kCRLF,
- kCR,
- kLF,
- };
-
- int32_t CountPages() const {
- return m_nLineCount == 0 ? 0 : ((m_nLineCount - 1) / m_nPageLineCount) + 1;
- }
-
- bool IsLocked() const { return m_bLock; }
-
- CFX_WideString InsertIntoTextCopy(int32_t nIndex,
- const wchar_t* lpText,
- int32_t nLength);
-
- void DeleteRange_DoRecord(int32_t nStart, int32_t nCount, bool bSel);
- void ResetEngine();
- void RebuildParagraphs();
- void RemoveAllParags() { m_ParagPtrArray.clear(); }
- void RemoveAllPages() { m_PagePtrArray.clear(); }
- void UpdateLineCounts();
- void UpdatePages();
- void UpdateTxtBreak();
-
- bool ReplaceParagEnd(wchar_t*& lpText, int32_t& nLength, bool bPreIsCR);
- void RecoverParagEnd(CFX_WideString& wsText) const;
- int32_t MovePage2Char(int32_t nIndex);
- void TextPos2ParagPos(int32_t nIndex, FDE_TXTEDTPARAGPOS& ParagPos) const;
- int32_t MoveForward(bool& bBefore);
- int32_t MoveBackward(bool& bBefore);
- bool MoveUp(CFX_PointF& ptCaret);
- bool MoveDown(CFX_PointF& ptCaret);
- bool MoveLineStart();
- bool MoveLineEnd();
- bool MoveHome();
- bool MoveEnd();
- bool IsFitArea(CFX_WideString& wsText);
- void UpdateCaretRect(int32_t nIndex, bool bBefore);
- void GetCaretRect(CFX_RectF& rtCaret,
- int32_t nPageIndex,
- int32_t nCaret,
- bool bBefore);
- void UpdateCaretIndex(const CFX_PointF& ptCaret);
-
- void DeleteSelect();
-
- std::unique_ptr<CFDE_TxtEdtBuf> m_pTxtBuf;
- CFX_TxtBreak m_TextBreak;
- FDE_TXTEDTPARAMS m_Param;
- std::vector<std::unique_ptr<CFDE_TxtEdtPage>> m_PagePtrArray;
- std::vector<std::unique_ptr<CFDE_TxtEdtParag>> m_ParagPtrArray;
- std::vector<std::unique_ptr<FDE_TXTEDTSELRANGE>> m_SelRangePtrArr;
- int32_t m_nPageLineCount;
- int32_t m_nLineCount;
- int32_t m_nAnchorPos;
- float m_fCaretPosReserve;
- int32_t m_nCaret;
- int32_t m_nCaretPage;
- CFX_RectF m_rtCaret;
- int32_t m_nLimit;
- wchar_t m_wcAliasChar;
- LineEnding m_FirstLineEnding;
- bool m_bBefore;
- bool m_bLock;
- bool m_bAutoLineEnd;
-};
-
-#endif // XFA_FDE_CFDE_TXTEDTENGINE_H_
diff --git a/xfa/fde/cfde_txtedtpage.cpp b/xfa/fde/cfde_txtedtpage.cpp
deleted file mode 100644
index 3020882c7e..0000000000
--- a/xfa/fde/cfde_txtedtpage.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fde/cfde_txtedtpage.h"
-
-#include <algorithm>
-
-#include "core/fxcrt/cfx_wordbreak.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fde/cfde_txtedtbuf.h"
-#include "xfa/fde/cfde_txtedtengine.h"
-#include "xfa/fde/cfde_txtedtparag.h"
-#include "xfa/fde/cfde_txtedttextset.h"
-#include "xfa/fgas/layout/cfx_txtbreak.h"
-
-namespace {
-
-const double kTolerance = 0.1f;
-
-} // namespace
-
-CFDE_TxtEdtPage::CFDE_TxtEdtPage(CFDE_TxtEdtEngine* pEngine, int32_t nPageIndex)
- : m_pEditEngine(pEngine),
- m_pBgnParag(nullptr),
- m_pEndParag(nullptr),
- m_nRefCount(0),
- m_nPageStart(-1),
- m_nCharCount(0),
- m_nPageIndex(nPageIndex),
- m_bLoaded(false) {
-}
-
-CFDE_TxtEdtPage::~CFDE_TxtEdtPage() {}
-
-int32_t CFDE_TxtEdtPage::GetCharRect(int32_t nIndex,
- CFX_RectF& rect,
- bool bBBox) const {
- ASSERT(m_nRefCount > 0);
- ASSERT(nIndex >= 0 && nIndex < m_nCharCount);
- if (m_nRefCount < 1)
- return 0;
-
- for (const auto& piece : m_Pieces) {
- if (nIndex >= piece.nStart && nIndex < piece.nStart + piece.nCount) {
- std::vector<CFX_RectF> rectArr = m_pTextSet->GetCharRects(&piece, bBBox);
- rect = rectArr[nIndex - piece.nStart];
- return piece.nBidiLevel;
- }
- }
- ASSERT(0);
- return 0;
-}
-
-int32_t CFDE_TxtEdtPage::GetCharIndex(const CFX_PointF& fPoint, bool& bBefore) {
- CFX_PointF ptF = fPoint;
- NormalizePt2Rect(ptF, m_rtPageContents, kTolerance);
- int32_t nCount = pdfium::CollectionSize<int32_t>(m_Pieces);
- CFX_RectF rtLine;
- int32_t nBgn = 0;
- int32_t nEnd = 0;
- bool bInLine = false;
- int32_t i = 0;
- for (i = 0; i < nCount; i++) {
- const FDE_TEXTEDITPIECE* pPiece = &m_Pieces[i];
- if (!bInLine &&
- (pPiece->rtPiece.top <= ptF.y && pPiece->rtPiece.bottom() > ptF.y)) {
- nBgn = nEnd = i;
- rtLine = pPiece->rtPiece;
- bInLine = true;
- } else if (bInLine) {
- if (pPiece->rtPiece.bottom() <= ptF.y || pPiece->rtPiece.top > ptF.y) {
- nEnd = i - 1;
- break;
- } else {
- rtLine.Union(pPiece->rtPiece);
- }
- }
- }
- NormalizePt2Rect(ptF, rtLine, kTolerance);
- int32_t nCaret = 0;
- FDE_TEXTEDITPIECE* pPiece = nullptr;
- for (i = nBgn; i <= nEnd; i++) {
- pPiece = &m_Pieces[i];
- nCaret = m_nPageStart + pPiece->nStart;
- if (pPiece->rtPiece.Contains(ptF)) {
- std::vector<CFX_RectF> rectArr = m_pTextSet->GetCharRects(pPiece, false);
- int32_t nRtCount = pdfium::CollectionSize<int32_t>(rectArr);
- for (int32_t j = 0; j < nRtCount; j++) {
- if (rectArr[j].Contains(ptF)) {
- nCaret = m_nPageStart + pPiece->nStart + j;
- if (nCaret >= m_pEditEngine->GetTextLength()) {
- bBefore = true;
- return m_pEditEngine->GetTextLength();
- }
- wchar_t wChar = m_pEditEngine->GetTextBuf()->GetCharByIndex(nCaret);
- if (wChar == L'\n' || wChar == L'\r') {
- if (wChar == L'\n') {
- if (m_pEditEngine->GetTextBuf()->GetCharByIndex(nCaret - 1) ==
- L'\r') {
- nCaret--;
- }
- }
- bBefore = true;
- return nCaret;
- }
- if (ptF.x > ((rectArr[j].left + rectArr[j].right()) / 2)) {
- bBefore = FX_IsOdd(pPiece->nBidiLevel);
- } else {
- bBefore = !FX_IsOdd(pPiece->nBidiLevel);
- }
- return nCaret;
- }
- }
- }
- }
- bBefore = true;
- return nCaret;
-}
-
-void CFDE_TxtEdtPage::CalcRangeRectArray(
- int32_t nStart,
- int32_t nCount,
- std::vector<CFX_RectF>* pRectFArr) const {
- int32_t nEnd = nStart + nCount - 1;
- bool bInRange = false;
- for (const auto& piece : m_Pieces) {
- if (!bInRange) {
- if (nStart >= piece.nStart && nStart < piece.nStart + piece.nCount) {
- int32_t nRangeEnd = piece.nCount - 1;
- bool bEnd = false;
- if (nEnd >= piece.nStart && nEnd < piece.nStart + piece.nCount) {
- nRangeEnd = nEnd - piece.nStart;
- bEnd = true;
- }
- std::vector<CFX_RectF> rcArr = m_pTextSet->GetCharRects(&piece, false);
- CFX_RectF rectPiece = rcArr[nStart - piece.nStart];
- rectPiece.Union(rcArr[nRangeEnd]);
- pRectFArr->push_back(rectPiece);
- if (bEnd)
- return;
-
- bInRange = true;
- }
- } else {
- if (nEnd >= piece.nStart && nEnd < piece.nStart + piece.nCount) {
- std::vector<CFX_RectF> rcArr = m_pTextSet->GetCharRects(&piece, false);
- CFX_RectF rectPiece = rcArr[0];
- rectPiece.Union(rcArr[nEnd - piece.nStart]);
- pRectFArr->push_back(rectPiece);
- return;
- }
- pRectFArr->push_back(piece.rtPiece);
- }
- }
-}
-
-int32_t CFDE_TxtEdtPage::SelectWord(const CFX_PointF& fPoint, int32_t& nCount) {
- if (m_nRefCount < 0) {
- return -1;
- }
- CFDE_TxtEdtBuf* pBuf = m_pEditEngine->GetTextBuf();
- bool bBefore;
- int32_t nIndex = GetCharIndex(fPoint, bBefore);
- if (nIndex == m_pEditEngine->GetTextLength()) {
- nIndex = m_pEditEngine->GetTextLength() - 1;
- }
- if (nIndex < 0) {
- return -1;
- }
- auto pIter = pdfium::MakeUnique<CFX_WordBreak>();
- pIter->Attach(new CFDE_TxtEdtBuf::Iterator(pBuf, 0));
- pIter->SetAt(nIndex);
- nCount = pIter->GetWordLength();
- return pIter->GetWordPos();
-}
-
-int32_t CFDE_TxtEdtPage::LoadPage() {
- if (m_nRefCount > 0) {
- m_nRefCount++;
- return m_nRefCount;
- }
-
- CFDE_TxtEdtBuf* pBuf = m_pEditEngine->GetTextBuf();
- const FDE_TXTEDTPARAMS* pParams = m_pEditEngine->GetEditParams();
- wchar_t wcAlias = 0;
- if (pParams->dwMode & FDE_TEXTEDITMODE_Password)
- wcAlias = m_pEditEngine->GetAliasChar();
-
- m_pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(
- static_cast<CFDE_TxtEdtBuf*>(pBuf), wcAlias);
- CFX_TxtBreak* pBreak = m_pEditEngine->GetTextBreak();
- pBreak->EndBreak(CFX_BreakType::Paragraph);
- pBreak->ClearBreakPieces();
- int32_t nPageLineCount = m_pEditEngine->GetPageLineCount();
- int32_t nStartLine = nPageLineCount * m_nPageIndex;
- int32_t nEndLine = std::min((nStartLine + nPageLineCount - 1),
- (m_pEditEngine->GetLineCount() - 1));
- int32_t nPageStart, nPageEnd, nTemp, nBgnParag, nStartLineInParag, nEndParag,
- nEndLineInParag;
- nBgnParag = m_pEditEngine->Line2Parag(0, 0, nStartLine, nStartLineInParag);
- m_pBgnParag =
- static_cast<CFDE_TxtEdtParag*>(m_pEditEngine->GetParag(nBgnParag));
- m_pBgnParag->LoadParag();
- m_pBgnParag->GetLineRange(nStartLine - nStartLineInParag, nPageStart, nTemp);
- nEndParag = m_pEditEngine->Line2Parag(nBgnParag, nStartLineInParag, nEndLine,
- nEndLineInParag);
- m_pEndParag =
- static_cast<CFDE_TxtEdtParag*>(m_pEditEngine->GetParag(nEndParag));
- m_pEndParag->LoadParag();
- m_pEndParag->GetLineRange(nEndLine - nEndLineInParag, nPageEnd, nTemp);
- nPageEnd += (nTemp - 1);
-
- float fLineStart = 0.0f;
- float fLineStep = pParams->fLineSpace;
- float fLinePos = fLineStart;
- if (!m_pTextSet)
- m_pTextSet = pdfium::MakeUnique<CFDE_TxtEdtTextSet>(this);
-
- m_Pieces.clear();
- CFX_BreakType dwBreakStatus = CFX_BreakType::None;
- int32_t nPieceStart = 0;
-
- m_CharWidths.resize(nPageEnd - nPageStart + 1, 0);
- pBreak->EndBreak(CFX_BreakType::Paragraph);
- pBreak->ClearBreakPieces();
- m_nPageStart = nPageStart;
- m_nCharCount = nPageEnd - nPageStart + 1;
- bool bReload = false;
- float fDefCharWidth = 0;
- std::unique_ptr<IFX_CharIter> pIter = m_pIter->Clone();
- pIter->SetAt(nPageStart);
- m_pIter->SetAt(nPageStart);
- bool bFirstPiece = true;
- do {
- if (bReload) {
- dwBreakStatus = pBreak->EndBreak(CFX_BreakType::Paragraph);
- } else {
- wchar_t wAppend = pIter->GetChar();
- dwBreakStatus = pBreak->AppendChar(wAppend);
- }
- if (pIter->GetAt() == nPageEnd && CFX_BreakTypeNoneOrPiece(dwBreakStatus))
- dwBreakStatus = pBreak->EndBreak(CFX_BreakType::Paragraph);
-
- if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus)) {
- int32_t nPieceCount = pBreak->CountBreakPieces();
- for (int32_t j = 0; j < nPieceCount; j++) {
- const CFX_BreakPiece* pPiece = pBreak->GetBreakPieceUnstable(j);
- FDE_TEXTEDITPIECE TxtEdtPiece;
- memset(&TxtEdtPiece, 0, sizeof(FDE_TEXTEDITPIECE));
- TxtEdtPiece.nBidiLevel = pPiece->m_iBidiLevel;
- TxtEdtPiece.nCount = pPiece->GetLength();
- TxtEdtPiece.nStart = nPieceStart;
- TxtEdtPiece.dwCharStyles = pPiece->m_dwCharStyles;
- if (FX_IsOdd(pPiece->m_iBidiLevel))
- TxtEdtPiece.dwCharStyles |= FX_TXTCHARSTYLE_OddBidiLevel;
-
- float fParaBreakWidth = 0.0f;
- if (!CFX_BreakTypeNoneOrPiece(pPiece->m_dwStatus)) {
- if (TxtEdtPiece.nCount >= 2) {
- wchar_t wChar = pBuf->GetCharByIndex(
- m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 1);
- wchar_t wCharPre = pBuf->GetCharByIndex(
- m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 2);
- if (wChar == L'\n') {
- fParaBreakWidth += fDefCharWidth;
- }
- if (wCharPre == L'\n') {
- fParaBreakWidth += fDefCharWidth;
- }
- } else if (TxtEdtPiece.nCount >= 1) {
- wchar_t wChar = pBuf->GetCharByIndex(
- m_nPageStart + TxtEdtPiece.nStart + TxtEdtPiece.nCount - 1);
- if (wChar == L'\n') {
- fParaBreakWidth += fDefCharWidth;
- }
- }
- }
-
- TxtEdtPiece.rtPiece.left = (float)pPiece->m_iStartPos / 20000.0f;
- TxtEdtPiece.rtPiece.top = fLinePos;
- TxtEdtPiece.rtPiece.width =
- (float)pPiece->m_iWidth / 20000.0f + fParaBreakWidth;
- TxtEdtPiece.rtPiece.height = pParams->fLineSpace;
-
- if (bFirstPiece) {
- m_rtPageContents = TxtEdtPiece.rtPiece;
- bFirstPiece = false;
- } else {
- m_rtPageContents.Union(TxtEdtPiece.rtPiece);
- }
- nPieceStart += TxtEdtPiece.nCount;
- m_Pieces.push_back(TxtEdtPiece);
- for (int32_t k = 0; k < TxtEdtPiece.nCount; k++) {
- m_CharWidths[TxtEdtPiece.nStart + k] =
- pPiece->GetChar(k)->m_iCharWidth;
- }
- }
- fLinePos += fLineStep;
- pBreak->ClearBreakPieces();
- }
- if (pIter->GetAt() == nPageEnd && dwBreakStatus == CFX_BreakType::Line) {
- bReload = true;
- pIter->Next(true);
- }
- } while (pIter->Next(false) && (pIter->GetAt() <= nPageEnd));
- if (m_rtPageContents.left != 0) {
- float fDelta = 0.0f;
- if (m_rtPageContents.width < pParams->fPlateWidth) {
- if (pParams->dwAlignment & FDE_TEXTEDITALIGN_Right) {
- fDelta = pParams->fPlateWidth - m_rtPageContents.width;
- } else if (pParams->dwAlignment & FDE_TEXTEDITALIGN_Center) {
- if ((pParams->dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) &&
- m_nCharCount > 1) {
- int32_t nCount = m_nCharCount - 1;
- int32_t n = (m_pEditEngine->GetLimit() - nCount) / 2;
- fDelta = (m_rtPageContents.width / nCount) * n;
- } else {
- fDelta = (pParams->fPlateWidth - m_rtPageContents.width) / 2;
- }
- }
- }
- float fOffset = m_rtPageContents.left - fDelta;
- for (auto& piece : m_Pieces)
- piece.rtPiece.Offset(-fOffset, 0.0f);
-
- m_rtPageContents.Offset(-fOffset, 0.0f);
- }
- if (m_pEditEngine->GetEditParams()->dwLayoutStyles &
- FDE_TEXTEDITLAYOUT_LastLineHeight) {
- m_rtPageContents.height -= pParams->fLineSpace - pParams->fFontSize;
- m_Pieces.back().rtPiece.height = pParams->fFontSize;
- }
- m_nRefCount = 1;
- m_bLoaded = true;
- return 0;
-}
-
-void CFDE_TxtEdtPage::UnloadPage() {
- ASSERT(m_nRefCount > 0);
- m_nRefCount--;
- if (m_nRefCount != 0)
- return;
-
- m_Pieces.clear();
- m_pTextSet.reset();
- m_CharWidths.clear();
- if (m_pBgnParag) {
- m_pBgnParag->UnloadParag();
- m_pBgnParag = nullptr;
- }
- if (m_pEndParag) {
- m_pEndParag->UnloadParag();
- m_pEndParag = nullptr;
- }
- m_pIter.reset();
-}
-
-const FDE_TEXTEDITPIECE& CFDE_TxtEdtPage::GetTextPiece(size_t pos) const {
- ASSERT(pos < m_Pieces.size());
- return m_Pieces[pos];
-}
-
-wchar_t CFDE_TxtEdtPage::GetChar(const FDE_TEXTEDITPIECE* pIdentity,
- int32_t index) const {
- int32_t nIndex = m_nPageStart + pIdentity->nStart + index;
- if (nIndex != m_pIter->GetAt())
- m_pIter->SetAt(nIndex);
-
- wchar_t wChar = m_pIter->GetChar();
- m_pIter->Next();
- return wChar;
-}
-
-int32_t CFDE_TxtEdtPage::GetWidth(const FDE_TEXTEDITPIECE* pIdentity,
- int32_t index) const {
- int32_t nWidth = m_CharWidths[pIdentity->nStart + index];
- return nWidth;
-}
-
-void CFDE_TxtEdtPage::NormalizePt2Rect(CFX_PointF& ptF,
- const CFX_RectF& rtF,
- float fTolerance) const {
- if (rtF.Contains(ptF))
- return;
- if (ptF.x < rtF.left)
- ptF.x = rtF.left;
- else if (ptF.x >= rtF.right())
- ptF.x = rtF.right() - fTolerance;
-
- if (ptF.y < rtF.top)
- ptF.y = rtF.top;
- else if (ptF.y >= rtF.bottom())
- ptF.y = rtF.bottom() - fTolerance;
-}
diff --git a/xfa/fde/cfde_txtedtpage.h b/xfa/fde/cfde_txtedtpage.h
deleted file mode 100644
index cdf6c55080..0000000000
--- a/xfa/fde/cfde_txtedtpage.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright 2014 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_TXTEDTPAGE_H_
-#define XFA_FDE_CFDE_TXTEDTPAGE_H_
-
-#include <deque>
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "core/fxcrt/ifx_chariter.h"
-#include "core/fxge/cfx_renderdevice.h"
-
-class CFDE_TxtEdtEngine;
-class CFDE_TxtEdtParag;
-class CFDE_TxtEdtTextSet;
-
-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_TxtEdtPage {
- public:
- CFDE_TxtEdtPage(CFDE_TxtEdtEngine* pEngine, int32_t nLineIndex);
- ~CFDE_TxtEdtPage();
-
- CFDE_TxtEdtEngine* GetEngine() const { return m_pEditEngine.Get(); }
-
- int32_t GetCharRect(int32_t nIndex, CFX_RectF& rect, bool bBBox) const;
- int32_t GetCharIndex(const CFX_PointF& fPoint, bool& bBefore);
-
- void CalcRangeRectArray(int32_t nStart,
- int32_t nCount,
- std::vector<CFX_RectF>* RectFArr) const;
-
- int32_t SelectWord(const CFX_PointF& fPoint, int32_t& nCount);
-
- int32_t GetCharStart() const { return m_nPageStart; }
- int32_t GetCharCount() const { return m_nCharCount; }
-
- int32_t LoadPage();
- void UnloadPage();
-
- const CFX_RectF& GetContentsBox() { return m_rtPageContents; }
-
- size_t GetTextPieceCount() const { return m_pTextSet ? m_Pieces.size() : 0; }
- const FDE_TEXTEDITPIECE& GetTextPiece(size_t pos) const;
-
- wchar_t GetChar(const FDE_TEXTEDITPIECE* pIdentity, int32_t index) const;
- int32_t GetWidth(const FDE_TEXTEDITPIECE* pIdentity, int32_t index) const;
-
- CFDE_TxtEdtTextSet* GetTextSet() const { return m_pTextSet.get(); }
-
- private:
- void NormalizePt2Rect(CFX_PointF& ptF,
- const CFX_RectF& rtF,
- float fTolerance) const;
-
- std::unique_ptr<IFX_CharIter> m_pIter;
- std::unique_ptr<CFDE_TxtEdtTextSet> m_pTextSet;
- CFX_UnownedPtr<CFDE_TxtEdtEngine> const m_pEditEngine;
- std::deque<FDE_TEXTEDITPIECE> m_Pieces;
- CFDE_TxtEdtParag* m_pBgnParag;
- CFDE_TxtEdtParag* m_pEndParag;
- int32_t m_nRefCount;
- int32_t m_nPageStart;
- int32_t m_nCharCount;
- int32_t m_nPageIndex;
- bool m_bLoaded;
- CFX_RectF m_rtPage;
- CFX_RectF m_rtPageMargin;
- CFX_RectF m_rtPageContents;
- CFX_RectF m_rtPageCanvas;
- std::vector<int32_t> m_CharWidths;
-};
-
-#endif // XFA_FDE_CFDE_TXTEDTPAGE_H_
diff --git a/xfa/fde/cfde_txtedtparag.cpp b/xfa/fde/cfde_txtedtparag.cpp
deleted file mode 100644
index 3c1c2adbda..0000000000
--- a/xfa/fde/cfde_txtedtparag.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2014 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
-
-#include "xfa/fde/cfde_txtedtparag.h"
-
-#include <memory>
-#include <vector>
-
-#include "core/fxcrt/ifx_chariter.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fde/cfde_txtedtbuf.h"
-#include "xfa/fde/cfde_txtedtengine.h"
-#include "xfa/fgas/layout/cfx_txtbreak.h"
-
-CFDE_TxtEdtParag::CFDE_TxtEdtParag(CFDE_TxtEdtEngine* pEngine)
- : m_nCharStart(0),
- m_nCharCount(0),
- m_nLineCount(0),
- m_lpData(nullptr),
- m_pEngine(pEngine) {
- ASSERT(m_pEngine);
-}
-
-CFDE_TxtEdtParag::~CFDE_TxtEdtParag() {
- if (m_lpData)
- FX_Free(m_lpData);
-}
-
-void CFDE_TxtEdtParag::LoadParag() {
- if (m_lpData) {
- m_lpData[0]++;
- return;
- }
- CFX_TxtBreak* pTxtBreak = m_pEngine->GetTextBreak();
- CFDE_TxtEdtBuf* pTxtBuf = m_pEngine->GetTextBuf();
- const FDE_TXTEDTPARAMS* pParam = m_pEngine->GetEditParams();
- wchar_t wcAlias = 0;
- if (pParam->dwMode & FDE_TEXTEDITMODE_Password)
- wcAlias = m_pEngine->GetAliasChar();
-
- auto pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(
- static_cast<CFDE_TxtEdtBuf*>(pTxtBuf), wcAlias);
- pIter->SetAt(m_nCharStart);
- int32_t nEndIndex = m_nCharStart + m_nCharCount;
- std::vector<int32_t> LineBaseArr;
- bool bReload = false;
- CFX_BreakType dwBreakStatus = CFX_BreakType::None;
- do {
- if (bReload) {
- dwBreakStatus = pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- } else {
- wchar_t wAppend = pIter->GetChar();
- dwBreakStatus = pTxtBreak->AppendChar(wAppend);
- }
- if (pIter->GetAt() + 1 == nEndIndex &&
- CFX_BreakTypeNoneOrPiece(dwBreakStatus)) {
- dwBreakStatus = pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- }
- if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus)) {
- int32_t nCount = pTxtBreak->CountBreakPieces();
- int32_t nTotal = 0;
- for (int32_t j = 0; j < nCount; j++) {
- const CFX_BreakPiece* Piece = pTxtBreak->GetBreakPieceUnstable(j);
- nTotal += Piece->GetLength();
- }
- LineBaseArr.push_back(nTotal);
- pTxtBreak->ClearBreakPieces();
- }
- if (pIter->GetAt() + 1 == nEndIndex &&
- dwBreakStatus == CFX_BreakType::Line) {
- bReload = true;
- pIter->Next(true);
- }
- } while (pIter->Next(false) && (pIter->GetAt() < nEndIndex));
- pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- pTxtBreak->ClearBreakPieces();
- int32_t nLineCount = pdfium::CollectionSize<int32_t>(LineBaseArr);
- m_nLineCount = nLineCount;
- if (m_lpData)
- m_lpData = FX_Realloc(int32_t, m_lpData, nLineCount + 1);
- else
- m_lpData = FX_Alloc(int32_t, nLineCount + 1);
-
- int32_t* pIntArr = m_lpData;
- pIntArr[0] = 1;
- m_nLineCount = nLineCount;
- pIntArr++;
- for (int32_t j = 0; j < nLineCount; j++, pIntArr++)
- *pIntArr = LineBaseArr[j];
-}
-
-void CFDE_TxtEdtParag::UnloadParag() {
- m_lpData[0]--;
- ASSERT(m_lpData[0] >= 0);
- if (m_lpData[0] == 0) {
- FX_Free(m_lpData);
- m_lpData = nullptr;
- }
-}
-
-void CFDE_TxtEdtParag::CalcLines() {
- CFX_TxtBreak* pTxtBreak = m_pEngine->GetTextBreak();
- CFDE_TxtEdtBuf* pTxtBuf = m_pEngine->GetTextBuf();
- int32_t nCount = 0;
- CFX_BreakType dwBreakStatus = CFX_BreakType::None;
- int32_t nEndIndex = m_nCharStart + m_nCharCount;
- auto pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(
- static_cast<CFDE_TxtEdtBuf*>(pTxtBuf), 0);
- pIter->SetAt(m_nCharStart);
- bool bReload = false;
- do {
- if (bReload) {
- dwBreakStatus = pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- } else {
- wchar_t wAppend = pIter->GetChar();
- dwBreakStatus = pTxtBreak->AppendChar(wAppend);
- }
- if (pIter->GetAt() + 1 == nEndIndex &&
- CFX_BreakTypeNoneOrPiece(dwBreakStatus)) {
- dwBreakStatus = pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- }
- if (!CFX_BreakTypeNoneOrPiece(dwBreakStatus)) {
- nCount++;
- pTxtBreak->ClearBreakPieces();
- }
- if (pIter->GetAt() + 1 == nEndIndex &&
- dwBreakStatus == CFX_BreakType::Line) {
- bReload = true;
- pIter->Next(true);
- }
- } while (pIter->Next(false) && (pIter->GetAt() < nEndIndex));
- pTxtBreak->EndBreak(CFX_BreakType::Paragraph);
- pTxtBreak->ClearBreakPieces();
- m_nLineCount = nCount;
-}
-
-void CFDE_TxtEdtParag::GetLineRange(int32_t nLineIndex,
- int32_t& nStart,
- int32_t& nCount) const {
- int32_t* pLineBaseArr = m_lpData;
- ASSERT(nLineIndex < m_nLineCount);
- nStart = m_nCharStart;
- pLineBaseArr++;
- for (int32_t i = 0; i < nLineIndex; i++) {
- nStart += *pLineBaseArr;
- pLineBaseArr++;
- }
- nCount = *pLineBaseArr;
-}
diff --git a/xfa/fde/cfde_txtedtparag.h b/xfa/fde/cfde_txtedtparag.h
deleted file mode 100644
index becfb61070..0000000000
--- a/xfa/fde/cfde_txtedtparag.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2014 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_TXTEDTPARAG_H_
-#define XFA_FDE_CFDE_TXTEDTPARAG_H_
-
-#include <stdint.h>
-
-#include "core/fxcrt/cfx_unowned_ptr.h"
-
-class CFDE_TxtEdtEngine;
-
-class CFDE_TxtEdtParag {
- public:
- explicit CFDE_TxtEdtParag(CFDE_TxtEdtEngine* pEngine);
- ~CFDE_TxtEdtParag();
-
- int32_t GetTextLength() const { return m_nCharCount; }
- int32_t GetStartIndex() const { return m_nCharStart; }
- int32_t GetLineCount() const { return m_nLineCount; }
-
- void SetTextLength(int32_t len) { m_nCharCount = len; }
- void IncrementTextLength(int32_t len) { m_nCharCount += len; }
- void SetStartIndex(int32_t idx) { m_nCharStart = idx; }
- void IncrementStartIndex(int32_t val) { m_nCharStart += val; }
- void DecrementStartIndex(int32_t val) { m_nCharStart -= val; }
- void SetLineCount(int32_t count) { m_nLineCount = count; }
-
- void GetLineRange(int32_t nLineIndex, int32_t& nStart, int32_t& nCount) const;
- void LoadParag();
- void UnloadParag();
- void CalcLines();
-
- private:
- int32_t m_nCharStart;
- int32_t m_nCharCount;
- int32_t m_nLineCount;
- int32_t* m_lpData;
- CFX_UnownedPtr<CFDE_TxtEdtEngine> m_pEngine;
-};
-
-#endif // XFA_FDE_CFDE_TXTEDTPARAG_H_
diff --git a/xfa/fde/cfde_txtedttextset.cpp b/xfa/fde/cfde_txtedttextset.cpp
deleted file mode 100644
index 0b6cf8214e..0000000000
--- a/xfa/fde/cfde_txtedttextset.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2016 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
-
-#include "xfa/fde/cfde_txtedttextset.h"
-
-#include "xfa/fde/cfde_txtedtengine.h"
-#include "xfa/fgas/font/cfgas_gefont.h"
-#include "xfa/fgas/layout/cfx_txtbreak.h"
-
-CFDE_TxtEdtTextSet::CFDE_TxtEdtTextSet(CFDE_TxtEdtPage* pPage)
- : m_pPage(pPage) {}
-
-CFDE_TxtEdtTextSet::~CFDE_TxtEdtTextSet() {}
-
-int32_t CFDE_TxtEdtTextSet::GetDisplayPos(const FDE_TEXTEDITPIECE& piece,
- FXTEXT_CHARPOS* pCharPos) const {
- int32_t nLength = piece.nCount;
- if (nLength < 1)
- return 0;
-
- CFDE_TxtEdtEngine* pEngine =
- static_cast<CFDE_TxtEdtEngine*>(m_pPage->GetEngine());
- const FDE_TXTEDTPARAMS* pTextParams = pEngine->GetEditParams();
- CFX_TxtBreak* pBreak = pEngine->GetTextBreak();
- uint32_t dwLayoutStyle = pBreak->GetLayoutStyles();
- FX_TXTRUN tr;
- tr.pAccess = m_pPage.Get();
- tr.pIdentity = &piece;
- tr.iLength = nLength;
- tr.pFont = pTextParams->pFont;
- tr.fFontSize = pTextParams->fFontSize;
- tr.dwStyles = dwLayoutStyle;
- tr.dwCharStyles = piece.dwCharStyles;
- tr.pRect = &piece.rtPiece;
- return pBreak->GetDisplayPos(&tr, pCharPos);
-}
-
-std::vector<CFX_RectF> CFDE_TxtEdtTextSet::GetCharRects(
- const FDE_TEXTEDITPIECE* pPiece,
- bool bBBox) const {
- if (!pPiece || pPiece->nCount < 1)
- return std::vector<CFX_RectF>();
-
- auto* pEngine = static_cast<CFDE_TxtEdtEngine*>(m_pPage->GetEngine());
- const FDE_TXTEDTPARAMS* pTextParams = pEngine->GetEditParams();
- uint32_t dwLayoutStyle = pEngine->GetTextBreak()->GetLayoutStyles();
- FX_TXTRUN tr;
- tr.pAccess = m_pPage.Get();
- tr.pIdentity = pPiece;
- tr.iLength = pPiece->nCount;
- tr.pFont = pTextParams->pFont;
- tr.fFontSize = pTextParams->fFontSize;
- tr.dwStyles = dwLayoutStyle;
- tr.dwCharStyles = pPiece->dwCharStyles;
- tr.pRect = &pPiece->rtPiece;
- return pEngine->GetTextBreak()->GetCharRects(&tr, bBBox);
-}
diff --git a/xfa/fde/cfde_txtedttextset.h b/xfa/fde/cfde_txtedttextset.h
deleted file mode 100644
index 4fbf2ac649..0000000000
--- a/xfa/fde/cfde_txtedttextset.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 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_TXTEDTTEXTSET_H_
-#define XFA_FDE_CFDE_TXTEDTTEXTSET_H_
-
-#include <vector>
-
-#include "core/fxcrt/fx_coordinates.h"
-#include "xfa/fde/cfde_txtedtpage.h"
-#include "xfa/fgas/font/cfgas_gefont.h"
-
-class CFDE_TxtEdtTextSet {
- public:
- explicit CFDE_TxtEdtTextSet(CFDE_TxtEdtPage* pPage);
- ~CFDE_TxtEdtTextSet();
-
- CFX_RectF GetRect(const FDE_TEXTEDITPIECE& pPiece) const {
- return pPiece.rtPiece;
- }
- int32_t GetDisplayPos(const FDE_TEXTEDITPIECE& pPiece,
- FXTEXT_CHARPOS* pCharPos) const;
- std::vector<CFX_RectF> GetCharRects(const FDE_TEXTEDITPIECE* pPiece,
- bool bBBox) const;
-
- private:
- CFX_UnownedPtr<CFDE_TxtEdtPage> const m_pPage;
-};
-
-#endif // XFA_FDE_CFDE_TXTEDTTEXTSET_H_
diff --git a/xfa/fde/ifde_txtedtdorecord.h b/xfa/fde/ifde_txtedtdorecord.h
deleted file mode 100644
index e464e7937c..0000000000
--- a/xfa/fde/ifde_txtedtdorecord.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2016 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_IFDE_TXTEDTDORECORD_H_
-#define XFA_FDE_IFDE_TXTEDTDORECORD_H_
-
-#include "core/fxcrt/fx_system.h"
-
-class IFDE_TxtEdtDoRecord {
- public:
- virtual ~IFDE_TxtEdtDoRecord() {}
-
- virtual void Redo() const = 0;
- virtual void Undo() const = 0;
-};
-
-#endif // XFA_FDE_IFDE_TXTEDTDORECORD_H_
diff --git a/xfa/fgas/layout/cfx_break.h b/xfa/fgas/layout/cfx_break.h
index 4a7185bd70..b45924e1e7 100644
--- a/xfa/fgas/layout/cfx_break.h
+++ b/xfa/fgas/layout/cfx_break.h
@@ -40,6 +40,7 @@ class CFX_Break {
void SetFont(const CFX_RetainPtr<CFGAS_GEFont>& pFont);
void SetFontSize(float fFontSize);
void SetTabWidth(float fTabWidth);
+ int32_t GetTabWidth() const { return m_iTabWidth; }
void SetHorizontalScale(int32_t iScale);
void SetVerticalScale(int32_t iScale);
diff --git a/xfa/fgas/layout/cfx_txtbreak.cpp b/xfa/fgas/layout/cfx_txtbreak.cpp
index 56199555ea..42365af127 100644
--- a/xfa/fgas/layout/cfx_txtbreak.cpp
+++ b/xfa/fgas/layout/cfx_txtbreak.cpp
@@ -11,6 +11,7 @@
#include "core/fxcrt/fx_arabic.h"
#include "core/fxcrt/fx_memory.h"
#include "third_party/base/ptr_util.h"
+#include "xfa/fde/cfde_texteditengine.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fgas/layout/cfx_linebreak.h"
@@ -220,33 +221,39 @@ CFX_BreakType CFX_TxtBreak::AppendChar(wchar_t wch) {
}
CFX_BreakType dwRet2 = CFX_BreakType::None;
- switch (chartype) {
- case FX_CHARTYPE_Tab:
- AppendChar_Tab(pCurChar);
- break;
- case FX_CHARTYPE_Control:
- dwRet2 = AppendChar_Control(pCurChar);
- break;
- case FX_CHARTYPE_Combination:
- AppendChar_Combination(pCurChar);
- break;
- case FX_CHARTYPE_ArabicAlef:
- case FX_CHARTYPE_ArabicSpecial:
- case FX_CHARTYPE_ArabicDistortion:
- case FX_CHARTYPE_ArabicNormal:
- case FX_CHARTYPE_ArabicForm:
- case FX_CHARTYPE_Arabic:
- dwRet2 = AppendChar_Arabic(pCurChar);
- break;
- case FX_CHARTYPE_Unknown:
- case FX_CHARTYPE_Space:
- case FX_CHARTYPE_Numeric:
- case FX_CHARTYPE_Normal:
- default:
- dwRet2 = AppendChar_Others(pCurChar);
- break;
+ if (wch == m_wParagraphBreakChar) {
+ // This is handled in AppendChar_Control, but it seems like \n and \r
+ // don't get matched as control characters so we go into AppendChar_other
+ // and never detect the new paragraph ...
+ dwRet2 = CFX_BreakType::Paragraph;
+ } else {
+ switch (chartype) {
+ case FX_CHARTYPE_Tab:
+ AppendChar_Tab(pCurChar);
+ break;
+ case FX_CHARTYPE_Control:
+ dwRet2 = AppendChar_Control(pCurChar);
+ break;
+ case FX_CHARTYPE_Combination:
+ AppendChar_Combination(pCurChar);
+ break;
+ case FX_CHARTYPE_ArabicAlef:
+ case FX_CHARTYPE_ArabicSpecial:
+ case FX_CHARTYPE_ArabicDistortion:
+ case FX_CHARTYPE_ArabicNormal:
+ case FX_CHARTYPE_ArabicForm:
+ case FX_CHARTYPE_Arabic:
+ dwRet2 = AppendChar_Arabic(pCurChar);
+ break;
+ case FX_CHARTYPE_Unknown:
+ case FX_CHARTYPE_Space:
+ case FX_CHARTYPE_Numeric:
+ case FX_CHARTYPE_Normal:
+ default:
+ dwRet2 = AppendChar_Others(pCurChar);
+ break;
+ }
}
-
return std::max(dwRet1, dwRet2);
}
@@ -638,8 +645,7 @@ int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
if (!pTxtRun || pTxtRun->iLength < 1)
return 0;
- CFDE_TxtEdtPage* pAccess = pTxtRun->pAccess;
- const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
+ CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine;
const wchar_t* pStr = pTxtRun->wsStr.c_str();
int32_t* pWidths = pTxtRun->pWidths;
int32_t iLength = pTxtRun->iLength - 1;
@@ -681,9 +687,9 @@ int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
for (int32_t i = 0; i <= iLength; i++) {
int32_t iWidth;
wchar_t wch;
- if (pAccess) {
- wch = pAccess->GetChar(pIdentity, i);
- iWidth = pAccess->GetWidth(pIdentity, i);
+ if (pEngine) {
+ wch = pEngine->GetChar(i);
+ iWidth = pEngine->GetWidthOfChar(i);
} else {
wch = *pStr++;
iWidth = *pWidths++;
@@ -699,10 +705,10 @@ int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
if (chartype >= FX_CHARTYPE_ArabicAlef) {
if (i < iLength) {
- if (pAccess) {
+ if (pEngine) {
iNext = i + 1;
while (iNext <= iLength) {
- wNext = pAccess->GetChar(pIdentity, iNext);
+ wNext = pEngine->GetChar(iNext);
dwProps = FX_GetUnicodeProperties(wNext);
if ((dwProps & FX_CHARTYPEBITSMASK) != FX_CHARTYPE_Combination)
break;
@@ -738,10 +744,10 @@ int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
bShadda = false;
} else {
wNext = 0xFEFF;
- if (pAccess) {
+ if (pEngine) {
iNext = i + 1;
if (iNext <= iLength)
- wNext = pAccess->GetChar(pIdentity, iNext);
+ wNext = pEngine->GetChar(iNext);
} else {
if (i < iLength)
wNext = *pStr;
@@ -836,6 +842,7 @@ int32_t CFX_TxtBreak::GetDisplayPos(const FX_TXTRUN* pTxtRun,
if (!bEmptyChar || (bEmptyChar && !bSkipSpace)) {
pCharPos->m_Origin = CFX_PointF(fX, fY);
+
if ((dwStyles & FX_LAYOUTSTYLE_CombText) != 0) {
int32_t iFormWidth = iCharWidth;
pFont->GetCharWidth(wForm, iFormWidth, false);
@@ -896,8 +903,7 @@ std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
if (!pTxtRun || pTxtRun->iLength < 1)
return std::vector<CFX_RectF>();
- CFDE_TxtEdtPage* pAccess = pTxtRun->pAccess;
- const FDE_TEXTEDITPIECE* pIdentity = pTxtRun->pIdentity;
+ CFDE_TextEditEngine* pEngine = pTxtRun->pEdtEngine;
const wchar_t* pStr = pTxtRun->wsStr.c_str();
int32_t* pWidths = pTxtRun->pWidths;
int32_t iLength = pTxtRun->iLength;
@@ -925,9 +931,9 @@ std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
std::vector<CFX_RectF> rtArray(iLength);
for (int32_t i = 0; i < iLength; i++) {
- if (pAccess) {
- wch = pAccess->GetChar(pIdentity, i);
- iCharSize = pAccess->GetWidth(pIdentity, i);
+ if (pEngine) {
+ wch = pEngine->GetChar(i);
+ iCharSize = pEngine->GetWidthOfChar(i);
} else {
wch = *pStr++;
iCharSize = *pWidths++;
@@ -976,7 +982,7 @@ std::vector<CFX_RectF> CFX_TxtBreak::GetCharRects(const FX_TXTRUN* pTxtRun,
}
FX_TXTRUN::FX_TXTRUN()
- : pAccess(nullptr),
+ : pEdtEngine(nullptr),
pIdentity(nullptr),
pWidths(nullptr),
iLength(0),
diff --git a/xfa/fgas/layout/cfx_txtbreak.h b/xfa/fgas/layout/cfx_txtbreak.h
index 95130c070d..72614bc2e7 100644
--- a/xfa/fgas/layout/cfx_txtbreak.h
+++ b/xfa/fgas/layout/cfx_txtbreak.h
@@ -14,9 +14,9 @@
#include "core/fxcrt/cfx_char.h"
#include "core/fxge/cfx_renderdevice.h"
#include "third_party/base/stl_util.h"
-#include "xfa/fde/cfde_txtedtpage.h"
#include "xfa/fgas/layout/cfx_break.h"
+class CFDE_TextEditEngine;
class CFGAS_GEFont;
struct FDE_TEXTEDITPIECE;
@@ -39,7 +39,7 @@ struct FX_TXTRUN {
FX_TXTRUN(const FX_TXTRUN& other);
~FX_TXTRUN();
- CFDE_TxtEdtPage* pAccess;
+ CFDE_TextEditEngine* pEdtEngine;
const FDE_TEXTEDITPIECE* pIdentity;
CFX_WideString wsStr;
int32_t* pWidths;
diff --git a/xfa/fwl/cfwl_combobox.cpp b/xfa/fwl/cfwl_combobox.cpp
index a3dbe8c946..cbfbd9a447 100644
--- a/xfa/fwl/cfwl_combobox.cpp
+++ b/xfa/fwl/cfwl_combobox.cpp
@@ -11,8 +11,8 @@
#include <utility>
#include "third_party/base/ptr_util.h"
+#include "xfa/fde/cfde_texteditengine.h"
#include "xfa/fde/cfde_textout.h"
-#include "xfa/fde/cfde_txtedtengine.h"
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_event.h"
#include "xfa/fwl/cfwl_eventselectchanged.h"
diff --git a/xfa/fwl/cfwl_combobox.h b/xfa/fwl/cfwl_combobox.h
index 0e1f815872..7242b1f450 100644
--- a/xfa/fwl/cfwl_combobox.h
+++ b/xfa/fwl/cfwl_combobox.h
@@ -76,7 +76,7 @@ class CFWL_ComboBox : public CFWL_Widget {
bool EditCanRedo() const { return m_pEdit->CanRedo(); }
bool EditUndo() { return m_pEdit->Undo(); }
bool EditRedo() { return m_pEdit->Redo(); }
- bool EditCanCopy() const { return m_pEdit->CountSelRanges() > 0; }
+ bool EditCanCopy() const { return m_pEdit->HasSelection(); }
bool EditCanCut() const {
if (m_pEdit->GetStylesEx() & FWL_STYLEEXT_EDT_ReadOnly)
return false;
@@ -88,9 +88,9 @@ class CFWL_ComboBox : public CFWL_Widget {
bool EditPaste(const CFX_WideString& wsPaste) {
return m_pEdit->Paste(wsPaste);
}
- void EditSelectAll() { m_pEdit->AddSelRange(0); }
+ void EditSelectAll() { m_pEdit->SelectAll(); }
void EditDelete() { m_pEdit->ClearText(); }
- void EditDeSelect() { m_pEdit->ClearSelections(); }
+ void EditDeSelect() { m_pEdit->ClearSelection(); }
CFX_RectF GetBBox() const;
void EditModifyStylesEx(uint32_t dwStylesExAdded, uint32_t dwStylesExRemoved);
diff --git a/xfa/fwl/cfwl_comboedit.cpp b/xfa/fwl/cfwl_comboedit.cpp
index 68cde76707..2e53dbdf80 100644
--- a/xfa/fwl/cfwl_comboedit.cpp
+++ b/xfa/fwl/cfwl_comboedit.cpp
@@ -9,7 +9,7 @@
#include <memory>
#include <utility>
-#include "xfa/fde/cfde_txtedtengine.h"
+#include "xfa/fde/cfde_texteditengine.h"
#include "xfa/fwl/cfwl_combobox.h"
#include "xfa/fwl/cfwl_messagemouse.h"
@@ -22,14 +22,16 @@ CFWL_ComboEdit::CFWL_ComboEdit(
}
void CFWL_ComboEdit::ClearSelected() {
- ClearSelections();
+ ClearSelection();
RepaintRect(GetRTClient());
}
void CFWL_ComboEdit::SetSelected() {
FlagFocus(true);
- GetTxtEdtEngine()->MoveCaretPos(FDE_CaretMove::End, false);
- AddSelRange(0);
+
+ // TODO(dsinclair): Fix CFWL_CombEdit::SetSelected
+ // GetTxtEdtEngine()->MoveCaretPos(FDE_CaretMove::End, false);
+ SelectAll();
}
void CFWL_ComboEdit::FlagFocus(bool bSet) {
diff --git a/xfa/fwl/cfwl_datetimepicker.h b/xfa/fwl/cfwl_datetimepicker.h
index fa7653ecf0..ece489e276 100644
--- a/xfa/fwl/cfwl_datetimepicker.h
+++ b/xfa/fwl/cfwl_datetimepicker.h
@@ -8,6 +8,7 @@
#define XFA_FWL_CFWL_DATETIMEPICKER_H_
#include <memory>
+#include <utility>
#include "xfa/fwl/cfwl_datetimeedit.h"
#include "xfa/fwl/cfwl_event.h"
@@ -51,9 +52,10 @@ class CFWL_DateTimePicker : public CFWL_Widget {
void SetEditText(const CFX_WideString& wsText);
CFX_WideString GetEditText() const;
- int32_t CountSelRanges() const { return m_pEdit->CountSelRanges(); }
- int32_t GetSelRange(int32_t nIndex, int32_t* nStart) const {
- return m_pEdit->GetSelRange(nIndex, nStart);
+ bool HasSelection() const { return m_pEdit->HasSelection(); }
+ // Returns <start, end> indices of the selection.
+ std::pair<size_t, size_t> GetSelection() const {
+ return m_pEdit->GetSelection();
}
CFX_RectF GetBBox() const;
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index 5ec9378f09..72adb5392b 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -13,10 +13,8 @@
#include "third_party/base/ptr_util.h"
#include "third_party/base/stl_util.h"
+#include "xfa/fde/cfde_texteditengine.h"
#include "xfa/fde/cfde_textout.h"
-#include "xfa/fde/cfde_txtedtengine.h"
-#include "xfa/fde/cfde_txtedtpage.h"
-#include "xfa/fde/cfde_txtedttextset.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_caret.h"
@@ -38,6 +36,12 @@ namespace {
const int kEditMargin = 3;
+#if (_FX_OS_ == _FX_MACOSX_)
+constexpr int kEditingModifier = FWL_KEYFLAG_Command;
+#else
+constexpr int kEditingModifier = FWL_KEYFLAG_Ctrl;
+#endif
+
bool FxEditIsLatinWord(wchar_t c) {
return c == 0x2D || (c <= 0x005A && c >= 0x0041) ||
(c <= 0x007A && c >= 0x0061) || (c <= 0x02AF && c >= 0x00C0) ||
@@ -65,24 +69,22 @@ CFWL_Edit::CFWL_Edit(const CFWL_App* app,
m_fScrollOffsetX(0.0f),
m_fScrollOffsetY(0.0f),
m_bLButtonDown(false),
- m_nSelStart(0),
+ m_CursorPosition(0),
m_nLimit(-1),
m_fFontSize(0),
m_bSetRange(false),
- m_iMax(0xFFFFFFF),
- m_iCurRecord(-1),
- m_iMaxRecord(128) {
+ m_iMax(0xFFFFFFF) {
m_rtClient.Reset();
m_rtEngine.Reset();
m_rtStatic.Reset();
InitCaret();
+ m_EdtEngine.SetDelegate(this);
}
CFWL_Edit::~CFWL_Edit() {
if (m_pProperties->m_dwStates & FWL_WGTSTATE_Focused)
HideCaret(nullptr);
- ClearRecord();
}
FWL_Type CFWL_Edit::GetClassID() const {
@@ -108,12 +110,14 @@ CFX_RectF CFWL_Edit::GetWidgetRect() {
CFX_RectF CFWL_Edit::GetAutosizedWidgetRect() {
CFX_RectF rect;
- if (m_EdtEngine.GetTextLength() > 0) {
- CFX_SizeF sz = CalcTextSize(
- m_EdtEngine.GetText(0, -1), m_pProperties->m_pThemeProvider,
+
+ if (m_EdtEngine.GetLength() > 0) {
+ CFX_SizeF size = CalcTextSize(
+ m_EdtEngine.GetText(), m_pProperties->m_pThemeProvider,
!!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine));
- rect = CFX_RectF(0, 0, sz);
+ rect = CFX_RectF(0, 0, size);
}
+
InflateWidgetRect(rect);
return rect;
}
@@ -163,23 +167,16 @@ void CFWL_Edit::AddSpellCheckObj(CXFA_Path& PathData,
int32_t nCount,
float fOffSetX,
float fOffSetY) {
- float fStartX = 0.0f;
- float fEndX = 0.0f;
- float fY = 0.0f;
- float fStep = 0.0f;
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- const FDE_TXTEDTPARAMS* txtEdtParams = m_EdtEngine.GetEditParams();
- float fAsent = static_cast<float>(txtEdtParams->pFont->GetAscent()) *
- txtEdtParams->fFontSize / 1000;
-
- std::vector<CFX_RectF> rectArray;
- pPage->CalcRangeRectArray(nStart, nCount, &rectArray);
-
- for (const auto& rectText : rectArray) {
- fY = rectText.top + fAsent + fOffSetY;
- fStep = txtEdtParams->fFontSize / 16.0f;
- fStartX = rectText.left + fOffSetX;
- fEndX = fStartX + rectText.Width();
+ float fStep = m_EdtEngine.GetFontSize() / 16.0f;
+ float font_ascent = m_EdtEngine.GetFontAscent();
+
+ std::vector<CFX_RectF> rects =
+ m_EdtEngine.GetCharacterRectsInRange(nStart, nCount);
+ for (const auto& rect : rects) {
+ float fY = rect.top + font_ascent + fOffSetY;
+ float fStartX = rect.left + fOffSetX;
+ float fEndX = fStartX + rect.Width();
+
AddSquigglyPath(&PathData, fStartX, fEndX, fY, fStep);
}
}
@@ -273,35 +270,36 @@ void CFWL_Edit::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
}
void CFWL_Edit::SetText(const CFX_WideString& wsText) {
- m_EdtEngine.SetText(wsText);
+ m_EdtEngine.Clear();
+ m_EdtEngine.Insert(0, wsText);
}
int32_t CFWL_Edit::GetTextLength() const {
- return m_EdtEngine.GetTextLength();
+ return m_EdtEngine.GetLength();
}
CFX_WideString CFWL_Edit::GetText() const {
- return m_EdtEngine.GetText(0, -1);
+ return m_EdtEngine.GetText();
}
void CFWL_Edit::ClearText() {
- m_EdtEngine.ClearText();
+ m_EdtEngine.Clear();
}
-void CFWL_Edit::AddSelRange(int32_t nStart) {
- m_EdtEngine.AddSelRange(nStart, -1);
+void CFWL_Edit::SelectAll() {
+ m_EdtEngine.SelectAll();
}
-int32_t CFWL_Edit::CountSelRanges() const {
- return m_EdtEngine.CountSelRanges();
+bool CFWL_Edit::HasSelection() const {
+ return m_EdtEngine.HasSelection();
}
-int32_t CFWL_Edit::GetSelRange(int32_t nIndex, int32_t* nStart) const {
- return m_EdtEngine.GetSelRange(nIndex, nStart);
+std::pair<size_t, size_t> CFWL_Edit::GetSelection() const {
+ return m_EdtEngine.GetSelection();
}
-void CFWL_Edit::ClearSelections() {
- m_EdtEngine.ClearSelection();
+void CFWL_Edit::ClearSelection() {
+ return m_EdtEngine.ClearSelection();
}
int32_t CFWL_Edit::GetLimit() const {
@@ -310,7 +308,13 @@ int32_t CFWL_Edit::GetLimit() const {
void CFWL_Edit::SetLimit(int32_t nLimit) {
m_nLimit = nLimit;
- m_EdtEngine.SetLimit(nLimit);
+
+ if (m_nLimit > 0) {
+ m_EdtEngine.SetHasCharacterLimit(true);
+ m_EdtEngine.SetCharacterLimit(nLimit);
+ } else {
+ m_EdtEngine.SetHasCharacterLimit(false);
+ }
}
void CFWL_Edit::SetAliasChar(wchar_t wAlias) {
@@ -318,73 +322,55 @@ void CFWL_Edit::SetAliasChar(wchar_t wAlias) {
}
bool CFWL_Edit::Copy(CFX_WideString& wsCopy) {
- int32_t nCount = m_EdtEngine.CountSelRanges();
- if (nCount == 0)
+ if (!m_EdtEngine.HasSelection())
return false;
- wsCopy.clear();
- int32_t nStart;
- int32_t nLength;
- for (int32_t i = 0; i < nCount; i++) {
- nLength = m_EdtEngine.GetSelRange(i, &nStart);
- wsCopy += m_EdtEngine.GetText(nStart, nLength);
- }
+ wsCopy = m_EdtEngine.GetSelectedText();
return true;
}
bool CFWL_Edit::Cut(CFX_WideString& wsCut) {
- int32_t nCount = m_EdtEngine.CountSelRanges();
- if (nCount == 0)
+ if (!m_EdtEngine.HasSelection())
return false;
- wsCut.clear();
- CFX_WideString wsTemp;
- int32_t nStart, nLength;
- for (int32_t i = 0; i < nCount; i++) {
- nLength = m_EdtEngine.GetSelRange(i, &nStart);
- wsTemp = m_EdtEngine.GetText(nStart, nLength);
- wsCut += wsTemp;
- wsTemp.clear();
- }
- m_EdtEngine.Delete(false);
+ wsCut = m_EdtEngine.DeleteSelectedText();
return true;
}
bool CFWL_Edit::Paste(const CFX_WideString& wsPaste) {
- FDE_EditResult iError = m_EdtEngine.Insert(wsPaste);
- if (iError != FDE_EditResult::kSuccess) {
- ProcessInsertError(iError);
- return false;
- }
+ if (m_EdtEngine.HasSelection())
+ m_EdtEngine.ReplaceSelectedText(wsPaste);
+ else
+ m_EdtEngine.Insert(m_CursorPosition, wsPaste);
+
return true;
}
bool CFWL_Edit::Undo() {
- if (!CanUndo())
- return false;
- m_EdtEngine.Undo(m_DoRecords[m_iCurRecord--].get());
- return true;
+ return CanUndo() ? m_EdtEngine.Undo() : false;
}
bool CFWL_Edit::Redo() {
- if (!CanRedo())
- return false;
- m_EdtEngine.Redo(m_DoRecords[++m_iCurRecord].get());
- return true;
+ return CanRedo() ? m_EdtEngine.Redo() : false;
}
bool CFWL_Edit::CanUndo() {
- return m_iCurRecord >= 0;
+ return m_EdtEngine.CanUndo();
}
bool CFWL_Edit::CanRedo() {
- return m_iCurRecord < pdfium::CollectionSize<int32_t>(m_DoRecords) - 1;
+ return m_EdtEngine.CanRedo();
}
void CFWL_Edit::SetOuter(CFWL_Widget* pOuter) {
m_pOuter = pOuter;
}
+void CFWL_Edit::NotifyTextFull() {
+ CFWL_Event evt(CFWL_Event::Type::TextFull, this);
+ DispatchEvent(&evt);
+}
+
void CFWL_Edit::OnCaretChanged() {
if (m_rtEngine.IsEmpty())
return;
@@ -425,10 +411,6 @@ void CFWL_Edit::OnSelChanged() {
RepaintRect(GetClientRect());
}
-void CFWL_Edit::OnAddDoRecord(std::unique_ptr<IFDE_TxtEdtDoRecord> pRecord) {
- AddDoRecord(std::move(pRecord));
-}
-
bool CFWL_Edit::OnValidate(const CFX_WideString& wsText) {
CFWL_Widget* pDst = GetOuter();
if (!pDst)
@@ -480,17 +462,15 @@ void CFWL_Edit::DrawTextBk(CXFA_Graphics* pGraphics,
void CFWL_Edit::DrawContent(CXFA_Graphics* pGraphics,
IFWL_ThemeProvider* pTheme,
const CFX_Matrix* pMatrix) {
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return;
-
pGraphics->SaveGraphState();
+
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText)
pGraphics->SaveGraphState();
CFX_RectF rtClip = m_rtEngine;
float fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
float fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
+
CFX_Matrix mt(1, 0, 0, 1, fOffSetX, fOffSetY);
if (pMatrix) {
rtClip = pMatrix->TransformRect(rtClip);
@@ -498,28 +478,15 @@ void CFWL_Edit::DrawContent(CXFA_Graphics* pGraphics,
}
bool bShowSel = !!(m_pProperties->m_dwStates & FWL_WGTSTATE_Focused);
- int32_t nSelCount = m_EdtEngine.CountSelRanges();
- if (bShowSel && nSelCount > 0) {
- int32_t nPageCharStart = pPage->GetCharStart();
- int32_t nPageCharCount = pPage->GetCharCount();
- int32_t nPageCharEnd = nPageCharStart + nPageCharCount - 1;
- int32_t nCharCount;
- int32_t nCharStart;
- std::vector<CFX_RectF> rectArr;
- for (int32_t i = 0; i < nSelCount; i++) {
- nCharCount = m_EdtEngine.GetSelRange(i, &nCharStart);
- int32_t nCharEnd = nCharStart + nCharCount - 1;
- if (nCharEnd < nPageCharStart || nCharStart > nPageCharEnd)
- continue;
-
- int32_t nBgn = std::max(nCharStart, nPageCharStart);
- int32_t nEnd = std::min(nCharEnd, nPageCharEnd);
- pPage->CalcRangeRectArray(nBgn - nPageCharStart, nEnd - nBgn + 1,
- &rectArr);
- }
+ if (bShowSel && m_EdtEngine.HasSelection()) {
+ size_t sel_start;
+ size_t sel_end;
+ std::tie(sel_start, sel_end) = m_EdtEngine.GetSelection();
+ std::vector<CFX_RectF> rects = m_EdtEngine.GetCharacterRectsInRange(
+ sel_start, sel_end - sel_start + 1);
CXFA_Path path;
- for (auto& rect : rectArr) {
+ for (auto& rect : rects) {
rect.left += fOffSetX;
rect.top += fOffSetY;
path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
@@ -539,10 +506,11 @@ void CFWL_Edit::DrawContent(CXFA_Graphics* pGraphics,
if (!pRenderDev)
return;
- RenderText(pRenderDev, rtClip, *pPage, mt);
+ RenderText(pRenderDev, rtClip, mt);
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText) {
pGraphics->RestoreGraphState();
+
CXFA_Path path;
int32_t iLimit = m_nLimit > 0 ? m_nLimit : 1;
float fStep = m_rtEngine.width / iLimit;
@@ -566,83 +534,66 @@ void CFWL_Edit::DrawContent(CXFA_Graphics* pGraphics,
void CFWL_Edit::RenderText(CFX_RenderDevice* pRenderDev,
const CFX_RectF& clipRect,
- const CFDE_TxtEdtPage& pPage,
const CFX_Matrix& mt) {
ASSERT(pRenderDev);
- CFDE_TxtEdtTextSet* pTextSet = pPage.GetTextSet();
- if (!pTextSet)
- return;
-
- CFDE_TxtEdtEngine* engine = pPage.GetEngine();
- ASSERT(engine);
- const FDE_TXTEDTPARAMS* params = engine->GetEditParams();
- ASSERT(params);
-
- CFX_RetainPtr<CFGAS_GEFont> pFont = params->pFont;
- if (!pFont)
+ CFX_RetainPtr<CFGAS_GEFont> font = m_EdtEngine.GetFont();
+ if (!font)
return;
pRenderDev->SetClip_Rect(clipRect);
CFX_RectF rtDocClip = clipRect;
if (rtDocClip.IsEmpty()) {
- rtDocClip.left = rtDocClip.top = 0;
+ rtDocClip.left = 0;
+ rtDocClip.top = 0;
rtDocClip.width = static_cast<float>(pRenderDev->GetWidth());
rtDocClip.height = static_cast<float>(pRenderDev->GetHeight());
}
rtDocClip = mt.GetInverse().TransformRect(rtDocClip);
- std::vector<FXTEXT_CHARPOS> char_pos;
-
- for (size_t i = 0; i < pPage.GetTextPieceCount(); ++i) {
- const FDE_TEXTEDITPIECE& pText = pPage.GetTextPiece(i);
- if (!rtDocClip.IntersectWith(pTextSet->GetRect(pText)))
+ for (const FDE_TEXTEDITPIECE& info : m_EdtEngine.GetTextPieces()) {
+ // If this character is outside the clip, skip it.
+ if (!rtDocClip.IntersectWith(info.rtPiece))
continue;
- int32_t iCount = pTextSet->GetDisplayPos(pText, nullptr);
- if (iCount < 1)
+ std::vector<FXTEXT_CHARPOS> char_pos = m_EdtEngine.GetDisplayPos(info);
+ if (char_pos.empty())
continue;
- if (char_pos.size() < static_cast<size_t>(iCount))
- char_pos.resize(iCount, FXTEXT_CHARPOS());
- iCount = pTextSet->GetDisplayPos(pText, char_pos.data());
- CFDE_TextOut::DrawString(pRenderDev, params->dwFontColor, pFont,
- char_pos.data(), iCount, params->fFontSize, &mt);
+ CFDE_TextOut::DrawString(pRenderDev, m_EdtEngine.GetFontColor(), font,
+ char_pos.data(), char_pos.size(),
+ m_EdtEngine.GetFontSize(), &mt);
}
}
void CFWL_Edit::UpdateEditEngine() {
UpdateEditParams();
UpdateEditLayout();
- if (m_nLimit > -1)
- m_EdtEngine.SetLimit(m_nLimit);
}
void CFWL_Edit::UpdateEditParams() {
- FDE_TXTEDTPARAMS params;
- params.fPlateWidth = m_rtEngine.width;
- params.fPlateHeight = m_rtEngine.height;
- if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText)
- params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_CombText;
- if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_LastLineHeight)
- params.dwLayoutStyles |= FDE_TEXTEDITLAYOUT_LastLineHeight;
- if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Validate)
- params.dwMode |= FDE_TEXTEDITMODE_Validate;
- if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Password)
- params.dwMode |= FDE_TEXTEDITMODE_Password;
+ m_EdtEngine.SetAvailableWidth(m_rtEngine.width);
+ m_EdtEngine.SetCombText(
+ !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_CombText));
+
+ m_EdtEngine.EnableValidation(
+ !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Validate));
+ m_EdtEngine.EnablePasswordMode(
+ !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Password));
+ uint32_t alignment = 0;
switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignMask) {
case FWL_STYLEEXT_EDT_HNear: {
- params.dwAlignment |= FDE_TEXTEDITALIGN_Left;
+ alignment |= CFX_TxtLineAlignment_Left;
break;
}
case FWL_STYLEEXT_EDT_HCenter: {
- params.dwAlignment |= FDE_TEXTEDITALIGN_Center;
+ alignment |= CFX_TxtLineAlignment_Center;
break;
}
case FWL_STYLEEXT_EDT_HFar: {
- params.dwAlignment |= FDE_TEXTEDITALIGN_Right;
+ alignment |= CFX_TxtLineAlignment_Right;
break;
}
default:
@@ -650,88 +601,74 @@ void CFWL_Edit::UpdateEditParams() {
}
switch (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_HAlignModeMask) {
case FWL_STYLEEXT_EDT_Justified: {
- params.dwAlignment |= FDE_TEXTEDITALIGN_Justified;
+ alignment |= CFX_TxtLineAlignment_Justified;
break;
}
default:
break;
}
+ m_EdtEngine.SetAlignment(alignment);
+
+ bool auto_hscroll =
+ !!(m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll);
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_MultiLine) {
- params.dwMode |= FDE_TEXTEDITMODE_MultiLines;
- if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) == 0) {
- params.dwMode |=
- FDE_TEXTEDITMODE_AutoLineWrap | FDE_TEXTEDITMODE_LimitArea_Horz;
- }
- if ((m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) == 0 &&
- (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoVScroll) == 0) {
- params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Vert;
- } else {
- params.fPlateHeight = 0x00FFFFFF;
- }
- } else if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoHScroll) ==
- 0) {
- params.dwMode |= FDE_TEXTEDITMODE_LimitArea_Horz;
+ m_EdtEngine.EnableMultiLine(true);
+ m_EdtEngine.EnableLineWrap(!auto_hscroll);
+ m_EdtEngine.LimitVerticalScroll(
+ (m_pProperties->m_dwStyles & FWL_WGTSTYLE_VScroll) == 0 &&
+ (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_AutoVScroll) == 0);
+ } else {
+ m_EdtEngine.EnableMultiLine(false);
+ m_EdtEngine.EnableLineWrap(false);
+ m_EdtEngine.LimitVerticalScroll(false);
}
+ m_EdtEngine.LimitHorizontalScroll(!auto_hscroll);
IFWL_ThemeProvider* theme = GetAvailableTheme();
CFWL_ThemePart part;
part.m_pWidget = this;
- m_fFontSize = theme ? theme->GetFontSize(&part) : FWLTHEME_CAPACITY_FontSize;
- if (!theme)
+ if (!theme) {
+ m_fFontSize = FWLTHEME_CAPACITY_FontSize;
return;
-
- params.dwFontColor = theme->GetTextColor(&part);
- params.fLineSpace = theme->GetLineHeight(&part);
+ }
+ m_fFontSize = theme->GetFontSize(&part);
CFX_RetainPtr<CFGAS_GEFont> pFont = theme->GetFont(&part);
if (!pFont)
return;
- params.pFont = pFont;
- params.fFontSize = m_fFontSize;
- params.nLineCount = (int32_t)(params.fPlateHeight / params.fLineSpace);
- if (params.nLineCount <= 0)
- params.nLineCount = 1;
- params.fTabWidth = params.fFontSize * 1;
- params.pEventSink = this;
- m_EdtEngine.SetEditParams(params);
+ m_EdtEngine.SetFont(pFont);
+ m_EdtEngine.SetFontColor(theme->GetTextColor(&part));
+ m_EdtEngine.SetFontSize(m_fFontSize);
+ m_EdtEngine.SetLineSpace(theme->GetLineHeight(&part));
+ m_EdtEngine.SetTabWidth(m_fFontSize);
+ m_EdtEngine.SetVisibleLineCount(m_rtEngine.height /
+ theme->GetLineHeight(&part));
}
void CFWL_Edit::UpdateEditLayout() {
- if (m_EdtEngine.GetTextLength() <= 0)
- m_EdtEngine.SetText(L"");
-
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (pPage)
- pPage->UnloadPage();
-
m_EdtEngine.Layout();
-
- pPage = m_EdtEngine.GetPage(0);
- if (pPage)
- pPage->LoadPage();
}
bool CFWL_Edit::UpdateOffset() {
- CFX_RectF rtCaret = m_EdtEngine.GetCaretRect();
+ CFX_RectF rtCaret = m_rtCaret;
+
float fOffSetX = m_rtEngine.left - m_fScrollOffsetX;
float fOffSetY = m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset;
rtCaret.Offset(fOffSetX, fOffSetY);
- const CFX_RectF& rtEidt = m_rtEngine;
- if (rtEidt.Contains(rtCaret)) {
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return false;
- CFX_RectF rtFDE = pPage->GetContentsBox();
- rtFDE.Offset(fOffSetX, fOffSetY);
- if (rtFDE.right() < rtEidt.right() && m_fScrollOffsetX > 0) {
- m_fScrollOffsetX += rtFDE.right() - rtEidt.right();
+ const CFX_RectF& edit_bounds = m_rtEngine;
+ if (edit_bounds.Contains(rtCaret)) {
+ CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
+ contents_bounds.Offset(fOffSetX, fOffSetY);
+ if (contents_bounds.right() < edit_bounds.right() && m_fScrollOffsetX > 0) {
+ m_fScrollOffsetX += contents_bounds.right() - edit_bounds.right();
m_fScrollOffsetX = std::max(m_fScrollOffsetX, 0.0f);
}
- if (rtFDE.bottom() < rtEidt.bottom() && m_fScrollOffsetY > 0) {
- m_fScrollOffsetY += rtFDE.bottom() - rtEidt.bottom();
+ if (contents_bounds.bottom() < edit_bounds.bottom() &&
+ m_fScrollOffsetY > 0) {
+ m_fScrollOffsetY += contents_bounds.bottom() - edit_bounds.bottom();
m_fScrollOffsetY = std::max(m_fScrollOffsetY, 0.0f);
}
return false;
@@ -739,18 +676,20 @@ bool CFWL_Edit::UpdateOffset() {
float offsetX = 0.0;
float offsetY = 0.0;
- if (rtCaret.left < rtEidt.left)
- offsetX = rtCaret.left - rtEidt.left;
- if (rtCaret.right() > rtEidt.right())
- offsetX = rtCaret.right() - rtEidt.right();
- if (rtCaret.top < rtEidt.top)
- offsetY = rtCaret.top - rtEidt.top;
- if (rtCaret.bottom() > rtEidt.bottom())
- offsetY = rtCaret.bottom() - rtEidt.bottom();
+ if (rtCaret.left < edit_bounds.left)
+ offsetX = rtCaret.left - edit_bounds.left;
+ if (rtCaret.right() > edit_bounds.right())
+ offsetX = rtCaret.right() - edit_bounds.right();
+ if (rtCaret.top < edit_bounds.top)
+ offsetY = rtCaret.top - edit_bounds.top;
+ if (rtCaret.bottom() > edit_bounds.bottom())
+ offsetY = rtCaret.bottom() - edit_bounds.bottom();
+
m_fScrollOffsetX += offsetX;
m_fScrollOffsetY += offsetY;
if (m_fFontSize > m_rtEngine.height)
m_fScrollOffsetY = 0;
+
return true;
}
@@ -763,12 +702,6 @@ bool CFWL_Edit::UpdateOffset(CFWL_ScrollBar* pScrollBar, float fPosChanged) {
}
void CFWL_Edit::UpdateVAlignment() {
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return;
-
- const CFX_RectF& rtFDE = pPage->GetContentsBox();
- float fOffsetY = 0.0f;
float fSpaceAbove = 0.0f;
float fSpaceBelow = 0.0f;
IFWL_ThemeProvider* theme = GetAvailableTheme();
@@ -777,23 +710,21 @@ void CFWL_Edit::UpdateVAlignment() {
part.m_pWidget = this;
CFX_SizeF pSpace = theme->GetSpaceAboveBelow(&part);
- fSpaceAbove = pSpace.width;
- fSpaceBelow = pSpace.height;
+ fSpaceAbove = pSpace.width >= 0.1f ? pSpace.width : 0.0f;
+ fSpaceBelow = pSpace.height >= 0.1f ? pSpace.height : 0.0f;
}
- if (fSpaceAbove < 0.1f)
- fSpaceAbove = 0;
- if (fSpaceBelow < 0.1f)
- fSpaceBelow = 0;
+ float fOffsetY = 0.0f;
+ CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VCenter) {
- fOffsetY = (m_rtEngine.height - rtFDE.height) / 2;
- if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2 &&
+ fOffsetY = (m_rtEngine.height - contents_bounds.height) / 2.0f;
+ if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2.0f &&
fSpaceAbove < fSpaceBelow) {
return;
}
- fOffsetY += (fSpaceAbove - fSpaceBelow) / 2;
+ fOffsetY += (fSpaceAbove - fSpaceBelow) / 2.0f;
} else if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_VFar) {
- fOffsetY = (m_rtEngine.height - rtFDE.height);
+ fOffsetY = (m_rtEngine.height - contents_bounds.height);
fOffsetY -= fSpaceBelow;
} else {
fOffsetY += fSpaceAbove;
@@ -802,11 +733,9 @@ void CFWL_Edit::UpdateVAlignment() {
}
void CFWL_Edit::UpdateCaret() {
- CFX_RectF rtFDE = m_EdtEngine.GetCaretRect();
-
- rtFDE.Offset(m_rtEngine.left - m_fScrollOffsetX,
- m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset);
- CFX_RectF rtCaret(rtFDE.left, rtFDE.top, rtFDE.width, rtFDE.height);
+ CFX_RectF rtCaret = m_rtCaret;
+ rtCaret.Offset(m_rtEngine.left - m_fScrollOffsetX,
+ m_rtEngine.top - m_fScrollOffsetY + m_fVAlignOffset);
CFX_RectF rtClient = GetClientRect();
rtCaret.Intersect(rtClient);
@@ -832,17 +761,13 @@ CFWL_ScrollBar* CFWL_Edit::UpdateScroll() {
if (!bShowHorz && !bShowVert)
return nullptr;
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return nullptr;
-
- const CFX_RectF& rtFDE = pPage->GetContentsBox();
+ CFX_RectF contents_bounds = m_EdtEngine.GetContentsBoundingBox();
CFWL_ScrollBar* pRepaint = nullptr;
if (bShowHorz) {
CFX_RectF rtScroll = m_pHorzScrollBar->GetWidgetRect();
- if (rtScroll.width < rtFDE.width) {
+ if (rtScroll.width < contents_bounds.width) {
m_pHorzScrollBar->LockUpdate();
- float fRange = rtFDE.width - rtScroll.width;
+ float fRange = contents_bounds.width - rtScroll.width;
m_pHorzScrollBar->SetRange(0.0f, fRange);
float fPos = pdfium::clamp(m_fScrollOffsetX, 0.0f, fRange);
@@ -866,10 +791,11 @@ CFWL_ScrollBar* CFWL_Edit::UpdateScroll() {
if (bShowVert) {
CFX_RectF rtScroll = m_pVertScrollBar->GetWidgetRect();
- if (rtScroll.height < rtFDE.height) {
+ if (rtScroll.height < contents_bounds.height) {
m_pVertScrollBar->LockUpdate();
- float fStep = m_EdtEngine.GetEditParams()->fLineSpace;
- float fRange = std::max(rtFDE.height - m_rtEngine.height, fStep);
+ float fStep = m_EdtEngine.GetLineSpace();
+ float fRange =
+ std::max(contents_bounds.height - m_rtEngine.height, fStep);
m_pVertScrollBar->SetRange(0.0f, fRange);
float fPos = pdfium::clamp(m_fScrollOffsetY, 0.0f, fRange);
@@ -907,27 +833,7 @@ bool CFWL_Edit::IsShowScrollBar(bool bVert) {
}
bool CFWL_Edit::IsContentHeightOverflow() {
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return false;
- return pPage->GetContentsBox().height > m_rtEngine.height + 1.0f;
-}
-
-int32_t CFWL_Edit::AddDoRecord(std::unique_ptr<IFDE_TxtEdtDoRecord> pRecord) {
- int32_t nCount = pdfium::CollectionSize<int32_t>(m_DoRecords);
- if (m_iCurRecord == nCount - 1) {
- if (nCount == m_iMaxRecord) {
- m_DoRecords.pop_front();
- m_iCurRecord--;
- }
- } else {
- m_DoRecords.erase(m_DoRecords.begin() + m_iCurRecord + 1,
- m_DoRecords.end());
- }
-
- m_DoRecords.push_back(std::move(pRecord));
- m_iCurRecord = pdfium::CollectionSize<int32_t>(m_DoRecords) - 1;
- return m_iCurRecord;
+ return m_EdtEngine.GetContentsBoundingBox().height > m_rtEngine.height + 1.0f;
}
void CFWL_Edit::Layout() {
@@ -1143,42 +1049,47 @@ bool CFWL_Edit::ValidateNumberChar(wchar_t cNum) {
if (!m_bSetRange)
return true;
- CFX_WideString wsText = m_EdtEngine.GetText(0, -1);
+ CFX_WideString wsText = m_EdtEngine.GetText();
if (wsText.IsEmpty())
return cNum != L'0';
- if (CountSelRanges() != 0)
+ if (HasSelection())
return wsText.GetInteger() <= m_iMax;
-
- int32_t caretPos = m_EdtEngine.GetCaretPos();
- if (cNum == L'0' && caretPos == 0)
+ if (cNum == L'0' && m_CursorPosition == 0)
return false;
int32_t nLen = wsText.GetLength();
- CFX_WideString l = wsText.Left(caretPos);
- CFX_WideString r = wsText.Right(nLen - caretPos);
+ CFX_WideString l = wsText.Left(m_CursorPosition);
+ CFX_WideString r = wsText.Right(nLen - m_CursorPosition);
CFX_WideString wsNew = l + cNum + r;
return wsNew.GetInteger() <= m_iMax;
}
void CFWL_Edit::InitCaret() {
m_pCaret.reset();
+ m_rtCaret = CFX_RectF();
}
-void CFWL_Edit::ClearRecord() {
- m_iCurRecord = -1;
- m_DoRecords.clear();
-}
+void CFWL_Edit::UpdateCursorRect() {
+ int32_t bidi_level = 0;
+ m_rtCaret = CFX_RectF();
+ std::tie(bidi_level, m_rtCaret) =
+ m_EdtEngine.GetCharacterInfo(m_CursorPosition);
+ // TODO(dsinclair): This should handle bidi level ...
-void CFWL_Edit::ProcessInsertError(FDE_EditResult iError) {
- // TODO(dsinclair): This should probably also send events for Validation
- // failure ....
+ if (m_rtCaret.width == 0 && m_rtCaret.left > 1.0f)
+ m_rtCaret.left -= 1.0f;
- if (iError != FDE_EditResult::kFull)
+ m_rtCaret.width = 1.0f;
+}
+
+void CFWL_Edit::SetCursorPosition(size_t position) {
+ if (m_CursorPosition == position)
return;
- CFWL_Event textFullEvent(CFWL_Event::Type::TextFull, this);
- DispatchEvent(&textFullEvent);
+ m_CursorPosition = position;
+ UpdateCursorRect();
+ OnCaretChanged();
}
void CFWL_Edit::OnProcessMessage(CFWL_Message* pMessage) {
@@ -1202,7 +1113,7 @@ void CFWL_Edit::OnProcessMessage(CFWL_Message* pMessage) {
OnLButtonUp(pMsg);
break;
case FWL_MouseCommand::LeftButtonDblClk:
- OnButtonDblClk(pMsg);
+ OnButtonDoubleClick(pMsg);
break;
case FWL_MouseCommand::Move:
OnMouseMove(pMsg);
@@ -1251,14 +1162,13 @@ void CFWL_Edit::DoButtonDown(CFWL_MessageMouse* pMsg) {
if ((m_pProperties->m_dwStates & FWL_WGTSTATE_Focused) == 0)
SetFocus(true);
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return;
+ // TODO(dsinclair): Handle DoButtonDown
+ // bool bBefore = true;
+ // int32_t nIndex =
+ // std::max(0, pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos),
+ // bBefore));
- bool bBefore = true;
- int32_t nIndex =
- std::max(0, pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos), bBefore));
- m_EdtEngine.SetCaretPos(nIndex, bBefore);
+ // SetCursorPosition(nIndex);
}
void CFWL_Edit::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
@@ -1273,15 +1183,11 @@ void CFWL_Edit::OnFocusChanged(CFWL_Message* pMsg, bool bSet) {
m_pProperties->m_dwStates &= ~FWL_WGTSTATE_Focused;
HideCaret(nullptr);
- int32_t nSel = CountSelRanges();
- if (nSel > 0) {
- ClearSelections();
+ if (HasSelection()) {
+ ClearSelection();
bRepaint = true;
}
- m_EdtEngine.SetCaretPos(0, true);
UpdateOffset();
-
- ClearRecord();
}
LayoutScrollBar();
@@ -1300,21 +1206,24 @@ void CFWL_Edit::OnLButtonDown(CFWL_MessageMouse* pMsg) {
m_bLButtonDown = true;
SetGrab(true);
DoButtonDown(pMsg);
- int32_t nIndex = m_EdtEngine.GetCaretPos();
+
bool bRepaint = false;
- if (m_EdtEngine.CountSelRanges() > 0) {
+ if (m_EdtEngine.HasSelection()) {
m_EdtEngine.ClearSelection();
bRepaint = true;
}
- if ((pMsg->m_dwFlags & FWL_KEYFLAG_Shift) && m_nSelStart != nIndex) {
- int32_t iStart = std::min(m_nSelStart, nIndex);
- int32_t iEnd = std::max(m_nSelStart, nIndex);
- m_EdtEngine.AddSelRange(iStart, iEnd - iStart);
+ size_t index_at_click =
+ m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
+ if (index_at_click != m_CursorPosition &&
+ !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift)) {
+ size_t start = std::min(m_CursorPosition, index_at_click);
+ size_t end = std::max(m_CursorPosition, index_at_click);
+
+ m_EdtEngine.SetSelection(start, end);
bRepaint = true;
- } else {
- m_nSelStart = nIndex;
}
+
if (bRepaint)
RepaintRect(m_rtEngine);
}
@@ -1324,80 +1233,83 @@ void CFWL_Edit::OnLButtonUp(CFWL_MessageMouse* pMsg) {
SetGrab(false);
}
-void CFWL_Edit::OnButtonDblClk(CFWL_MessageMouse* pMsg) {
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
- return;
-
- int32_t nCount = 0;
- int32_t nIndex = pPage->SelectWord(DeviceToEngine(pMsg->m_pos), nCount);
- if (nIndex < 0)
- return;
-
- m_EdtEngine.AddSelRange(nIndex, nCount);
- m_EdtEngine.SetCaretPos(nIndex + nCount - 1, false);
+void CFWL_Edit::OnButtonDoubleClick(CFWL_MessageMouse* pMsg) {
+ // TODO(dsinclair): Handle OnButtonDoubleClick
+ // int32_t nCount = 0;
+ // int32_t nIndex = pPage->SelectWord(DeviceToEngine(pMsg->m_pos), nCount);
+ // if (nIndex < 0)
+ // return;
+ //
+ // m_EdtEngine.AddSelRange(nIndex, nCount);
+ // SetCursorPosition(nIndex + nCount - 1);
RepaintRect(m_rtEngine);
}
void CFWL_Edit::OnMouseMove(CFWL_MessageMouse* pMsg) {
- if (m_nSelStart == -1 || !m_bLButtonDown)
+ bool shift = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift);
+ if (!m_bLButtonDown || !shift)
return;
- CFDE_TxtEdtPage* pPage = m_EdtEngine.GetPage(0);
- if (!pPage)
+ size_t old_cursor_pos = m_CursorPosition;
+ SetCursorPosition(m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
+ if (old_cursor_pos == m_CursorPosition)
return;
- bool bBefore = true;
- int32_t nIndex = pPage->GetCharIndex(DeviceToEngine(pMsg->m_pos), bBefore);
- m_EdtEngine.SetCaretPos(nIndex, bBefore);
- nIndex = m_EdtEngine.GetCaretPos();
- m_EdtEngine.ClearSelection();
+ size_t length = m_EdtEngine.GetLength();
+ if (m_CursorPosition > length)
+ SetCursorPosition(length);
- if (nIndex == m_nSelStart)
- return;
-
- int32_t nLen = m_EdtEngine.GetTextLength();
- if (m_nSelStart >= nLen)
- m_nSelStart = nLen;
-
- m_EdtEngine.AddSelRange(std::min(m_nSelStart, nIndex),
- abs(nIndex - m_nSelStart));
+ size_t sel_start;
+ size_t sel_end;
+ std::tie(sel_start, sel_end) = m_EdtEngine.GetSelection();
+ m_EdtEngine.SetSelection(std::min(sel_start, m_CursorPosition),
+ std::max(sel_end, m_CursorPosition));
}
void CFWL_Edit::OnKeyDown(CFWL_MessageKey* pMsg) {
bool bShift = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Shift);
bool bCtrl = !!(pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl);
+
+ size_t sel_start = m_CursorPosition;
+ if (m_EdtEngine.HasSelection()) {
+ size_t start_idx;
+ size_t end_idx;
+ std::tie(start_idx, end_idx) = m_EdtEngine.GetSelection();
+ sel_start = start_idx;
+ }
+
switch (pMsg->m_dwKeyCode) {
case FWL_VKEY_Left:
- m_EdtEngine.MoveCaretPos(FDE_CaretMove::Left, bShift);
+ SetCursorPosition(m_EdtEngine.GetIndexLeft(m_CursorPosition));
break;
case FWL_VKEY_Right:
- m_EdtEngine.MoveCaretPos(FDE_CaretMove::Right, bShift);
+ SetCursorPosition(m_EdtEngine.GetIndexRight(m_CursorPosition));
break;
case FWL_VKEY_Up:
- m_EdtEngine.MoveCaretPos(FDE_CaretMove::Up, bShift);
+ SetCursorPosition(m_EdtEngine.GetIndexUp(m_CursorPosition));
break;
case FWL_VKEY_Down:
- m_EdtEngine.MoveCaretPos(FDE_CaretMove::Down, bShift);
+ SetCursorPosition(m_EdtEngine.GetIndexDown(m_CursorPosition));
break;
case FWL_VKEY_Home:
- m_EdtEngine.MoveCaretPos(
- bCtrl ? FDE_CaretMove::Home : FDE_CaretMove::LineStart, bShift);
+ SetCursorPosition(
+ bCtrl ? 0 : m_EdtEngine.GetIndexAtStartOfLine(m_CursorPosition));
break;
case FWL_VKEY_End:
- m_EdtEngine.MoveCaretPos(
- bCtrl ? FDE_CaretMove::End : FDE_CaretMove::LineEnd, bShift);
+ SetCursorPosition(
+ bCtrl ? m_EdtEngine.GetLength()
+ : m_EdtEngine.GetIndexAtEndOfLine(m_CursorPosition));
break;
case FWL_VKEY_Delete: {
if ((m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_ReadOnly) ||
(m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled)) {
break;
}
-#if (_FX_OS_ == _FX_MACOSX_)
- m_EdtEngine.Delete(true);
-#else
- m_EdtEngine.Delete(false);
-#endif
+
+ if (m_CursorPosition > 0) {
+ SetCursorPosition(m_EdtEngine.GetIndexBefore(m_CursorPosition));
+ m_EdtEngine.Delete(m_CursorPosition, 1);
+ }
break;
}
case FWL_VKEY_Insert:
@@ -1406,6 +1318,13 @@ void CFWL_Edit::OnKeyDown(CFWL_MessageKey* pMsg) {
default:
break;
}
+
+ // Update the selection.
+ if (bShift && sel_start != m_CursorPosition) {
+ m_EdtEngine.SetSelection(std::min(sel_start, m_CursorPosition),
+ std::max(sel_start, m_CursorPosition));
+ RepaintRect(m_rtEngine);
+ }
}
void CFWL_Edit::OnChar(CFWL_MessageKey* pMsg) {
@@ -1414,25 +1333,27 @@ void CFWL_Edit::OnChar(CFWL_MessageKey* pMsg) {
return;
}
- FDE_EditResult iError = FDE_EditResult::kSuccess;
wchar_t c = static_cast<wchar_t>(pMsg->m_dwKeyCode);
switch (c) {
case FWL_VKEY_Back:
- m_EdtEngine.Delete(true);
+ if (m_CursorPosition > 0) {
+ SetCursorPosition(m_EdtEngine.GetIndexBefore(m_CursorPosition));
+ m_EdtEngine.Delete(m_CursorPosition, 1);
+ }
break;
case FWL_VKEY_NewLine:
case FWL_VKEY_Escape:
break;
- case FWL_VKEY_Tab: {
- iError = m_EdtEngine.Insert(L"\t");
+ case FWL_VKEY_Tab:
+ m_EdtEngine.Insert(m_CursorPosition, L"\t");
+ SetCursorPosition(m_CursorPosition + 1);
break;
- }
- case FWL_VKEY_Return: {
+ case FWL_VKEY_Return:
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_WantReturn) {
- iError = m_EdtEngine.Insert(L"\n");
+ m_EdtEngine.Insert(m_CursorPosition, L"\n");
+ SetCursorPosition(m_CursorPosition + 1);
}
break;
- }
default: {
if (!m_pWidgetMgr->IsFormDisabled()) {
if (m_pProperties->m_dwStyleExes & FWL_STYLEEXT_EDT_Number) {
@@ -1445,20 +1366,14 @@ void CFWL_Edit::OnChar(CFWL_MessageKey* pMsg) {
break;
}
}
-#if (_FX_OS_ == _FX_MACOSX_)
- if (pMsg->m_dwFlags & FWL_KEYFLAG_Command)
-#else
- if (pMsg->m_dwFlags & FWL_KEYFLAG_Ctrl)
-#endif
- {
+ if (pMsg->m_dwFlags & kEditingModifier)
break;
- }
- iError = m_EdtEngine.Insert(CFX_WideString(c));
+
+ m_EdtEngine.Insert(m_CursorPosition, CFX_WideString(c));
+ SetCursorPosition(m_CursorPosition + 1);
break;
}
}
- if (iError != FDE_EditResult::kSuccess)
- ProcessInsertError(iError);
}
bool CFWL_Edit::OnScroll(CFWL_ScrollBar* pScrollBar,
diff --git a/xfa/fwl/cfwl_edit.h b/xfa/fwl/cfwl_edit.h
index 4a30904b0a..310cb81578 100644
--- a/xfa/fwl/cfwl_edit.h
+++ b/xfa/fwl/cfwl_edit.h
@@ -7,12 +7,11 @@
#ifndef XFA_FWL_CFWL_EDIT_H_
#define XFA_FWL_CFWL_EDIT_H_
-#include <deque>
#include <memory>
+#include <utility>
#include <vector>
-#include "xfa/fde/cfde_txtedtengine.h"
-#include "xfa/fde/ifde_txtedtdorecord.h"
+#include "xfa/fde/cfde_texteditengine.h"
#include "xfa/fwl/cfwl_event.h"
#include "xfa/fwl/cfwl_scrollbar.h"
#include "xfa/fwl/cfwl_widget.h"
@@ -39,15 +38,13 @@
#define FWL_STYLEEXT_EDT_HAlignModeMask (3L << 22)
#define FWL_STYLEEXT_EDT_ShowScrollbarFocus (1L << 25)
#define FWL_STYLEEXT_EDT_OuterScrollbar (1L << 26)
-#define FWL_STYLEEXT_EDT_LastLineHeight (1L << 27)
-class IFDE_TxtEdtDoRecord;
class CFWL_Edit;
class CFWL_MessageMouse;
class CFWL_WidgetProperties;
class CFWL_Caret;
-class CFWL_Edit : public CFWL_Widget {
+class CFWL_Edit : public CFWL_Widget, public CFDE_TextEditEngine::Delegate {
public:
CFWL_Edit(const CFWL_App* app,
std::unique_ptr<CFWL_WidgetProperties> properties,
@@ -74,10 +71,12 @@ class CFWL_Edit : public CFWL_Widget {
CFX_WideString GetText() const;
void ClearText();
- void AddSelRange(int32_t nStart);
- int32_t CountSelRanges() const;
- int32_t GetSelRange(int32_t nIndex, int32_t* nStart) const;
- void ClearSelections();
+ void SelectAll();
+ void ClearSelection();
+ bool HasSelection() const;
+ // Returns <start, end> indices of the selection.
+ std::pair<size_t, size_t> GetSelection() const;
+
int32_t GetLimit() const;
void SetLimit(int32_t nLimit);
void SetAliasChar(wchar_t wAlias);
@@ -91,23 +90,23 @@ class CFWL_Edit : public CFWL_Widget {
void SetOuter(CFWL_Widget* pOuter);
- void OnCaretChanged();
- void OnTextChanged(const CFX_WideString& prevText);
- void OnSelChanged();
- void OnAddDoRecord(std::unique_ptr<IFDE_TxtEdtDoRecord> pRecord);
- bool OnValidate(const CFX_WideString& wsText);
- void SetScrollOffset(float fScrollOffset);
+ // CFDE_TextEditEngine::Delegate
+ void NotifyTextFull() override;
+ void OnCaretChanged() override;
+ void OnTextChanged(const CFX_WideString& prevText) override;
+ void OnSelChanged() override;
+ bool OnValidate(const CFX_WideString& wsText) override;
+ void SetScrollOffset(float fScrollOffset) override;
protected:
void ShowCaret(CFX_RectF* pRect);
void HideCaret(CFX_RectF* pRect);
const CFX_RectF& GetRTClient() const { return m_rtClient; }
- CFDE_TxtEdtEngine* GetTxtEdtEngine() { return &m_EdtEngine; }
+ CFDE_TextEditEngine* GetTxtEdtEngine() { return &m_EdtEngine; }
private:
void RenderText(CFX_RenderDevice* pRenderDev,
const CFX_RectF& clipRect,
- const CFDE_TxtEdtPage& pPage,
const CFX_Matrix& mt);
void DrawTextBk(CXFA_Graphics* pGraphics,
IFWL_ThemeProvider* pTheme,
@@ -133,22 +132,21 @@ class CFWL_Edit : public CFWL_Widget {
void InitEngine();
void InitCaret();
bool ValidateNumberChar(wchar_t cNum);
- void ClearRecord();
bool IsShowScrollBar(bool bVert);
bool IsContentHeightOverflow();
- int32_t AddDoRecord(std::unique_ptr<IFDE_TxtEdtDoRecord> pRecord);
- void ProcessInsertError(FDE_EditResult iError);
void AddSpellCheckObj(CXFA_Path& PathData,
int32_t nStart,
int32_t nCount,
float fOffSetX,
float fOffSetY);
+ void SetCursorPosition(size_t position);
+ void UpdateCursorRect();
void DoButtonDown(CFWL_MessageMouse* pMsg);
void OnFocusChanged(CFWL_Message* pMsg, bool bSet);
void OnLButtonDown(CFWL_MessageMouse* pMsg);
void OnLButtonUp(CFWL_MessageMouse* pMsg);
- void OnButtonDblClk(CFWL_MessageMouse* pMsg);
+ void OnButtonDoubleClick(CFWL_MessageMouse* pMsg);
void OnMouseMove(CFWL_MessageMouse* pMsg);
void OnKeyDown(CFWL_MessageKey* pMsg);
void OnChar(CFWL_MessageKey* pMsg);
@@ -159,12 +157,13 @@ class CFWL_Edit : public CFWL_Widget {
CFX_RectF m_rtClient;
CFX_RectF m_rtEngine;
CFX_RectF m_rtStatic;
+ CFX_RectF m_rtCaret;
float m_fVAlignOffset;
float m_fScrollOffsetX;
float m_fScrollOffsetY;
- CFDE_TxtEdtEngine m_EdtEngine;
+ CFDE_TextEditEngine m_EdtEngine;
bool m_bLButtonDown;
- int32_t m_nSelStart;
+ size_t m_CursorPosition;
int32_t m_nLimit;
float m_fFontSize;
bool m_bSetRange;
@@ -174,9 +173,6 @@ class CFWL_Edit : public CFWL_Widget {
std::unique_ptr<CFWL_Caret> m_pCaret;
CFX_WideString m_wsCache;
CFX_WideString m_wsFont;
- std::deque<std::unique_ptr<IFDE_TxtEdtDoRecord>> m_DoRecords;
- int32_t m_iCurRecord;
- int32_t m_iMaxRecord;
};
#endif // XFA_FWL_CFWL_EDIT_H_
diff --git a/xfa/fxfa/cxfa_ffcombobox.cpp b/xfa/fxfa/cxfa_ffcombobox.cpp
index 0c8c80c290..950cab5daf 100644
--- a/xfa/fxfa/cxfa_ffcombobox.cpp
+++ b/xfa/fxfa/cxfa_ffcombobox.cpp
@@ -74,8 +74,7 @@ void CXFA_FFComboBox::UpdateWidgetProperty() {
return;
uint32_t dwExtendedStyle = 0;
- uint32_t dwEditStyles =
- FWL_STYLEEXT_EDT_ReadOnly | FWL_STYLEEXT_EDT_LastLineHeight;
+ uint32_t dwEditStyles = FWL_STYLEEXT_EDT_ReadOnly;
dwExtendedStyle |= UpdateUIProperty();
if (m_pDataAcc->IsChoiceListAllowTextEntry()) {
dwEditStyles &= ~FWL_STYLEEXT_EDT_ReadOnly;
diff --git a/xfa/fxfa/cxfa_ffdatetimeedit.cpp b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
index b47175aa84..cfef664039 100644
--- a/xfa/fxfa/cxfa_ffdatetimeedit.cpp
+++ b/xfa/fxfa/cxfa_ffdatetimeedit.cpp
@@ -77,7 +77,7 @@ void CXFA_FFDateTimeEdit::UpdateWidgetProperty() {
dwExtendedStyle |= UpdateUIProperty();
dwExtendedStyle |= GetAlignment();
m_pNormalWidget->ModifyStylesEx(dwExtendedStyle, 0xFFFFFFFF);
- uint32_t dwEditStyles = FWL_STYLEEXT_EDT_LastLineHeight;
+ uint32_t dwEditStyles = 0;
int32_t iNumCells = m_pDataAcc->GetNumberOfCells();
if (iNumCells > 0) {
dwEditStyles |= FWL_STYLEEXT_EDT_CombText;
diff --git a/xfa/fxfa/cxfa_ffnumericedit.cpp b/xfa/fxfa/cxfa_ffnumericedit.cpp
index b397753c7e..4da98ac7fd 100644
--- a/xfa/fxfa/cxfa_ffnumericedit.cpp
+++ b/xfa/fxfa/cxfa_ffnumericedit.cpp
@@ -48,8 +48,7 @@ void CXFA_FFNumericEdit::UpdateWidgetProperty() {
uint32_t dwExtendedStyle =
FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar |
- FWL_STYLEEXT_EDT_Validate | FWL_STYLEEXT_EDT_Number |
- FWL_STYLEEXT_EDT_LastLineHeight;
+ FWL_STYLEEXT_EDT_Validate | FWL_STYLEEXT_EDT_Number;
dwExtendedStyle |= UpdateUIProperty();
if (m_pDataAcc->GetHorizontalScrollPolicy() != XFA_ATTRIBUTEENUM_Off)
dwExtendedStyle |= FWL_STYLEEXT_EDT_AutoHScroll;
diff --git a/xfa/fxfa/cxfa_ffpasswordedit.cpp b/xfa/fxfa/cxfa_ffpasswordedit.cpp
index df2ea99cde..46105f135b 100644
--- a/xfa/fxfa/cxfa_ffpasswordedit.cpp
+++ b/xfa/fxfa/cxfa_ffpasswordedit.cpp
@@ -44,9 +44,9 @@ void CXFA_FFPasswordEdit::UpdateWidgetProperty() {
if (!pWidget)
return;
- uint32_t dwExtendedStyle =
- FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar |
- FWL_STYLEEXT_EDT_Password | FWL_STYLEEXT_EDT_LastLineHeight;
+ uint32_t dwExtendedStyle = FWL_STYLEEXT_EDT_ShowScrollbarFocus |
+ FWL_STYLEEXT_EDT_OuterScrollbar |
+ FWL_STYLEEXT_EDT_Password;
dwExtendedStyle |= UpdateUIProperty();
CFX_WideString wsPassWord;
diff --git a/xfa/fxfa/cxfa_fftextedit.cpp b/xfa/fxfa/cxfa_fftextedit.cpp
index dfa4c41309..35c20fab6f 100644
--- a/xfa/fxfa/cxfa_fftextedit.cpp
+++ b/xfa/fxfa/cxfa_fftextedit.cpp
@@ -60,9 +60,8 @@ void CXFA_FFTextEdit::UpdateWidgetProperty() {
return;
uint32_t dwStyle = 0;
- uint32_t dwExtendedStyle = FWL_STYLEEXT_EDT_ShowScrollbarFocus |
- FWL_STYLEEXT_EDT_OuterScrollbar |
- FWL_STYLEEXT_EDT_LastLineHeight;
+ uint32_t dwExtendedStyle =
+ FWL_STYLEEXT_EDT_ShowScrollbarFocus | FWL_STYLEEXT_EDT_OuterScrollbar;
dwExtendedStyle |= UpdateUIProperty();
if (m_pDataAcc->IsMultiLine()) {
dwExtendedStyle |= FWL_STYLEEXT_EDT_MultiLine | FWL_STYLEEXT_EDT_WantReturn;
@@ -300,14 +299,14 @@ void CXFA_FFTextEdit::OnTextChanged(CFWL_Widget* pWidget,
if (m_pDataAcc->GetUIType() == XFA_Element::DateTimeEdit) {
CFWL_DateTimePicker* pDateTime = (CFWL_DateTimePicker*)pEdit;
eParam.m_wsNewText = pDateTime->GetEditText();
- int32_t iSels = pDateTime->CountSelRanges();
- if (iSels)
- eParam.m_iSelEnd = pDateTime->GetSelRange(0, &eParam.m_iSelStart);
+ if (pDateTime->HasSelection()) {
+ std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) =
+ pDateTime->GetSelection();
+ }
} else {
eParam.m_wsNewText = pEdit->GetText();
- int32_t iSels = pEdit->CountSelRanges();
- if (iSels)
- eParam.m_iSelEnd = pEdit->GetSelRange(0, &eParam.m_iSelStart);
+ if (pEdit->HasSelection())
+ std::tie(eParam.m_iSelStart, eParam.m_iSelEnd) = pEdit->GetSelection();
}
m_pDataAcc->ProcessEvent(XFA_ATTRIBUTEENUM_Change, &eParam);
}