diff options
Diffstat (limited to 'fpdfsdk/pdfwindow')
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_appstream.cpp | 14 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_combo_box.cpp | 2 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_edit.cpp | 13 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp | 6 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_edit_ctrl.h | 4 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_edit_impl.cpp | 2053 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_edit_impl.h | 515 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_list_box.cpp | 27 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_list_box.h | 4 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_list_impl.cpp | 637 | ||||
-rw-r--r-- | fpdfsdk/pdfwindow/cpwl_list_impl.h | 168 |
11 files changed, 3409 insertions, 34 deletions
diff --git a/fpdfsdk/pdfwindow/cpwl_appstream.cpp b/fpdfsdk/pdfwindow/cpwl_appstream.cpp index f7ba4c465c..9ac08fa078 100644 --- a/fpdfsdk/pdfwindow/cpwl_appstream.cpp +++ b/fpdfsdk/pdfwindow/cpwl_appstream.cpp @@ -22,8 +22,8 @@ #include "fpdfsdk/cpdfsdk_pageview.h" #include "fpdfsdk/cpdfsdk_widget.h" #include "fpdfsdk/formfiller/cba_fontmap.h" -#include "fpdfsdk/fxedit/fxet_edit.h" #include "fpdfsdk/pdfwindow/cpwl_edit.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_impl.h" #include "fpdfsdk/pdfwindow/cpwl_icon.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" @@ -523,11 +523,11 @@ CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) { return CFX_ByteString(); } -CFX_ByteString GetEditAppStream(CFX_Edit* pEdit, +CFX_ByteString GetEditAppStream(CPWL_EditImpl* pEdit, const CFX_PointF& ptOffset, bool bContinuous, uint16_t SubWord) { - CFX_Edit_Iterator* pIterator = pEdit->GetIterator(); + CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator(); pIterator->SetAt(0); std::ostringstream sEditStream; @@ -686,7 +686,7 @@ CFX_ByteString GetPushButtonAppStream(const CFX_FloatRect& rcBBox, ButtonStyle nLayOut) { const float fAutoFontScale = 1.0f / 3.0f; - auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>(); pEdit->SetFontMap(pFontMap); pEdit->SetAlignmentH(1, true); pEdit->SetAlignmentV(1, true); @@ -1515,7 +1515,7 @@ void CPWL_AppStream::SetAsComboBox(const CFX_WideString* sValue) { rcButton.left = rcButton.right - 13; rcButton.Normalize(); - auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>(); pEdit->EnableRefresh(false); CBA_FontMap font_map( @@ -1578,7 +1578,7 @@ void CPWL_AppStream::SetAsListBox() { CFX_FloatRect rcClient = widget_->GetClientRect(); std::ostringstream sBody; - auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>(); pEdit->EnableRefresh(false); CBA_FontMap font_map( @@ -1658,7 +1658,7 @@ void CPWL_AppStream::SetAsTextField(const CFX_WideString* sValue) { std::ostringstream sBody; std::ostringstream sLines; - auto pEdit = pdfium::MakeUnique<CFX_Edit>(); + auto pEdit = pdfium::MakeUnique<CPWL_EditImpl>(); pEdit->EnableRefresh(false); CBA_FontMap font_map( diff --git a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp index 484027eba2..8de2f1e733 100644 --- a/fpdfsdk/pdfwindow/cpwl_combo_box.cpp +++ b/fpdfsdk/pdfwindow/cpwl_combo_box.cpp @@ -11,10 +11,10 @@ #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" -#include "fpdfsdk/fxedit/fxet_list.h" #include "fpdfsdk/pdfwindow/cpwl_edit.h" #include "fpdfsdk/pdfwindow/cpwl_edit_ctrl.h" #include "fpdfsdk/pdfwindow/cpwl_list_box.h" +#include "fpdfsdk/pdfwindow/cpwl_list_impl.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" #include "public/fpdf_fwlevent.h" diff --git a/fpdfsdk/pdfwindow/cpwl_edit.cpp b/fpdfsdk/pdfwindow/cpwl_edit.cpp index 89361b5835..8588de73c6 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit.cpp +++ b/fpdfsdk/pdfwindow/cpwl_edit.cpp @@ -20,9 +20,9 @@ #include "core/fxge/cfx_pathdata.h" #include "core/fxge/cfx_renderdevice.h" #include "core/fxge/fx_font.h" -#include "fpdfsdk/fxedit/fxet_edit.h" #include "fpdfsdk/pdfwindow/cpwl_caret.h" #include "fpdfsdk/pdfwindow/cpwl_edit_ctrl.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_impl.h" #include "fpdfsdk/pdfwindow/cpwl_font_map.h" #include "fpdfsdk/pdfwindow/cpwl_scroll_bar.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" @@ -281,9 +281,10 @@ void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice, } CFX_SystemHandler* pSysHandler = GetSystemHandler(); - CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pEdit.get(), - GetTextColor().ToFXColor(GetTransparency()), rcClip, - CFX_PointF(), pRange, pSysHandler, m_pFormFiller.Get()); + CPWL_EditImpl::DrawEdit(pDevice, pUser2Device, m_pEdit.get(), + GetTextColor().ToFXColor(GetTransparency()), rcClip, + CFX_PointF(), pRange, pSysHandler, + m_pFormFiller.Get()); } bool CPWL_Edit::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) { @@ -373,7 +374,7 @@ CPVT_WordRange CPWL_Edit::GetSelectWordRange() const { } CFX_PointF CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) { - CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator(); + CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); CPVT_WordPlace wpOld = pIterator->GetAt(); pIterator->SetAt(wpWord); @@ -660,7 +661,7 @@ CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place, bool bArabic) const { CPVT_WordRange range; - CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator(); + CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); CPVT_Word wordinfo; CPVT_WordPlace wpStart(place), wpEnd(place); pIterator->SetAt(place); diff --git a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp index 7b90579a5f..c7e1f14499 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp +++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.cpp @@ -9,15 +9,15 @@ #include "core/fpdfdoc/cpvt_section.h" #include "core/fpdfdoc/cpvt_word.h" #include "core/fxge/fx_font.h" -#include "fpdfsdk/fxedit/fxet_edit.h" #include "fpdfsdk/pdfwindow/cpwl_caret.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_impl.h" #include "fpdfsdk/pdfwindow/cpwl_font_map.h" #include "fpdfsdk/pdfwindow/cpwl_scroll_bar.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" #include "public/fpdf_fwlevent.h" CPWL_EditCtrl::CPWL_EditCtrl() - : m_pEdit(new CFX_Edit), + : m_pEdit(new CPWL_EditImpl), m_pEditCaret(nullptr), m_bMouseDown(false), m_nCharSet(FX_CHARSET_Default) {} @@ -302,7 +302,7 @@ void CPWL_EditCtrl::SetEditCaret(bool bVisible) { } void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const { - CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator(); + CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); pIterator->SetAt(m_pEdit->GetCaret()); CPVT_Word word; CPVT_Line line; diff --git a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h index fca3bd8fe4..ef6989e637 100644 --- a/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h +++ b/fpdfsdk/pdfwindow/cpwl_edit_ctrl.h @@ -12,7 +12,7 @@ #include "core/fxcrt/fx_string.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" -class CFX_Edit; +class CPWL_EditImpl; class CPWL_Caret; struct CPVT_WordPlace; @@ -82,7 +82,7 @@ class CPWL_EditCtrl : public CPWL_Wnd { void SetEditCaret(bool bVisible); - std::unique_ptr<CFX_Edit> m_pEdit; + std::unique_ptr<CPWL_EditImpl> m_pEdit; CPWL_Caret* m_pEditCaret; bool m_bMouseDown; diff --git a/fpdfsdk/pdfwindow/cpwl_edit_impl.cpp b/fpdfsdk/pdfwindow/cpwl_edit_impl.cpp new file mode 100644 index 0000000000..0f5cf05b10 --- /dev/null +++ b/fpdfsdk/pdfwindow/cpwl_edit_impl.cpp @@ -0,0 +1,2053 @@ +// 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 "fpdfsdk/pdfwindow/cpwl_edit_impl.h" + +#include <algorithm> +#include <memory> +#include <sstream> +#include <utility> + +#include "core/fpdfapi/font/cpdf_font.h" +#include "core/fpdfapi/page/cpdf_pageobject.h" +#include "core/fpdfapi/page/cpdf_pageobjectholder.h" +#include "core/fpdfapi/page/cpdf_pathobject.h" +#include "core/fpdfapi/page/cpdf_textobject.h" +#include "core/fpdfapi/parser/fpdf_parser_decode.h" +#include "core/fpdfapi/render/cpdf_renderoptions.h" +#include "core/fpdfapi/render/cpdf_textrenderer.h" +#include "core/fpdfdoc/cpvt_section.h" +#include "core/fpdfdoc/cpvt_word.h" +#include "core/fpdfdoc/ipvt_fontmap.h" +#include "core/fxcrt/fx_codepage.h" +#include "core/fxge/cfx_graphstatedata.h" +#include "core/fxge/cfx_pathdata.h" +#include "core/fxge/cfx_renderdevice.h" +#include "fpdfsdk/cfx_systemhandler.h" +#include "fpdfsdk/pdfwindow/cpwl_edit.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_ctrl.h" +#include "fpdfsdk/pdfwindow/cpwl_scroll_bar.h" +#include "third_party/base/ptr_util.h" +#include "third_party/base/stl_util.h" + +namespace { + +const int kEditUndoMaxItems = 10000; + +void DrawTextString(CFX_RenderDevice* pDevice, + const CFX_PointF& pt, + CPDF_Font* pFont, + float fFontSize, + CFX_Matrix* pUser2Device, + const CFX_ByteString& str, + FX_ARGB crTextFill, + int32_t nHorzScale) { + CFX_PointF pos = pUser2Device->Transform(pt); + + if (pFont) { + if (nHorzScale != 100) { + CFX_Matrix mt(nHorzScale / 100.0f, 0, 0, 1, 0, 0); + mt.Concat(*pUser2Device); + + CPDF_RenderOptions ro; + ro.m_Flags = RENDER_CLEARTYPE; + ro.m_ColorMode = CPDF_RenderOptions::kNormal; + + CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize, + &mt, str, crTextFill, nullptr, &ro); + } else { + CPDF_RenderOptions ro; + ro.m_Flags = RENDER_CLEARTYPE; + ro.m_ColorMode = CPDF_RenderOptions::kNormal; + + CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize, + pUser2Device, str, crTextFill, nullptr, + &ro); + } + } +} + +} // namespace + +CPWL_EditImpl_Iterator::CPWL_EditImpl_Iterator( + CPWL_EditImpl* pEdit, + CPDF_VariableText::Iterator* pVTIterator) + : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {} + +CPWL_EditImpl_Iterator::~CPWL_EditImpl_Iterator() {} + +bool CPWL_EditImpl_Iterator::NextWord() { + return m_pVTIterator->NextWord(); +} + +bool CPWL_EditImpl_Iterator::PrevWord() { + return m_pVTIterator->PrevWord(); +} + +bool CPWL_EditImpl_Iterator::GetWord(CPVT_Word& word) const { + ASSERT(m_pEdit); + + if (m_pVTIterator->GetWord(word)) { + word.ptWord = m_pEdit->VTToEdit(word.ptWord); + return true; + } + return false; +} + +bool CPWL_EditImpl_Iterator::GetLine(CPVT_Line& line) const { + ASSERT(m_pEdit); + + if (m_pVTIterator->GetLine(line)) { + line.ptLine = m_pEdit->VTToEdit(line.ptLine); + return true; + } + return false; +} + +void CPWL_EditImpl_Iterator::SetAt(int32_t nWordIndex) { + m_pVTIterator->SetAt(nWordIndex); +} + +void CPWL_EditImpl_Iterator::SetAt(const CPVT_WordPlace& place) { + m_pVTIterator->SetAt(place); +} + +const CPVT_WordPlace& CPWL_EditImpl_Iterator::GetAt() const { + return m_pVTIterator->GetAt(); +} + +CPWL_EditImpl_Provider::CPWL_EditImpl_Provider(IPVT_FontMap* pFontMap) + : CPDF_VariableText::Provider(pFontMap), m_pFontMap(pFontMap) { + ASSERT(m_pFontMap); +} + +CPWL_EditImpl_Provider::~CPWL_EditImpl_Provider() {} + +IPVT_FontMap* CPWL_EditImpl_Provider::GetFontMap() const { + return m_pFontMap; +} + +int32_t CPWL_EditImpl_Provider::GetCharWidth(int32_t nFontIndex, + uint16_t word) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) { + uint32_t charcode = word; + + if (pPDFFont->IsUnicodeCompatible()) + charcode = pPDFFont->CharCodeFromUnicode(word); + else + charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word); + + if (charcode != CPDF_Font::kInvalidCharCode) + return pPDFFont->GetCharWidthF(charcode); + } + + return 0; +} + +int32_t CPWL_EditImpl_Provider::GetTypeAscent(int32_t nFontIndex) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) + return pPDFFont->GetTypeAscent(); + + return 0; +} + +int32_t CPWL_EditImpl_Provider::GetTypeDescent(int32_t nFontIndex) { + if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) + return pPDFFont->GetTypeDescent(); + + return 0; +} + +int32_t CPWL_EditImpl_Provider::GetWordFontIndex(uint16_t word, + int32_t charset, + int32_t nFontIndex) { + return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex); +} + +int32_t CPWL_EditImpl_Provider::GetDefaultFontIndex() { + return 0; +} + +bool CPWL_EditImpl_Provider::IsLatinWord(uint16_t word) { + return FX_EDIT_ISLATINWORD(word); +} + +CPWL_EditImpl_Refresh::CPWL_EditImpl_Refresh() {} + +CPWL_EditImpl_Refresh::~CPWL_EditImpl_Refresh() {} + +void CPWL_EditImpl_Refresh::BeginRefresh() { + m_RefreshRects.Clear(); + m_OldLineRects = std::move(m_NewLineRects); +} + +void CPWL_EditImpl_Refresh::Push(const CPVT_WordRange& linerange, + const CFX_FloatRect& rect) { + m_NewLineRects.Add(linerange, rect); +} + +void CPWL_EditImpl_Refresh::NoAnalyse() { + { + for (int32_t i = 0, sz = m_OldLineRects.GetSize(); i < sz; i++) + if (CPWL_EditImpl_LineRect* pOldRect = m_OldLineRects.GetAt(i)) + m_RefreshRects.Add(pOldRect->m_rcLine); + } + + { + for (int32_t i = 0, sz = m_NewLineRects.GetSize(); i < sz; i++) + if (CPWL_EditImpl_LineRect* pNewRect = m_NewLineRects.GetAt(i)) + m_RefreshRects.Add(pNewRect->m_rcLine); + } +} + +const CPWL_EditImpl_RectArray* CPWL_EditImpl_Refresh::GetRefreshRects() const { + return &m_RefreshRects; +} + +void CPWL_EditImpl_Refresh::EndRefresh() { + m_RefreshRects.Clear(); +} + +CPWL_EditImpl_Undo::CPWL_EditImpl_Undo(int32_t nBufsize) + : m_nCurUndoPos(0), m_nBufSize(nBufsize), m_bWorking(false) {} + +CPWL_EditImpl_Undo::~CPWL_EditImpl_Undo() { + Reset(); +} + +bool CPWL_EditImpl_Undo::CanUndo() const { + return m_nCurUndoPos > 0; +} + +void CPWL_EditImpl_Undo::Undo() { + m_bWorking = true; + if (m_nCurUndoPos > 0) { + m_UndoItemStack[m_nCurUndoPos - 1]->Undo(); + m_nCurUndoPos--; + } + m_bWorking = false; +} + +bool CPWL_EditImpl_Undo::CanRedo() const { + return m_nCurUndoPos < m_UndoItemStack.size(); +} + +void CPWL_EditImpl_Undo::Redo() { + m_bWorking = true; + if (m_nCurUndoPos < m_UndoItemStack.size()) { + m_UndoItemStack[m_nCurUndoPos]->Redo(); + m_nCurUndoPos++; + } + m_bWorking = false; +} + +void CPWL_EditImpl_Undo::AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem) { + ASSERT(!m_bWorking); + ASSERT(pItem); + ASSERT(m_nBufSize > 1); + if (m_nCurUndoPos < m_UndoItemStack.size()) + RemoveTails(); + + if (m_UndoItemStack.size() >= m_nBufSize) + RemoveHeads(); + + m_UndoItemStack.push_back(std::move(pItem)); + m_nCurUndoPos = m_UndoItemStack.size(); +} + +void CPWL_EditImpl_Undo::RemoveHeads() { + ASSERT(m_UndoItemStack.size() > 1); + m_UndoItemStack.pop_front(); +} + +void CPWL_EditImpl_Undo::RemoveTails() { + while (m_UndoItemStack.size() > m_nCurUndoPos) + m_UndoItemStack.pop_back(); +} + +void CPWL_EditImpl_Undo::Reset() { + m_UndoItemStack.clear(); + m_nCurUndoPos = 0; +} + +CPWL_EditImpl_UndoItem::CPWL_EditImpl_UndoItem() + : m_bFirst(true), m_bLast(true) {} + +CPWL_EditImpl_UndoItem::~CPWL_EditImpl_UndoItem() {} + +CFX_WideString CPWL_EditImpl_UndoItem::GetUndoTitle() const { + return CFX_WideString(); +} + +void CPWL_EditImpl_UndoItem::SetFirst(bool bFirst) { + m_bFirst = bFirst; +} + +void CPWL_EditImpl_UndoItem::SetLast(bool bLast) { + m_bLast = bLast; +} + +bool CPWL_EditImpl_UndoItem::IsLast() { + return m_bLast; +} + +CFXEU_InsertWord::CFXEU_InsertWord(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_WordProps* pWordProps) + : m_pEdit(pEdit), + m_wpOld(wpOldPlace), + m_wpNew(wpNewPlace), + m_Word(word), + m_nCharset(charset), + m_WordProps() { + if (pWordProps) + m_WordProps = *pWordProps; +} + +CFXEU_InsertWord::~CFXEU_InsertWord() {} + +void CFXEU_InsertWord::Redo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpOld); + m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true); + } +} + +void CFXEU_InsertWord::Undo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpNew); + m_pEdit->Backspace(false, true); + } +} + +CFXEU_InsertReturn::CFXEU_InsertReturn(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps) + : m_pEdit(pEdit), + m_wpOld(wpOldPlace), + m_wpNew(wpNewPlace), + m_SecProps(), + m_WordProps() { + if (pSecProps) + m_SecProps = *pSecProps; + if (pWordProps) + m_WordProps = *pWordProps; +} + +CFXEU_InsertReturn::~CFXEU_InsertReturn() {} + +void CFXEU_InsertReturn::Redo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpOld); + m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true); + } +} + +void CFXEU_InsertReturn::Undo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpNew); + m_pEdit->Backspace(false, true); + } +} + +CFXEU_Backspace::CFXEU_Backspace(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_SecProps& SecProps, + const CPVT_WordProps& WordProps) + : m_pEdit(pEdit), + m_wpOld(wpOldPlace), + m_wpNew(wpNewPlace), + m_Word(word), + m_nCharset(charset), + m_SecProps(SecProps), + m_WordProps(WordProps) {} + +CFXEU_Backspace::~CFXEU_Backspace() {} + +void CFXEU_Backspace::Redo() { + if (!m_pEdit) + return; + + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpOld); + m_pEdit->Backspace(false, true); +} + +void CFXEU_Backspace::Undo() { + if (!m_pEdit) + return; + + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpNew); + if (m_wpNew.nSecIndex != m_wpOld.nSecIndex) + m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true); + else + m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true); +} + +CFXEU_Delete::CFXEU_Delete(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_SecProps& SecProps, + const CPVT_WordProps& WordProps, + bool bSecEnd) + : m_pEdit(pEdit), + m_wpOld(wpOldPlace), + m_wpNew(wpNewPlace), + m_Word(word), + m_nCharset(charset), + m_SecProps(SecProps), + m_WordProps(WordProps), + m_bSecEnd(bSecEnd) {} + +CFXEU_Delete::~CFXEU_Delete() {} + +void CFXEU_Delete::Redo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpOld); + m_pEdit->Delete(false, true); + } +} + +void CFXEU_Delete::Undo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpNew); + if (m_bSecEnd) { + m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true); + } else { + m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true); + } + } +} + +CFXEU_Clear::CFXEU_Clear(CPWL_EditImpl* pEdit, + const CPVT_WordRange& wrSel, + const CFX_WideString& swText) + : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {} + +CFXEU_Clear::~CFXEU_Clear() {} + +void CFXEU_Clear::Redo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos); + m_pEdit->Clear(false, true); + } +} + +void CFXEU_Clear::Undo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wrSel.BeginPos); + m_pEdit->InsertText(m_swText, FX_CHARSET_Default, false, true); + m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos); + } +} + +CFXEU_InsertText::CFXEU_InsertText(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + const CFX_WideString& swText, + int32_t charset) + : m_pEdit(pEdit), + m_wpOld(wpOldPlace), + m_wpNew(wpNewPlace), + m_swText(swText), + m_nCharset(charset) {} + +CFXEU_InsertText::~CFXEU_InsertText() {} + +void CFXEU_InsertText::Redo() { + if (m_pEdit && IsLast()) { + m_pEdit->SelectNone(); + m_pEdit->SetCaret(m_wpOld); + m_pEdit->InsertText(m_swText, m_nCharset, false, true); + } +} + +void CFXEU_InsertText::Undo() { + if (m_pEdit) { + m_pEdit->SelectNone(); + m_pEdit->SetSelection(m_wpOld, m_wpNew); + m_pEdit->Clear(false, true); + } +} + +// static +void CPWL_EditImpl::DrawEdit(CFX_RenderDevice* pDevice, + CFX_Matrix* pUser2Device, + CPWL_EditImpl* pEdit, + FX_COLORREF crTextFill, + const CFX_FloatRect& rcClip, + const CFX_PointF& ptOffset, + const CPVT_WordRange* pRange, + CFX_SystemHandler* pSystemHandler, + CFFL_FormFiller* pFFLData) { + const bool bContinuous = + pEdit->GetCharArray() == 0 && pEdit->GetCharSpace() <= 0.0f; + uint16_t SubWord = pEdit->GetPasswordChar(); + float fFontSize = pEdit->GetFontSize(); + CPVT_WordRange wrSelect = pEdit->GetSelectWordRange(); + int32_t nHorzScale = pEdit->GetHorzScale(); + + FX_COLORREF crCurFill = crTextFill; + FX_COLORREF crOldFill = crCurFill; + + bool bSelect = false; + const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255); + const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113); + + std::ostringstream sTextBuf; + int32_t nFontIndex = -1; + CFX_PointF ptBT; + CFX_RenderDevice::StateRestorer restorer(pDevice); + if (!rcClip.IsEmpty()) { + CFX_FloatRect rcTemp = rcClip; + pUser2Device->TransformRect(rcTemp); + pDevice->SetClip_Rect(rcTemp.ToFxRect()); + } + + CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator(); + if (IPVT_FontMap* pFontMap = pEdit->GetFontMap()) { + if (pRange) + pIterator->SetAt(pRange->BeginPos); + else + pIterator->SetAt(0); + + CPVT_WordPlace oldplace; + while (pIterator->NextWord()) { + CPVT_WordPlace place = pIterator->GetAt(); + if (pRange && place > pRange->EndPos) + break; + + if (!wrSelect.IsEmpty()) { + bSelect = place > wrSelect.BeginPos && place <= wrSelect.EndPos; + crCurFill = bSelect ? crWhite : crTextFill; + } + if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) { + crCurFill = crTextFill; + crOldFill = crCurFill; + } + CPVT_Word word; + if (pIterator->GetWord(word)) { + if (bSelect) { + CPVT_Line line; + pIterator->GetLine(line); + + if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) { + CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent, + word.ptWord.x + word.fWidth, + line.ptLine.y + line.fLineAscent); + rc.Intersect(rcClip); + pSystemHandler->OutputSelectedRect(pFFLData, rc); + } else { + CFX_PathData pathSelBK; + pathSelBK.AppendRect( + word.ptWord.x, line.ptLine.y + line.fLineDescent, + word.ptWord.x + word.fWidth, line.ptLine.y + line.fLineAscent); + + pDevice->DrawPath(&pathSelBK, pUser2Device, nullptr, crSelBK, 0, + FXFILL_WINDING); + } + } + + if (bContinuous) { + if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex || + crOldFill != crCurFill) { + if (sTextBuf.tellp() > 0) { + DrawTextString( + pDevice, CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), + pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device, + CFX_ByteString(sTextBuf), crOldFill, nHorzScale); + + sTextBuf.str(""); + } + nFontIndex = word.nFontIndex; + ptBT = word.ptWord; + crOldFill = crCurFill; + } + + sTextBuf << pEdit->GetPDFWordString(word.nFontIndex, word.Word, + SubWord); + } else { + DrawTextString( + pDevice, + CFX_PointF(word.ptWord.x + ptOffset.x, + word.ptWord.y + ptOffset.y), + pFontMap->GetPDFFont(word.nFontIndex), fFontSize, pUser2Device, + pEdit->GetPDFWordString(word.nFontIndex, word.Word, SubWord), + crCurFill, nHorzScale); + } + oldplace = place; + } + } + + if (sTextBuf.tellp() > 0) { + DrawTextString(pDevice, + CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y), + pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device, + CFX_ByteString(sTextBuf), crOldFill, nHorzScale); + } + } +} + +CPWL_EditImpl::CPWL_EditImpl() + : m_pVT(new CPDF_VariableText), + m_pNotify(nullptr), + m_pOprNotify(nullptr), + m_wpCaret(-1, -1, -1), + m_wpOldCaret(-1, -1, -1), + m_SelState(), + m_bEnableScroll(false), + m_Undo(kEditUndoMaxItems), + m_nAlignment(0), + m_bNotifyFlag(false), + m_bEnableOverflow(false), + m_bEnableRefresh(true), + m_rcOldContent(0.0f, 0.0f, 0.0f, 0.0f), + m_bEnableUndo(true), + m_bOprNotify(false) {} + +CPWL_EditImpl::~CPWL_EditImpl() {} + +void CPWL_EditImpl::Initialize() { + m_pVT->Initialize(); + SetCaret(m_pVT->GetBeginWordPlace()); + SetCaretOrigin(); +} + +void CPWL_EditImpl::SetFontMap(IPVT_FontMap* pFontMap) { + m_pVTProvider = pdfium::MakeUnique<CPWL_EditImpl_Provider>(pFontMap); + m_pVT->SetProvider(m_pVTProvider.get()); +} + +void CPWL_EditImpl::SetNotify(CPWL_EditCtrl* pNotify) { + m_pNotify = pNotify; +} + +void CPWL_EditImpl::SetOprNotify(CPWL_Edit* pOprNotify) { + m_pOprNotify = pOprNotify; +} + +CPWL_EditImpl_Iterator* CPWL_EditImpl::GetIterator() { + if (!m_pIterator) { + m_pIterator = + pdfium::MakeUnique<CPWL_EditImpl_Iterator>(this, m_pVT->GetIterator()); + } + return m_pIterator.get(); +} + +IPVT_FontMap* CPWL_EditImpl::GetFontMap() { + return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr; +} + +void CPWL_EditImpl::SetPlateRect(const CFX_FloatRect& rect) { + m_pVT->SetPlateRect(rect); + m_ptScrollPos = CFX_PointF(rect.left, rect.top); + Paint(); +} + +void CPWL_EditImpl::SetAlignmentH(int32_t nFormat, bool bPaint) { + m_pVT->SetAlignment(nFormat); + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetAlignmentV(int32_t nFormat, bool bPaint) { + m_nAlignment = nFormat; + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetPasswordChar(uint16_t wSubWord, bool bPaint) { + m_pVT->SetPasswordChar(wSubWord); + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetLimitChar(int32_t nLimitChar) { + m_pVT->SetLimitChar(nLimitChar); + Paint(); +} + +void CPWL_EditImpl::SetCharArray(int32_t nCharArray) { + m_pVT->SetCharArray(nCharArray); + Paint(); +} + +void CPWL_EditImpl::SetCharSpace(float fCharSpace) { + m_pVT->SetCharSpace(fCharSpace); + Paint(); +} + +void CPWL_EditImpl::SetMultiLine(bool bMultiLine, bool bPaint) { + m_pVT->SetMultiLine(bMultiLine); + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetAutoReturn(bool bAuto, bool bPaint) { + m_pVT->SetAutoReturn(bAuto); + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetAutoFontSize(bool bAuto, bool bPaint) { + m_pVT->SetAutoFontSize(bAuto); + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetFontSize(float fFontSize) { + m_pVT->SetFontSize(fFontSize); + Paint(); +} + +void CPWL_EditImpl::SetAutoScroll(bool bAuto, bool bPaint) { + m_bEnableScroll = bAuto; + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetTextOverflow(bool bAllowed, bool bPaint) { + m_bEnableOverflow = bAllowed; + if (bPaint) + Paint(); +} + +void CPWL_EditImpl::SetSelection(int32_t nStartChar, int32_t nEndChar) { + if (m_pVT->IsValid()) { + if (nStartChar == 0 && nEndChar < 0) { + SelectAll(); + } else if (nStartChar < 0) { + SelectNone(); + } else { + if (nStartChar < nEndChar) { + SetSelection(m_pVT->WordIndexToWordPlace(nStartChar), + m_pVT->WordIndexToWordPlace(nEndChar)); + } else { + SetSelection(m_pVT->WordIndexToWordPlace(nEndChar), + m_pVT->WordIndexToWordPlace(nStartChar)); + } + } + } +} + +void CPWL_EditImpl::SetSelection(const CPVT_WordPlace& begin, + const CPVT_WordPlace& end) { + if (!m_pVT->IsValid()) + return; + + SelectNone(); + m_SelState.Set(begin, end); + SetCaret(m_SelState.EndPos); + ScrollToCaret(); + if (!m_SelState.IsEmpty()) + Refresh(); + SetCaretInfo(); +} + +void CPWL_EditImpl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const { + nStartChar = -1; + nEndChar = -1; + if (!m_pVT->IsValid()) + return; + + if (m_SelState.IsEmpty()) { + nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret); + nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret); + return; + } + if (m_SelState.BeginPos < m_SelState.EndPos) { + nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos); + nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos); + return; + } + nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos); + nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos); +} + +int32_t CPWL_EditImpl::GetCaret() const { + if (m_pVT->IsValid()) + return m_pVT->WordPlaceToWordIndex(m_wpCaret); + + return -1; +} + +CPVT_WordPlace CPWL_EditImpl::GetCaretWordPlace() const { + return m_wpCaret; +} + +CFX_WideString CPWL_EditImpl::GetText() const { + CFX_WideString swRet; + if (!m_pVT->IsValid()) + return swRet; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(0); + + CPVT_Word wordinfo; + CPVT_WordPlace oldplace = pIterator->GetAt(); + while (pIterator->NextWord()) { + CPVT_WordPlace place = pIterator->GetAt(); + if (pIterator->GetWord(wordinfo)) + swRet += wordinfo.Word; + if (oldplace.nSecIndex != place.nSecIndex) + swRet += L"\r\n"; + oldplace = place; + } + return swRet; +} + +CFX_WideString CPWL_EditImpl::GetRangeText(const CPVT_WordRange& range) const { + CFX_WideString swRet; + if (!m_pVT->IsValid()) + return swRet; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + CPVT_WordRange wrTemp = range; + m_pVT->UpdateWordPlace(wrTemp.BeginPos); + m_pVT->UpdateWordPlace(wrTemp.EndPos); + pIterator->SetAt(wrTemp.BeginPos); + + CPVT_Word wordinfo; + CPVT_WordPlace oldplace = wrTemp.BeginPos; + while (pIterator->NextWord()) { + CPVT_WordPlace place = pIterator->GetAt(); + if (place > wrTemp.EndPos) + break; + if (pIterator->GetWord(wordinfo)) + swRet += wordinfo.Word; + if (oldplace.nSecIndex != place.nSecIndex) + swRet += L"\r\n"; + oldplace = place; + } + return swRet; +} + +CFX_WideString CPWL_EditImpl::GetSelectedText() const { + return GetRangeText(m_SelState.ConvertToWordRange()); +} + +int32_t CPWL_EditImpl::GetTotalLines() const { + int32_t nLines = 1; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(0); + while (pIterator->NextLine()) + ++nLines; + + return nLines; +} + +CPVT_WordRange CPWL_EditImpl::GetSelectWordRange() const { + return m_SelState.ConvertToWordRange(); +} + +void CPWL_EditImpl::SetText(const CFX_WideString& sText) { + Empty(); + DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FX_CHARSET_Default); + Paint(); +} + +bool CPWL_EditImpl::InsertWord(uint16_t word, int32_t charset) { + return InsertWord(word, charset, nullptr, true, true); +} + +bool CPWL_EditImpl::InsertReturn() { + return InsertReturn(nullptr, nullptr, true, true); +} + +bool CPWL_EditImpl::Backspace() { + return Backspace(true, true); +} + +bool CPWL_EditImpl::Delete() { + return Delete(true, true); +} + +bool CPWL_EditImpl::ClearSelection() { + return Clear(true, true); +} + +bool CPWL_EditImpl::InsertText(const CFX_WideString& sText, int32_t charset) { + return InsertText(sText, charset, true, true); +} + +float CPWL_EditImpl::GetFontSize() const { + return m_pVT->GetFontSize(); +} + +uint16_t CPWL_EditImpl::GetPasswordChar() const { + return m_pVT->GetPasswordChar(); +} + +int32_t CPWL_EditImpl::GetCharArray() const { + return m_pVT->GetCharArray(); +} + +CFX_FloatRect CPWL_EditImpl::GetContentRect() const { + return VTToEdit(m_pVT->GetContentRect()); +} + +int32_t CPWL_EditImpl::GetHorzScale() const { + return m_pVT->GetHorzScale(); +} + +float CPWL_EditImpl::GetCharSpace() const { + return m_pVT->GetCharSpace(); +} + +CPVT_WordRange CPWL_EditImpl::GetWholeWordRange() const { + if (m_pVT->IsValid()) + return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace()); + + return CPVT_WordRange(); +} + +CPVT_WordRange CPWL_EditImpl::GetVisibleWordRange() const { + if (m_bEnableOverflow) + return GetWholeWordRange(); + + if (m_pVT->IsValid()) { + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + + CPVT_WordPlace place1 = + m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top))); + CPVT_WordPlace place2 = m_pVT->SearchWordPlace( + EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom))); + + return CPVT_WordRange(place1, place2); + } + + return CPVT_WordRange(); +} + +CPVT_WordPlace CPWL_EditImpl::SearchWordPlace(const CFX_PointF& point) const { + if (m_pVT->IsValid()) { + return m_pVT->SearchWordPlace(EditToVT(point)); + } + + return CPVT_WordPlace(); +} + +void CPWL_EditImpl::Paint() { + if (m_pVT->IsValid()) { + RearrangeAll(); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } +} + +void CPWL_EditImpl::RearrangeAll() { + if (m_pVT->IsValid()) { + m_pVT->UpdateWordPlace(m_wpCaret); + m_pVT->RearrangeAll(); + m_pVT->UpdateWordPlace(m_wpCaret); + SetScrollInfo(); + SetContentChanged(); + } +} + +void CPWL_EditImpl::RearrangePart(const CPVT_WordRange& range) { + if (m_pVT->IsValid()) { + m_pVT->UpdateWordPlace(m_wpCaret); + m_pVT->RearrangePart(range); + m_pVT->UpdateWordPlace(m_wpCaret); + SetScrollInfo(); + SetContentChanged(); + } +} + +void CPWL_EditImpl::SetContentChanged() { + if (m_pNotify) { + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + if (rcContent.Width() != m_rcOldContent.Width() || + rcContent.Height() != m_rcOldContent.Height()) { + m_rcOldContent = rcContent; + } + } +} + +void CPWL_EditImpl::SelectAll() { + if (!m_pVT->IsValid()) + return; + m_SelState = CPWL_EditImpl_Select(GetWholeWordRange()); + SetCaret(m_SelState.EndPos); + ScrollToCaret(); + Refresh(); + SetCaretInfo(); +} + +void CPWL_EditImpl::SelectNone() { + if (!m_pVT->IsValid() || m_SelState.IsEmpty()) + return; + + m_SelState.Reset(); + Refresh(); +} + +bool CPWL_EditImpl::IsSelected() const { + return !m_SelState.IsEmpty(); +} + +CFX_PointF CPWL_EditImpl::VTToEdit(const CFX_PointF& point) const { + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + + float fPadding = 0.0f; + + switch (m_nAlignment) { + case 0: + fPadding = 0.0f; + break; + case 1: + fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f; + break; + case 2: + fPadding = rcPlate.Height() - rcContent.Height(); + break; + } + + return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left), + point.y - (m_ptScrollPos.y + fPadding - rcPlate.top)); +} + +CFX_PointF CPWL_EditImpl::EditToVT(const CFX_PointF& point) const { + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + + float fPadding = 0.0f; + + switch (m_nAlignment) { + case 0: + fPadding = 0.0f; + break; + case 1: + fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f; + break; + case 2: + fPadding = rcPlate.Height() - rcContent.Height(); + break; + } + + return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left), + point.y + (m_ptScrollPos.y + fPadding - rcPlate.top)); +} + +CFX_FloatRect CPWL_EditImpl::VTToEdit(const CFX_FloatRect& rect) const { + CFX_PointF ptLeftBottom = VTToEdit(CFX_PointF(rect.left, rect.bottom)); + CFX_PointF ptRightTop = VTToEdit(CFX_PointF(rect.right, rect.top)); + + return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, + ptRightTop.y); +} + +void CPWL_EditImpl::SetScrollInfo() { + if (!m_pNotify) + return; + + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + if (m_bNotifyFlag) + return; + + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + + PWL_SCROLL_INFO Info; + Info.fPlateWidth = rcPlate.top - rcPlate.bottom; + Info.fContentMin = rcContent.bottom; + Info.fContentMax = rcContent.top; + Info.fSmallStep = rcPlate.Height() / 3; + Info.fBigStep = rcPlate.Height(); + m_pNotify->SetScrollInfo(Info); +} + +void CPWL_EditImpl::SetScrollPosX(float fx) { + if (!m_bEnableScroll) + return; + + if (m_pVT->IsValid()) { + if (!IsFloatEqual(m_ptScrollPos.x, fx)) { + m_ptScrollPos.x = fx; + Refresh(); + } + } +} + +void CPWL_EditImpl::SetScrollPosY(float fy) { + if (!m_bEnableScroll) + return; + + if (m_pVT->IsValid()) { + if (!IsFloatEqual(m_ptScrollPos.y, fy)) { + m_ptScrollPos.y = fy; + Refresh(); + + if (m_pNotify) { + if (!m_bNotifyFlag) { + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + m_pNotify->SetScrollPosition(fy); + } + } + } + } +} + +void CPWL_EditImpl::SetScrollPos(const CFX_PointF& point) { + SetScrollPosX(point.x); + SetScrollPosY(point.y); + SetScrollLimit(); + SetCaretInfo(); +} + +CFX_PointF CPWL_EditImpl::GetScrollPos() const { + return m_ptScrollPos; +} + +void CPWL_EditImpl::SetScrollLimit() { + if (m_pVT->IsValid()) { + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + + if (rcPlate.Width() > rcContent.Width()) { + SetScrollPosX(rcPlate.left); + } else { + if (IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) { + SetScrollPosX(rcContent.left); + } else if (IsFloatBigger(m_ptScrollPos.x, + rcContent.right - rcPlate.Width())) { + SetScrollPosX(rcContent.right - rcPlate.Width()); + } + } + + if (rcPlate.Height() > rcContent.Height()) { + SetScrollPosY(rcPlate.top); + } else { + if (IsFloatSmaller(m_ptScrollPos.y, + rcContent.bottom + rcPlate.Height())) { + SetScrollPosY(rcContent.bottom + rcPlate.Height()); + } else if (IsFloatBigger(m_ptScrollPos.y, rcContent.top)) { + SetScrollPosY(rcContent.top); + } + } + } +} + +void CPWL_EditImpl::ScrollToCaret() { + SetScrollLimit(); + + if (!m_pVT->IsValid()) + return; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(m_wpCaret); + + CFX_PointF ptHead; + CFX_PointF ptFoot; + CPVT_Word word; + CPVT_Line line; + if (pIterator->GetWord(word)) { + ptHead.x = word.ptWord.x + word.fWidth; + ptHead.y = word.ptWord.y + word.fAscent; + ptFoot.x = word.ptWord.x + word.fWidth; + ptFoot.y = word.ptWord.y + word.fDescent; + } else if (pIterator->GetLine(line)) { + ptHead.x = line.ptLine.x; + ptHead.y = line.ptLine.y + line.fLineAscent; + ptFoot.x = line.ptLine.x; + ptFoot.y = line.ptLine.y + line.fLineDescent; + } + + CFX_PointF ptHeadEdit = VTToEdit(ptHead); + CFX_PointF ptFootEdit = VTToEdit(ptFoot); + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + if (!IsFloatEqual(rcPlate.left, rcPlate.right)) { + if (IsFloatSmaller(ptHeadEdit.x, rcPlate.left) || + IsFloatEqual(ptHeadEdit.x, rcPlate.left)) { + SetScrollPosX(ptHead.x); + } else if (IsFloatBigger(ptHeadEdit.x, rcPlate.right)) { + SetScrollPosX(ptHead.x - rcPlate.Width()); + } + } + + if (!IsFloatEqual(rcPlate.top, rcPlate.bottom)) { + if (IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) || + IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) { + if (IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) { + SetScrollPosY(ptFoot.y + rcPlate.Height()); + } + } else if (IsFloatBigger(ptHeadEdit.y, rcPlate.top)) { + if (IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) { + SetScrollPosY(ptHead.y); + } + } + } +} + +void CPWL_EditImpl::Refresh() { + if (m_bEnableRefresh && m_pVT->IsValid()) { + m_Refresh.BeginRefresh(); + RefreshPushLineRects(GetVisibleWordRange()); + + m_Refresh.NoAnalyse(); + m_ptRefreshScrollPos = m_ptScrollPos; + + if (m_pNotify) { + if (!m_bNotifyFlag) { + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + if (const CPWL_EditImpl_RectArray* pRects = + m_Refresh.GetRefreshRects()) { + for (int32_t i = 0, sz = pRects->GetSize(); i < sz; i++) + m_pNotify->InvalidateRect(pRects->GetAt(i)); + } + } + } + + m_Refresh.EndRefresh(); + } +} + +void CPWL_EditImpl::RefreshPushLineRects(const CPVT_WordRange& wr) { + if (!m_pVT->IsValid()) + return; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + CPVT_WordPlace wpBegin = wr.BeginPos; + m_pVT->UpdateWordPlace(wpBegin); + CPVT_WordPlace wpEnd = wr.EndPos; + m_pVT->UpdateWordPlace(wpEnd); + pIterator->SetAt(wpBegin); + + CPVT_Line lineinfo; + do { + if (!pIterator->GetLine(lineinfo)) + break; + if (lineinfo.lineplace.LineCmp(wpEnd) > 0) + break; + + CFX_FloatRect rcLine(lineinfo.ptLine.x, + lineinfo.ptLine.y + lineinfo.fLineDescent, + lineinfo.ptLine.x + lineinfo.fLineWidth, + lineinfo.ptLine.y + lineinfo.fLineAscent); + + m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd), + VTToEdit(rcLine)); + } while (pIterator->NextLine()); +} + +void CPWL_EditImpl::RefreshWordRange(const CPVT_WordRange& wr) { + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + CPVT_WordRange wrTemp = wr; + + m_pVT->UpdateWordPlace(wrTemp.BeginPos); + m_pVT->UpdateWordPlace(wrTemp.EndPos); + pIterator->SetAt(wrTemp.BeginPos); + + CPVT_Word wordinfo; + CPVT_Line lineinfo; + CPVT_WordPlace place; + + while (pIterator->NextWord()) { + place = pIterator->GetAt(); + if (place > wrTemp.EndPos) + break; + + pIterator->GetWord(wordinfo); + pIterator->GetLine(lineinfo); + if (place.LineCmp(wrTemp.BeginPos) == 0 || + place.LineCmp(wrTemp.EndPos) == 0) { + CFX_FloatRect rcWord(wordinfo.ptWord.x, + lineinfo.ptLine.y + lineinfo.fLineDescent, + wordinfo.ptWord.x + wordinfo.fWidth, + lineinfo.ptLine.y + lineinfo.fLineAscent); + + if (m_pNotify) { + if (!m_bNotifyFlag) { + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + CFX_FloatRect rcRefresh = VTToEdit(rcWord); + m_pNotify->InvalidateRect(&rcRefresh); + } + } + } else { + CFX_FloatRect rcLine(lineinfo.ptLine.x, + lineinfo.ptLine.y + lineinfo.fLineDescent, + lineinfo.ptLine.x + lineinfo.fLineWidth, + lineinfo.ptLine.y + lineinfo.fLineAscent); + + if (m_pNotify) { + if (!m_bNotifyFlag) { + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + CFX_FloatRect rcRefresh = VTToEdit(rcLine); + m_pNotify->InvalidateRect(&rcRefresh); + } + } + + pIterator->NextLine(); + } + } +} + +void CPWL_EditImpl::SetCaret(const CPVT_WordPlace& place) { + m_wpOldCaret = m_wpCaret; + m_wpCaret = place; +} + +void CPWL_EditImpl::SetCaretInfo() { + if (m_pNotify) { + if (!m_bNotifyFlag) { + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(m_wpCaret); + + CFX_PointF ptHead; + CFX_PointF ptFoot; + CPVT_Word word; + CPVT_Line line; + if (pIterator->GetWord(word)) { + ptHead.x = word.ptWord.x + word.fWidth; + ptHead.y = word.ptWord.y + word.fAscent; + ptFoot.x = word.ptWord.x + word.fWidth; + ptFoot.y = word.ptWord.y + word.fDescent; + } else if (pIterator->GetLine(line)) { + ptHead.x = line.ptLine.x; + ptHead.y = line.ptLine.y + line.fLineAscent; + ptFoot.x = line.ptLine.x; + ptFoot.y = line.ptLine.y + line.fLineDescent; + } + + CFX_AutoRestorer<bool> restorer(&m_bNotifyFlag); + m_bNotifyFlag = true; + m_pNotify->SetCaret(m_SelState.IsEmpty(), VTToEdit(ptHead), + VTToEdit(ptFoot)); + } + } +} + +void CPWL_EditImpl::OnMouseDown(const CFX_PointF& point, + bool bShift, + bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + SelectNone(); + SetCaret(m_pVT->SearchWordPlace(EditToVT(point))); + m_SelState.Set(m_wpCaret, m_wpCaret); + ScrollToCaret(); + SetCaretOrigin(); + SetCaretInfo(); +} + +void CPWL_EditImpl::OnMouseMove(const CFX_PointF& point, + bool bShift, + bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + SetCaret(m_pVT->SearchWordPlace(EditToVT(point))); + if (m_wpCaret == m_wpOldCaret) + return; + + m_SelState.SetEndPos(m_wpCaret); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); +} + +void CPWL_EditImpl::OnVK_UP(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret)); + if (bShift) { + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + if (m_wpOldCaret != m_wpCaret) { + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } + } else { + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } +} + +void CPWL_EditImpl::OnVK_DOWN(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret)); + if (bShift) { + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + if (m_wpOldCaret != m_wpCaret) { + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } + } else { + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } +} + +void CPWL_EditImpl::OnVK_LEFT(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + if (bShift) { + if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) && + m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) { + SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret)); + } + SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret)); + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + if (m_wpOldCaret != m_wpCaret) { + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } + } else { + if (!m_SelState.IsEmpty()) { + if (m_SelState.BeginPos < m_SelState.EndPos) + SetCaret(m_SelState.BeginPos); + else + SetCaret(m_SelState.EndPos); + + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } else { + if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) && + m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) { + SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret)); + } + SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret)); + ScrollToCaret(); + SetCaretOrigin(); + SetCaretInfo(); + } + } +} + +void CPWL_EditImpl::OnVK_RIGHT(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + if (bShift) { + SetCaret(m_pVT->GetNextWordPlace(m_wpCaret)); + if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) && + m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret)) + SetCaret(m_pVT->GetNextWordPlace(m_wpCaret)); + + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + if (m_wpOldCaret != m_wpCaret) { + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } + } else { + if (!m_SelState.IsEmpty()) { + if (m_SelState.BeginPos > m_SelState.EndPos) + SetCaret(m_SelState.BeginPos); + else + SetCaret(m_SelState.EndPos); + + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } else { + SetCaret(m_pVT->GetNextWordPlace(m_wpCaret)); + if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) && + m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret)) { + SetCaret(m_pVT->GetNextWordPlace(m_wpCaret)); + } + ScrollToCaret(); + SetCaretOrigin(); + SetCaretInfo(); + } + } +} + +void CPWL_EditImpl::OnVK_HOME(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + if (bShift) { + if (bCtrl) + SetCaret(m_pVT->GetBeginWordPlace()); + else + SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret)); + + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } else { + if (!m_SelState.IsEmpty()) { + SetCaret(std::min(m_SelState.BeginPos, m_SelState.EndPos)); + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } else { + if (bCtrl) + SetCaret(m_pVT->GetBeginWordPlace()); + else + SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret)); + + ScrollToCaret(); + SetCaretOrigin(); + SetCaretInfo(); + } + } +} + +void CPWL_EditImpl::OnVK_END(bool bShift, bool bCtrl) { + if (!m_pVT->IsValid()) + return; + + if (bShift) { + if (bCtrl) + SetCaret(m_pVT->GetEndWordPlace()); + else + SetCaret(m_pVT->GetLineEndPlace(m_wpCaret)); + + if (m_SelState.IsEmpty()) + m_SelState.Set(m_wpOldCaret, m_wpCaret); + else + m_SelState.SetEndPos(m_wpCaret); + + ScrollToCaret(); + Refresh(); + SetCaretInfo(); + } else { + if (!m_SelState.IsEmpty()) { + SetCaret(std::max(m_SelState.BeginPos, m_SelState.EndPos)); + SelectNone(); + ScrollToCaret(); + SetCaretInfo(); + } else { + if (bCtrl) + SetCaret(m_pVT->GetEndWordPlace()); + else + SetCaret(m_pVT->GetLineEndPlace(m_wpCaret)); + + ScrollToCaret(); + SetCaretOrigin(); + SetCaretInfo(); + } + } +} + +bool CPWL_EditImpl::InsertWord(uint16_t word, + int32_t charset, + const CPVT_WordProps* pWordProps, + bool bAddUndo, + bool bPaint) { + if (IsTextOverflow() || !m_pVT->IsValid()) + return false; + + m_pVT->UpdateWordPlace(m_wpCaret); + SetCaret(m_pVT->InsertWord(m_wpCaret, word, + GetCharSetFromUnicode(word, charset), pWordProps)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (m_wpCaret == m_wpOldCaret) + return false; + + if (bAddUndo && m_bEnableUndo) { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertWord>( + this, m_wpOldCaret, m_wpCaret, word, charset, pWordProps)); + } + if (bPaint) + PaintInsertText(m_wpOldCaret, m_wpCaret); + + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnInsertWord(m_wpCaret, m_wpOldCaret); + + return true; +} + +bool CPWL_EditImpl::InsertReturn(const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps, + bool bAddUndo, + bool bPaint) { + if (IsTextOverflow() || !m_pVT->IsValid()) + return false; + + m_pVT->UpdateWordPlace(m_wpCaret); + SetCaret(m_pVT->InsertSection(m_wpCaret, pSecProps, pWordProps)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (m_wpCaret == m_wpOldCaret) + return false; + + if (bAddUndo && m_bEnableUndo) { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertReturn>( + this, m_wpOldCaret, m_wpCaret, pSecProps, pWordProps)); + } + if (bPaint) { + RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret)); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret); + + return true; +} + +bool CPWL_EditImpl::Backspace(bool bAddUndo, bool bPaint) { + if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace()) + return false; + + CPVT_Section section; + CPVT_Word word; + if (bAddUndo) { + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(m_wpCaret); + pIterator->GetSection(section); + pIterator->GetWord(word); + } + m_pVT->UpdateWordPlace(m_wpCaret); + SetCaret(m_pVT->BackSpaceWord(m_wpCaret)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (m_wpCaret == m_wpOldCaret) + return false; + + if (bAddUndo && m_bEnableUndo) { + if (m_wpCaret.nSecIndex != m_wpOldCaret.nSecIndex) { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>( + this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, + section.SecProps, section.WordProps)); + } else { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>( + this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, + section.SecProps, word.WordProps)); + } + } + if (bPaint) { + RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret)); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnBackSpace(m_wpCaret, m_wpOldCaret); + + return true; +} + +bool CPWL_EditImpl::Delete(bool bAddUndo, bool bPaint) { + if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace()) + return false; + + CPVT_Section section; + CPVT_Word word; + if (bAddUndo) { + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret)); + pIterator->GetSection(section); + pIterator->GetWord(word); + } + m_pVT->UpdateWordPlace(m_wpCaret); + bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret)); + SetCaret(m_pVT->DeleteWord(m_wpCaret)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (bAddUndo && m_bEnableUndo) { + if (bSecEnd) { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>( + this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, + section.SecProps, section.WordProps, bSecEnd)); + } else { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>( + this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, + section.SecProps, word.WordProps, bSecEnd)); + } + } + if (bPaint) { + RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret)); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnDelete(m_wpCaret, m_wpOldCaret); + + return true; +} + +bool CPWL_EditImpl::Empty() { + if (m_pVT->IsValid()) { + m_pVT->DeleteWords(GetWholeWordRange()); + SetCaret(m_pVT->GetBeginWordPlace()); + + return true; + } + + return false; +} + +bool CPWL_EditImpl::Clear(bool bAddUndo, bool bPaint) { + if (!m_pVT->IsValid() || m_SelState.IsEmpty()) + return false; + + CPVT_WordRange range = m_SelState.ConvertToWordRange(); + if (bAddUndo && m_bEnableUndo) { + AddEditUndoItem( + pdfium::MakeUnique<CFXEU_Clear>(this, range, GetSelectedText())); + } + + SelectNone(); + SetCaret(m_pVT->DeleteWords(range)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (bPaint) { + RearrangePart(range); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnClear(m_wpCaret, m_wpOldCaret); + + return true; +} + +bool CPWL_EditImpl::InsertText(const CFX_WideString& sText, + int32_t charset, + bool bAddUndo, + bool bPaint) { + if (IsTextOverflow()) + return false; + + m_pVT->UpdateWordPlace(m_wpCaret); + SetCaret(DoInsertText(m_wpCaret, sText, charset)); + m_SelState.Set(m_wpCaret, m_wpCaret); + if (m_wpCaret == m_wpOldCaret) + return false; + + if (bAddUndo && m_bEnableUndo) { + AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>( + this, m_wpOldCaret, m_wpCaret, sText, charset)); + } + if (bPaint) + PaintInsertText(m_wpOldCaret, m_wpCaret); + + if (m_bOprNotify && m_pOprNotify) + m_pOprNotify->OnInsertText(m_wpCaret, m_wpOldCaret); + + return true; +} + +void CPWL_EditImpl::PaintInsertText(const CPVT_WordPlace& wpOld, + const CPVT_WordPlace& wpNew) { + if (m_pVT->IsValid()) { + RearrangePart(CPVT_WordRange(wpOld, wpNew)); + ScrollToCaret(); + Refresh(); + SetCaretOrigin(); + SetCaretInfo(); + } +} + +bool CPWL_EditImpl::Redo() { + if (m_bEnableUndo) { + if (m_Undo.CanRedo()) { + m_Undo.Redo(); + return true; + } + } + + return false; +} + +bool CPWL_EditImpl::Undo() { + if (m_bEnableUndo) { + if (m_Undo.CanUndo()) { + m_Undo.Undo(); + return true; + } + } + + return false; +} + +void CPWL_EditImpl::SetCaretOrigin() { + if (!m_pVT->IsValid()) + return; + + CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator(); + pIterator->SetAt(m_wpCaret); + CPVT_Word word; + CPVT_Line line; + if (pIterator->GetWord(word)) { + m_ptCaret.x = word.ptWord.x + word.fWidth; + m_ptCaret.y = word.ptWord.y; + } else if (pIterator->GetLine(line)) { + m_ptCaret.x = line.ptLine.x; + m_ptCaret.y = line.ptLine.y; + } +} + +CPVT_WordPlace CPWL_EditImpl::WordIndexToWordPlace(int32_t index) const { + if (m_pVT->IsValid()) + return m_pVT->WordIndexToWordPlace(index); + + return CPVT_WordPlace(); +} + +bool CPWL_EditImpl::IsTextFull() const { + int32_t nTotalWords = m_pVT->GetTotalWords(); + int32_t nLimitChar = m_pVT->GetLimitChar(); + int32_t nCharArray = m_pVT->GetCharArray(); + + return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) || + (nCharArray > 0 && nTotalWords >= nCharArray); +} + +bool CPWL_EditImpl::IsTextOverflow() const { + if (!m_bEnableScroll && !m_bEnableOverflow) { + CFX_FloatRect rcPlate = m_pVT->GetPlateRect(); + CFX_FloatRect rcContent = m_pVT->GetContentRect(); + + if (m_pVT->IsMultiLine() && GetTotalLines() > 1 && + IsFloatBigger(rcContent.Height(), rcPlate.Height())) { + return true; + } + + if (IsFloatBigger(rcContent.Width(), rcPlate.Width())) + return true; + } + + return false; +} + +bool CPWL_EditImpl::CanUndo() const { + if (m_bEnableUndo) { + return m_Undo.CanUndo(); + } + + return false; +} + +bool CPWL_EditImpl::CanRedo() const { + if (m_bEnableUndo) { + return m_Undo.CanRedo(); + } + + return false; +} + +void CPWL_EditImpl::EnableRefresh(bool bRefresh) { + m_bEnableRefresh = bRefresh; +} + +void CPWL_EditImpl::EnableUndo(bool bUndo) { + m_bEnableUndo = bUndo; +} + +void CPWL_EditImpl::EnableOprNotify(bool bNotify) { + m_bOprNotify = bNotify; +} + +CPVT_WordPlace CPWL_EditImpl::DoInsertText(const CPVT_WordPlace& place, + const CFX_WideString& sText, + int32_t charset) { + CPVT_WordPlace wp = place; + + if (m_pVT->IsValid()) { + for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) { + uint16_t word = sText[i]; + switch (word) { + case 0x0D: + wp = m_pVT->InsertSection(wp, nullptr, nullptr); + if (sText[i + 1] == 0x0A) + i++; + break; + case 0x0A: + wp = m_pVT->InsertSection(wp, nullptr, nullptr); + if (sText[i + 1] == 0x0D) + i++; + break; + case 0x09: + word = 0x20; + default: + wp = m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset), + nullptr); + break; + } + } + } + + return wp; +} + +int32_t CPWL_EditImpl::GetCharSetFromUnicode(uint16_t word, + int32_t nOldCharset) { + if (IPVT_FontMap* pFontMap = GetFontMap()) + return pFontMap->CharSetFromUnicode(word, nOldCharset); + return nOldCharset; +} + +void CPWL_EditImpl::AddEditUndoItem( + std::unique_ptr<CPWL_EditImpl_UndoItem> pEditUndoItem) { + m_Undo.AddItem(std::move(pEditUndoItem)); +} + +CFX_ByteString CPWL_EditImpl::GetPDFWordString(int32_t nFontIndex, + uint16_t Word, + uint16_t SubWord) { + IPVT_FontMap* pFontMap = GetFontMap(); + CPDF_Font* pPDFFont = pFontMap->GetPDFFont(nFontIndex); + if (!pPDFFont) + return CFX_ByteString(); + + CFX_ByteString sWord; + if (SubWord > 0) { + Word = SubWord; + } else { + uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible() + ? pPDFFont->CharCodeFromUnicode(Word) + : pFontMap->CharCodeFromUnicode(nFontIndex, Word); + if (dwCharCode > 0) { + pPDFFont->AppendChar(&sWord, dwCharCode); + return sWord; + } + } + pPDFFont->AppendChar(&sWord, Word); + return sWord; +} + +CPWL_EditImpl_LineRectArray::CPWL_EditImpl_LineRectArray() {} + +CPWL_EditImpl_LineRectArray::~CPWL_EditImpl_LineRectArray() {} + +void CPWL_EditImpl_LineRectArray::operator=( + CPWL_EditImpl_LineRectArray&& that) { + m_LineRects = std::move(that.m_LineRects); +} + +void CPWL_EditImpl_LineRectArray::Add(const CPVT_WordRange& wrLine, + const CFX_FloatRect& rcLine) { + m_LineRects.push_back( + pdfium::MakeUnique<CPWL_EditImpl_LineRect>(wrLine, rcLine)); +} + +int32_t CPWL_EditImpl_LineRectArray::GetSize() const { + return pdfium::CollectionSize<int32_t>(m_LineRects); +} + +CPWL_EditImpl_LineRect* CPWL_EditImpl_LineRectArray::GetAt( + int32_t nIndex) const { + if (nIndex < 0 || nIndex >= GetSize()) + return nullptr; + + return m_LineRects[nIndex].get(); +} + +CPWL_EditImpl_Select::CPWL_EditImpl_Select() {} + +CPWL_EditImpl_Select::CPWL_EditImpl_Select(const CPVT_WordRange& range) { + Set(range.BeginPos, range.EndPos); +} + +CPVT_WordRange CPWL_EditImpl_Select::ConvertToWordRange() const { + return CPVT_WordRange(BeginPos, EndPos); +} + +void CPWL_EditImpl_Select::Reset() { + BeginPos.Reset(); + EndPos.Reset(); +} + +void CPWL_EditImpl_Select::Set(const CPVT_WordPlace& begin, + const CPVT_WordPlace& end) { + BeginPos = begin; + EndPos = end; +} + +void CPWL_EditImpl_Select::SetEndPos(const CPVT_WordPlace& end) { + EndPos = end; +} + +bool CPWL_EditImpl_Select::IsEmpty() const { + return BeginPos == EndPos; +} + +CPWL_EditImpl_RectArray::CPWL_EditImpl_RectArray() {} + +CPWL_EditImpl_RectArray::~CPWL_EditImpl_RectArray() {} + +void CPWL_EditImpl_RectArray::Clear() { + m_Rects.clear(); +} + +void CPWL_EditImpl_RectArray::Add(const CFX_FloatRect& rect) { + // check for overlapped area + for (const auto& pRect : m_Rects) { + if (pRect && pRect->Contains(rect)) + return; + } + m_Rects.push_back(pdfium::MakeUnique<CFX_FloatRect>(rect)); +} + +int32_t CPWL_EditImpl_RectArray::GetSize() const { + return pdfium::CollectionSize<int32_t>(m_Rects); +} + +CFX_FloatRect* CPWL_EditImpl_RectArray::GetAt(int32_t nIndex) const { + if (nIndex < 0 || nIndex >= GetSize()) + return nullptr; + + return m_Rects[nIndex].get(); +} diff --git a/fpdfsdk/pdfwindow/cpwl_edit_impl.h b/fpdfsdk/pdfwindow/cpwl_edit_impl.h new file mode 100644 index 0000000000..53ed8da0c2 --- /dev/null +++ b/fpdfsdk/pdfwindow/cpwl_edit_impl.h @@ -0,0 +1,515 @@ +// 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 FPDFSDK_PDFWINDOW_CPWL_EDIT_IMPL_H_ +#define FPDFSDK_PDFWINDOW_CPWL_EDIT_IMPL_H_ + +#include <deque> +#include <memory> +#include <vector> + +#include "core/fpdfdoc/cpvt_secprops.h" +#include "core/fpdfdoc/cpvt_wordprops.h" +#include "core/fxcrt/cfx_unowned_ptr.h" + +#define FX_EDIT_ISLATINWORD(u) \ + (u == 0x2D || (u <= 0x005A && u >= 0x0041) || \ + (u <= 0x007A && u >= 0x0061) || (u <= 0x02AF && u >= 0x00C0)) + +class CFFL_FormFiller; +class CPWL_EditImpl; +class CPWL_EditImpl_Iterator; +class CPWL_EditImpl_Provider; +class CFX_RenderDevice; +class CFX_SystemHandler; +class CPWL_Edit; +class CPWL_EditCtrl; +class IFX_Edit_UndoItem; + +struct CPWL_EditImpl_LineRect { + CPWL_EditImpl_LineRect(const CPVT_WordRange& wrLine, + const CFX_FloatRect& rcLine) + : m_wrLine(wrLine), m_rcLine(rcLine) {} + + CPVT_WordRange m_wrLine; + CFX_FloatRect m_rcLine; +}; + +class CPWL_EditImpl_LineRectArray { + public: + CPWL_EditImpl_LineRectArray(); + ~CPWL_EditImpl_LineRectArray(); + + void operator=(CPWL_EditImpl_LineRectArray&& rects); + void Add(const CPVT_WordRange& wrLine, const CFX_FloatRect& rcLine); + + int32_t GetSize() const; + CPWL_EditImpl_LineRect* GetAt(int32_t nIndex) const; + + private: + std::vector<std::unique_ptr<CPWL_EditImpl_LineRect>> m_LineRects; +}; + +class CPWL_EditImpl_RectArray { + public: + CPWL_EditImpl_RectArray(); + ~CPWL_EditImpl_RectArray(); + + void Clear(); + void Add(const CFX_FloatRect& rect); + + int32_t GetSize() const; + CFX_FloatRect* GetAt(int32_t nIndex) const; + + private: + std::vector<std::unique_ptr<CFX_FloatRect>> m_Rects; +}; + +class CPWL_EditImpl_Refresh { + public: + CPWL_EditImpl_Refresh(); + ~CPWL_EditImpl_Refresh(); + + void BeginRefresh(); + void Push(const CPVT_WordRange& linerange, const CFX_FloatRect& rect); + void NoAnalyse(); + const CPWL_EditImpl_RectArray* GetRefreshRects() const; + void EndRefresh(); + + private: + CPWL_EditImpl_LineRectArray m_NewLineRects; + CPWL_EditImpl_LineRectArray m_OldLineRects; + CPWL_EditImpl_RectArray m_RefreshRects; +}; + +class CPWL_EditImpl_Select { + public: + CPWL_EditImpl_Select(); + explicit CPWL_EditImpl_Select(const CPVT_WordRange& range); + + void Reset(); + void Set(const CPVT_WordPlace& begin, const CPVT_WordPlace& end); + void SetEndPos(const CPVT_WordPlace& end); + + CPVT_WordRange ConvertToWordRange() const; + bool IsEmpty() const; + + CPVT_WordPlace BeginPos; + CPVT_WordPlace EndPos; +}; + +class CPWL_EditImpl_Undo { + public: + explicit CPWL_EditImpl_Undo(int32_t nBufsize); + ~CPWL_EditImpl_Undo(); + + void AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem); + void Undo(); + void Redo(); + bool CanUndo() const; + bool CanRedo() const; + void Reset(); + + private: + void RemoveHeads(); + void RemoveTails(); + + std::deque<std::unique_ptr<IFX_Edit_UndoItem>> m_UndoItemStack; + size_t m_nCurUndoPos; + size_t m_nBufSize; + bool m_bWorking; +}; + +class IFX_Edit_UndoItem { + public: + virtual ~IFX_Edit_UndoItem() {} + + virtual void Undo() = 0; + virtual void Redo() = 0; + virtual CFX_WideString GetUndoTitle() const = 0; +}; + +class CPWL_EditImpl_UndoItem : public IFX_Edit_UndoItem { + public: + CPWL_EditImpl_UndoItem(); + ~CPWL_EditImpl_UndoItem() override; + + CFX_WideString GetUndoTitle() const override; + + void SetFirst(bool bFirst); + void SetLast(bool bLast); + bool IsLast(); + + private: + bool m_bFirst; + bool m_bLast; +}; + +class CFXEU_InsertWord : public CPWL_EditImpl_UndoItem { + public: + CFXEU_InsertWord(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_WordProps* pWordProps); + ~CFXEU_InsertWord() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordPlace m_wpOld; + CPVT_WordPlace m_wpNew; + uint16_t m_Word; + int32_t m_nCharset; + CPVT_WordProps m_WordProps; +}; + +class CFXEU_InsertReturn : public CPWL_EditImpl_UndoItem { + public: + CFXEU_InsertReturn(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps); + ~CFXEU_InsertReturn() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordPlace m_wpOld; + CPVT_WordPlace m_wpNew; + CPVT_SecProps m_SecProps; + CPVT_WordProps m_WordProps; +}; + +class CFXEU_Backspace : public CPWL_EditImpl_UndoItem { + public: + CFXEU_Backspace(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_SecProps& SecProps, + const CPVT_WordProps& WordProps); + ~CFXEU_Backspace() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordPlace m_wpOld; + CPVT_WordPlace m_wpNew; + uint16_t m_Word; + int32_t m_nCharset; + CPVT_SecProps m_SecProps; + CPVT_WordProps m_WordProps; +}; + +class CFXEU_Delete : public CPWL_EditImpl_UndoItem { + public: + CFXEU_Delete(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + uint16_t word, + int32_t charset, + const CPVT_SecProps& SecProps, + const CPVT_WordProps& WordProps, + bool bSecEnd); + ~CFXEU_Delete() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordPlace m_wpOld; + CPVT_WordPlace m_wpNew; + uint16_t m_Word; + int32_t m_nCharset; + CPVT_SecProps m_SecProps; + CPVT_WordProps m_WordProps; + bool m_bSecEnd; +}; + +class CFXEU_Clear : public CPWL_EditImpl_UndoItem { + public: + CFXEU_Clear(CPWL_EditImpl* pEdit, + const CPVT_WordRange& wrSel, + const CFX_WideString& swText); + ~CFXEU_Clear() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordRange m_wrSel; + CFX_WideString m_swText; +}; + +class CFXEU_InsertText : public CPWL_EditImpl_UndoItem { + public: + CFXEU_InsertText(CPWL_EditImpl* pEdit, + const CPVT_WordPlace& wpOldPlace, + const CPVT_WordPlace& wpNewPlace, + const CFX_WideString& swText, + int32_t charset); + ~CFXEU_InsertText() override; + + // CPWL_EditImpl_UndoItem + void Redo() override; + void Undo() override; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + + CPVT_WordPlace m_wpOld; + CPVT_WordPlace m_wpNew; + CFX_WideString m_swText; + int32_t m_nCharset; +}; + +class CPWL_EditImpl { + public: + static void DrawEdit(CFX_RenderDevice* pDevice, + CFX_Matrix* pUser2Device, + CPWL_EditImpl* pEdit, + FX_COLORREF crTextFill, + const CFX_FloatRect& rcClip, + const CFX_PointF& ptOffset, + const CPVT_WordRange* pRange, + CFX_SystemHandler* pSystemHandler, + CFFL_FormFiller* pFFLData); + + CPWL_EditImpl(); + ~CPWL_EditImpl(); + + void SetFontMap(IPVT_FontMap* pFontMap); + void SetNotify(CPWL_EditCtrl* pNotify); + void SetOprNotify(CPWL_Edit* pOprNotify); + + // Returns an iterator for the contents. Should not be released. + CPWL_EditImpl_Iterator* GetIterator(); + IPVT_FontMap* GetFontMap(); + void Initialize(); + + // Set the bounding box of the text area. + void SetPlateRect(const CFX_FloatRect& rect); + void SetScrollPos(const CFX_PointF& point); + + // Set the horizontal text alignment. (nFormat [0:left, 1:middle, 2:right]) + void SetAlignmentH(int32_t nFormat, bool bPaint); + // Set the vertical text alignment. (nFormat [0:left, 1:middle, 2:right]) + void SetAlignmentV(int32_t nFormat, bool bPaint); + + // Set the substitution character for hidden text. + void SetPasswordChar(uint16_t wSubWord, bool bPaint); + + // Set the maximum number of words in the text. + void SetLimitChar(int32_t nLimitChar); + void SetCharArray(int32_t nCharArray); + void SetCharSpace(float fCharSpace); + void SetMultiLine(bool bMultiLine, bool bPaint); + void SetAutoReturn(bool bAuto, bool bPaint); + void SetAutoFontSize(bool bAuto, bool bPaint); + void SetAutoScroll(bool bAuto, bool bPaint); + void SetFontSize(float fFontSize); + void SetTextOverflow(bool bAllowed, bool bPaint); + void OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl); + void OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl); + void OnVK_UP(bool bShift, bool bCtrl); + void OnVK_DOWN(bool bShift, bool bCtrl); + void OnVK_LEFT(bool bShift, bool bCtrl); + void OnVK_RIGHT(bool bShift, bool bCtrl); + void OnVK_HOME(bool bShift, bool bCtrl); + void OnVK_END(bool bShift, bool bCtrl); + void SetText(const CFX_WideString& sText); + bool InsertWord(uint16_t word, int32_t charset); + bool InsertReturn(); + bool Backspace(); + bool Delete(); + bool ClearSelection(); + bool InsertText(const CFX_WideString& sText, int32_t charset); + bool Redo(); + bool Undo(); + CPVT_WordPlace WordIndexToWordPlace(int32_t index) const; + CPVT_WordPlace SearchWordPlace(const CFX_PointF& point) const; + int32_t GetCaret() const; + CPVT_WordPlace GetCaretWordPlace() const; + CFX_WideString GetSelectedText() const; + CFX_WideString GetText() const; + float GetFontSize() const; + uint16_t GetPasswordChar() const; + CFX_PointF GetScrollPos() const; + int32_t GetCharArray() const; + CFX_FloatRect GetContentRect() const; + CFX_WideString GetRangeText(const CPVT_WordRange& range) const; + int32_t GetHorzScale() const; + float GetCharSpace() const; + void SetSelection(int32_t nStartChar, int32_t nEndChar); + void GetSelection(int32_t& nStartChar, int32_t& nEndChar) const; + void SelectAll(); + void SelectNone(); + bool IsSelected() const; + void Paint(); + void EnableRefresh(bool bRefresh); + void RefreshWordRange(const CPVT_WordRange& wr); + CPVT_WordRange GetWholeWordRange() const; + CPVT_WordRange GetSelectWordRange() const; + void EnableUndo(bool bUndo); + void EnableOprNotify(bool bNotify); + bool IsTextFull() const; + bool IsTextOverflow() const; + bool CanUndo() const; + bool CanRedo() const; + CPVT_WordRange GetVisibleWordRange() const; + + bool Empty(); + + CPVT_WordPlace DoInsertText(const CPVT_WordPlace& place, + const CFX_WideString& sText, + int32_t charset); + int32_t GetCharSetFromUnicode(uint16_t word, int32_t nOldCharset); + + int32_t GetTotalLines() const; + + CFX_ByteString GetPDFWordString(int32_t nFontIndex, + uint16_t Word, + uint16_t SubWord); + + private: + friend class CPWL_EditImpl_Iterator; + friend class CFXEU_InsertWord; + friend class CFXEU_InsertReturn; + friend class CFXEU_Backspace; + friend class CFXEU_Delete; + friend class CFXEU_Clear; + friend class CFXEU_InsertText; + + void SetSelection(const CPVT_WordPlace& begin, const CPVT_WordPlace& end); + + void RearrangeAll(); + void RearrangePart(const CPVT_WordRange& range); + void ScrollToCaret(); + void SetScrollInfo(); + void SetScrollPosX(float fx); + void SetScrollPosY(float fy); + void SetScrollLimit(); + void SetContentChanged(); + + bool InsertWord(uint16_t word, + int32_t charset, + const CPVT_WordProps* pWordProps, + bool bAddUndo, + bool bPaint); + bool InsertReturn(const CPVT_SecProps* pSecProps, + const CPVT_WordProps* pWordProps, + bool bAddUndo, + bool bPaint); + bool Backspace(bool bAddUndo, bool bPaint); + bool Delete(bool bAddUndo, bool bPaint); + bool Clear(bool bAddUndo, bool bPaint); + bool InsertText(const CFX_WideString& sText, + int32_t charset, + bool bAddUndo, + bool bPaint); + void PaintInsertText(const CPVT_WordPlace& wpOld, + const CPVT_WordPlace& wpNew); + + inline CFX_PointF VTToEdit(const CFX_PointF& point) const; + inline CFX_PointF EditToVT(const CFX_PointF& point) const; + inline CFX_FloatRect VTToEdit(const CFX_FloatRect& rect) const; + + void Refresh(); + void RefreshPushLineRects(const CPVT_WordRange& wr); + + void SetCaret(const CPVT_WordPlace& place); + void SetCaretInfo(); + void SetCaretOrigin(); + + void AddEditUndoItem(std::unique_ptr<CPWL_EditImpl_UndoItem> pEditUndoItem); + + private: + std::unique_ptr<CPDF_VariableText> m_pVT; + CFX_UnownedPtr<CPWL_EditCtrl> m_pNotify; + CFX_UnownedPtr<CPWL_Edit> m_pOprNotify; + std::unique_ptr<CPWL_EditImpl_Provider> m_pVTProvider; + CPVT_WordPlace m_wpCaret; + CPVT_WordPlace m_wpOldCaret; + CPWL_EditImpl_Select m_SelState; + CFX_PointF m_ptScrollPos; + CFX_PointF m_ptRefreshScrollPos; + bool m_bEnableScroll; + std::unique_ptr<CPWL_EditImpl_Iterator> m_pIterator; + CPWL_EditImpl_Refresh m_Refresh; + CFX_PointF m_ptCaret; + CPWL_EditImpl_Undo m_Undo; + int32_t m_nAlignment; + bool m_bNotifyFlag; + bool m_bEnableOverflow; + bool m_bEnableRefresh; + CFX_FloatRect m_rcOldContent; + bool m_bEnableUndo; + bool m_bOprNotify; +}; + +class CPWL_EditImpl_Iterator { + public: + CPWL_EditImpl_Iterator(CPWL_EditImpl* pEdit, + CPDF_VariableText::Iterator* pVTIterator); + ~CPWL_EditImpl_Iterator(); + + bool NextWord(); + bool PrevWord(); + bool GetWord(CPVT_Word& word) const; + bool GetLine(CPVT_Line& line) const; + void SetAt(int32_t nWordIndex); + void SetAt(const CPVT_WordPlace& place); + const CPVT_WordPlace& GetAt() const; + + private: + CFX_UnownedPtr<CPWL_EditImpl> m_pEdit; + CPDF_VariableText::Iterator* m_pVTIterator; +}; + +class CPWL_EditImpl_Provider : public CPDF_VariableText::Provider { + public: + explicit CPWL_EditImpl_Provider(IPVT_FontMap* pFontMap); + ~CPWL_EditImpl_Provider() override; + + IPVT_FontMap* GetFontMap() const; + + // CPDF_VariableText::Provider: + int32_t GetCharWidth(int32_t nFontIndex, uint16_t word) override; + int32_t GetTypeAscent(int32_t nFontIndex) override; + int32_t GetTypeDescent(int32_t nFontIndex) override; + int32_t GetWordFontIndex(uint16_t word, + int32_t charset, + int32_t nFontIndex) override; + int32_t GetDefaultFontIndex() override; + bool IsLatinWord(uint16_t word) override; + + private: + IPVT_FontMap* m_pFontMap; +}; + +#endif // FPDFSDK_PDFWINDOW_CPWL_EDIT_IMPL_H_ diff --git a/fpdfsdk/pdfwindow/cpwl_list_box.cpp b/fpdfsdk/pdfwindow/cpwl_list_box.cpp index ffa5b4780f..7e820bfbfa 100644 --- a/fpdfsdk/pdfwindow/cpwl_list_box.cpp +++ b/fpdfsdk/pdfwindow/cpwl_list_box.cpp @@ -9,10 +9,10 @@ #include <sstream> #include "core/fxge/cfx_renderdevice.h" -#include "fpdfsdk/fxedit/fxet_edit.h" -#include "fpdfsdk/fxedit/fxet_list.h" #include "fpdfsdk/pdfwindow/cpwl_edit.h" #include "fpdfsdk/pdfwindow/cpwl_edit_ctrl.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_impl.h" +#include "fpdfsdk/pdfwindow/cpwl_list_impl.h" #include "fpdfsdk/pdfwindow/cpwl_scroll_bar.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" #include "public/fpdf_fwlevent.h" @@ -63,7 +63,7 @@ void CPWL_List_Notify::IOnInvalidateRect(CFX_FloatRect* pRect) { } CPWL_ListBox::CPWL_ListBox() - : m_pList(new CFX_ListCtrl), + : m_pList(new CPWL_ListCtrl), m_bMouseDown(false), m_bHoverSel(false), m_pFillerNotify(nullptr) {} @@ -107,7 +107,7 @@ void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice, continue; CFX_PointF ptOffset(rcItem.left, (rcItem.top + rcItem.bottom) * 0.5f); - if (CFX_Edit* pEdit = m_pList->GetItemEdit(i)) { + if (CPWL_EditImpl* pEdit = m_pList->GetItemEdit(i)) { CFX_FloatRect rcContent = pEdit->GetContentRect(); if (rcContent.Width() > rcClient.Width()) rcItem.Intersect(rcList); @@ -118,22 +118,23 @@ void CPWL_ListBox::DrawThisAppearance(CFX_RenderDevice* pDevice, if (m_pList->IsItemSelected(i)) { CFX_SystemHandler* pSysHandler = GetSystemHandler(); if (pSysHandler && pSysHandler->IsSelectionImplemented()) { - CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), - GetTextColor().ToFXColor(255), rcList, ptOffset, - nullptr, pSysHandler, m_pFormFiller.Get()); + CPWL_EditImpl::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), + GetTextColor().ToFXColor(255), rcList, ptOffset, + nullptr, pSysHandler, m_pFormFiller.Get()); pSysHandler->OutputSelectedRect(m_pFormFiller.Get(), rcItem); } else { pDevice->DrawFillRect(pUser2Device, rcItem, ArgbEncode(255, 0, 51, 113)); - CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), - ArgbEncode(255, 255, 255, 255), rcList, ptOffset, - nullptr, pSysHandler, m_pFormFiller.Get()); + CPWL_EditImpl::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), + ArgbEncode(255, 255, 255, 255), rcList, + ptOffset, nullptr, pSysHandler, + m_pFormFiller.Get()); } } else { CFX_SystemHandler* pSysHandler = GetSystemHandler(); - CFX_Edit::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), - GetTextColor().ToFXColor(255), rcList, ptOffset, - nullptr, pSysHandler, nullptr); + CPWL_EditImpl::DrawEdit(pDevice, pUser2Device, m_pList->GetItemEdit(i), + GetTextColor().ToFXColor(255), rcList, ptOffset, + nullptr, pSysHandler, nullptr); } } } diff --git a/fpdfsdk/pdfwindow/cpwl_list_box.h b/fpdfsdk/pdfwindow/cpwl_list_box.h index f41a6dd87f..d76c7a5c5a 100644 --- a/fpdfsdk/pdfwindow/cpwl_list_box.h +++ b/fpdfsdk/pdfwindow/cpwl_list_box.h @@ -12,7 +12,7 @@ #include "core/fxcrt/cfx_unowned_ptr.h" #include "fpdfsdk/pdfwindow/cpwl_wnd.h" -class CFX_ListCtrl; +class CPWL_ListCtrl; class CPWL_List_Notify; class CPWL_ListBox; class IPWL_Filler_Notify; @@ -97,7 +97,7 @@ class CPWL_ListBox : public CPWL_Wnd { void AttachFFLData(CFFL_FormFiller* pData) { m_pFormFiller = pData; } protected: - std::unique_ptr<CFX_ListCtrl> m_pList; + std::unique_ptr<CPWL_ListCtrl> m_pList; std::unique_ptr<CPWL_List_Notify> m_pListNotify; bool m_bMouseDown; bool m_bHoverSel; diff --git a/fpdfsdk/pdfwindow/cpwl_list_impl.cpp b/fpdfsdk/pdfwindow/cpwl_list_impl.cpp new file mode 100644 index 0000000000..66b2e77747 --- /dev/null +++ b/fpdfsdk/pdfwindow/cpwl_list_impl.cpp @@ -0,0 +1,637 @@ +// 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 "fpdfsdk/pdfwindow/cpwl_list_impl.h" + +#include <algorithm> +#include <utility> + +#include "core/fpdfdoc/cpvt_word.h" +#include "core/fxcrt/fx_extension.h" +#include "fpdfsdk/pdfwindow/cpwl_edit_impl.h" +#include "fpdfsdk/pdfwindow/cpwl_list_box.h" +#include "third_party/base/stl_util.h" + +CPWL_ListCtrl::Item::Item() + : m_pEdit(new CPWL_EditImpl), + m_bSelected(false), + m_rcListItem(0.0f, 0.0f, 0.0f, 0.0f) { + m_pEdit->SetAlignmentV(1, true); + m_pEdit->Initialize(); +} + +CPWL_ListCtrl::Item::~Item() {} + +void CPWL_ListCtrl::Item::SetFontMap(IPVT_FontMap* pFontMap) { + m_pEdit->SetFontMap(pFontMap); +} + +void CPWL_ListCtrl::Item::SetText(const CFX_WideString& text) { + m_pEdit->SetText(text); +} + +void CPWL_ListCtrl::Item::SetFontSize(float fFontSize) { + m_pEdit->SetFontSize(fFontSize); +} + +float CPWL_ListCtrl::Item::GetItemHeight() const { + return m_pEdit->GetContentRect().Height(); +} + +uint16_t CPWL_ListCtrl::Item::GetFirstChar() const { + CPVT_Word word; + CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); + pIterator->SetAt(1); + pIterator->GetWord(word); + return word.Word; +} + +CFX_WideString CPWL_ListCtrl::Item::GetText() const { + return m_pEdit->GetText(); +} + +CPLST_Select::CPLST_Select() {} + +CPLST_Select::~CPLST_Select() {} + +void CPLST_Select::Add(int32_t nItemIndex) { + m_Items[nItemIndex] = SELECTING; +} + +void CPLST_Select::Add(int32_t nBeginIndex, int32_t nEndIndex) { + if (nBeginIndex > nEndIndex) + std::swap(nBeginIndex, nEndIndex); + + for (int32_t i = nBeginIndex; i <= nEndIndex; ++i) + Add(i); +} + +void CPLST_Select::Sub(int32_t nItemIndex) { + auto it = m_Items.find(nItemIndex); + if (it != m_Items.end()) + it->second = DESELECTING; +} + +void CPLST_Select::Sub(int32_t nBeginIndex, int32_t nEndIndex) { + if (nBeginIndex > nEndIndex) + std::swap(nBeginIndex, nEndIndex); + + for (int32_t i = nBeginIndex; i <= nEndIndex; ++i) + Sub(i); +} + +void CPLST_Select::DeselectAll() { + for (auto& item : m_Items) + item.second = DESELECTING; +} + +void CPLST_Select::Done() { + auto it = m_Items.begin(); + while (it != m_Items.end()) { + if (it->second == DESELECTING) + it = m_Items.erase(it); + else + (it++)->second = NORMAL; + } +} + +CPWL_ListCtrl::CPWL_ListCtrl() + : m_pNotify(nullptr), + m_bNotifyFlag(false), + m_nSelItem(-1), + m_nFootIndex(-1), + m_bCtrlSel(false), + m_nCaretIndex(-1), + m_fFontSize(0.0f), + m_pFontMap(nullptr), + m_bMultiple(false) {} + +CPWL_ListCtrl::~CPWL_ListCtrl() { + Empty(); +} + +CFX_PointF CPWL_ListCtrl::InToOut(const CFX_PointF& point) const { + CFX_FloatRect rcPlate = m_rcPlate; + return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left), + point.y - (m_ptScrollPos.y - rcPlate.top)); +} + +CFX_PointF CPWL_ListCtrl::OutToIn(const CFX_PointF& point) const { + CFX_FloatRect rcPlate = m_rcPlate; + return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left), + point.y + (m_ptScrollPos.y - rcPlate.top)); +} + +CFX_FloatRect CPWL_ListCtrl::InToOut(const CFX_FloatRect& rect) const { + CFX_PointF ptLeftBottom = InToOut(CFX_PointF(rect.left, rect.bottom)); + CFX_PointF ptRightTop = InToOut(CFX_PointF(rect.right, rect.top)); + return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, + ptRightTop.y); +} + +CFX_FloatRect CPWL_ListCtrl::OutToIn(const CFX_FloatRect& rect) const { + CFX_PointF ptLeftBottom = OutToIn(CFX_PointF(rect.left, rect.bottom)); + CFX_PointF ptRightTop = OutToIn(CFX_PointF(rect.right, rect.top)); + return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, + ptRightTop.y); +} + +CFX_PointF CPWL_ListCtrl::InnerToOuter(const CFX_PointF& point) const { + return CFX_PointF(point.x + GetBTPoint().x, GetBTPoint().y - point.y); +} + +CFX_PointF CPWL_ListCtrl::OuterToInner(const CFX_PointF& point) const { + return CFX_PointF(point.x - GetBTPoint().x, GetBTPoint().y - point.y); +} + +CFX_FloatRect CPWL_ListCtrl::InnerToOuter(const CFX_FloatRect& rect) const { + CFX_PointF ptLeftTop = InnerToOuter(CFX_PointF(rect.left, rect.top)); + CFX_PointF ptRightBottom = InnerToOuter(CFX_PointF(rect.right, rect.bottom)); + return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x, + ptLeftTop.y); +} + +CFX_FloatRect CPWL_ListCtrl::OuterToInner(const CFX_FloatRect& rect) const { + CFX_PointF ptLeftTop = OuterToInner(CFX_PointF(rect.left, rect.top)); + CFX_PointF ptRightBottom = OuterToInner(CFX_PointF(rect.right, rect.bottom)); + return CFX_FloatRect(ptLeftTop.x, ptRightBottom.y, ptRightBottom.x, + ptLeftTop.y); +} + +void CPWL_ListCtrl::OnMouseDown(const CFX_PointF& point, + bool bShift, + bool bCtrl) { + int32_t nHitIndex = GetItemIndex(point); + + if (IsMultipleSel()) { + if (bCtrl) { + if (IsItemSelected(nHitIndex)) { + m_aSelItems.Sub(nHitIndex); + SelectItems(); + m_bCtrlSel = false; + } else { + m_aSelItems.Add(nHitIndex); + SelectItems(); + m_bCtrlSel = true; + } + + m_nFootIndex = nHitIndex; + } else if (bShift) { + m_aSelItems.DeselectAll(); + m_aSelItems.Add(m_nFootIndex, nHitIndex); + SelectItems(); + } else { + m_aSelItems.DeselectAll(); + m_aSelItems.Add(nHitIndex); + SelectItems(); + + m_nFootIndex = nHitIndex; + } + + SetCaret(nHitIndex); + } else { + SetSingleSelect(nHitIndex); + } + + if (!IsItemVisible(nHitIndex)) + ScrollToListItem(nHitIndex); +} + +void CPWL_ListCtrl::OnMouseMove(const CFX_PointF& point, + bool bShift, + bool bCtrl) { + int32_t nHitIndex = GetItemIndex(point); + + if (IsMultipleSel()) { + if (bCtrl) { + if (m_bCtrlSel) + m_aSelItems.Add(m_nFootIndex, nHitIndex); + else + m_aSelItems.Sub(m_nFootIndex, nHitIndex); + + SelectItems(); + } else { + m_aSelItems.DeselectAll(); + m_aSelItems.Add(m_nFootIndex, nHitIndex); + SelectItems(); + } + + SetCaret(nHitIndex); + } else { + SetSingleSelect(nHitIndex); + } + + if (!IsItemVisible(nHitIndex)) + ScrollToListItem(nHitIndex); +} + +void CPWL_ListCtrl::OnVK(int32_t nItemIndex, bool bShift, bool bCtrl) { + if (IsMultipleSel()) { + if (nItemIndex >= 0 && nItemIndex < GetCount()) { + if (bCtrl) { + } else if (bShift) { + m_aSelItems.DeselectAll(); + m_aSelItems.Add(m_nFootIndex, nItemIndex); + SelectItems(); + } else { + m_aSelItems.DeselectAll(); + m_aSelItems.Add(nItemIndex); + SelectItems(); + m_nFootIndex = nItemIndex; + } + + SetCaret(nItemIndex); + } + } else { + SetSingleSelect(nItemIndex); + } + + if (!IsItemVisible(nItemIndex)) + ScrollToListItem(nItemIndex); +} + +void CPWL_ListCtrl::OnVK_UP(bool bShift, bool bCtrl) { + OnVK(IsMultipleSel() ? GetCaret() - 1 : GetSelect() - 1, bShift, bCtrl); +} + +void CPWL_ListCtrl::OnVK_DOWN(bool bShift, bool bCtrl) { + OnVK(IsMultipleSel() ? GetCaret() + 1 : GetSelect() + 1, bShift, bCtrl); +} + +void CPWL_ListCtrl::OnVK_LEFT(bool bShift, bool bCtrl) { + OnVK(0, bShift, bCtrl); +} + +void CPWL_ListCtrl::OnVK_RIGHT(bool bShift, bool bCtrl) { + OnVK(GetCount() - 1, bShift, bCtrl); +} + +void CPWL_ListCtrl::OnVK_HOME(bool bShift, bool bCtrl) { + OnVK(0, bShift, bCtrl); +} + +void CPWL_ListCtrl::OnVK_END(bool bShift, bool bCtrl) { + OnVK(GetCount() - 1, bShift, bCtrl); +} + +bool CPWL_ListCtrl::OnChar(uint16_t nChar, bool bShift, bool bCtrl) { + int32_t nIndex = GetLastSelected(); + int32_t nFindIndex = FindNext(nIndex, nChar); + + if (nFindIndex != nIndex) { + OnVK(nFindIndex, bShift, bCtrl); + return true; + } + return false; +} + +void CPWL_ListCtrl::SetPlateRect(const CFX_FloatRect& rect) { + m_rcPlate = rect; + m_ptScrollPos.x = rect.left; + SetScrollPos(CFX_PointF(rect.left, rect.top)); + ReArrange(0); + InvalidateItem(-1); +} + +CFX_FloatRect CPWL_ListCtrl::GetItemRect(int32_t nIndex) const { + return InToOut(GetItemRectInternal(nIndex)); +} + +CFX_FloatRect CPWL_ListCtrl::GetItemRectInternal(int32_t nIndex) const { + if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex]) + return CFX_FloatRect(); + + CFX_FloatRect rcItem = m_ListItems[nIndex]->GetRect(); + rcItem.left = 0.0f; + rcItem.right = m_rcPlate.Width(); + return InnerToOuter(rcItem); +} + +void CPWL_ListCtrl::AddString(const CFX_WideString& str) { + AddItem(str); + ReArrange(GetCount() - 1); +} + +void CPWL_ListCtrl::SetMultipleSelect(int32_t nItemIndex, bool bSelected) { + if (!IsValid(nItemIndex)) + return; + + if (bSelected != IsItemSelected(nItemIndex)) { + if (bSelected) { + SetItemSelect(nItemIndex, true); + InvalidateItem(nItemIndex); + } else { + SetItemSelect(nItemIndex, false); + InvalidateItem(nItemIndex); + } + } +} + +void CPWL_ListCtrl::SetSingleSelect(int32_t nItemIndex) { + if (!IsValid(nItemIndex)) + return; + + if (m_nSelItem != nItemIndex) { + if (m_nSelItem >= 0) { + SetItemSelect(m_nSelItem, false); + InvalidateItem(m_nSelItem); + } + + SetItemSelect(nItemIndex, true); + InvalidateItem(nItemIndex); + m_nSelItem = nItemIndex; + } +} + +void CPWL_ListCtrl::SetCaret(int32_t nItemIndex) { + if (!IsValid(nItemIndex)) + return; + + if (IsMultipleSel()) { + int32_t nOldIndex = m_nCaretIndex; + + if (nOldIndex != nItemIndex) { + m_nCaretIndex = nItemIndex; + InvalidateItem(nOldIndex); + InvalidateItem(nItemIndex); + } + } +} + +void CPWL_ListCtrl::InvalidateItem(int32_t nItemIndex) { + if (m_pNotify) { + if (nItemIndex == -1) { + if (!m_bNotifyFlag) { + m_bNotifyFlag = true; + CFX_FloatRect rcRefresh = m_rcPlate; + m_pNotify->IOnInvalidateRect(&rcRefresh); + m_bNotifyFlag = false; + } + } else { + if (!m_bNotifyFlag) { + m_bNotifyFlag = true; + CFX_FloatRect rcRefresh = GetItemRect(nItemIndex); + rcRefresh.left -= 1.0f; + rcRefresh.right += 1.0f; + rcRefresh.bottom -= 1.0f; + rcRefresh.top += 1.0f; + + m_pNotify->IOnInvalidateRect(&rcRefresh); + m_bNotifyFlag = false; + } + } + } +} + +void CPWL_ListCtrl::SelectItems() { + for (const auto& item : m_aSelItems) { + if (item.second != CPLST_Select::NORMAL) + SetMultipleSelect(item.first, item.second == CPLST_Select::SELECTING); + } + m_aSelItems.Done(); +} + +void CPWL_ListCtrl::Select(int32_t nItemIndex) { + if (!IsValid(nItemIndex)) + return; + + if (IsMultipleSel()) { + m_aSelItems.Add(nItemIndex); + SelectItems(); + } else { + SetSingleSelect(nItemIndex); + } +} + +bool CPWL_ListCtrl::IsItemVisible(int32_t nItemIndex) const { + CFX_FloatRect rcPlate = m_rcPlate; + CFX_FloatRect rcItem = GetItemRect(nItemIndex); + + return rcItem.bottom >= rcPlate.bottom && rcItem.top <= rcPlate.top; +} + +void CPWL_ListCtrl::ScrollToListItem(int32_t nItemIndex) { + if (!IsValid(nItemIndex)) + return; + + CFX_FloatRect rcPlate = m_rcPlate; + CFX_FloatRect rcItem = GetItemRectInternal(nItemIndex); + CFX_FloatRect rcItemCtrl = GetItemRect(nItemIndex); + + if (IsFloatSmaller(rcItemCtrl.bottom, rcPlate.bottom)) { + if (IsFloatSmaller(rcItemCtrl.top, rcPlate.top)) { + SetScrollPosY(rcItem.bottom + rcPlate.Height()); + } + } else if (IsFloatBigger(rcItemCtrl.top, rcPlate.top)) { + if (IsFloatBigger(rcItemCtrl.bottom, rcPlate.bottom)) { + SetScrollPosY(rcItem.top); + } + } +} + +void CPWL_ListCtrl::SetScrollInfo() { + if (m_pNotify) { + CFX_FloatRect rcPlate = m_rcPlate; + CFX_FloatRect rcContent = GetContentRectInternal(); + + if (!m_bNotifyFlag) { + m_bNotifyFlag = true; + m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top, + rcContent.bottom, rcContent.top, + GetFirstHeight(), rcPlate.Height()); + m_bNotifyFlag = false; + } + } +} + +void CPWL_ListCtrl::SetScrollPos(const CFX_PointF& point) { + SetScrollPosY(point.y); +} + +void CPWL_ListCtrl::SetScrollPosY(float fy) { + if (!IsFloatEqual(m_ptScrollPos.y, fy)) { + CFX_FloatRect rcPlate = m_rcPlate; + CFX_FloatRect rcContent = GetContentRectInternal(); + + if (rcPlate.Height() > rcContent.Height()) { + fy = rcPlate.top; + } else { + if (IsFloatSmaller(fy - rcPlate.Height(), rcContent.bottom)) { + fy = rcContent.bottom + rcPlate.Height(); + } else if (IsFloatBigger(fy, rcContent.top)) { + fy = rcContent.top; + } + } + + m_ptScrollPos.y = fy; + InvalidateItem(-1); + + if (m_pNotify) { + if (!m_bNotifyFlag) { + m_bNotifyFlag = true; + m_pNotify->IOnSetScrollPosY(fy); + m_bNotifyFlag = false; + } + } + } +} + +CFX_FloatRect CPWL_ListCtrl::GetContentRectInternal() const { + return InnerToOuter(m_rcContent); +} + +CFX_FloatRect CPWL_ListCtrl::GetContentRect() const { + return InToOut(GetContentRectInternal()); +} + +void CPWL_ListCtrl::ReArrange(int32_t nItemIndex) { + float fPosY = 0.0f; + if (pdfium::IndexInBounds(m_ListItems, nItemIndex - 1) && + m_ListItems[nItemIndex - 1]) { + fPosY = m_ListItems[nItemIndex - 1]->GetRect().bottom; + } + for (const auto& pListItem : m_ListItems) { + if (pListItem) { + float fListItemHeight = pListItem->GetItemHeight(); + pListItem->SetRect( + CFX_FloatRect(0.0f, fPosY + fListItemHeight, 0.0f, fPosY)); + fPosY += fListItemHeight; + } + } + SetContentRect(CFX_FloatRect(0.0f, fPosY, 0.0f, 0.0f)); + SetScrollInfo(); +} + +void CPWL_ListCtrl::SetTopItem(int32_t nIndex) { + if (IsValid(nIndex)) { + CFX_FloatRect rcItem = GetItemRectInternal(nIndex); + SetScrollPosY(rcItem.top); + } +} + +int32_t CPWL_ListCtrl::GetTopItem() const { + int32_t nItemIndex = GetItemIndex(GetBTPoint()); + if (!IsItemVisible(nItemIndex) && IsItemVisible(nItemIndex + 1)) + nItemIndex += 1; + + return nItemIndex; +} + +void CPWL_ListCtrl::Empty() { + m_ListItems.clear(); + InvalidateItem(-1); +} + +void CPWL_ListCtrl::Cancel() { + m_aSelItems.DeselectAll(); +} + +int32_t CPWL_ListCtrl::GetItemIndex(const CFX_PointF& point) const { + CFX_PointF pt = OuterToInner(OutToIn(point)); + bool bFirst = true; + bool bLast = true; + for (const auto& pListItem : m_ListItems) { + if (!pListItem) + continue; + CFX_FloatRect rcListItem = pListItem->GetRect(); + if (IsFloatBigger(pt.y, rcListItem.top)) + bFirst = false; + if (IsFloatSmaller(pt.y, rcListItem.bottom)) + bLast = false; + if (pt.y >= rcListItem.top && pt.y < rcListItem.bottom) + return &pListItem - &m_ListItems.front(); + } + if (bFirst) + return 0; + if (bLast) + return pdfium::CollectionSize<int32_t>(m_ListItems) - 1; + return -1; +} + +CFX_WideString CPWL_ListCtrl::GetText() const { + if (IsMultipleSel()) + return GetItemText(m_nCaretIndex); + return GetItemText(m_nSelItem); +} + +void CPWL_ListCtrl::AddItem(const CFX_WideString& str) { + auto pListItem = pdfium::MakeUnique<Item>(); + pListItem->SetFontMap(m_pFontMap.Get()); + pListItem->SetFontSize(m_fFontSize); + pListItem->SetText(str); + m_ListItems.push_back(std::move(pListItem)); +} + +CPWL_EditImpl* CPWL_ListCtrl::GetItemEdit(int32_t nIndex) const { + if (!pdfium::IndexInBounds(m_ListItems, nIndex) || !m_ListItems[nIndex]) + return nullptr; + return m_ListItems[nIndex]->GetEdit(); +} + +int32_t CPWL_ListCtrl::GetCount() const { + return pdfium::CollectionSize<int32_t>(m_ListItems); +} + +float CPWL_ListCtrl::GetFirstHeight() const { + if (m_ListItems.empty() || !m_ListItems.front()) + return 1.0f; + return m_ListItems.front()->GetItemHeight(); +} + +int32_t CPWL_ListCtrl::GetFirstSelected() const { + int32_t i = 0; + for (const auto& pListItem : m_ListItems) { + if (pListItem && pListItem->IsSelected()) + return i; + ++i; + } + return -1; +} + +int32_t CPWL_ListCtrl::GetLastSelected() const { + for (auto iter = m_ListItems.rbegin(); iter != m_ListItems.rend(); ++iter) { + if (*iter && (*iter)->IsSelected()) + return &*iter - &m_ListItems.front(); + } + return -1; +} + +int32_t CPWL_ListCtrl::FindNext(int32_t nIndex, wchar_t nChar) const { + int32_t nCircleIndex = nIndex; + int32_t sz = pdfium::CollectionSize<int32_t>(m_ListItems); + for (int32_t i = 0; i < sz; i++) { + nCircleIndex++; + if (nCircleIndex >= sz) + nCircleIndex = 0; + + if (Item* pListItem = m_ListItems[nCircleIndex].get()) { + if (FXSYS_toupper(pListItem->GetFirstChar()) == FXSYS_toupper(nChar)) + return nCircleIndex; + } + } + + return nCircleIndex; +} + +bool CPWL_ListCtrl::IsItemSelected(int32_t nIndex) const { + return pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex] && + m_ListItems[nIndex]->IsSelected(); +} + +void CPWL_ListCtrl::SetItemSelect(int32_t nIndex, bool bSelected) { + if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex]) + m_ListItems[nIndex]->SetSelect(bSelected); +} + +bool CPWL_ListCtrl::IsValid(int32_t nItemIndex) const { + return pdfium::IndexInBounds(m_ListItems, nItemIndex); +} + +CFX_WideString CPWL_ListCtrl::GetItemText(int32_t nIndex) const { + if (pdfium::IndexInBounds(m_ListItems, nIndex) && m_ListItems[nIndex]) + return m_ListItems[nIndex]->GetText(); + return L""; +} diff --git a/fpdfsdk/pdfwindow/cpwl_list_impl.h b/fpdfsdk/pdfwindow/cpwl_list_impl.h new file mode 100644 index 0000000000..167def057e --- /dev/null +++ b/fpdfsdk/pdfwindow/cpwl_list_impl.h @@ -0,0 +1,168 @@ +// 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 FPDFSDK_PDFWINDOW_CPWL_LIST_IMPL_H_ +#define FPDFSDK_PDFWINDOW_CPWL_LIST_IMPL_H_ + +#include <map> +#include <memory> +#include <vector> + +#include "core/fxcrt/cfx_unowned_ptr.h" +#include "core/fxcrt/fx_coordinates.h" + +class CPWL_EditImpl; +class CPWL_EditImpl_Iterator; +class CPWL_List_Notify; +class IPVT_FontMap; + +class CPLST_Select { + public: + enum State { DESELECTING = -1, NORMAL = 0, SELECTING = 1 }; + using const_iterator = std::map<int32_t, State>::const_iterator; + + CPLST_Select(); + virtual ~CPLST_Select(); + + void Add(int32_t nItemIndex); + void Add(int32_t nBeginIndex, int32_t nEndIndex); + void Sub(int32_t nItemIndex); + void Sub(int32_t nBeginIndex, int32_t nEndIndex); + void DeselectAll(); + void Done(); + + const_iterator begin() const { return m_Items.begin(); } + const_iterator end() const { return m_Items.end(); } + + private: + std::map<int32_t, State> m_Items; +}; + +class CPWL_ListCtrl { + public: + CPWL_ListCtrl(); + ~CPWL_ListCtrl(); + + void SetNotify(CPWL_List_Notify* pNotify) { m_pNotify = pNotify; } + void OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl); + void OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl); + void OnVK_UP(bool bShift, bool bCtrl); + void OnVK_DOWN(bool bShift, bool bCtrl); + void OnVK_LEFT(bool bShift, bool bCtrl); + void OnVK_RIGHT(bool bShift, bool bCtrl); + void OnVK_HOME(bool bShift, bool bCtrl); + void OnVK_END(bool bShift, bool bCtrl); + bool OnChar(uint16_t nChar, bool bShift, bool bCtrl); + + void SetScrollPos(const CFX_PointF& point); + void ScrollToListItem(int32_t nItemIndex); + CFX_FloatRect GetItemRect(int32_t nIndex) const; + int32_t GetCaret() const { return m_nCaretIndex; } + int32_t GetSelect() const { return m_nSelItem; } + int32_t GetTopItem() const; + void SetContentRect(const CFX_FloatRect& rect) { m_rcContent = rect; } + CFX_FloatRect GetContentRect() const; + + int32_t GetItemIndex(const CFX_PointF& point) const; + void AddString(const CFX_WideString& str); + void SetTopItem(int32_t nIndex); + void Select(int32_t nItemIndex); + void SetCaret(int32_t nItemIndex); + void Empty(); + void Cancel(); + CFX_WideString GetText() const; + + void SetFontMap(IPVT_FontMap* pFontMap) { m_pFontMap = pFontMap; } + void SetFontSize(float fFontSize) { m_fFontSize = fFontSize; } + CFX_FloatRect GetPlateRect() const { return m_rcPlate; } + void SetPlateRect(const CFX_FloatRect& rect); + + float GetFontSize() const { return m_fFontSize; } + CPWL_EditImpl* GetItemEdit(int32_t nIndex) const; + int32_t GetCount() const; + bool IsItemSelected(int32_t nIndex) const; + float GetFirstHeight() const; + void SetMultipleSel(bool bMultiple) { m_bMultiple = bMultiple; } + bool IsMultipleSel() const { return m_bMultiple; } + int32_t FindNext(int32_t nIndex, wchar_t nChar) const; + int32_t GetFirstSelected() const; + + private: + class Item { + public: + Item(); + ~Item(); + + void SetFontMap(IPVT_FontMap* pFontMap); + CPWL_EditImpl* GetEdit() const { return m_pEdit.get(); } + + void SetRect(const CFX_FloatRect& rect) { m_rcListItem = rect; } + void SetSelect(bool bSelected) { m_bSelected = bSelected; } + void SetText(const CFX_WideString& text); + void SetFontSize(float fFontSize); + CFX_WideString GetText() const; + + CFX_FloatRect GetRect() const { return m_rcListItem; } + bool IsSelected() const { return m_bSelected; } + float GetItemHeight() const; + uint16_t GetFirstChar() const; + + private: + CPWL_EditImpl_Iterator* GetIterator() const; + + std::unique_ptr<CPWL_EditImpl> m_pEdit; + bool m_bSelected; + CFX_FloatRect m_rcListItem; + }; + + CFX_PointF InToOut(const CFX_PointF& point) const; + CFX_PointF OutToIn(const CFX_PointF& point) const; + CFX_FloatRect InToOut(const CFX_FloatRect& rect) const; + CFX_FloatRect OutToIn(const CFX_FloatRect& rect) const; + + CFX_PointF InnerToOuter(const CFX_PointF& point) const; + CFX_PointF OuterToInner(const CFX_PointF& point) const; + CFX_FloatRect InnerToOuter(const CFX_FloatRect& rect) const; + CFX_FloatRect OuterToInner(const CFX_FloatRect& rect) const; + + void OnVK(int32_t nItemIndex, bool bShift, bool bCtrl); + bool IsValid(int32_t nItemIndex) const; + + void ReArrange(int32_t nItemIndex); + CFX_FloatRect GetItemRectInternal(int32_t nIndex) const; + CFX_FloatRect GetContentRectInternal() const; + void SetMultipleSelect(int32_t nItemIndex, bool bSelected); + void SetSingleSelect(int32_t nItemIndex); + void InvalidateItem(int32_t nItemIndex); + void SelectItems(); + bool IsItemVisible(int32_t nItemIndex) const; + void SetScrollInfo(); + void SetScrollPosY(float fy); + void AddItem(const CFX_WideString& str); + CFX_WideString GetItemText(int32_t nIndex) const; + void SetItemSelect(int32_t nItemIndex, bool bSelected); + int32_t GetLastSelected() const; + CFX_PointF GetBTPoint() const { + return CFX_PointF(m_rcPlate.left, m_rcPlate.top); + } + + CFX_FloatRect m_rcPlate; + CFX_FloatRect m_rcContent; + CFX_UnownedPtr<CPWL_List_Notify> m_pNotify; + bool m_bNotifyFlag; + CFX_PointF m_ptScrollPos; + CPLST_Select m_aSelItems; // for multiple + int32_t m_nSelItem; // for single + int32_t m_nFootIndex; // for multiple + bool m_bCtrlSel; // for multiple + int32_t m_nCaretIndex; // for multiple + std::vector<std::unique_ptr<Item>> m_ListItems; + float m_fFontSize; + CFX_UnownedPtr<IPVT_FontMap> m_pFontMap; + bool m_bMultiple; +}; + +#endif // FPDFSDK_PDFWINDOW_CPWL_LIST_IMPL_H_ |