summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2017-09-06 11:44:39 -0400
committerChromium commit bot <commit-bot@chromium.org>2017-09-06 15:54:37 +0000
commiteb57e0d0b396606b39ef76a864b8bf9dd91a8ed8 (patch)
tree3d4ee88701eed1cbb56f456ea6ebc7c7c0f47f6c
parent746552254ad113ef88b40aca4dbc0e57cefbac85 (diff)
downloadpdfium-eb57e0d0b396606b39ef76a864b8bf9dd91a8ed8.tar.xz
Implement word selection in CFDE_TextEditEngine
This CL implements the needed logic in CFDE_TextEditEngine to handle word selection. Change-Id: I6b388c23655037fec107d68ec07d33638b959374 Reviewed-on: https://pdfium-review.googlesource.com/13211 Commit-Queue: dsinclair <dsinclair@chromium.org> Reviewed-by: Ryan Harrison <rharrison@chromium.org> Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
-rw-r--r--core/fxcrt/cfx_wordbreak.cpp24
-rw-r--r--core/fxcrt/cfx_wordbreak.h10
-rw-r--r--xfa/fde/cfde_texteditengine.cpp25
-rw-r--r--xfa/fde/cfde_texteditengine.h6
-rw-r--r--xfa/fde/cfde_texteditengine_unittest.cpp112
-rw-r--r--xfa/fwl/cfwl_edit.cpp15
6 files changed, 153 insertions, 39 deletions
diff --git a/core/fxcrt/cfx_wordbreak.cpp b/core/fxcrt/cfx_wordbreak.cpp
index 7a5d8f7dcd..86c6d40522 100644
--- a/core/fxcrt/cfx_wordbreak.cpp
+++ b/core/fxcrt/cfx_wordbreak.cpp
@@ -2779,16 +2779,14 @@ FX_WordBreakProp GetWordBreakProperty(wchar_t wcCodePoint) {
} // namespace
-CFX_WordBreak::CFX_WordBreak() {}
+CFX_WordBreak::CFX_WordBreak(std::unique_ptr<IFX_CharIter> pIter)
+ : m_pCurIter(std::move(pIter)) {
+ ASSERT(m_pCurIter);
+}
CFX_WordBreak::~CFX_WordBreak() {}
-void CFX_WordBreak::Attach(IFX_CharIter* pIter) {
- ASSERT(pIter);
- m_pCurIter.reset(pIter);
-}
-
-void CFX_WordBreak::SetAt(int32_t nIndex) {
+std::pair<size_t, size_t> CFX_WordBreak::BoundsAt(int32_t nIndex) {
m_pPreIter.reset();
m_pCurIter->SetAt(nIndex);
FindNextBreakPos(m_pCurIter.get(), true);
@@ -2796,18 +2794,8 @@ void CFX_WordBreak::SetAt(int32_t nIndex) {
m_pPreIter = std::move(m_pCurIter);
m_pCurIter = m_pPreIter->Clone();
FindNextBreakPos(m_pCurIter.get(), false);
-}
-
-int32_t CFX_WordBreak::GetWordPos() const {
- return m_pPreIter->GetAt();
-}
-
-int32_t CFX_WordBreak::GetWordLength() const {
- return m_pCurIter->GetAt() - m_pPreIter->GetAt() + 1;
-}
-bool CFX_WordBreak::IsEOF(bool bTail) const {
- return m_pCurIter->IsEOF(bTail);
+ return {m_pPreIter->GetAt(), m_pCurIter->GetAt()};
}
bool CFX_WordBreak::FindNextBreakPos(IFX_CharIter* pIter, bool bPrev) {
diff --git a/core/fxcrt/cfx_wordbreak.h b/core/fxcrt/cfx_wordbreak.h
index 59c071be03..6e94c71e95 100644
--- a/core/fxcrt/cfx_wordbreak.h
+++ b/core/fxcrt/cfx_wordbreak.h
@@ -8,22 +8,20 @@
#define CORE_FXCRT_CFX_WORDBREAK_H_
#include <memory>
+#include <utility>
class IFX_CharIter;
class CFX_WordBreak {
public:
- CFX_WordBreak();
+ explicit CFX_WordBreak(std::unique_ptr<IFX_CharIter> pIter);
~CFX_WordBreak();
- void Attach(IFX_CharIter* pIter);
- void SetAt(int32_t nIndex);
- int32_t GetWordPos() const;
- int32_t GetWordLength() const;
+ // <start_idx, end_idx>
+ std::pair<size_t, size_t> BoundsAt(int32_t nIndex);
private:
bool FindNextBreakPos(IFX_CharIter* pIter, bool bPrev);
- bool IsEOF(bool bTail) const;
std::unique_ptr<IFX_CharIter> m_pPreIter;
std::unique_ptr<IFX_CharIter> m_pCurIter;
diff --git a/xfa/fde/cfde_texteditengine.cpp b/xfa/fde/cfde_texteditengine.cpp
index e92897ea7d..b5948d45ce 100644
--- a/xfa/fde/cfde_texteditengine.cpp
+++ b/xfa/fde/cfde_texteditengine.cpp
@@ -9,6 +9,7 @@
#include <algorithm>
#include <limits>
+#include "core/fxcrt/cfx_wordbreak.h"
#include "xfa/fde/cfde_textout.h"
namespace {
@@ -927,7 +928,14 @@ std::vector<CFX_RectF> CFDE_TextEditEngine::GetCharacterRectsInRange(
return rects;
}
-CFDE_TextEditEngine::Iterator::Iterator(CFDE_TextEditEngine* engine)
+std::pair<size_t, size_t> CFDE_TextEditEngine::BoundsForWordAt(
+ size_t idx) const {
+ CFX_WordBreak breaker(
+ pdfium::MakeUnique<CFDE_TextEditEngine::Iterator>(this));
+ return breaker.BoundsAt(idx);
+}
+
+CFDE_TextEditEngine::Iterator::Iterator(const CFDE_TextEditEngine* engine)
: engine_(engine), current_position_(-1) {}
CFDE_TextEditEngine::Iterator::~Iterator() {}
@@ -936,8 +944,9 @@ 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())
+ static_cast<size_t>(current_position_) == engine_->GetLength()) {
return false;
+ }
if (bPrev)
--current_position_;
@@ -952,7 +961,12 @@ wchar_t CFDE_TextEditEngine::Iterator::GetChar() const {
}
void CFDE_TextEditEngine::Iterator::SetAt(int32_t nIndex) {
- NOTREACHED();
+ if (nIndex < 0)
+ current_position_ = 0;
+ else if (static_cast<size_t>(nIndex) >= engine_->GetLength())
+ current_position_ = engine_->GetLength();
+ else
+ current_position_ = nIndex;
}
int32_t CFDE_TextEditEngine::Iterator::GetAt() const {
@@ -967,6 +981,7 @@ bool CFDE_TextEditEngine::Iterator::IsEOF(bool bTail) const {
}
std::unique_ptr<IFX_CharIter> CFDE_TextEditEngine::Iterator::Clone() const {
- NOTREACHED();
- return pdfium::MakeUnique<CFDE_TextEditEngine::Iterator>(engine_.Get());
+ auto it = pdfium::MakeUnique<CFDE_TextEditEngine::Iterator>(engine_.Get());
+ it->current_position_ = current_position_;
+ return it;
}
diff --git a/xfa/fde/cfde_texteditengine.h b/xfa/fde/cfde_texteditengine.h
index 35d9664f99..0277b0cc64 100644
--- a/xfa/fde/cfde_texteditengine.h
+++ b/xfa/fde/cfde_texteditengine.h
@@ -40,7 +40,7 @@ class CFDE_TextEditEngine {
public:
class Iterator : public IFX_CharIter {
public:
- explicit Iterator(CFDE_TextEditEngine* engine);
+ explicit Iterator(const CFDE_TextEditEngine* engine);
~Iterator() override;
bool Next(bool bPrev = false) override;
@@ -51,7 +51,7 @@ class CFDE_TextEditEngine {
std::unique_ptr<IFX_CharIter> Clone() const override;
private:
- CFX_UnownedPtr<CFDE_TextEditEngine> engine_;
+ CFX_UnownedPtr<const CFDE_TextEditEngine> engine_;
int32_t current_position_;
};
@@ -160,6 +160,8 @@ class CFDE_TextEditEngine {
size_t GetWidthOfChar(size_t idx);
// Non-const so we can force a Layout() if needed.
size_t GetIndexForPoint(const CFX_PointF& point);
+ // <start_idx, end_idx>
+ std::pair<size_t, size_t> BoundsForWordAt(size_t idx) const;
// Returns <bidi level, character rect>
std::pair<int32_t, CFX_RectF> GetCharacterInfo(int32_t start_idx);
diff --git a/xfa/fde/cfde_texteditengine_unittest.cpp b/xfa/fde/cfde_texteditengine_unittest.cpp
index da11e46daa..2084914bbf 100644
--- a/xfa/fde/cfde_texteditengine_unittest.cpp
+++ b/xfa/fde/cfde_texteditengine_unittest.cpp
@@ -416,3 +416,115 @@ TEST_F(CFDE_TextEditEngineTest, GetIndexForPoint) {
EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f}));
EXPECT_EQ(1U, engine()->GetIndexForPoint({10.0f, 5.0f}));
}
+
+TEST_F(CFDE_TextEditEngineTest, BoundsForWordAt) {
+ size_t start_idx;
+ size_t end_idx;
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(100);
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(0U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(0);
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(4U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"Hello", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"Hello World");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(100);
+ EXPECT_EQ(11U, start_idx);
+ EXPECT_EQ(11U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(0);
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(4U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"Hello", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(1);
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(4U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"Hello", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(4);
+ EXPECT_EQ(0U, start_idx);
+ EXPECT_EQ(4U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"Hello", engine()->GetSelectedText().c_str());
+
+ // Select the space
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(5);
+ EXPECT_EQ(5U, start_idx);
+ EXPECT_EQ(5U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(6);
+ EXPECT_EQ(6U, start_idx);
+ EXPECT_EQ(10U, end_idx);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"World", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"123 456 789");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(5);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"456", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"123def789");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(5);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"123def789", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"abc456ghi");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(5);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"abc456ghi", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"hello, world");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(0);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"hello", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"hello, world");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(5);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"np-complete");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(6);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"complete", engine()->GetSelectedText().c_str());
+
+ engine()->Clear();
+ engine()->Insert(0, L"(123) 456-7890");
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(0);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(1);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"123", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(7);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"456", engine()->GetSelectedText().c_str());
+
+ std::tie(start_idx, end_idx) = engine()->BoundsForWordAt(11);
+ engine()->SetSelection(start_idx, end_idx);
+ EXPECT_STREQ(L"7890", engine()->GetSelectedText().c_str());
+}
diff --git a/xfa/fwl/cfwl_edit.cpp b/xfa/fwl/cfwl_edit.cpp
index 72adb5392b..99a312bfca 100644
--- a/xfa/fwl/cfwl_edit.cpp
+++ b/xfa/fwl/cfwl_edit.cpp
@@ -1234,14 +1234,13 @@ void CFWL_Edit::OnLButtonUp(CFWL_MessageMouse* pMsg) {
}
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);
+ size_t click_idx = m_EdtEngine.GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
+ size_t start_idx;
+ size_t end_idx;
+ std::tie(start_idx, end_idx) = m_EdtEngine.BoundsForWordAt(click_idx);
+
+ m_EdtEngine.SetSelection(start_idx, end_idx);
+ m_CursorPosition = end_idx;
RepaintRect(m_rtEngine);
}