• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <sstream>
12 #include <utility>
13 
14 #include "core/fpdfapi/font/cpdf_font.h"
15 #include "core/fpdfapi/render/cpdf_renderoptions.h"
16 #include "core/fpdfapi/render/cpdf_textrenderer.h"
17 #include "core/fpdfdoc/cpvt_word.h"
18 #include "core/fpdfdoc/ipvt_fontmap.h"
19 #include "core/fxcrt/autorestorer.h"
20 #include "core/fxcrt/fx_codepage.h"
21 #include "core/fxge/cfx_graphstatedata.h"
22 #include "core/fxge/cfx_pathdata.h"
23 #include "core/fxge/cfx_renderdevice.h"
24 #include "fpdfsdk/pwl/cpwl_edit.h"
25 #include "fpdfsdk/pwl/cpwl_edit_ctrl.h"
26 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
27 #include "fpdfsdk/pwl/ipwl_systemhandler.h"
28 #include "third_party/base/compiler_specific.h"
29 #include "third_party/base/ptr_util.h"
30 
31 namespace {
32 
33 const int kEditUndoMaxItems = 10000;
34 
DrawTextString(CFX_RenderDevice * pDevice,const CFX_PointF & pt,CPDF_Font * pFont,float fFontSize,const CFX_Matrix & mtUser2Device,const ByteString & str,FX_ARGB crTextFill)35 void DrawTextString(CFX_RenderDevice* pDevice,
36                     const CFX_PointF& pt,
37                     CPDF_Font* pFont,
38                     float fFontSize,
39                     const CFX_Matrix& mtUser2Device,
40                     const ByteString& str,
41                     FX_ARGB crTextFill) {
42   if (!pFont)
43     return;
44 
45   CFX_PointF pos = mtUser2Device.Transform(pt);
46   CPDF_RenderOptions ro;
47   ASSERT(ro.GetOptions().bClearType);
48   ro.SetColorMode(CPDF_RenderOptions::kNormal);
49   CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
50                                     mtUser2Device, str, crTextFill, ro);
51 }
52 
53 }  // namespace
54 
CPWL_EditImpl_Iterator(CPWL_EditImpl * pEdit,CPDF_VariableText::Iterator * pVTIterator)55 CPWL_EditImpl_Iterator::CPWL_EditImpl_Iterator(
56     CPWL_EditImpl* pEdit,
57     CPDF_VariableText::Iterator* pVTIterator)
58     : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
59 
~CPWL_EditImpl_Iterator()60 CPWL_EditImpl_Iterator::~CPWL_EditImpl_Iterator() {}
61 
NextWord()62 bool CPWL_EditImpl_Iterator::NextWord() {
63   return m_pVTIterator->NextWord();
64 }
65 
PrevWord()66 bool CPWL_EditImpl_Iterator::PrevWord() {
67   return m_pVTIterator->PrevWord();
68 }
69 
GetWord(CPVT_Word & word) const70 bool CPWL_EditImpl_Iterator::GetWord(CPVT_Word& word) const {
71   ASSERT(m_pEdit);
72 
73   if (m_pVTIterator->GetWord(word)) {
74     word.ptWord = m_pEdit->VTToEdit(word.ptWord);
75     return true;
76   }
77   return false;
78 }
79 
GetLine(CPVT_Line & line) const80 bool CPWL_EditImpl_Iterator::GetLine(CPVT_Line& line) const {
81   ASSERT(m_pEdit);
82 
83   if (m_pVTIterator->GetLine(line)) {
84     line.ptLine = m_pEdit->VTToEdit(line.ptLine);
85     return true;
86   }
87   return false;
88 }
89 
SetAt(int32_t nWordIndex)90 void CPWL_EditImpl_Iterator::SetAt(int32_t nWordIndex) {
91   m_pVTIterator->SetAt(nWordIndex);
92 }
93 
SetAt(const CPVT_WordPlace & place)94 void CPWL_EditImpl_Iterator::SetAt(const CPVT_WordPlace& place) {
95   m_pVTIterator->SetAt(place);
96 }
97 
GetAt() const98 const CPVT_WordPlace& CPWL_EditImpl_Iterator::GetAt() const {
99   return m_pVTIterator->GetWordPlace();
100 }
101 
CPWL_EditImpl_Provider(IPVT_FontMap * pFontMap)102 CPWL_EditImpl_Provider::CPWL_EditImpl_Provider(IPVT_FontMap* pFontMap)
103     : CPDF_VariableText::Provider(pFontMap), m_pFontMap(pFontMap) {
104   ASSERT(m_pFontMap);
105 }
106 
~CPWL_EditImpl_Provider()107 CPWL_EditImpl_Provider::~CPWL_EditImpl_Provider() {}
108 
GetFontMap() const109 IPVT_FontMap* CPWL_EditImpl_Provider::GetFontMap() const {
110   return m_pFontMap;
111 }
112 
GetCharWidth(int32_t nFontIndex,uint16_t word)113 uint32_t CPWL_EditImpl_Provider::GetCharWidth(int32_t nFontIndex,
114                                               uint16_t word) {
115   RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
116   if (!pPDFFont)
117     return 0;
118 
119   uint32_t charcode = pPDFFont->IsUnicodeCompatible()
120                           ? pPDFFont->CharCodeFromUnicode(word)
121                           : m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
122 
123   if (charcode == CPDF_Font::kInvalidCharCode)
124     return 0;
125 
126   return pPDFFont->GetCharWidthF(charcode);
127 }
128 
GetTypeAscent(int32_t nFontIndex)129 int32_t CPWL_EditImpl_Provider::GetTypeAscent(int32_t nFontIndex) {
130   RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
131   return pPDFFont ? pPDFFont->GetTypeAscent() : 0;
132 }
133 
GetTypeDescent(int32_t nFontIndex)134 int32_t CPWL_EditImpl_Provider::GetTypeDescent(int32_t nFontIndex) {
135   RetainPtr<CPDF_Font> pPDFFont = m_pFontMap->GetPDFFont(nFontIndex);
136   return pPDFFont ? pPDFFont->GetTypeDescent() : 0;
137 }
138 
GetWordFontIndex(uint16_t word,int32_t charset,int32_t nFontIndex)139 int32_t CPWL_EditImpl_Provider::GetWordFontIndex(uint16_t word,
140                                                  int32_t charset,
141                                                  int32_t nFontIndex) {
142   return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex);
143 }
144 
GetDefaultFontIndex()145 int32_t CPWL_EditImpl_Provider::GetDefaultFontIndex() {
146   return 0;
147 }
148 
IsLatinWord(uint16_t word)149 bool CPWL_EditImpl_Provider::IsLatinWord(uint16_t word) {
150   return FX_EDIT_ISLATINWORD(word);
151 }
152 
CPWL_EditImpl_Refresh()153 CPWL_EditImpl_Refresh::CPWL_EditImpl_Refresh() {}
154 
~CPWL_EditImpl_Refresh()155 CPWL_EditImpl_Refresh::~CPWL_EditImpl_Refresh() {}
156 
BeginRefresh()157 void CPWL_EditImpl_Refresh::BeginRefresh() {
158   m_OldLineRects = std::move(m_NewLineRects);
159   m_NewLineRects.clear();
160   m_RefreshRects.clear();
161 }
162 
Push(const CPVT_WordRange & linerange,const CFX_FloatRect & rect)163 void CPWL_EditImpl_Refresh::Push(const CPVT_WordRange& linerange,
164                                  const CFX_FloatRect& rect) {
165   m_NewLineRects.emplace_back(CPWL_EditImpl_LineRect(linerange, rect));
166 }
167 
NoAnalyse()168 void CPWL_EditImpl_Refresh::NoAnalyse() {
169   for (const auto& lineRect : m_OldLineRects)
170     Add(lineRect.m_rcLine);
171 
172   for (const auto& lineRect : m_NewLineRects)
173     Add(lineRect.m_rcLine);
174 }
175 
GetRefreshRects()176 std::vector<CFX_FloatRect>* CPWL_EditImpl_Refresh::GetRefreshRects() {
177   return &m_RefreshRects;
178 }
179 
EndRefresh()180 void CPWL_EditImpl_Refresh::EndRefresh() {
181   m_RefreshRects.clear();
182 }
183 
Add(const CFX_FloatRect & new_rect)184 void CPWL_EditImpl_Refresh::Add(const CFX_FloatRect& new_rect) {
185   // Check for overlapped area.
186   for (const auto& rect : m_RefreshRects) {
187     if (rect.Contains(new_rect))
188       return;
189   }
190   m_RefreshRects.emplace_back(CFX_FloatRect(new_rect));
191 }
192 
CPWL_EditImpl_Undo()193 CPWL_EditImpl_Undo::CPWL_EditImpl_Undo()
194     : m_nCurUndoPos(0), m_bWorking(false) {}
195 
~CPWL_EditImpl_Undo()196 CPWL_EditImpl_Undo::~CPWL_EditImpl_Undo() {}
197 
CanUndo() const198 bool CPWL_EditImpl_Undo::CanUndo() const {
199   return m_nCurUndoPos > 0;
200 }
201 
Undo()202 void CPWL_EditImpl_Undo::Undo() {
203   ASSERT(!m_bWorking);
204   m_bWorking = true;
205   int nUndoRemain = 1;
206   while (CanUndo() && nUndoRemain > 0) {
207     nUndoRemain += m_UndoItemStack[m_nCurUndoPos - 1]->Undo();
208     m_nCurUndoPos--;
209     nUndoRemain--;
210   }
211   ASSERT(nUndoRemain == 0);
212   ASSERT(m_bWorking);
213   m_bWorking = false;
214 }
215 
CanRedo() const216 bool CPWL_EditImpl_Undo::CanRedo() const {
217   return m_nCurUndoPos < m_UndoItemStack.size();
218 }
219 
Redo()220 void CPWL_EditImpl_Undo::Redo() {
221   ASSERT(!m_bWorking);
222   m_bWorking = true;
223   int nRedoRemain = 1;
224   while (CanRedo() && nRedoRemain > 0) {
225     nRedoRemain += m_UndoItemStack[m_nCurUndoPos]->Redo();
226     m_nCurUndoPos++;
227     nRedoRemain--;
228   }
229   ASSERT(nRedoRemain == 0);
230   ASSERT(m_bWorking);
231   m_bWorking = false;
232 }
233 
AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem)234 void CPWL_EditImpl_Undo::AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem) {
235   ASSERT(!m_bWorking);
236   ASSERT(pItem);
237   if (CanRedo())
238     RemoveTails();
239 
240   if (m_UndoItemStack.size() >= kEditUndoMaxItems)
241     RemoveHeads();
242 
243   m_UndoItemStack.push_back(std::move(pItem));
244   m_nCurUndoPos = m_UndoItemStack.size();
245 }
246 
RemoveHeads()247 void CPWL_EditImpl_Undo::RemoveHeads() {
248   ASSERT(m_UndoItemStack.size() > 1);
249   m_UndoItemStack.pop_front();
250 }
251 
RemoveTails()252 void CPWL_EditImpl_Undo::RemoveTails() {
253   while (CanRedo())
254     m_UndoItemStack.pop_back();
255 }
256 
CFXEU_InsertWord(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,int32_t charset)257 CFXEU_InsertWord::CFXEU_InsertWord(CPWL_EditImpl* pEdit,
258                                    const CPVT_WordPlace& wpOldPlace,
259                                    const CPVT_WordPlace& wpNewPlace,
260                                    uint16_t word,
261                                    int32_t charset)
262     : m_pEdit(pEdit),
263       m_wpOld(wpOldPlace),
264       m_wpNew(wpNewPlace),
265       m_Word(word),
266       m_nCharset(charset) {
267   ASSERT(m_pEdit);
268 }
269 
~CFXEU_InsertWord()270 CFXEU_InsertWord::~CFXEU_InsertWord() {}
271 
Redo()272 int CFXEU_InsertWord::Redo() {
273   m_pEdit->SelectNone();
274   m_pEdit->SetCaret(m_wpOld);
275   m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
276   return 0;
277 }
278 
Undo()279 int CFXEU_InsertWord::Undo() {
280   m_pEdit->SelectNone();
281   m_pEdit->SetCaret(m_wpNew);
282   m_pEdit->Backspace(false, true);
283   return 0;
284 }
285 
CFXEU_InsertReturn(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace)286 CFXEU_InsertReturn::CFXEU_InsertReturn(CPWL_EditImpl* pEdit,
287                                        const CPVT_WordPlace& wpOldPlace,
288                                        const CPVT_WordPlace& wpNewPlace)
289     : m_pEdit(pEdit), m_wpOld(wpOldPlace), m_wpNew(wpNewPlace) {
290   ASSERT(m_pEdit);
291 }
292 
~CFXEU_InsertReturn()293 CFXEU_InsertReturn::~CFXEU_InsertReturn() {}
294 
Redo()295 int CFXEU_InsertReturn::Redo() {
296   m_pEdit->SelectNone();
297   m_pEdit->SetCaret(m_wpOld);
298   m_pEdit->InsertReturn(false, true);
299   return 0;
300 }
301 
Undo()302 int CFXEU_InsertReturn::Undo() {
303   m_pEdit->SelectNone();
304   m_pEdit->SetCaret(m_wpNew);
305   m_pEdit->Backspace(false, true);
306   return 0;
307 }
308 
CFXEU_ReplaceSelection(CPWL_EditImpl * pEdit,bool bIsEnd)309 CFXEU_ReplaceSelection::CFXEU_ReplaceSelection(CPWL_EditImpl* pEdit,
310                                                bool bIsEnd)
311     : m_pEdit(pEdit), m_bEnd(bIsEnd) {
312   ASSERT(m_pEdit);
313 }
314 
~CFXEU_ReplaceSelection()315 CFXEU_ReplaceSelection::~CFXEU_ReplaceSelection() {}
316 
Redo()317 int CFXEU_ReplaceSelection::Redo() {
318   m_pEdit->SelectNone();
319   if (IsEnd())
320     return 0;
321   // Redo ClearSelection, InsertText and ReplaceSelection's end marker
322   return 3;
323 }
324 
Undo()325 int CFXEU_ReplaceSelection::Undo() {
326   m_pEdit->SelectNone();
327   if (!IsEnd())
328     return 0;
329   // Undo InsertText, ClearSelection and ReplaceSelection's beginning
330   // marker
331   return 3;
332 }
333 
CFXEU_Backspace(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,int32_t charset)334 CFXEU_Backspace::CFXEU_Backspace(CPWL_EditImpl* pEdit,
335                                  const CPVT_WordPlace& wpOldPlace,
336                                  const CPVT_WordPlace& wpNewPlace,
337                                  uint16_t word,
338                                  int32_t charset)
339     : m_pEdit(pEdit),
340       m_wpOld(wpOldPlace),
341       m_wpNew(wpNewPlace),
342       m_Word(word),
343       m_nCharset(charset) {
344   ASSERT(m_pEdit);
345 }
346 
~CFXEU_Backspace()347 CFXEU_Backspace::~CFXEU_Backspace() {}
348 
Redo()349 int CFXEU_Backspace::Redo() {
350   m_pEdit->SelectNone();
351   m_pEdit->SetCaret(m_wpOld);
352   m_pEdit->Backspace(false, true);
353   return 0;
354 }
355 
Undo()356 int CFXEU_Backspace::Undo() {
357   m_pEdit->SelectNone();
358   m_pEdit->SetCaret(m_wpNew);
359   if (m_wpNew.nSecIndex != m_wpOld.nSecIndex)
360     m_pEdit->InsertReturn(false, true);
361   else
362     m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
363   return 0;
364 }
365 
CFXEU_Delete(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,int32_t charset,bool bSecEnd)366 CFXEU_Delete::CFXEU_Delete(CPWL_EditImpl* pEdit,
367                            const CPVT_WordPlace& wpOldPlace,
368                            const CPVT_WordPlace& wpNewPlace,
369                            uint16_t word,
370                            int32_t charset,
371                            bool bSecEnd)
372     : m_pEdit(pEdit),
373       m_wpOld(wpOldPlace),
374       m_wpNew(wpNewPlace),
375       m_Word(word),
376       m_nCharset(charset),
377       m_bSecEnd(bSecEnd) {
378   ASSERT(m_pEdit);
379 }
380 
~CFXEU_Delete()381 CFXEU_Delete::~CFXEU_Delete() {}
382 
Redo()383 int CFXEU_Delete::Redo() {
384   m_pEdit->SelectNone();
385   m_pEdit->SetCaret(m_wpOld);
386   m_pEdit->Delete(false, true);
387   return 0;
388 }
389 
Undo()390 int CFXEU_Delete::Undo() {
391   m_pEdit->SelectNone();
392   m_pEdit->SetCaret(m_wpNew);
393   if (m_bSecEnd)
394     m_pEdit->InsertReturn(false, true);
395   else
396     m_pEdit->InsertWord(m_Word, m_nCharset, false, true);
397   return 0;
398 }
399 
CFXEU_Clear(CPWL_EditImpl * pEdit,const CPVT_WordRange & wrSel,const WideString & swText)400 CFXEU_Clear::CFXEU_Clear(CPWL_EditImpl* pEdit,
401                          const CPVT_WordRange& wrSel,
402                          const WideString& swText)
403     : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {
404   ASSERT(m_pEdit);
405 }
406 
~CFXEU_Clear()407 CFXEU_Clear::~CFXEU_Clear() {}
408 
Redo()409 int CFXEU_Clear::Redo() {
410   m_pEdit->SelectNone();
411   m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
412   m_pEdit->Clear(false, true);
413   return 0;
414 }
415 
Undo()416 int CFXEU_Clear::Undo() {
417   m_pEdit->SelectNone();
418   m_pEdit->SetCaret(m_wrSel.BeginPos);
419   m_pEdit->InsertText(m_swText, FX_CHARSET_Default, false, true);
420   m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
421   return 0;
422 }
423 
CFXEU_InsertText(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,const WideString & swText,int32_t charset)424 CFXEU_InsertText::CFXEU_InsertText(CPWL_EditImpl* pEdit,
425                                    const CPVT_WordPlace& wpOldPlace,
426                                    const CPVT_WordPlace& wpNewPlace,
427                                    const WideString& swText,
428                                    int32_t charset)
429     : m_pEdit(pEdit),
430       m_wpOld(wpOldPlace),
431       m_wpNew(wpNewPlace),
432       m_swText(swText),
433       m_nCharset(charset) {
434   ASSERT(m_pEdit);
435 }
436 
~CFXEU_InsertText()437 CFXEU_InsertText::~CFXEU_InsertText() {}
438 
Redo()439 int CFXEU_InsertText::Redo() {
440   m_pEdit->SelectNone();
441   m_pEdit->SetCaret(m_wpOld);
442   m_pEdit->InsertText(m_swText, m_nCharset, false, true);
443   return 0;
444 }
445 
Undo()446 int CFXEU_InsertText::Undo() {
447   m_pEdit->SelectNone();
448   m_pEdit->SetSelection(m_wpOld, m_wpNew);
449   m_pEdit->Clear(false, true);
450   return 0;
451 }
452 
453 // static
DrawEdit(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,CPWL_EditImpl * pEdit,FX_COLORREF crTextFill,const CFX_FloatRect & rcClip,const CFX_PointF & ptOffset,const CPVT_WordRange * pRange,IPWL_SystemHandler * pSystemHandler,CFFL_FormFiller * pFFLData)454 void CPWL_EditImpl::DrawEdit(CFX_RenderDevice* pDevice,
455                              const CFX_Matrix& mtUser2Device,
456                              CPWL_EditImpl* pEdit,
457                              FX_COLORREF crTextFill,
458                              const CFX_FloatRect& rcClip,
459                              const CFX_PointF& ptOffset,
460                              const CPVT_WordRange* pRange,
461                              IPWL_SystemHandler* pSystemHandler,
462                              CFFL_FormFiller* pFFLData) {
463   const bool bContinuous =
464       pEdit->GetCharArray() == 0 && pEdit->GetCharSpace() <= 0.0f;
465   uint16_t SubWord = pEdit->GetPasswordChar();
466   float fFontSize = pEdit->GetFontSize();
467   CPVT_WordRange wrSelect = pEdit->GetSelectWordRange();
468   FX_COLORREF crCurFill = crTextFill;
469   FX_COLORREF crOldFill = crCurFill;
470   bool bSelect = false;
471   const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255);
472   const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113);
473 
474   std::ostringstream sTextBuf;
475   int32_t nFontIndex = -1;
476   CFX_PointF ptBT;
477   CFX_RenderDevice::StateRestorer restorer(pDevice);
478   if (!rcClip.IsEmpty())
479     pDevice->SetClip_Rect(mtUser2Device.TransformRect(rcClip).ToFxRect());
480 
481   CPWL_EditImpl_Iterator* pIterator = pEdit->GetIterator();
482   IPVT_FontMap* pFontMap = pEdit->GetFontMap();
483   if (!pFontMap)
484     return;
485 
486   if (pRange)
487     pIterator->SetAt(pRange->BeginPos);
488   else
489     pIterator->SetAt(0);
490 
491   CPVT_WordPlace oldplace;
492   while (pIterator->NextWord()) {
493     CPVT_WordPlace place = pIterator->GetAt();
494     if (pRange && place > pRange->EndPos)
495       break;
496 
497     if (!wrSelect.IsEmpty()) {
498       bSelect = place > wrSelect.BeginPos && place <= wrSelect.EndPos;
499       crCurFill = bSelect ? crWhite : crTextFill;
500     }
501     if (pSystemHandler->IsSelectionImplemented()) {
502       crCurFill = crTextFill;
503       crOldFill = crCurFill;
504     }
505     CPVT_Word word;
506     if (pIterator->GetWord(word)) {
507       if (bSelect) {
508         CPVT_Line line;
509         pIterator->GetLine(line);
510 
511         if (pSystemHandler->IsSelectionImplemented()) {
512           CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent,
513                            word.ptWord.x + word.fWidth,
514                            line.ptLine.y + line.fLineAscent);
515           rc.Intersect(rcClip);
516           pSystemHandler->OutputSelectedRect(pFFLData, rc);
517         } else {
518           CFX_PathData pathSelBK;
519           pathSelBK.AppendRect(word.ptWord.x, line.ptLine.y + line.fLineDescent,
520                                word.ptWord.x + word.fWidth,
521                                line.ptLine.y + line.fLineAscent);
522 
523           pDevice->DrawPath(&pathSelBK, &mtUser2Device, nullptr, crSelBK, 0,
524                             FXFILL_WINDING);
525         }
526       }
527 
528       if (bContinuous) {
529         if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex ||
530             crOldFill != crCurFill) {
531           if (sTextBuf.tellp() > 0) {
532             DrawTextString(pDevice,
533                            CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
534                            pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
535                            mtUser2Device, ByteString(sTextBuf), crOldFill);
536 
537             sTextBuf.str("");
538           }
539           nFontIndex = word.nFontIndex;
540           ptBT = word.ptWord;
541           crOldFill = crCurFill;
542         }
543 
544         sTextBuf << pEdit->GetPDFWordString(word.nFontIndex, word.Word,
545                                             SubWord);
546       } else {
547         DrawTextString(
548             pDevice,
549             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y),
550             pFontMap->GetPDFFont(word.nFontIndex).Get(), fFontSize,
551             mtUser2Device,
552             pEdit->GetPDFWordString(word.nFontIndex, word.Word, SubWord),
553             crCurFill);
554       }
555       oldplace = place;
556     }
557   }
558 
559   if (sTextBuf.tellp() > 0) {
560     DrawTextString(pDevice,
561                    CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
562                    pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
563                    mtUser2Device, ByteString(sTextBuf), crOldFill);
564   }
565 }
566 
CPWL_EditImpl()567 CPWL_EditImpl::CPWL_EditImpl()
568     : m_pVT(pdfium::MakeUnique<CPDF_VariableText>()),
569       m_bEnableScroll(false),
570       m_nAlignment(0),
571       m_bNotifyFlag(false),
572       m_bEnableOverflow(false),
573       m_bEnableRefresh(true),
574       m_bEnableUndo(true) {}
575 
~CPWL_EditImpl()576 CPWL_EditImpl::~CPWL_EditImpl() {}
577 
Initialize()578 void CPWL_EditImpl::Initialize() {
579   m_pVT->Initialize();
580   SetCaret(m_pVT->GetBeginWordPlace());
581   SetCaretOrigin();
582 }
583 
SetFontMap(IPVT_FontMap * pFontMap)584 void CPWL_EditImpl::SetFontMap(IPVT_FontMap* pFontMap) {
585   m_pVTProvider = pdfium::MakeUnique<CPWL_EditImpl_Provider>(pFontMap);
586   m_pVT->SetProvider(m_pVTProvider.get());
587 }
588 
SetNotify(CPWL_EditCtrl * pNotify)589 void CPWL_EditImpl::SetNotify(CPWL_EditCtrl* pNotify) {
590   m_pNotify = pNotify;
591 }
592 
SetOperationNotify(CPWL_Edit * pOperationNotify)593 void CPWL_EditImpl::SetOperationNotify(CPWL_Edit* pOperationNotify) {
594   m_pOperationNotify = pOperationNotify;
595 }
596 
GetIterator()597 CPWL_EditImpl_Iterator* CPWL_EditImpl::GetIterator() {
598   if (!m_pIterator) {
599     m_pIterator =
600         pdfium::MakeUnique<CPWL_EditImpl_Iterator>(this, m_pVT->GetIterator());
601   }
602   return m_pIterator.get();
603 }
604 
GetFontMap()605 IPVT_FontMap* CPWL_EditImpl::GetFontMap() {
606   return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr;
607 }
608 
SetPlateRect(const CFX_FloatRect & rect)609 void CPWL_EditImpl::SetPlateRect(const CFX_FloatRect& rect) {
610   m_pVT->SetPlateRect(rect);
611   m_ptScrollPos = CFX_PointF(rect.left, rect.top);
612   Paint();
613 }
614 
SetAlignmentH(int32_t nFormat,bool bPaint)615 void CPWL_EditImpl::SetAlignmentH(int32_t nFormat, bool bPaint) {
616   m_pVT->SetAlignment(nFormat);
617   if (bPaint)
618     Paint();
619 }
620 
SetAlignmentV(int32_t nFormat,bool bPaint)621 void CPWL_EditImpl::SetAlignmentV(int32_t nFormat, bool bPaint) {
622   m_nAlignment = nFormat;
623   if (bPaint)
624     Paint();
625 }
626 
SetPasswordChar(uint16_t wSubWord,bool bPaint)627 void CPWL_EditImpl::SetPasswordChar(uint16_t wSubWord, bool bPaint) {
628   m_pVT->SetPasswordChar(wSubWord);
629   if (bPaint)
630     Paint();
631 }
632 
SetLimitChar(int32_t nLimitChar)633 void CPWL_EditImpl::SetLimitChar(int32_t nLimitChar) {
634   m_pVT->SetLimitChar(nLimitChar);
635   Paint();
636 }
637 
SetCharArray(int32_t nCharArray)638 void CPWL_EditImpl::SetCharArray(int32_t nCharArray) {
639   m_pVT->SetCharArray(nCharArray);
640   Paint();
641 }
642 
SetCharSpace(float fCharSpace)643 void CPWL_EditImpl::SetCharSpace(float fCharSpace) {
644   m_pVT->SetCharSpace(fCharSpace);
645   Paint();
646 }
647 
SetMultiLine(bool bMultiLine,bool bPaint)648 void CPWL_EditImpl::SetMultiLine(bool bMultiLine, bool bPaint) {
649   m_pVT->SetMultiLine(bMultiLine);
650   if (bPaint)
651     Paint();
652 }
653 
SetAutoReturn(bool bAuto,bool bPaint)654 void CPWL_EditImpl::SetAutoReturn(bool bAuto, bool bPaint) {
655   m_pVT->SetAutoReturn(bAuto);
656   if (bPaint)
657     Paint();
658 }
659 
SetAutoFontSize(bool bAuto,bool bPaint)660 void CPWL_EditImpl::SetAutoFontSize(bool bAuto, bool bPaint) {
661   m_pVT->SetAutoFontSize(bAuto);
662   if (bPaint)
663     Paint();
664 }
665 
SetFontSize(float fFontSize)666 void CPWL_EditImpl::SetFontSize(float fFontSize) {
667   m_pVT->SetFontSize(fFontSize);
668   Paint();
669 }
670 
SetAutoScroll(bool bAuto,bool bPaint)671 void CPWL_EditImpl::SetAutoScroll(bool bAuto, bool bPaint) {
672   m_bEnableScroll = bAuto;
673   if (bPaint)
674     Paint();
675 }
676 
SetTextOverflow(bool bAllowed,bool bPaint)677 void CPWL_EditImpl::SetTextOverflow(bool bAllowed, bool bPaint) {
678   m_bEnableOverflow = bAllowed;
679   if (bPaint)
680     Paint();
681 }
682 
SetSelection(int32_t nStartChar,int32_t nEndChar)683 void CPWL_EditImpl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
684   if (m_pVT->IsValid()) {
685     if (nStartChar == 0 && nEndChar < 0) {
686       SelectAll();
687     } else if (nStartChar < 0) {
688       SelectNone();
689     } else {
690       if (nStartChar < nEndChar) {
691         SetSelection(m_pVT->WordIndexToWordPlace(nStartChar),
692                      m_pVT->WordIndexToWordPlace(nEndChar));
693       } else {
694         SetSelection(m_pVT->WordIndexToWordPlace(nEndChar),
695                      m_pVT->WordIndexToWordPlace(nStartChar));
696       }
697     }
698   }
699 }
700 
SetSelection(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)701 void CPWL_EditImpl::SetSelection(const CPVT_WordPlace& begin,
702                                  const CPVT_WordPlace& end) {
703   if (!m_pVT->IsValid())
704     return;
705 
706   SelectNone();
707   m_SelState.Set(begin, end);
708   SetCaret(m_SelState.EndPos);
709   ScrollToCaret();
710   if (!m_SelState.IsEmpty())
711     Refresh();
712   SetCaretInfo();
713 }
714 
GetSelection(int32_t & nStartChar,int32_t & nEndChar) const715 void CPWL_EditImpl::GetSelection(int32_t& nStartChar, int32_t& nEndChar) const {
716   nStartChar = -1;
717   nEndChar = -1;
718   if (!m_pVT->IsValid())
719     return;
720 
721   if (m_SelState.IsEmpty()) {
722     nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
723     nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
724     return;
725   }
726   if (m_SelState.BeginPos < m_SelState.EndPos) {
727     nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
728     nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
729     return;
730   }
731   nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
732   nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
733 }
734 
GetCaret() const735 int32_t CPWL_EditImpl::GetCaret() const {
736   if (m_pVT->IsValid())
737     return m_pVT->WordPlaceToWordIndex(m_wpCaret);
738 
739   return -1;
740 }
741 
GetCaretWordPlace() const742 CPVT_WordPlace CPWL_EditImpl::GetCaretWordPlace() const {
743   return m_wpCaret;
744 }
745 
GetText() const746 WideString CPWL_EditImpl::GetText() const {
747   WideString swRet;
748   if (!m_pVT->IsValid())
749     return swRet;
750 
751   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
752   pIterator->SetAt(0);
753 
754   CPVT_Word wordinfo;
755   CPVT_WordPlace oldplace = pIterator->GetWordPlace();
756   while (pIterator->NextWord()) {
757     CPVT_WordPlace place = pIterator->GetWordPlace();
758     if (pIterator->GetWord(wordinfo))
759       swRet += wordinfo.Word;
760     if (oldplace.nSecIndex != place.nSecIndex)
761       swRet += L"\r\n";
762     oldplace = place;
763   }
764   return swRet;
765 }
766 
GetRangeText(const CPVT_WordRange & range) const767 WideString CPWL_EditImpl::GetRangeText(const CPVT_WordRange& range) const {
768   WideString swRet;
769   if (!m_pVT->IsValid())
770     return swRet;
771 
772   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
773   CPVT_WordRange wrTemp = range;
774   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
775   m_pVT->UpdateWordPlace(wrTemp.EndPos);
776   pIterator->SetAt(wrTemp.BeginPos);
777 
778   CPVT_Word wordinfo;
779   CPVT_WordPlace oldplace = wrTemp.BeginPos;
780   while (pIterator->NextWord()) {
781     CPVT_WordPlace place = pIterator->GetWordPlace();
782     if (place > wrTemp.EndPos)
783       break;
784     if (pIterator->GetWord(wordinfo))
785       swRet += wordinfo.Word;
786     if (oldplace.nSecIndex != place.nSecIndex)
787       swRet += L"\r\n";
788     oldplace = place;
789   }
790   return swRet;
791 }
792 
GetSelectedText() const793 WideString CPWL_EditImpl::GetSelectedText() const {
794   return GetRangeText(m_SelState.ConvertToWordRange());
795 }
796 
GetTotalLines() const797 int32_t CPWL_EditImpl::GetTotalLines() const {
798   int32_t nLines = 1;
799 
800   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
801   pIterator->SetAt(0);
802   while (pIterator->NextLine())
803     ++nLines;
804 
805   return nLines;
806 }
807 
GetSelectWordRange() const808 CPVT_WordRange CPWL_EditImpl::GetSelectWordRange() const {
809   return m_SelState.ConvertToWordRange();
810 }
811 
SetText(const WideString & sText)812 void CPWL_EditImpl::SetText(const WideString& sText) {
813   Clear();
814   DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FX_CHARSET_Default);
815   Paint();
816 }
817 
InsertWord(uint16_t word,int32_t charset)818 bool CPWL_EditImpl::InsertWord(uint16_t word, int32_t charset) {
819   return InsertWord(word, charset, true, true);
820 }
821 
InsertReturn()822 bool CPWL_EditImpl::InsertReturn() {
823   return InsertReturn(true, true);
824 }
825 
Backspace()826 bool CPWL_EditImpl::Backspace() {
827   return Backspace(true, true);
828 }
829 
Delete()830 bool CPWL_EditImpl::Delete() {
831   return Delete(true, true);
832 }
833 
ClearSelection()834 bool CPWL_EditImpl::ClearSelection() {
835   return Clear(true, true);
836 }
837 
InsertText(const WideString & sText,int32_t charset)838 bool CPWL_EditImpl::InsertText(const WideString& sText, int32_t charset) {
839   return InsertText(sText, charset, true, true);
840 }
841 
GetFontSize() const842 float CPWL_EditImpl::GetFontSize() const {
843   return m_pVT->GetFontSize();
844 }
845 
GetPasswordChar() const846 uint16_t CPWL_EditImpl::GetPasswordChar() const {
847   return m_pVT->GetPasswordChar();
848 }
849 
GetCharArray() const850 int32_t CPWL_EditImpl::GetCharArray() const {
851   return m_pVT->GetCharArray();
852 }
853 
GetContentRect() const854 CFX_FloatRect CPWL_EditImpl::GetContentRect() const {
855   return VTToEdit(m_pVT->GetContentRect());
856 }
857 
GetCharSpace() const858 float CPWL_EditImpl::GetCharSpace() const {
859   return m_pVT->GetCharSpace();
860 }
861 
GetWholeWordRange() const862 CPVT_WordRange CPWL_EditImpl::GetWholeWordRange() const {
863   if (m_pVT->IsValid())
864     return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
865 
866   return CPVT_WordRange();
867 }
868 
GetVisibleWordRange() const869 CPVT_WordRange CPWL_EditImpl::GetVisibleWordRange() const {
870   if (m_bEnableOverflow)
871     return GetWholeWordRange();
872 
873   if (m_pVT->IsValid()) {
874     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
875 
876     CPVT_WordPlace place1 =
877         m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
878     CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
879         EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
880 
881     return CPVT_WordRange(place1, place2);
882   }
883 
884   return CPVT_WordRange();
885 }
886 
SearchWordPlace(const CFX_PointF & point) const887 CPVT_WordPlace CPWL_EditImpl::SearchWordPlace(const CFX_PointF& point) const {
888   if (m_pVT->IsValid()) {
889     return m_pVT->SearchWordPlace(EditToVT(point));
890   }
891 
892   return CPVT_WordPlace();
893 }
894 
Paint()895 void CPWL_EditImpl::Paint() {
896   if (m_pVT->IsValid()) {
897     RearrangeAll();
898     ScrollToCaret();
899     Refresh();
900     SetCaretOrigin();
901     SetCaretInfo();
902   }
903 }
904 
RearrangeAll()905 void CPWL_EditImpl::RearrangeAll() {
906   if (m_pVT->IsValid()) {
907     m_pVT->UpdateWordPlace(m_wpCaret);
908     m_pVT->RearrangeAll();
909     m_pVT->UpdateWordPlace(m_wpCaret);
910     SetScrollInfo();
911     SetContentChanged();
912   }
913 }
914 
RearrangePart(const CPVT_WordRange & range)915 void CPWL_EditImpl::RearrangePart(const CPVT_WordRange& range) {
916   if (m_pVT->IsValid()) {
917     m_pVT->UpdateWordPlace(m_wpCaret);
918     m_pVT->RearrangePart(range);
919     m_pVT->UpdateWordPlace(m_wpCaret);
920     SetScrollInfo();
921     SetContentChanged();
922   }
923 }
924 
SetContentChanged()925 void CPWL_EditImpl::SetContentChanged() {
926   if (m_pNotify) {
927     CFX_FloatRect rcContent = m_pVT->GetContentRect();
928     if (rcContent.Width() != m_rcOldContent.Width() ||
929         rcContent.Height() != m_rcOldContent.Height()) {
930       m_rcOldContent = rcContent;
931     }
932   }
933 }
934 
SelectAll()935 void CPWL_EditImpl::SelectAll() {
936   if (!m_pVT->IsValid())
937     return;
938   m_SelState = CPWL_EditImpl_Select(GetWholeWordRange());
939   SetCaret(m_SelState.EndPos);
940   ScrollToCaret();
941   Refresh();
942   SetCaretInfo();
943 }
944 
SelectNone()945 void CPWL_EditImpl::SelectNone() {
946   if (!m_pVT->IsValid() || m_SelState.IsEmpty())
947     return;
948 
949   m_SelState.Reset();
950   Refresh();
951 }
952 
IsSelected() const953 bool CPWL_EditImpl::IsSelected() const {
954   return !m_SelState.IsEmpty();
955 }
956 
VTToEdit(const CFX_PointF & point) const957 CFX_PointF CPWL_EditImpl::VTToEdit(const CFX_PointF& point) const {
958   CFX_FloatRect rcContent = m_pVT->GetContentRect();
959   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
960 
961   float fPadding = 0.0f;
962 
963   switch (m_nAlignment) {
964     case 0:
965       fPadding = 0.0f;
966       break;
967     case 1:
968       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
969       break;
970     case 2:
971       fPadding = rcPlate.Height() - rcContent.Height();
972       break;
973   }
974 
975   return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
976                     point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
977 }
978 
EditToVT(const CFX_PointF & point) const979 CFX_PointF CPWL_EditImpl::EditToVT(const CFX_PointF& point) const {
980   CFX_FloatRect rcContent = m_pVT->GetContentRect();
981   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
982 
983   float fPadding = 0.0f;
984 
985   switch (m_nAlignment) {
986     case 0:
987       fPadding = 0.0f;
988       break;
989     case 1:
990       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
991       break;
992     case 2:
993       fPadding = rcPlate.Height() - rcContent.Height();
994       break;
995   }
996 
997   return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
998                     point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
999 }
1000 
VTToEdit(const CFX_FloatRect & rect) const1001 CFX_FloatRect CPWL_EditImpl::VTToEdit(const CFX_FloatRect& rect) const {
1002   CFX_PointF ptLeftBottom = VTToEdit(CFX_PointF(rect.left, rect.bottom));
1003   CFX_PointF ptRightTop = VTToEdit(CFX_PointF(rect.right, rect.top));
1004 
1005   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
1006                        ptRightTop.y);
1007 }
1008 
SetScrollInfo()1009 void CPWL_EditImpl::SetScrollInfo() {
1010   if (!m_pNotify)
1011     return;
1012 
1013   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1014   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1015   if (m_bNotifyFlag)
1016     return;
1017 
1018   AutoRestorer<bool> restorer(&m_bNotifyFlag);
1019   m_bNotifyFlag = true;
1020 
1021   PWL_SCROLL_INFO Info;
1022   Info.fPlateWidth = rcPlate.top - rcPlate.bottom;
1023   Info.fContentMin = rcContent.bottom;
1024   Info.fContentMax = rcContent.top;
1025   Info.fSmallStep = rcPlate.Height() / 3;
1026   Info.fBigStep = rcPlate.Height();
1027   m_pNotify->SetScrollInfo(Info);
1028 }
1029 
SetScrollPosX(float fx)1030 void CPWL_EditImpl::SetScrollPosX(float fx) {
1031   if (!m_bEnableScroll)
1032     return;
1033 
1034   if (m_pVT->IsValid()) {
1035     if (!IsFloatEqual(m_ptScrollPos.x, fx)) {
1036       m_ptScrollPos.x = fx;
1037       Refresh();
1038     }
1039   }
1040 }
1041 
SetScrollPosY(float fy)1042 void CPWL_EditImpl::SetScrollPosY(float fy) {
1043   if (!m_bEnableScroll)
1044     return;
1045 
1046   if (m_pVT->IsValid()) {
1047     if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
1048       m_ptScrollPos.y = fy;
1049       Refresh();
1050 
1051       if (m_pNotify) {
1052         if (!m_bNotifyFlag) {
1053           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1054           m_bNotifyFlag = true;
1055           m_pNotify->SetScrollPosition(fy);
1056         }
1057       }
1058     }
1059   }
1060 }
1061 
SetScrollPos(const CFX_PointF & point)1062 void CPWL_EditImpl::SetScrollPos(const CFX_PointF& point) {
1063   SetScrollPosX(point.x);
1064   SetScrollPosY(point.y);
1065   SetScrollLimit();
1066   SetCaretInfo();
1067 }
1068 
GetScrollPos() const1069 CFX_PointF CPWL_EditImpl::GetScrollPos() const {
1070   return m_ptScrollPos;
1071 }
1072 
SetScrollLimit()1073 void CPWL_EditImpl::SetScrollLimit() {
1074   if (m_pVT->IsValid()) {
1075     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1076     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1077 
1078     if (rcPlate.Width() > rcContent.Width()) {
1079       SetScrollPosX(rcPlate.left);
1080     } else {
1081       if (IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
1082         SetScrollPosX(rcContent.left);
1083       } else if (IsFloatBigger(m_ptScrollPos.x,
1084                                rcContent.right - rcPlate.Width())) {
1085         SetScrollPosX(rcContent.right - rcPlate.Width());
1086       }
1087     }
1088 
1089     if (rcPlate.Height() > rcContent.Height()) {
1090       SetScrollPosY(rcPlate.top);
1091     } else {
1092       if (IsFloatSmaller(m_ptScrollPos.y,
1093                          rcContent.bottom + rcPlate.Height())) {
1094         SetScrollPosY(rcContent.bottom + rcPlate.Height());
1095       } else if (IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
1096         SetScrollPosY(rcContent.top);
1097       }
1098     }
1099   }
1100 }
1101 
ScrollToCaret()1102 void CPWL_EditImpl::ScrollToCaret() {
1103   SetScrollLimit();
1104 
1105   if (!m_pVT->IsValid())
1106     return;
1107 
1108   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1109   pIterator->SetAt(m_wpCaret);
1110 
1111   CFX_PointF ptHead;
1112   CFX_PointF ptFoot;
1113   CPVT_Word word;
1114   CPVT_Line line;
1115   if (pIterator->GetWord(word)) {
1116     ptHead.x = word.ptWord.x + word.fWidth;
1117     ptHead.y = word.ptWord.y + word.fAscent;
1118     ptFoot.x = word.ptWord.x + word.fWidth;
1119     ptFoot.y = word.ptWord.y + word.fDescent;
1120   } else if (pIterator->GetLine(line)) {
1121     ptHead.x = line.ptLine.x;
1122     ptHead.y = line.ptLine.y + line.fLineAscent;
1123     ptFoot.x = line.ptLine.x;
1124     ptFoot.y = line.ptLine.y + line.fLineDescent;
1125   }
1126 
1127   CFX_PointF ptHeadEdit = VTToEdit(ptHead);
1128   CFX_PointF ptFootEdit = VTToEdit(ptFoot);
1129   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1130   if (!IsFloatEqual(rcPlate.left, rcPlate.right)) {
1131     if (IsFloatSmaller(ptHeadEdit.x, rcPlate.left) ||
1132         IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
1133       SetScrollPosX(ptHead.x);
1134     } else if (IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
1135       SetScrollPosX(ptHead.x - rcPlate.Width());
1136     }
1137   }
1138 
1139   if (!IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
1140     if (IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
1141         IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
1142       if (IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
1143         SetScrollPosY(ptFoot.y + rcPlate.Height());
1144       }
1145     } else if (IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
1146       if (IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
1147         SetScrollPosY(ptHead.y);
1148       }
1149     }
1150   }
1151 }
1152 
Refresh()1153 void CPWL_EditImpl::Refresh() {
1154   if (m_bEnableRefresh && m_pVT->IsValid()) {
1155     m_Refresh.BeginRefresh();
1156     RefreshPushLineRects(GetVisibleWordRange());
1157 
1158     m_Refresh.NoAnalyse();
1159     m_ptRefreshScrollPos = m_ptScrollPos;
1160 
1161     if (m_pNotify) {
1162       if (!m_bNotifyFlag) {
1163         AutoRestorer<bool> restorer(&m_bNotifyFlag);
1164         m_bNotifyFlag = true;
1165         if (std::vector<CFX_FloatRect>* pRects = m_Refresh.GetRefreshRects()) {
1166           for (auto& rect : *pRects)
1167             m_pNotify->InvalidateRect(&rect);
1168         }
1169       }
1170     }
1171 
1172     m_Refresh.EndRefresh();
1173   }
1174 }
1175 
RefreshPushLineRects(const CPVT_WordRange & wr)1176 void CPWL_EditImpl::RefreshPushLineRects(const CPVT_WordRange& wr) {
1177   if (!m_pVT->IsValid())
1178     return;
1179 
1180   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1181   CPVT_WordPlace wpBegin = wr.BeginPos;
1182   m_pVT->UpdateWordPlace(wpBegin);
1183   CPVT_WordPlace wpEnd = wr.EndPos;
1184   m_pVT->UpdateWordPlace(wpEnd);
1185   pIterator->SetAt(wpBegin);
1186 
1187   CPVT_Line lineinfo;
1188   do {
1189     if (!pIterator->GetLine(lineinfo))
1190       break;
1191     if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
1192       break;
1193 
1194     CFX_FloatRect rcLine(lineinfo.ptLine.x,
1195                          lineinfo.ptLine.y + lineinfo.fLineDescent,
1196                          lineinfo.ptLine.x + lineinfo.fLineWidth,
1197                          lineinfo.ptLine.y + lineinfo.fLineAscent);
1198 
1199     m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
1200                    VTToEdit(rcLine));
1201   } while (pIterator->NextLine());
1202 }
1203 
RefreshWordRange(const CPVT_WordRange & wr)1204 void CPWL_EditImpl::RefreshWordRange(const CPVT_WordRange& wr) {
1205   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1206   CPVT_WordRange wrTemp = wr;
1207 
1208   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1209   m_pVT->UpdateWordPlace(wrTemp.EndPos);
1210   pIterator->SetAt(wrTemp.BeginPos);
1211 
1212   CPVT_Word wordinfo;
1213   CPVT_Line lineinfo;
1214   CPVT_WordPlace place;
1215 
1216   while (pIterator->NextWord()) {
1217     place = pIterator->GetWordPlace();
1218     if (place > wrTemp.EndPos)
1219       break;
1220 
1221     pIterator->GetWord(wordinfo);
1222     pIterator->GetLine(lineinfo);
1223     if (place.LineCmp(wrTemp.BeginPos) == 0 ||
1224         place.LineCmp(wrTemp.EndPos) == 0) {
1225       CFX_FloatRect rcWord(wordinfo.ptWord.x,
1226                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1227                            wordinfo.ptWord.x + wordinfo.fWidth,
1228                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1229 
1230       if (m_pNotify) {
1231         if (!m_bNotifyFlag) {
1232           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1233           m_bNotifyFlag = true;
1234           CFX_FloatRect rcRefresh = VTToEdit(rcWord);
1235           m_pNotify->InvalidateRect(&rcRefresh);
1236         }
1237       }
1238     } else {
1239       CFX_FloatRect rcLine(lineinfo.ptLine.x,
1240                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1241                            lineinfo.ptLine.x + lineinfo.fLineWidth,
1242                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1243 
1244       if (m_pNotify) {
1245         if (!m_bNotifyFlag) {
1246           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1247           m_bNotifyFlag = true;
1248           CFX_FloatRect rcRefresh = VTToEdit(rcLine);
1249           m_pNotify->InvalidateRect(&rcRefresh);
1250         }
1251       }
1252 
1253       pIterator->NextLine();
1254     }
1255   }
1256 }
1257 
SetCaret(const CPVT_WordPlace & place)1258 void CPWL_EditImpl::SetCaret(const CPVT_WordPlace& place) {
1259   m_wpOldCaret = m_wpCaret;
1260   m_wpCaret = place;
1261 }
1262 
SetCaretInfo()1263 void CPWL_EditImpl::SetCaretInfo() {
1264   if (m_pNotify) {
1265     if (!m_bNotifyFlag) {
1266       CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1267       pIterator->SetAt(m_wpCaret);
1268 
1269       CFX_PointF ptHead;
1270       CFX_PointF ptFoot;
1271       CPVT_Word word;
1272       CPVT_Line line;
1273       if (pIterator->GetWord(word)) {
1274         ptHead.x = word.ptWord.x + word.fWidth;
1275         ptHead.y = word.ptWord.y + word.fAscent;
1276         ptFoot.x = word.ptWord.x + word.fWidth;
1277         ptFoot.y = word.ptWord.y + word.fDescent;
1278       } else if (pIterator->GetLine(line)) {
1279         ptHead.x = line.ptLine.x;
1280         ptHead.y = line.ptLine.y + line.fLineAscent;
1281         ptFoot.x = line.ptLine.x;
1282         ptFoot.y = line.ptLine.y + line.fLineDescent;
1283       }
1284 
1285       AutoRestorer<bool> restorer(&m_bNotifyFlag);
1286       m_bNotifyFlag = true;
1287       m_pNotify->SetCaret(m_SelState.IsEmpty(), VTToEdit(ptHead),
1288                           VTToEdit(ptFoot));
1289     }
1290   }
1291 }
1292 
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)1293 void CPWL_EditImpl::OnMouseDown(const CFX_PointF& point,
1294                                 bool bShift,
1295                                 bool bCtrl) {
1296   if (!m_pVT->IsValid())
1297     return;
1298 
1299   SelectNone();
1300   SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1301   m_SelState.Set(m_wpCaret, m_wpCaret);
1302   ScrollToCaret();
1303   SetCaretOrigin();
1304   SetCaretInfo();
1305 }
1306 
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)1307 void CPWL_EditImpl::OnMouseMove(const CFX_PointF& point,
1308                                 bool bShift,
1309                                 bool bCtrl) {
1310   if (!m_pVT->IsValid())
1311     return;
1312 
1313   SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1314   if (m_wpCaret == m_wpOldCaret)
1315     return;
1316 
1317   m_SelState.SetEndPos(m_wpCaret);
1318   ScrollToCaret();
1319   Refresh();
1320   SetCaretOrigin();
1321   SetCaretInfo();
1322 }
1323 
OnVK_UP(bool bShift,bool bCtrl)1324 void CPWL_EditImpl::OnVK_UP(bool bShift, bool bCtrl) {
1325   if (!m_pVT->IsValid())
1326     return;
1327 
1328   SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
1329   if (bShift) {
1330     if (m_SelState.IsEmpty())
1331       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1332     else
1333       m_SelState.SetEndPos(m_wpCaret);
1334 
1335     if (m_wpOldCaret != m_wpCaret) {
1336       ScrollToCaret();
1337       Refresh();
1338       SetCaretInfo();
1339     }
1340   } else {
1341     SelectNone();
1342     ScrollToCaret();
1343     SetCaretInfo();
1344   }
1345 }
1346 
OnVK_DOWN(bool bShift,bool bCtrl)1347 void CPWL_EditImpl::OnVK_DOWN(bool bShift, bool bCtrl) {
1348   if (!m_pVT->IsValid())
1349     return;
1350 
1351   SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
1352   if (bShift) {
1353     if (m_SelState.IsEmpty())
1354       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1355     else
1356       m_SelState.SetEndPos(m_wpCaret);
1357 
1358     if (m_wpOldCaret != m_wpCaret) {
1359       ScrollToCaret();
1360       Refresh();
1361       SetCaretInfo();
1362     }
1363   } else {
1364     SelectNone();
1365     ScrollToCaret();
1366     SetCaretInfo();
1367   }
1368 }
1369 
OnVK_LEFT(bool bShift,bool bCtrl)1370 void CPWL_EditImpl::OnVK_LEFT(bool bShift, bool bCtrl) {
1371   if (!m_pVT->IsValid())
1372     return;
1373 
1374   if (bShift) {
1375     if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1376         m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
1377       SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1378     }
1379     SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1380     if (m_SelState.IsEmpty())
1381       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1382     else
1383       m_SelState.SetEndPos(m_wpCaret);
1384 
1385     if (m_wpOldCaret != m_wpCaret) {
1386       ScrollToCaret();
1387       Refresh();
1388       SetCaretInfo();
1389     }
1390   } else {
1391     if (!m_SelState.IsEmpty()) {
1392       if (m_SelState.BeginPos < m_SelState.EndPos)
1393         SetCaret(m_SelState.BeginPos);
1394       else
1395         SetCaret(m_SelState.EndPos);
1396 
1397       SelectNone();
1398       ScrollToCaret();
1399       SetCaretInfo();
1400     } else {
1401       if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1402           m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
1403         SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1404       }
1405       SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1406       ScrollToCaret();
1407       SetCaretOrigin();
1408       SetCaretInfo();
1409     }
1410   }
1411 }
1412 
OnVK_RIGHT(bool bShift,bool bCtrl)1413 void CPWL_EditImpl::OnVK_RIGHT(bool bShift, bool bCtrl) {
1414   if (!m_pVT->IsValid())
1415     return;
1416 
1417   if (bShift) {
1418     SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1419     if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1420         m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
1421       SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1422 
1423     if (m_SelState.IsEmpty())
1424       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1425     else
1426       m_SelState.SetEndPos(m_wpCaret);
1427 
1428     if (m_wpOldCaret != m_wpCaret) {
1429       ScrollToCaret();
1430       Refresh();
1431       SetCaretInfo();
1432     }
1433   } else {
1434     if (!m_SelState.IsEmpty()) {
1435       if (m_SelState.BeginPos > m_SelState.EndPos)
1436         SetCaret(m_SelState.BeginPos);
1437       else
1438         SetCaret(m_SelState.EndPos);
1439 
1440       SelectNone();
1441       ScrollToCaret();
1442       SetCaretInfo();
1443     } else {
1444       SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1445       if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1446           m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret)) {
1447         SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1448       }
1449       ScrollToCaret();
1450       SetCaretOrigin();
1451       SetCaretInfo();
1452     }
1453   }
1454 }
1455 
OnVK_HOME(bool bShift,bool bCtrl)1456 void CPWL_EditImpl::OnVK_HOME(bool bShift, bool bCtrl) {
1457   if (!m_pVT->IsValid())
1458     return;
1459 
1460   if (bShift) {
1461     if (bCtrl)
1462       SetCaret(m_pVT->GetBeginWordPlace());
1463     else
1464       SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1465 
1466     if (m_SelState.IsEmpty())
1467       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1468     else
1469       m_SelState.SetEndPos(m_wpCaret);
1470 
1471     ScrollToCaret();
1472     Refresh();
1473     SetCaretInfo();
1474   } else {
1475     if (!m_SelState.IsEmpty()) {
1476       SetCaret(std::min(m_SelState.BeginPos, m_SelState.EndPos));
1477       SelectNone();
1478       ScrollToCaret();
1479       SetCaretInfo();
1480     } else {
1481       if (bCtrl)
1482         SetCaret(m_pVT->GetBeginWordPlace());
1483       else
1484         SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1485 
1486       ScrollToCaret();
1487       SetCaretOrigin();
1488       SetCaretInfo();
1489     }
1490   }
1491 }
1492 
OnVK_END(bool bShift,bool bCtrl)1493 void CPWL_EditImpl::OnVK_END(bool bShift, bool bCtrl) {
1494   if (!m_pVT->IsValid())
1495     return;
1496 
1497   if (bShift) {
1498     if (bCtrl)
1499       SetCaret(m_pVT->GetEndWordPlace());
1500     else
1501       SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1502 
1503     if (m_SelState.IsEmpty())
1504       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1505     else
1506       m_SelState.SetEndPos(m_wpCaret);
1507 
1508     ScrollToCaret();
1509     Refresh();
1510     SetCaretInfo();
1511   } else {
1512     if (!m_SelState.IsEmpty()) {
1513       SetCaret(std::max(m_SelState.BeginPos, m_SelState.EndPos));
1514       SelectNone();
1515       ScrollToCaret();
1516       SetCaretInfo();
1517     } else {
1518       if (bCtrl)
1519         SetCaret(m_pVT->GetEndWordPlace());
1520       else
1521         SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1522 
1523       ScrollToCaret();
1524       SetCaretOrigin();
1525       SetCaretInfo();
1526     }
1527   }
1528 }
1529 
InsertWord(uint16_t word,int32_t charset,bool bAddUndo,bool bPaint)1530 bool CPWL_EditImpl::InsertWord(uint16_t word,
1531                                int32_t charset,
1532                                bool bAddUndo,
1533                                bool bPaint) {
1534   if (IsTextOverflow() || !m_pVT->IsValid())
1535     return false;
1536 
1537   m_pVT->UpdateWordPlace(m_wpCaret);
1538   SetCaret(
1539       m_pVT->InsertWord(m_wpCaret, word, GetCharSetFromUnicode(word, charset)));
1540   m_SelState.Set(m_wpCaret, m_wpCaret);
1541   if (m_wpCaret == m_wpOldCaret)
1542     return false;
1543 
1544   if (bAddUndo && m_bEnableUndo) {
1545     AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertWord>(
1546         this, m_wpOldCaret, m_wpCaret, word, charset));
1547   }
1548   if (bPaint)
1549     PaintInsertText(m_wpOldCaret, m_wpCaret);
1550 
1551   if (m_pOperationNotify)
1552     m_pOperationNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
1553 
1554   return true;
1555 }
1556 
InsertReturn(bool bAddUndo,bool bPaint)1557 bool CPWL_EditImpl::InsertReturn(bool bAddUndo, bool bPaint) {
1558   if (IsTextOverflow() || !m_pVT->IsValid())
1559     return false;
1560 
1561   m_pVT->UpdateWordPlace(m_wpCaret);
1562   SetCaret(m_pVT->InsertSection(m_wpCaret));
1563   m_SelState.Set(m_wpCaret, m_wpCaret);
1564   if (m_wpCaret == m_wpOldCaret)
1565     return false;
1566 
1567   if (bAddUndo && m_bEnableUndo) {
1568     AddEditUndoItem(
1569         pdfium::MakeUnique<CFXEU_InsertReturn>(this, m_wpOldCaret, m_wpCaret));
1570   }
1571   if (bPaint) {
1572     RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1573     ScrollToCaret();
1574     Refresh();
1575     SetCaretOrigin();
1576     SetCaretInfo();
1577   }
1578   if (m_pOperationNotify)
1579     m_pOperationNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
1580 
1581   return true;
1582 }
1583 
Backspace(bool bAddUndo,bool bPaint)1584 bool CPWL_EditImpl::Backspace(bool bAddUndo, bool bPaint) {
1585   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
1586     return false;
1587 
1588   CPVT_Word word;
1589   if (bAddUndo) {
1590     CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1591     pIterator->SetAt(m_wpCaret);
1592     pIterator->GetWord(word);
1593   }
1594   m_pVT->UpdateWordPlace(m_wpCaret);
1595   SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
1596   m_SelState.Set(m_wpCaret, m_wpCaret);
1597   if (m_wpCaret == m_wpOldCaret)
1598     return false;
1599 
1600   if (bAddUndo && m_bEnableUndo) {
1601     AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
1602         this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset));
1603   }
1604   if (bPaint) {
1605     RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
1606     ScrollToCaret();
1607     Refresh();
1608     SetCaretOrigin();
1609     SetCaretInfo();
1610   }
1611   if (m_pOperationNotify)
1612     m_pOperationNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
1613 
1614   return true;
1615 }
1616 
Delete(bool bAddUndo,bool bPaint)1617 bool CPWL_EditImpl::Delete(bool bAddUndo, bool bPaint) {
1618   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace())
1619     return false;
1620 
1621   CPVT_Word word;
1622   if (bAddUndo) {
1623     CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1624     pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
1625     pIterator->GetWord(word);
1626   }
1627   m_pVT->UpdateWordPlace(m_wpCaret);
1628   bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
1629   SetCaret(m_pVT->DeleteWord(m_wpCaret));
1630   m_SelState.Set(m_wpCaret, m_wpCaret);
1631   if (bAddUndo && m_bEnableUndo) {
1632     if (bSecEnd) {
1633       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
1634           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, bSecEnd));
1635     } else {
1636       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
1637           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, bSecEnd));
1638     }
1639   }
1640   if (bPaint) {
1641     RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1642     ScrollToCaret();
1643     Refresh();
1644     SetCaretOrigin();
1645     SetCaretInfo();
1646   }
1647   if (m_pOperationNotify)
1648     m_pOperationNotify->OnDelete(m_wpCaret, m_wpOldCaret);
1649 
1650   return true;
1651 }
1652 
Clear()1653 bool CPWL_EditImpl::Clear() {
1654   if (m_pVT->IsValid()) {
1655     m_pVT->DeleteWords(GetWholeWordRange());
1656     SetCaret(m_pVT->GetBeginWordPlace());
1657 
1658     return true;
1659   }
1660 
1661   return false;
1662 }
1663 
Clear(bool bAddUndo,bool bPaint)1664 bool CPWL_EditImpl::Clear(bool bAddUndo, bool bPaint) {
1665   if (!m_pVT->IsValid() || m_SelState.IsEmpty())
1666     return false;
1667 
1668   CPVT_WordRange range = m_SelState.ConvertToWordRange();
1669   if (bAddUndo && m_bEnableUndo) {
1670     AddEditUndoItem(
1671         pdfium::MakeUnique<CFXEU_Clear>(this, range, GetSelectedText()));
1672   }
1673 
1674   SelectNone();
1675   SetCaret(m_pVT->DeleteWords(range));
1676   m_SelState.Set(m_wpCaret, m_wpCaret);
1677   if (bPaint) {
1678     RearrangePart(range);
1679     ScrollToCaret();
1680     Refresh();
1681     SetCaretOrigin();
1682     SetCaretInfo();
1683   }
1684   if (m_pOperationNotify)
1685     m_pOperationNotify->OnClear(m_wpCaret, m_wpOldCaret);
1686 
1687   return true;
1688 }
1689 
InsertText(const WideString & sText,int32_t charset,bool bAddUndo,bool bPaint)1690 bool CPWL_EditImpl::InsertText(const WideString& sText,
1691                                int32_t charset,
1692                                bool bAddUndo,
1693                                bool bPaint) {
1694   if (IsTextOverflow())
1695     return false;
1696 
1697   m_pVT->UpdateWordPlace(m_wpCaret);
1698   SetCaret(DoInsertText(m_wpCaret, sText, charset));
1699   m_SelState.Set(m_wpCaret, m_wpCaret);
1700   if (m_wpCaret == m_wpOldCaret)
1701     return false;
1702 
1703   if (bAddUndo && m_bEnableUndo) {
1704     AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>(
1705         this, m_wpOldCaret, m_wpCaret, sText, charset));
1706   }
1707   if (bPaint)
1708     PaintInsertText(m_wpOldCaret, m_wpCaret);
1709 
1710   if (m_pOperationNotify)
1711     m_pOperationNotify->OnInsertText(m_wpCaret, m_wpOldCaret);
1712 
1713   return true;
1714 }
1715 
PaintInsertText(const CPVT_WordPlace & wpOld,const CPVT_WordPlace & wpNew)1716 void CPWL_EditImpl::PaintInsertText(const CPVT_WordPlace& wpOld,
1717                                     const CPVT_WordPlace& wpNew) {
1718   if (m_pVT->IsValid()) {
1719     RearrangePart(CPVT_WordRange(wpOld, wpNew));
1720     ScrollToCaret();
1721     Refresh();
1722     SetCaretOrigin();
1723     SetCaretInfo();
1724   }
1725 }
1726 
ReplaceSelection(const WideString & text)1727 void CPWL_EditImpl::ReplaceSelection(const WideString& text) {
1728   AddEditUndoItem(pdfium::MakeUnique<CFXEU_ReplaceSelection>(this, false));
1729   ClearSelection();
1730   InsertText(text, FX_CHARSET_Default);
1731   AddEditUndoItem(pdfium::MakeUnique<CFXEU_ReplaceSelection>(this, true));
1732 }
1733 
Redo()1734 bool CPWL_EditImpl::Redo() {
1735   if (m_bEnableUndo) {
1736     if (m_Undo.CanRedo()) {
1737       m_Undo.Redo();
1738       return true;
1739     }
1740   }
1741 
1742   return false;
1743 }
1744 
Undo()1745 bool CPWL_EditImpl::Undo() {
1746   if (m_bEnableUndo) {
1747     if (m_Undo.CanUndo()) {
1748       m_Undo.Undo();
1749       return true;
1750     }
1751   }
1752 
1753   return false;
1754 }
1755 
SetCaretOrigin()1756 void CPWL_EditImpl::SetCaretOrigin() {
1757   if (!m_pVT->IsValid())
1758     return;
1759 
1760   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1761   pIterator->SetAt(m_wpCaret);
1762   CPVT_Word word;
1763   CPVT_Line line;
1764   if (pIterator->GetWord(word)) {
1765     m_ptCaret.x = word.ptWord.x + word.fWidth;
1766     m_ptCaret.y = word.ptWord.y;
1767   } else if (pIterator->GetLine(line)) {
1768     m_ptCaret.x = line.ptLine.x;
1769     m_ptCaret.y = line.ptLine.y;
1770   }
1771 }
1772 
WordIndexToWordPlace(int32_t index) const1773 CPVT_WordPlace CPWL_EditImpl::WordIndexToWordPlace(int32_t index) const {
1774   if (m_pVT->IsValid())
1775     return m_pVT->WordIndexToWordPlace(index);
1776 
1777   return CPVT_WordPlace();
1778 }
1779 
IsTextFull() const1780 bool CPWL_EditImpl::IsTextFull() const {
1781   int32_t nTotalWords = m_pVT->GetTotalWords();
1782   int32_t nLimitChar = m_pVT->GetLimitChar();
1783   int32_t nCharArray = m_pVT->GetCharArray();
1784 
1785   return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
1786          (nCharArray > 0 && nTotalWords >= nCharArray);
1787 }
1788 
IsTextOverflow() const1789 bool CPWL_EditImpl::IsTextOverflow() const {
1790   if (!m_bEnableScroll && !m_bEnableOverflow) {
1791     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1792     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1793 
1794     if (m_pVT->IsMultiLine() && GetTotalLines() > 1 &&
1795         IsFloatBigger(rcContent.Height(), rcPlate.Height())) {
1796       return true;
1797     }
1798 
1799     if (IsFloatBigger(rcContent.Width(), rcPlate.Width()))
1800       return true;
1801   }
1802 
1803   return false;
1804 }
1805 
CanUndo() const1806 bool CPWL_EditImpl::CanUndo() const {
1807   if (m_bEnableUndo) {
1808     return m_Undo.CanUndo();
1809   }
1810 
1811   return false;
1812 }
1813 
CanRedo() const1814 bool CPWL_EditImpl::CanRedo() const {
1815   if (m_bEnableUndo) {
1816     return m_Undo.CanRedo();
1817   }
1818 
1819   return false;
1820 }
1821 
EnableRefresh(bool bRefresh)1822 void CPWL_EditImpl::EnableRefresh(bool bRefresh) {
1823   m_bEnableRefresh = bRefresh;
1824 }
1825 
EnableUndo(bool bUndo)1826 void CPWL_EditImpl::EnableUndo(bool bUndo) {
1827   m_bEnableUndo = bUndo;
1828 }
1829 
DoInsertText(const CPVT_WordPlace & place,const WideString & sText,int32_t charset)1830 CPVT_WordPlace CPWL_EditImpl::DoInsertText(const CPVT_WordPlace& place,
1831                                            const WideString& sText,
1832                                            int32_t charset) {
1833   CPVT_WordPlace wp = place;
1834 
1835   if (m_pVT->IsValid()) {
1836     for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) {
1837       uint16_t word = sText[i];
1838       switch (word) {
1839         case '\r':
1840           wp = m_pVT->InsertSection(wp);
1841           if (i + 1 < sz && sText[i + 1] == '\n')
1842             i++;
1843           break;
1844         case '\n':
1845           wp = m_pVT->InsertSection(wp);
1846           break;
1847         case '\t':
1848           word = ' ';
1849           FALLTHROUGH;
1850         default:
1851           wp =
1852               m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset));
1853           break;
1854       }
1855     }
1856   }
1857 
1858   return wp;
1859 }
1860 
GetCharSetFromUnicode(uint16_t word,int32_t nOldCharset)1861 int32_t CPWL_EditImpl::GetCharSetFromUnicode(uint16_t word,
1862                                              int32_t nOldCharset) {
1863   if (IPVT_FontMap* pFontMap = GetFontMap())
1864     return pFontMap->CharSetFromUnicode(word, nOldCharset);
1865   return nOldCharset;
1866 }
1867 
AddEditUndoItem(std::unique_ptr<IFX_Edit_UndoItem> pEditUndoItem)1868 void CPWL_EditImpl::AddEditUndoItem(
1869     std::unique_ptr<IFX_Edit_UndoItem> pEditUndoItem) {
1870   m_Undo.AddItem(std::move(pEditUndoItem));
1871 }
1872 
GetPDFWordString(int32_t nFontIndex,uint16_t Word,uint16_t SubWord)1873 ByteString CPWL_EditImpl::GetPDFWordString(int32_t nFontIndex,
1874                                            uint16_t Word,
1875                                            uint16_t SubWord) {
1876   IPVT_FontMap* pFontMap = GetFontMap();
1877   RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex);
1878   if (!pPDFFont)
1879     return ByteString();
1880 
1881   ByteString sWord;
1882   if (SubWord > 0) {
1883     Word = SubWord;
1884   } else {
1885     uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible()
1886                               ? pPDFFont->CharCodeFromUnicode(Word)
1887                               : pFontMap->CharCodeFromUnicode(nFontIndex, Word);
1888     if (dwCharCode > 0) {
1889       pPDFFont->AppendChar(&sWord, dwCharCode);
1890       return sWord;
1891     }
1892   }
1893   pPDFFont->AppendChar(&sWord, Word);
1894   return sWord;
1895 }
1896 
CPWL_EditImpl_Select()1897 CPWL_EditImpl_Select::CPWL_EditImpl_Select() {}
1898 
CPWL_EditImpl_Select(const CPVT_WordRange & range)1899 CPWL_EditImpl_Select::CPWL_EditImpl_Select(const CPVT_WordRange& range) {
1900   Set(range.BeginPos, range.EndPos);
1901 }
1902 
ConvertToWordRange() const1903 CPVT_WordRange CPWL_EditImpl_Select::ConvertToWordRange() const {
1904   return CPVT_WordRange(BeginPos, EndPos);
1905 }
1906 
Reset()1907 void CPWL_EditImpl_Select::Reset() {
1908   BeginPos.Reset();
1909   EndPos.Reset();
1910 }
1911 
Set(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)1912 void CPWL_EditImpl_Select::Set(const CPVT_WordPlace& begin,
1913                                const CPVT_WordPlace& end) {
1914   BeginPos = begin;
1915   EndPos = end;
1916 }
1917 
SetEndPos(const CPVT_WordPlace & end)1918 void CPWL_EditImpl_Select::SetEndPos(const CPVT_WordPlace& end) {
1919   EndPos = end;
1920 }
1921 
IsEmpty() const1922 bool CPWL_EditImpl_Select::IsEmpty() const {
1923   return BeginPos == EndPos;
1924 }
1925