• 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/fxedit/fxet_edit.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fpdfapi/font/cpdf_font.h"
14 #include "core/fpdfapi/page/cpdf_pageobject.h"
15 #include "core/fpdfapi/page/cpdf_pageobjectholder.h"
16 #include "core/fpdfapi/page/cpdf_pathobject.h"
17 #include "core/fpdfapi/page/cpdf_textobject.h"
18 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
19 #include "core/fpdfapi/render/cpdf_renderoptions.h"
20 #include "core/fpdfapi/render/cpdf_textrenderer.h"
21 #include "core/fpdfdoc/cpvt_section.h"
22 #include "core/fpdfdoc/cpvt_word.h"
23 #include "core/fpdfdoc/ipvt_fontmap.h"
24 #include "core/fxge/cfx_graphstatedata.h"
25 #include "core/fxge/cfx_pathdata.h"
26 #include "core/fxge/cfx_renderdevice.h"
27 #include "fpdfsdk/cfx_systemhandler.h"
28 #include "fpdfsdk/fxedit/fx_edit.h"
29 #include "fpdfsdk/pdfwindow/PWL_Edit.h"
30 #include "fpdfsdk/pdfwindow/PWL_EditCtrl.h"
31 #include "third_party/base/ptr_util.h"
32 #include "third_party/base/stl_util.h"
33 
34 namespace {
35 
36 const int kEditUndoMaxItems = 10000;
37 
GetWordRenderString(const CFX_ByteString & strWords)38 CFX_ByteString GetWordRenderString(const CFX_ByteString& strWords) {
39   if (strWords.GetLength() > 0)
40     return PDF_EncodeString(strWords) + " Tj\n";
41   return CFX_ByteString();
42 }
43 
GetFontSetString(IPVT_FontMap * pFontMap,int32_t nFontIndex,FX_FLOAT fFontSize)44 CFX_ByteString GetFontSetString(IPVT_FontMap* pFontMap,
45                                 int32_t nFontIndex,
46                                 FX_FLOAT fFontSize) {
47   if (!pFontMap)
48     return CFX_ByteString();
49 
50   CFX_ByteString sFontAlias = pFontMap->GetPDFFontAlias(nFontIndex);
51   if (sFontAlias.GetLength() <= 0 || fFontSize <= 0)
52     return CFX_ByteString();
53 
54   CFX_ByteTextBuf sRet;
55   sRet << "/" << sFontAlias << " " << fFontSize << " Tf\n";
56   return sRet.MakeString();
57 }
58 
DrawTextString(CFX_RenderDevice * pDevice,const CFX_PointF & pt,CPDF_Font * pFont,FX_FLOAT fFontSize,CFX_Matrix * pUser2Device,const CFX_ByteString & str,FX_ARGB crTextFill,int32_t nHorzScale)59 void DrawTextString(CFX_RenderDevice* pDevice,
60                     const CFX_PointF& pt,
61                     CPDF_Font* pFont,
62                     FX_FLOAT fFontSize,
63                     CFX_Matrix* pUser2Device,
64                     const CFX_ByteString& str,
65                     FX_ARGB crTextFill,
66                     int32_t nHorzScale) {
67   CFX_PointF pos = pUser2Device->Transform(pt);
68 
69   if (pFont) {
70     if (nHorzScale != 100) {
71       CFX_Matrix mt(nHorzScale / 100.0f, 0, 0, 1, 0, 0);
72       mt.Concat(*pUser2Device);
73 
74       CPDF_RenderOptions ro;
75       ro.m_Flags = RENDER_CLEARTYPE;
76       ro.m_ColorMode = RENDER_COLOR_NORMAL;
77 
78       CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
79                                         &mt, str, crTextFill, nullptr, &ro);
80     } else {
81       CPDF_RenderOptions ro;
82       ro.m_Flags = RENDER_CLEARTYPE;
83       ro.m_ColorMode = RENDER_COLOR_NORMAL;
84 
85       CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
86                                         pUser2Device, str, crTextFill, nullptr,
87                                         &ro);
88     }
89   }
90 }
91 
92 }  // namespace
93 
CFX_Edit_Iterator(CFX_Edit * pEdit,CPDF_VariableText::Iterator * pVTIterator)94 CFX_Edit_Iterator::CFX_Edit_Iterator(CFX_Edit* pEdit,
95                                      CPDF_VariableText::Iterator* pVTIterator)
96     : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
97 
~CFX_Edit_Iterator()98 CFX_Edit_Iterator::~CFX_Edit_Iterator() {}
99 
NextWord()100 bool CFX_Edit_Iterator::NextWord() {
101   return m_pVTIterator->NextWord();
102 }
103 
PrevWord()104 bool CFX_Edit_Iterator::PrevWord() {
105   return m_pVTIterator->PrevWord();
106 }
107 
GetWord(CPVT_Word & word) const108 bool CFX_Edit_Iterator::GetWord(CPVT_Word& word) const {
109   ASSERT(m_pEdit);
110 
111   if (m_pVTIterator->GetWord(word)) {
112     word.ptWord = m_pEdit->VTToEdit(word.ptWord);
113     return true;
114   }
115   return false;
116 }
117 
GetLine(CPVT_Line & line) const118 bool CFX_Edit_Iterator::GetLine(CPVT_Line& line) const {
119   ASSERT(m_pEdit);
120 
121   if (m_pVTIterator->GetLine(line)) {
122     line.ptLine = m_pEdit->VTToEdit(line.ptLine);
123     return true;
124   }
125   return false;
126 }
127 
GetSection(CPVT_Section & section) const128 bool CFX_Edit_Iterator::GetSection(CPVT_Section& section) const {
129   ASSERT(m_pEdit);
130 
131   if (m_pVTIterator->GetSection(section)) {
132     section.rcSection = m_pEdit->VTToEdit(section.rcSection);
133     return true;
134   }
135   return false;
136 }
137 
SetAt(int32_t nWordIndex)138 void CFX_Edit_Iterator::SetAt(int32_t nWordIndex) {
139   m_pVTIterator->SetAt(nWordIndex);
140 }
141 
SetAt(const CPVT_WordPlace & place)142 void CFX_Edit_Iterator::SetAt(const CPVT_WordPlace& place) {
143   m_pVTIterator->SetAt(place);
144 }
145 
GetAt() const146 const CPVT_WordPlace& CFX_Edit_Iterator::GetAt() const {
147   return m_pVTIterator->GetAt();
148 }
149 
CFX_Edit_Provider(IPVT_FontMap * pFontMap)150 CFX_Edit_Provider::CFX_Edit_Provider(IPVT_FontMap* pFontMap)
151     : CPDF_VariableText::Provider(pFontMap), m_pFontMap(pFontMap) {
152   ASSERT(m_pFontMap);
153 }
154 
~CFX_Edit_Provider()155 CFX_Edit_Provider::~CFX_Edit_Provider() {}
156 
GetFontMap()157 IPVT_FontMap* CFX_Edit_Provider::GetFontMap() {
158   return m_pFontMap;
159 }
160 
GetCharWidth(int32_t nFontIndex,uint16_t word)161 int32_t CFX_Edit_Provider::GetCharWidth(int32_t nFontIndex, uint16_t word) {
162   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
163     uint32_t charcode = word;
164 
165     if (pPDFFont->IsUnicodeCompatible())
166       charcode = pPDFFont->CharCodeFromUnicode(word);
167     else
168       charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
169 
170     if (charcode != CPDF_Font::kInvalidCharCode)
171       return pPDFFont->GetCharWidthF(charcode);
172   }
173 
174   return 0;
175 }
176 
GetTypeAscent(int32_t nFontIndex)177 int32_t CFX_Edit_Provider::GetTypeAscent(int32_t nFontIndex) {
178   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
179     return pPDFFont->GetTypeAscent();
180 
181   return 0;
182 }
183 
GetTypeDescent(int32_t nFontIndex)184 int32_t CFX_Edit_Provider::GetTypeDescent(int32_t nFontIndex) {
185   if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
186     return pPDFFont->GetTypeDescent();
187 
188   return 0;
189 }
190 
GetWordFontIndex(uint16_t word,int32_t charset,int32_t nFontIndex)191 int32_t CFX_Edit_Provider::GetWordFontIndex(uint16_t word,
192                                             int32_t charset,
193                                             int32_t nFontIndex) {
194   return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex);
195 }
196 
GetDefaultFontIndex()197 int32_t CFX_Edit_Provider::GetDefaultFontIndex() {
198   return 0;
199 }
200 
IsLatinWord(uint16_t word)201 bool CFX_Edit_Provider::IsLatinWord(uint16_t word) {
202   return FX_EDIT_ISLATINWORD(word);
203 }
204 
CFX_Edit_Refresh()205 CFX_Edit_Refresh::CFX_Edit_Refresh() {}
206 
~CFX_Edit_Refresh()207 CFX_Edit_Refresh::~CFX_Edit_Refresh() {}
208 
BeginRefresh()209 void CFX_Edit_Refresh::BeginRefresh() {
210   m_RefreshRects.Clear();
211   m_OldLineRects = std::move(m_NewLineRects);
212 }
213 
Push(const CPVT_WordRange & linerange,const CFX_FloatRect & rect)214 void CFX_Edit_Refresh::Push(const CPVT_WordRange& linerange,
215                             const CFX_FloatRect& rect) {
216   m_NewLineRects.Add(linerange, rect);
217 }
218 
NoAnalyse()219 void CFX_Edit_Refresh::NoAnalyse() {
220   {
221     for (int32_t i = 0, sz = m_OldLineRects.GetSize(); i < sz; i++)
222       if (CFX_Edit_LineRect* pOldRect = m_OldLineRects.GetAt(i))
223         m_RefreshRects.Add(pOldRect->m_rcLine);
224   }
225 
226   {
227     for (int32_t i = 0, sz = m_NewLineRects.GetSize(); i < sz; i++)
228       if (CFX_Edit_LineRect* pNewRect = m_NewLineRects.GetAt(i))
229         m_RefreshRects.Add(pNewRect->m_rcLine);
230   }
231 }
232 
AddRefresh(const CFX_FloatRect & rect)233 void CFX_Edit_Refresh::AddRefresh(const CFX_FloatRect& rect) {
234   m_RefreshRects.Add(rect);
235 }
236 
GetRefreshRects() const237 const CFX_Edit_RectArray* CFX_Edit_Refresh::GetRefreshRects() const {
238   return &m_RefreshRects;
239 }
240 
EndRefresh()241 void CFX_Edit_Refresh::EndRefresh() {
242   m_RefreshRects.Clear();
243 }
244 
CFX_Edit_Undo(int32_t nBufsize)245 CFX_Edit_Undo::CFX_Edit_Undo(int32_t nBufsize)
246     : m_nCurUndoPos(0),
247       m_nBufSize(nBufsize),
248       m_bModified(false),
249       m_bVirgin(true),
250       m_bWorking(false) {}
251 
~CFX_Edit_Undo()252 CFX_Edit_Undo::~CFX_Edit_Undo() {
253   Reset();
254 }
255 
CanUndo() const256 bool CFX_Edit_Undo::CanUndo() const {
257   return m_nCurUndoPos > 0;
258 }
259 
Undo()260 void CFX_Edit_Undo::Undo() {
261   m_bWorking = true;
262   if (m_nCurUndoPos > 0) {
263     m_UndoItemStack[m_nCurUndoPos - 1]->Undo();
264     m_nCurUndoPos--;
265     m_bModified = (m_nCurUndoPos != 0);
266   }
267   m_bWorking = false;
268 }
269 
CanRedo() const270 bool CFX_Edit_Undo::CanRedo() const {
271   return m_nCurUndoPos < m_UndoItemStack.size();
272 }
273 
Redo()274 void CFX_Edit_Undo::Redo() {
275   m_bWorking = true;
276   if (m_nCurUndoPos < m_UndoItemStack.size()) {
277     m_UndoItemStack[m_nCurUndoPos]->Redo();
278     m_nCurUndoPos++;
279     m_bModified = true;
280   }
281   m_bWorking = false;
282 }
283 
AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem)284 void CFX_Edit_Undo::AddItem(std::unique_ptr<IFX_Edit_UndoItem> pItem) {
285   ASSERT(!m_bWorking);
286   ASSERT(pItem);
287   ASSERT(m_nBufSize > 1);
288   if (m_nCurUndoPos < m_UndoItemStack.size())
289     RemoveTails();
290 
291   if (m_UndoItemStack.size() >= m_nBufSize) {
292     RemoveHeads();
293     m_bVirgin = false;
294   }
295 
296   m_UndoItemStack.push_back(std::move(pItem));
297   m_nCurUndoPos = m_UndoItemStack.size();
298   m_bModified = true;
299 }
300 
IsModified() const301 bool CFX_Edit_Undo::IsModified() const {
302   return m_bVirgin ? m_bModified : true;
303 }
304 
RemoveHeads()305 void CFX_Edit_Undo::RemoveHeads() {
306   ASSERT(m_UndoItemStack.size() > 1);
307   m_UndoItemStack.pop_front();
308 }
309 
RemoveTails()310 void CFX_Edit_Undo::RemoveTails() {
311   while (m_UndoItemStack.size() > m_nCurUndoPos)
312     m_UndoItemStack.pop_back();
313 }
314 
Reset()315 void CFX_Edit_Undo::Reset() {
316   m_UndoItemStack.clear();
317   m_nCurUndoPos = 0;
318 }
319 
CFX_Edit_UndoItem()320 CFX_Edit_UndoItem::CFX_Edit_UndoItem() : m_bFirst(true), m_bLast(true) {}
321 
~CFX_Edit_UndoItem()322 CFX_Edit_UndoItem::~CFX_Edit_UndoItem() {}
323 
GetUndoTitle() const324 CFX_WideString CFX_Edit_UndoItem::GetUndoTitle() const {
325   return CFX_WideString();
326 }
327 
SetFirst(bool bFirst)328 void CFX_Edit_UndoItem::SetFirst(bool bFirst) {
329   m_bFirst = bFirst;
330 }
331 
SetLast(bool bLast)332 void CFX_Edit_UndoItem::SetLast(bool bLast) {
333   m_bLast = bLast;
334 }
335 
IsLast()336 bool CFX_Edit_UndoItem::IsLast() {
337   return m_bLast;
338 }
339 
CFX_Edit_GroupUndoItem(const CFX_WideString & sTitle)340 CFX_Edit_GroupUndoItem::CFX_Edit_GroupUndoItem(const CFX_WideString& sTitle)
341     : m_sTitle(sTitle) {}
342 
~CFX_Edit_GroupUndoItem()343 CFX_Edit_GroupUndoItem::~CFX_Edit_GroupUndoItem() {}
344 
AddUndoItem(std::unique_ptr<CFX_Edit_UndoItem> pUndoItem)345 void CFX_Edit_GroupUndoItem::AddUndoItem(
346     std::unique_ptr<CFX_Edit_UndoItem> pUndoItem) {
347   pUndoItem->SetFirst(false);
348   pUndoItem->SetLast(false);
349   if (m_sTitle.IsEmpty())
350     m_sTitle = pUndoItem->GetUndoTitle();
351 
352   m_Items.push_back(std::move(pUndoItem));
353 }
354 
UpdateItems()355 void CFX_Edit_GroupUndoItem::UpdateItems() {
356   if (!m_Items.empty()) {
357     m_Items.front()->SetFirst(true);
358     m_Items.back()->SetLast(true);
359   }
360 }
361 
Undo()362 void CFX_Edit_GroupUndoItem::Undo() {
363   for (auto iter = m_Items.rbegin(); iter != m_Items.rend(); ++iter)
364     (*iter)->Undo();
365 }
366 
Redo()367 void CFX_Edit_GroupUndoItem::Redo() {
368   for (auto iter = m_Items.begin(); iter != m_Items.end(); ++iter)
369     (*iter)->Redo();
370 }
371 
GetUndoTitle() const372 CFX_WideString CFX_Edit_GroupUndoItem::GetUndoTitle() const {
373   return m_sTitle;
374 }
375 
CFXEU_InsertWord(CFX_Edit * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,int32_t charset,const CPVT_WordProps * pWordProps)376 CFXEU_InsertWord::CFXEU_InsertWord(CFX_Edit* pEdit,
377                                    const CPVT_WordPlace& wpOldPlace,
378                                    const CPVT_WordPlace& wpNewPlace,
379                                    uint16_t word,
380                                    int32_t charset,
381                                    const CPVT_WordProps* pWordProps)
382     : m_pEdit(pEdit),
383       m_wpOld(wpOldPlace),
384       m_wpNew(wpNewPlace),
385       m_Word(word),
386       m_nCharset(charset),
387       m_WordProps() {
388   if (pWordProps)
389     m_WordProps = *pWordProps;
390 }
391 
~CFXEU_InsertWord()392 CFXEU_InsertWord::~CFXEU_InsertWord() {}
393 
Redo()394 void CFXEU_InsertWord::Redo() {
395   if (m_pEdit) {
396     m_pEdit->SelectNone();
397     m_pEdit->SetCaret(m_wpOld);
398     m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
399   }
400 }
401 
Undo()402 void CFXEU_InsertWord::Undo() {
403   if (m_pEdit) {
404     m_pEdit->SelectNone();
405     m_pEdit->SetCaret(m_wpNew);
406     m_pEdit->Backspace(false, true);
407   }
408 }
409 
CFXEU_InsertReturn(CFX_Edit * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,const CPVT_SecProps * pSecProps,const CPVT_WordProps * pWordProps)410 CFXEU_InsertReturn::CFXEU_InsertReturn(CFX_Edit* pEdit,
411                                        const CPVT_WordPlace& wpOldPlace,
412                                        const CPVT_WordPlace& wpNewPlace,
413                                        const CPVT_SecProps* pSecProps,
414                                        const CPVT_WordProps* pWordProps)
415     : m_pEdit(pEdit),
416       m_wpOld(wpOldPlace),
417       m_wpNew(wpNewPlace),
418       m_SecProps(),
419       m_WordProps() {
420   if (pSecProps)
421     m_SecProps = *pSecProps;
422   if (pWordProps)
423     m_WordProps = *pWordProps;
424 }
425 
~CFXEU_InsertReturn()426 CFXEU_InsertReturn::~CFXEU_InsertReturn() {}
427 
Redo()428 void CFXEU_InsertReturn::Redo() {
429   if (m_pEdit) {
430     m_pEdit->SelectNone();
431     m_pEdit->SetCaret(m_wpOld);
432     m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
433   }
434 }
435 
Undo()436 void CFXEU_InsertReturn::Undo() {
437   if (m_pEdit) {
438     m_pEdit->SelectNone();
439     m_pEdit->SetCaret(m_wpNew);
440     m_pEdit->Backspace(false, true);
441   }
442 }
443 
CFXEU_Backspace(CFX_Edit * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,int32_t charset,const CPVT_SecProps & SecProps,const CPVT_WordProps & WordProps)444 CFXEU_Backspace::CFXEU_Backspace(CFX_Edit* pEdit,
445                                  const CPVT_WordPlace& wpOldPlace,
446                                  const CPVT_WordPlace& wpNewPlace,
447                                  uint16_t word,
448                                  int32_t charset,
449                                  const CPVT_SecProps& SecProps,
450                                  const CPVT_WordProps& WordProps)
451     : m_pEdit(pEdit),
452       m_wpOld(wpOldPlace),
453       m_wpNew(wpNewPlace),
454       m_Word(word),
455       m_nCharset(charset),
456       m_SecProps(SecProps),
457       m_WordProps(WordProps) {}
458 
~CFXEU_Backspace()459 CFXEU_Backspace::~CFXEU_Backspace() {}
460 
Redo()461 void CFXEU_Backspace::Redo() {
462   if (m_pEdit) {
463     m_pEdit->SelectNone();
464     m_pEdit->SetCaret(m_wpOld);
465     m_pEdit->Backspace(false, true);
466   }
467 }
468 
Undo()469 void CFXEU_Backspace::Undo() {
470   if (m_pEdit) {
471     m_pEdit->SelectNone();
472     m_pEdit->SetCaret(m_wpNew);
473     if (m_wpNew.SecCmp(m_wpOld) != 0) {
474       m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
475     } else {
476       m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
477     }
478   }
479 }
480 
CFXEU_Delete(CFX_Edit * 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)481 CFXEU_Delete::CFXEU_Delete(CFX_Edit* pEdit,
482                            const CPVT_WordPlace& wpOldPlace,
483                            const CPVT_WordPlace& wpNewPlace,
484                            uint16_t word,
485                            int32_t charset,
486                            const CPVT_SecProps& SecProps,
487                            const CPVT_WordProps& WordProps,
488                            bool bSecEnd)
489     : m_pEdit(pEdit),
490       m_wpOld(wpOldPlace),
491       m_wpNew(wpNewPlace),
492       m_Word(word),
493       m_nCharset(charset),
494       m_SecProps(SecProps),
495       m_WordProps(WordProps),
496       m_bSecEnd(bSecEnd) {}
497 
~CFXEU_Delete()498 CFXEU_Delete::~CFXEU_Delete() {}
499 
Redo()500 void CFXEU_Delete::Redo() {
501   if (m_pEdit) {
502     m_pEdit->SelectNone();
503     m_pEdit->SetCaret(m_wpOld);
504     m_pEdit->Delete(false, true);
505   }
506 }
507 
Undo()508 void CFXEU_Delete::Undo() {
509   if (m_pEdit) {
510     m_pEdit->SelectNone();
511     m_pEdit->SetCaret(m_wpNew);
512     if (m_bSecEnd) {
513       m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, false, true);
514     } else {
515       m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, false, true);
516     }
517   }
518 }
519 
CFXEU_Clear(CFX_Edit * pEdit,const CPVT_WordRange & wrSel,const CFX_WideString & swText)520 CFXEU_Clear::CFXEU_Clear(CFX_Edit* pEdit,
521                          const CPVT_WordRange& wrSel,
522                          const CFX_WideString& swText)
523     : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {}
524 
~CFXEU_Clear()525 CFXEU_Clear::~CFXEU_Clear() {}
526 
Redo()527 void CFXEU_Clear::Redo() {
528   if (m_pEdit) {
529     m_pEdit->SelectNone();
530     m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
531     m_pEdit->Clear(false, true);
532   }
533 }
534 
Undo()535 void CFXEU_Clear::Undo() {
536   if (m_pEdit) {
537     m_pEdit->SelectNone();
538     m_pEdit->SetCaret(m_wrSel.BeginPos);
539     m_pEdit->InsertText(m_swText, FXFONT_DEFAULT_CHARSET, false, true);
540     m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
541   }
542 }
543 
CFXEU_InsertText(CFX_Edit * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,const CFX_WideString & swText,int32_t charset)544 CFXEU_InsertText::CFXEU_InsertText(CFX_Edit* pEdit,
545                                    const CPVT_WordPlace& wpOldPlace,
546                                    const CPVT_WordPlace& wpNewPlace,
547                                    const CFX_WideString& swText,
548                                    int32_t charset)
549     : m_pEdit(pEdit),
550       m_wpOld(wpOldPlace),
551       m_wpNew(wpNewPlace),
552       m_swText(swText),
553       m_nCharset(charset) {}
554 
~CFXEU_InsertText()555 CFXEU_InsertText::~CFXEU_InsertText() {}
556 
Redo()557 void CFXEU_InsertText::Redo() {
558   if (m_pEdit && IsLast()) {
559     m_pEdit->SelectNone();
560     m_pEdit->SetCaret(m_wpOld);
561     m_pEdit->InsertText(m_swText, m_nCharset, false, true);
562   }
563 }
564 
Undo()565 void CFXEU_InsertText::Undo() {
566   if (m_pEdit) {
567     m_pEdit->SelectNone();
568     m_pEdit->SetSel(m_wpOld, m_wpNew);
569     m_pEdit->Clear(false, true);
570   }
571 }
572 
573 // static
GetEditAppearanceStream(CFX_Edit * pEdit,const CFX_PointF & ptOffset,const CPVT_WordRange * pRange,bool bContinuous,uint16_t SubWord)574 CFX_ByteString CFX_Edit::GetEditAppearanceStream(CFX_Edit* pEdit,
575                                                  const CFX_PointF& ptOffset,
576                                                  const CPVT_WordRange* pRange,
577                                                  bool bContinuous,
578                                                  uint16_t SubWord) {
579   CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
580   if (pRange)
581     pIterator->SetAt(pRange->BeginPos);
582   else
583     pIterator->SetAt(0);
584 
585   CFX_ByteTextBuf sEditStream;
586   CFX_ByteTextBuf sWords;
587   int32_t nCurFontIndex = -1;
588   CFX_PointF ptOld;
589   CFX_PointF ptNew;
590   CPVT_WordPlace oldplace;
591 
592   while (pIterator->NextWord()) {
593     CPVT_WordPlace place = pIterator->GetAt();
594     if (pRange && place.WordCmp(pRange->EndPos) > 0)
595       break;
596 
597     if (bContinuous) {
598       if (place.LineCmp(oldplace) != 0) {
599         if (sWords.GetSize() > 0) {
600           sEditStream << GetWordRenderString(sWords.MakeString());
601           sWords.Clear();
602         }
603 
604         CPVT_Word word;
605         if (pIterator->GetWord(word)) {
606           ptNew = CFX_PointF(word.ptWord.x + ptOffset.x,
607                              word.ptWord.y + ptOffset.y);
608         } else {
609           CPVT_Line line;
610           pIterator->GetLine(line);
611           ptNew = CFX_PointF(line.ptLine.x + ptOffset.x,
612                              line.ptLine.y + ptOffset.y);
613         }
614 
615         if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
616           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
617                       << " Td\n";
618 
619           ptOld = ptNew;
620         }
621       }
622 
623       CPVT_Word word;
624       if (pIterator->GetWord(word)) {
625         if (word.nFontIndex != nCurFontIndex) {
626           if (sWords.GetSize() > 0) {
627             sEditStream << GetWordRenderString(sWords.MakeString());
628             sWords.Clear();
629           }
630           sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
631                                           word.fFontSize);
632           nCurFontIndex = word.nFontIndex;
633         }
634 
635         sWords << GetPDFWordString(pEdit->GetFontMap(), nCurFontIndex,
636                                    word.Word, SubWord);
637       }
638 
639       oldplace = place;
640     } else {
641       CPVT_Word word;
642       if (pIterator->GetWord(word)) {
643         ptNew =
644             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y);
645 
646         if (ptNew.x != ptOld.x || ptNew.y != ptOld.y) {
647           sEditStream << ptNew.x - ptOld.x << " " << ptNew.y - ptOld.y
648                       << " Td\n";
649           ptOld = ptNew;
650         }
651 
652         if (word.nFontIndex != nCurFontIndex) {
653           sEditStream << GetFontSetString(pEdit->GetFontMap(), word.nFontIndex,
654                                           word.fFontSize);
655           nCurFontIndex = word.nFontIndex;
656         }
657 
658         sEditStream << GetWordRenderString(GetPDFWordString(
659             pEdit->GetFontMap(), nCurFontIndex, word.Word, SubWord));
660       }
661     }
662   }
663 
664   if (sWords.GetSize() > 0) {
665     sEditStream << GetWordRenderString(sWords.MakeString());
666     sWords.Clear();
667   }
668 
669   CFX_ByteTextBuf sAppStream;
670   if (sEditStream.GetSize() > 0) {
671     int32_t nHorzScale = pEdit->GetHorzScale();
672     if (nHorzScale != 100) {
673       sAppStream << nHorzScale << " Tz\n";
674     }
675 
676     FX_FLOAT fCharSpace = pEdit->GetCharSpace();
677     if (!IsFloatZero(fCharSpace)) {
678       sAppStream << fCharSpace << " Tc\n";
679     }
680 
681     sAppStream << sEditStream;
682   }
683 
684   return sAppStream.MakeString();
685 }
686 
687 // static
GetSelectAppearanceStream(CFX_Edit * pEdit,const CFX_PointF & ptOffset,const CPVT_WordRange * pRange)688 CFX_ByteString CFX_Edit::GetSelectAppearanceStream(
689     CFX_Edit* pEdit,
690     const CFX_PointF& ptOffset,
691     const CPVT_WordRange* pRange) {
692   if (!pRange || !pRange->IsExist())
693     return CFX_ByteString();
694 
695   CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
696   pIterator->SetAt(pRange->BeginPos);
697 
698   CFX_ByteTextBuf sRet;
699   while (pIterator->NextWord()) {
700     CPVT_WordPlace place = pIterator->GetAt();
701     if (place.WordCmp(pRange->EndPos) > 0)
702       break;
703 
704     CPVT_Word word;
705     CPVT_Line line;
706     if (pIterator->GetWord(word) && pIterator->GetLine(line)) {
707       sRet << word.ptWord.x + ptOffset.x << " "
708            << line.ptLine.y + line.fLineDescent << " " << word.fWidth << " "
709            << line.fLineAscent - line.fLineDescent << " re\nf\n";
710     }
711   }
712 
713   return sRet.MakeString();
714 }
715 
716 // static
DrawEdit(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device,CFX_Edit * pEdit,FX_COLORREF crTextFill,const CFX_FloatRect & rcClip,const CFX_PointF & ptOffset,const CPVT_WordRange * pRange,CFX_SystemHandler * pSystemHandler,CFFL_FormFiller * pFFLData)717 void CFX_Edit::DrawEdit(CFX_RenderDevice* pDevice,
718                         CFX_Matrix* pUser2Device,
719                         CFX_Edit* pEdit,
720                         FX_COLORREF crTextFill,
721                         const CFX_FloatRect& rcClip,
722                         const CFX_PointF& ptOffset,
723                         const CPVT_WordRange* pRange,
724                         CFX_SystemHandler* pSystemHandler,
725                         CFFL_FormFiller* pFFLData) {
726   const bool bContinuous =
727       pEdit->GetCharArray() == 0 && pEdit->GetCharSpace() <= 0.0f;
728   uint16_t SubWord = pEdit->GetPasswordChar();
729   FX_FLOAT fFontSize = pEdit->GetFontSize();
730   CPVT_WordRange wrSelect = pEdit->GetSelectWordRange();
731   int32_t nHorzScale = pEdit->GetHorzScale();
732 
733   FX_COLORREF crCurFill = crTextFill;
734   FX_COLORREF crOldFill = crCurFill;
735 
736   bool bSelect = false;
737   const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255);
738   const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113);
739 
740   CFX_ByteTextBuf sTextBuf;
741   int32_t nFontIndex = -1;
742   CFX_PointF ptBT;
743   pDevice->SaveState();
744   if (!rcClip.IsEmpty()) {
745     CFX_FloatRect rcTemp = rcClip;
746     pUser2Device->TransformRect(rcTemp);
747     pDevice->SetClip_Rect(rcTemp.ToFxRect());
748   }
749 
750   CFX_Edit_Iterator* pIterator = pEdit->GetIterator();
751   if (IPVT_FontMap* pFontMap = pEdit->GetFontMap()) {
752     if (pRange)
753       pIterator->SetAt(pRange->BeginPos);
754     else
755       pIterator->SetAt(0);
756 
757     CPVT_WordPlace oldplace;
758     while (pIterator->NextWord()) {
759       CPVT_WordPlace place = pIterator->GetAt();
760       if (pRange && place.WordCmp(pRange->EndPos) > 0)
761         break;
762 
763       if (wrSelect.IsExist()) {
764         bSelect = place.WordCmp(wrSelect.BeginPos) > 0 &&
765                   place.WordCmp(wrSelect.EndPos) <= 0;
766         crCurFill = bSelect ? crWhite : crTextFill;
767       }
768       if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
769         crCurFill = crTextFill;
770         crOldFill = crCurFill;
771       }
772       CPVT_Word word;
773       if (pIterator->GetWord(word)) {
774         if (bSelect) {
775           CPVT_Line line;
776           pIterator->GetLine(line);
777 
778           if (pSystemHandler && pSystemHandler->IsSelectionImplemented()) {
779             CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent,
780                              word.ptWord.x + word.fWidth,
781                              line.ptLine.y + line.fLineAscent);
782             rc.Intersect(rcClip);
783             pSystemHandler->OutputSelectedRect(pFFLData, rc);
784           } else {
785             CFX_PathData pathSelBK;
786             pathSelBK.AppendRect(
787                 word.ptWord.x, line.ptLine.y + line.fLineDescent,
788                 word.ptWord.x + word.fWidth, line.ptLine.y + line.fLineAscent);
789 
790             pDevice->DrawPath(&pathSelBK, pUser2Device, nullptr, crSelBK, 0,
791                               FXFILL_WINDING);
792           }
793         }
794 
795         if (bContinuous) {
796           if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex ||
797               crOldFill != crCurFill) {
798             if (sTextBuf.GetLength() > 0) {
799               DrawTextString(
800                   pDevice, CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
801                   pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
802                   sTextBuf.MakeString(), crOldFill, nHorzScale);
803 
804               sTextBuf.Clear();
805             }
806             nFontIndex = word.nFontIndex;
807             ptBT = word.ptWord;
808             crOldFill = crCurFill;
809           }
810 
811           sTextBuf << GetPDFWordString(pFontMap, word.nFontIndex, word.Word,
812                                        SubWord)
813                           .AsStringC();
814         } else {
815           DrawTextString(
816               pDevice, CFX_PointF(word.ptWord.x + ptOffset.x,
817                                   word.ptWord.y + ptOffset.y),
818               pFontMap->GetPDFFont(word.nFontIndex), fFontSize, pUser2Device,
819               GetPDFWordString(pFontMap, word.nFontIndex, word.Word, SubWord),
820               crCurFill, nHorzScale);
821         }
822         oldplace = place;
823       }
824     }
825 
826     if (sTextBuf.GetLength() > 0) {
827       DrawTextString(pDevice,
828                      CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
829                      pFontMap->GetPDFFont(nFontIndex), fFontSize, pUser2Device,
830                      sTextBuf.MakeString(), crOldFill, nHorzScale);
831     }
832   }
833 
834   pDevice->RestoreState(false);
835 }
836 
CFX_Edit()837 CFX_Edit::CFX_Edit()
838     : m_pVT(new CPDF_VariableText),
839       m_pNotify(nullptr),
840       m_pOprNotify(nullptr),
841       m_wpCaret(-1, -1, -1),
842       m_wpOldCaret(-1, -1, -1),
843       m_SelState(),
844       m_bEnableScroll(false),
845       m_Undo(kEditUndoMaxItems),
846       m_nAlignment(0),
847       m_bNotifyFlag(false),
848       m_bEnableOverflow(false),
849       m_bEnableRefresh(true),
850       m_rcOldContent(0.0f, 0.0f, 0.0f, 0.0f),
851       m_bEnableUndo(true),
852       m_bOprNotify(false),
853       m_pGroupUndoItem(nullptr) {}
854 
~CFX_Edit()855 CFX_Edit::~CFX_Edit() {
856   ASSERT(!m_pGroupUndoItem);
857 }
858 
Initialize()859 void CFX_Edit::Initialize() {
860   m_pVT->Initialize();
861   SetCaret(m_pVT->GetBeginWordPlace());
862   SetCaretOrigin();
863 }
864 
SetFontMap(IPVT_FontMap * pFontMap)865 void CFX_Edit::SetFontMap(IPVT_FontMap* pFontMap) {
866   m_pVTProvider = pdfium::MakeUnique<CFX_Edit_Provider>(pFontMap);
867   m_pVT->SetProvider(m_pVTProvider.get());
868 }
869 
SetNotify(CPWL_EditCtrl * pNotify)870 void CFX_Edit::SetNotify(CPWL_EditCtrl* pNotify) {
871   m_pNotify = pNotify;
872 }
873 
SetOprNotify(CPWL_Edit * pOprNotify)874 void CFX_Edit::SetOprNotify(CPWL_Edit* pOprNotify) {
875   m_pOprNotify = pOprNotify;
876 }
877 
GetIterator()878 CFX_Edit_Iterator* CFX_Edit::GetIterator() {
879   if (!m_pIterator) {
880     m_pIterator =
881         pdfium::MakeUnique<CFX_Edit_Iterator>(this, m_pVT->GetIterator());
882   }
883   return m_pIterator.get();
884 }
885 
GetFontMap()886 IPVT_FontMap* CFX_Edit::GetFontMap() {
887   return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr;
888 }
889 
SetPlateRect(const CFX_FloatRect & rect)890 void CFX_Edit::SetPlateRect(const CFX_FloatRect& rect) {
891   m_pVT->SetPlateRect(rect);
892   m_ptScrollPos = CFX_PointF(rect.left, rect.top);
893   Paint();
894 }
895 
SetAlignmentH(int32_t nFormat,bool bPaint)896 void CFX_Edit::SetAlignmentH(int32_t nFormat, bool bPaint) {
897   m_pVT->SetAlignment(nFormat);
898   if (bPaint)
899     Paint();
900 }
901 
SetAlignmentV(int32_t nFormat,bool bPaint)902 void CFX_Edit::SetAlignmentV(int32_t nFormat, bool bPaint) {
903   m_nAlignment = nFormat;
904   if (bPaint)
905     Paint();
906 }
907 
SetPasswordChar(uint16_t wSubWord,bool bPaint)908 void CFX_Edit::SetPasswordChar(uint16_t wSubWord, bool bPaint) {
909   m_pVT->SetPasswordChar(wSubWord);
910   if (bPaint)
911     Paint();
912 }
913 
SetLimitChar(int32_t nLimitChar)914 void CFX_Edit::SetLimitChar(int32_t nLimitChar) {
915   m_pVT->SetLimitChar(nLimitChar);
916   Paint();
917 }
918 
SetCharArray(int32_t nCharArray)919 void CFX_Edit::SetCharArray(int32_t nCharArray) {
920   m_pVT->SetCharArray(nCharArray);
921   Paint();
922 }
923 
SetCharSpace(FX_FLOAT fCharSpace)924 void CFX_Edit::SetCharSpace(FX_FLOAT fCharSpace) {
925   m_pVT->SetCharSpace(fCharSpace);
926   Paint();
927 }
928 
SetMultiLine(bool bMultiLine,bool bPaint)929 void CFX_Edit::SetMultiLine(bool bMultiLine, bool bPaint) {
930   m_pVT->SetMultiLine(bMultiLine);
931   if (bPaint)
932     Paint();
933 }
934 
SetAutoReturn(bool bAuto,bool bPaint)935 void CFX_Edit::SetAutoReturn(bool bAuto, bool bPaint) {
936   m_pVT->SetAutoReturn(bAuto);
937   if (bPaint)
938     Paint();
939 }
940 
SetAutoFontSize(bool bAuto,bool bPaint)941 void CFX_Edit::SetAutoFontSize(bool bAuto, bool bPaint) {
942   m_pVT->SetAutoFontSize(bAuto);
943   if (bPaint)
944     Paint();
945 }
946 
SetFontSize(FX_FLOAT fFontSize)947 void CFX_Edit::SetFontSize(FX_FLOAT fFontSize) {
948   m_pVT->SetFontSize(fFontSize);
949   Paint();
950 }
951 
SetAutoScroll(bool bAuto,bool bPaint)952 void CFX_Edit::SetAutoScroll(bool bAuto, bool bPaint) {
953   m_bEnableScroll = bAuto;
954   if (bPaint)
955     Paint();
956 }
957 
SetTextOverflow(bool bAllowed,bool bPaint)958 void CFX_Edit::SetTextOverflow(bool bAllowed, bool bPaint) {
959   m_bEnableOverflow = bAllowed;
960   if (bPaint)
961     Paint();
962 }
963 
SetSel(int32_t nStartChar,int32_t nEndChar)964 void CFX_Edit::SetSel(int32_t nStartChar, int32_t nEndChar) {
965   if (m_pVT->IsValid()) {
966     if (nStartChar == 0 && nEndChar < 0) {
967       SelectAll();
968     } else if (nStartChar < 0) {
969       SelectNone();
970     } else {
971       if (nStartChar < nEndChar) {
972         SetSel(m_pVT->WordIndexToWordPlace(nStartChar),
973                m_pVT->WordIndexToWordPlace(nEndChar));
974       } else {
975         SetSel(m_pVT->WordIndexToWordPlace(nEndChar),
976                m_pVT->WordIndexToWordPlace(nStartChar));
977       }
978     }
979   }
980 }
981 
SetSel(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)982 void CFX_Edit::SetSel(const CPVT_WordPlace& begin, const CPVT_WordPlace& end) {
983   if (m_pVT->IsValid()) {
984     SelectNone();
985 
986     m_SelState.Set(begin, end);
987 
988     SetCaret(m_SelState.EndPos);
989 
990     if (m_SelState.IsExist()) {
991       ScrollToCaret();
992       Refresh();
993       SetCaretInfo();
994     } else {
995       ScrollToCaret();
996       SetCaretInfo();
997     }
998   }
999 }
1000 
GetSel(int32_t & nStartChar,int32_t & nEndChar) const1001 void CFX_Edit::GetSel(int32_t& nStartChar, int32_t& nEndChar) const {
1002   nStartChar = -1;
1003   nEndChar = -1;
1004 
1005   if (m_pVT->IsValid()) {
1006     if (m_SelState.IsExist()) {
1007       if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0) {
1008         nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
1009         nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
1010       } else {
1011         nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
1012         nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
1013       }
1014     } else {
1015       nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
1016       nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
1017     }
1018   }
1019 }
1020 
GetCaret() const1021 int32_t CFX_Edit::GetCaret() const {
1022   if (m_pVT->IsValid())
1023     return m_pVT->WordPlaceToWordIndex(m_wpCaret);
1024 
1025   return -1;
1026 }
1027 
GetCaretWordPlace() const1028 CPVT_WordPlace CFX_Edit::GetCaretWordPlace() const {
1029   return m_wpCaret;
1030 }
1031 
GetText() const1032 CFX_WideString CFX_Edit::GetText() const {
1033   CFX_WideString swRet;
1034 
1035   if (!m_pVT->IsValid())
1036     return swRet;
1037 
1038   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1039   pIterator->SetAt(0);
1040 
1041   CPVT_Word wordinfo;
1042   CPVT_WordPlace oldplace = pIterator->GetAt();
1043   while (pIterator->NextWord()) {
1044     CPVT_WordPlace place = pIterator->GetAt();
1045 
1046     if (pIterator->GetWord(wordinfo))
1047       swRet += wordinfo.Word;
1048 
1049     if (oldplace.SecCmp(place) != 0)
1050       swRet += L"\r\n";
1051 
1052     oldplace = place;
1053   }
1054 
1055   return swRet;
1056 }
1057 
GetRangeText(const CPVT_WordRange & range) const1058 CFX_WideString CFX_Edit::GetRangeText(const CPVT_WordRange& range) const {
1059   CFX_WideString swRet;
1060 
1061   if (!m_pVT->IsValid())
1062     return swRet;
1063 
1064   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1065   CPVT_WordRange wrTemp = range;
1066   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1067   m_pVT->UpdateWordPlace(wrTemp.EndPos);
1068   pIterator->SetAt(wrTemp.BeginPos);
1069 
1070   CPVT_Word wordinfo;
1071   CPVT_WordPlace oldplace = wrTemp.BeginPos;
1072   while (pIterator->NextWord()) {
1073     CPVT_WordPlace place = pIterator->GetAt();
1074     if (place.WordCmp(wrTemp.EndPos) > 0)
1075       break;
1076 
1077     if (pIterator->GetWord(wordinfo))
1078       swRet += wordinfo.Word;
1079 
1080     if (oldplace.SecCmp(place) != 0)
1081       swRet += L"\r\n";
1082 
1083     oldplace = place;
1084   }
1085 
1086   return swRet;
1087 }
1088 
GetSelText() const1089 CFX_WideString CFX_Edit::GetSelText() const {
1090   return GetRangeText(m_SelState.ConvertToWordRange());
1091 }
1092 
GetTotalWords() const1093 int32_t CFX_Edit::GetTotalWords() const {
1094   return m_pVT->GetTotalWords();
1095 }
1096 
GetTotalLines() const1097 int32_t CFX_Edit::GetTotalLines() const {
1098   int32_t nLines = 1;
1099 
1100   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1101   pIterator->SetAt(0);
1102   while (pIterator->NextLine())
1103     ++nLines;
1104 
1105   return nLines;
1106 }
1107 
GetSelectWordRange() const1108 CPVT_WordRange CFX_Edit::GetSelectWordRange() const {
1109   return m_SelState.ConvertToWordRange();
1110 }
1111 
SetText(const CFX_WideString & sText)1112 void CFX_Edit::SetText(const CFX_WideString& sText) {
1113   Empty();
1114   DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FXFONT_DEFAULT_CHARSET);
1115   Paint();
1116 }
1117 
InsertWord(uint16_t word,int32_t charset)1118 bool CFX_Edit::InsertWord(uint16_t word, int32_t charset) {
1119   return InsertWord(word, charset, nullptr, true, true);
1120 }
1121 
InsertReturn()1122 bool CFX_Edit::InsertReturn() {
1123   return InsertReturn(nullptr, nullptr, true, true);
1124 }
1125 
Backspace()1126 bool CFX_Edit::Backspace() {
1127   return Backspace(true, true);
1128 }
1129 
Delete()1130 bool CFX_Edit::Delete() {
1131   return Delete(true, true);
1132 }
1133 
Clear()1134 bool CFX_Edit::Clear() {
1135   return Clear(true, true);
1136 }
1137 
InsertText(const CFX_WideString & sText,int32_t charset)1138 bool CFX_Edit::InsertText(const CFX_WideString& sText, int32_t charset) {
1139   return InsertText(sText, charset, true, true);
1140 }
1141 
GetFontSize() const1142 FX_FLOAT CFX_Edit::GetFontSize() const {
1143   return m_pVT->GetFontSize();
1144 }
1145 
GetPasswordChar() const1146 uint16_t CFX_Edit::GetPasswordChar() const {
1147   return m_pVT->GetPasswordChar();
1148 }
1149 
GetCharArray() const1150 int32_t CFX_Edit::GetCharArray() const {
1151   return m_pVT->GetCharArray();
1152 }
1153 
GetContentRect() const1154 CFX_FloatRect CFX_Edit::GetContentRect() const {
1155   return VTToEdit(m_pVT->GetContentRect());
1156 }
1157 
GetHorzScale() const1158 int32_t CFX_Edit::GetHorzScale() const {
1159   return m_pVT->GetHorzScale();
1160 }
1161 
GetCharSpace() const1162 FX_FLOAT CFX_Edit::GetCharSpace() const {
1163   return m_pVT->GetCharSpace();
1164 }
1165 
GetWholeWordRange() const1166 CPVT_WordRange CFX_Edit::GetWholeWordRange() const {
1167   if (m_pVT->IsValid())
1168     return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
1169 
1170   return CPVT_WordRange();
1171 }
1172 
GetVisibleWordRange() const1173 CPVT_WordRange CFX_Edit::GetVisibleWordRange() const {
1174   if (m_bEnableOverflow)
1175     return GetWholeWordRange();
1176 
1177   if (m_pVT->IsValid()) {
1178     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1179 
1180     CPVT_WordPlace place1 =
1181         m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
1182     CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
1183         EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
1184 
1185     return CPVT_WordRange(place1, place2);
1186   }
1187 
1188   return CPVT_WordRange();
1189 }
1190 
SearchWordPlace(const CFX_PointF & point) const1191 CPVT_WordPlace CFX_Edit::SearchWordPlace(const CFX_PointF& point) const {
1192   if (m_pVT->IsValid()) {
1193     return m_pVT->SearchWordPlace(EditToVT(point));
1194   }
1195 
1196   return CPVT_WordPlace();
1197 }
1198 
Paint()1199 void CFX_Edit::Paint() {
1200   if (m_pVT->IsValid()) {
1201     RearrangeAll();
1202     ScrollToCaret();
1203     Refresh();
1204     SetCaretOrigin();
1205     SetCaretInfo();
1206   }
1207 }
1208 
RearrangeAll()1209 void CFX_Edit::RearrangeAll() {
1210   if (m_pVT->IsValid()) {
1211     m_pVT->UpdateWordPlace(m_wpCaret);
1212     m_pVT->RearrangeAll();
1213     m_pVT->UpdateWordPlace(m_wpCaret);
1214     SetScrollInfo();
1215     SetContentChanged();
1216   }
1217 }
1218 
RearrangePart(const CPVT_WordRange & range)1219 void CFX_Edit::RearrangePart(const CPVT_WordRange& range) {
1220   if (m_pVT->IsValid()) {
1221     m_pVT->UpdateWordPlace(m_wpCaret);
1222     m_pVT->RearrangePart(range);
1223     m_pVT->UpdateWordPlace(m_wpCaret);
1224     SetScrollInfo();
1225     SetContentChanged();
1226   }
1227 }
1228 
SetContentChanged()1229 void CFX_Edit::SetContentChanged() {
1230   if (m_pNotify) {
1231     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1232     if (rcContent.Width() != m_rcOldContent.Width() ||
1233         rcContent.Height() != m_rcOldContent.Height()) {
1234       if (!m_bNotifyFlag) {
1235         m_bNotifyFlag = true;
1236         m_pNotify->IOnContentChange(rcContent);
1237         m_bNotifyFlag = false;
1238       }
1239       m_rcOldContent = rcContent;
1240     }
1241   }
1242 }
1243 
SelectAll()1244 void CFX_Edit::SelectAll() {
1245   if (m_pVT->IsValid()) {
1246     m_SelState = CFX_Edit_Select(GetWholeWordRange());
1247     SetCaret(m_SelState.EndPos);
1248 
1249     ScrollToCaret();
1250     Refresh();
1251     SetCaretInfo();
1252   }
1253 }
1254 
SelectNone()1255 void CFX_Edit::SelectNone() {
1256   if (m_pVT->IsValid()) {
1257     if (m_SelState.IsExist()) {
1258       m_SelState.Default();
1259       Refresh();
1260     }
1261   }
1262 }
1263 
IsSelected() const1264 bool CFX_Edit::IsSelected() const {
1265   return m_SelState.IsExist();
1266 }
1267 
VTToEdit(const CFX_PointF & point) const1268 CFX_PointF CFX_Edit::VTToEdit(const CFX_PointF& point) const {
1269   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1270   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1271 
1272   FX_FLOAT fPadding = 0.0f;
1273 
1274   switch (m_nAlignment) {
1275     case 0:
1276       fPadding = 0.0f;
1277       break;
1278     case 1:
1279       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1280       break;
1281     case 2:
1282       fPadding = rcPlate.Height() - rcContent.Height();
1283       break;
1284   }
1285 
1286   return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
1287                     point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
1288 }
1289 
EditToVT(const CFX_PointF & point) const1290 CFX_PointF CFX_Edit::EditToVT(const CFX_PointF& point) const {
1291   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1292   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1293 
1294   FX_FLOAT fPadding = 0.0f;
1295 
1296   switch (m_nAlignment) {
1297     case 0:
1298       fPadding = 0.0f;
1299       break;
1300     case 1:
1301       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1302       break;
1303     case 2:
1304       fPadding = rcPlate.Height() - rcContent.Height();
1305       break;
1306   }
1307 
1308   return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
1309                     point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
1310 }
1311 
VTToEdit(const CFX_FloatRect & rect) const1312 CFX_FloatRect CFX_Edit::VTToEdit(const CFX_FloatRect& rect) const {
1313   CFX_PointF ptLeftBottom = VTToEdit(CFX_PointF(rect.left, rect.bottom));
1314   CFX_PointF ptRightTop = VTToEdit(CFX_PointF(rect.right, rect.top));
1315 
1316   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
1317                        ptRightTop.y);
1318 }
1319 
SetScrollInfo()1320 void CFX_Edit::SetScrollInfo() {
1321   if (m_pNotify) {
1322     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1323     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1324 
1325     if (!m_bNotifyFlag) {
1326       m_bNotifyFlag = true;
1327       m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
1328                                    rcContent.bottom, rcContent.top,
1329                                    rcPlate.Height() / 3, rcPlate.Height());
1330       m_bNotifyFlag = false;
1331     }
1332   }
1333 }
1334 
SetScrollPosX(FX_FLOAT fx)1335 void CFX_Edit::SetScrollPosX(FX_FLOAT fx) {
1336   if (!m_bEnableScroll)
1337     return;
1338 
1339   if (m_pVT->IsValid()) {
1340     if (!IsFloatEqual(m_ptScrollPos.x, fx)) {
1341       m_ptScrollPos.x = fx;
1342       Refresh();
1343     }
1344   }
1345 }
1346 
SetScrollPosY(FX_FLOAT fy)1347 void CFX_Edit::SetScrollPosY(FX_FLOAT fy) {
1348   if (!m_bEnableScroll)
1349     return;
1350 
1351   if (m_pVT->IsValid()) {
1352     if (!IsFloatEqual(m_ptScrollPos.y, fy)) {
1353       m_ptScrollPos.y = fy;
1354       Refresh();
1355 
1356       if (m_pNotify) {
1357         if (!m_bNotifyFlag) {
1358           m_bNotifyFlag = true;
1359           m_pNotify->IOnSetScrollPosY(fy);
1360           m_bNotifyFlag = false;
1361         }
1362       }
1363     }
1364   }
1365 }
1366 
SetScrollPos(const CFX_PointF & point)1367 void CFX_Edit::SetScrollPos(const CFX_PointF& point) {
1368   SetScrollPosX(point.x);
1369   SetScrollPosY(point.y);
1370   SetScrollLimit();
1371   SetCaretInfo();
1372 }
1373 
GetScrollPos() const1374 CFX_PointF CFX_Edit::GetScrollPos() const {
1375   return m_ptScrollPos;
1376 }
1377 
SetScrollLimit()1378 void CFX_Edit::SetScrollLimit() {
1379   if (m_pVT->IsValid()) {
1380     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1381     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1382 
1383     if (rcPlate.Width() > rcContent.Width()) {
1384       SetScrollPosX(rcPlate.left);
1385     } else {
1386       if (IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
1387         SetScrollPosX(rcContent.left);
1388       } else if (IsFloatBigger(m_ptScrollPos.x,
1389                                rcContent.right - rcPlate.Width())) {
1390         SetScrollPosX(rcContent.right - rcPlate.Width());
1391       }
1392     }
1393 
1394     if (rcPlate.Height() > rcContent.Height()) {
1395       SetScrollPosY(rcPlate.top);
1396     } else {
1397       if (IsFloatSmaller(m_ptScrollPos.y,
1398                          rcContent.bottom + rcPlate.Height())) {
1399         SetScrollPosY(rcContent.bottom + rcPlate.Height());
1400       } else if (IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
1401         SetScrollPosY(rcContent.top);
1402       }
1403     }
1404   }
1405 }
1406 
ScrollToCaret()1407 void CFX_Edit::ScrollToCaret() {
1408   SetScrollLimit();
1409 
1410   if (!m_pVT->IsValid())
1411     return;
1412 
1413   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1414   pIterator->SetAt(m_wpCaret);
1415 
1416   CFX_PointF ptHead;
1417   CFX_PointF ptFoot;
1418   CPVT_Word word;
1419   CPVT_Line line;
1420   if (pIterator->GetWord(word)) {
1421     ptHead.x = word.ptWord.x + word.fWidth;
1422     ptHead.y = word.ptWord.y + word.fAscent;
1423     ptFoot.x = word.ptWord.x + word.fWidth;
1424     ptFoot.y = word.ptWord.y + word.fDescent;
1425   } else if (pIterator->GetLine(line)) {
1426     ptHead.x = line.ptLine.x;
1427     ptHead.y = line.ptLine.y + line.fLineAscent;
1428     ptFoot.x = line.ptLine.x;
1429     ptFoot.y = line.ptLine.y + line.fLineDescent;
1430   }
1431 
1432   CFX_PointF ptHeadEdit = VTToEdit(ptHead);
1433   CFX_PointF ptFootEdit = VTToEdit(ptFoot);
1434   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1435   if (!IsFloatEqual(rcPlate.left, rcPlate.right)) {
1436     if (IsFloatSmaller(ptHeadEdit.x, rcPlate.left) ||
1437         IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
1438       SetScrollPosX(ptHead.x);
1439     } else if (IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
1440       SetScrollPosX(ptHead.x - rcPlate.Width());
1441     }
1442   }
1443 
1444   if (!IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
1445     if (IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
1446         IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
1447       if (IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
1448         SetScrollPosY(ptFoot.y + rcPlate.Height());
1449       }
1450     } else if (IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
1451       if (IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
1452         SetScrollPosY(ptHead.y);
1453       }
1454     }
1455   }
1456 }
1457 
Refresh()1458 void CFX_Edit::Refresh() {
1459   if (m_bEnableRefresh && m_pVT->IsValid()) {
1460     m_Refresh.BeginRefresh();
1461     RefreshPushLineRects(GetVisibleWordRange());
1462 
1463     m_Refresh.NoAnalyse();
1464     m_ptRefreshScrollPos = m_ptScrollPos;
1465 
1466     if (m_pNotify) {
1467       if (!m_bNotifyFlag) {
1468         m_bNotifyFlag = true;
1469         if (const CFX_Edit_RectArray* pRects = m_Refresh.GetRefreshRects()) {
1470           for (int32_t i = 0, sz = pRects->GetSize(); i < sz; i++)
1471             m_pNotify->IOnInvalidateRect(pRects->GetAt(i));
1472         }
1473         m_bNotifyFlag = false;
1474       }
1475     }
1476 
1477     m_Refresh.EndRefresh();
1478   }
1479 }
1480 
RefreshPushLineRects(const CPVT_WordRange & wr)1481 void CFX_Edit::RefreshPushLineRects(const CPVT_WordRange& wr) {
1482   if (!m_pVT->IsValid())
1483     return;
1484 
1485   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1486   CPVT_WordPlace wpBegin = wr.BeginPos;
1487   m_pVT->UpdateWordPlace(wpBegin);
1488   CPVT_WordPlace wpEnd = wr.EndPos;
1489   m_pVT->UpdateWordPlace(wpEnd);
1490   pIterator->SetAt(wpBegin);
1491 
1492   CPVT_Line lineinfo;
1493   do {
1494     if (!pIterator->GetLine(lineinfo))
1495       break;
1496     if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
1497       break;
1498 
1499     CFX_FloatRect rcLine(lineinfo.ptLine.x,
1500                          lineinfo.ptLine.y + lineinfo.fLineDescent,
1501                          lineinfo.ptLine.x + lineinfo.fLineWidth,
1502                          lineinfo.ptLine.y + lineinfo.fLineAscent);
1503 
1504     m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
1505                    VTToEdit(rcLine));
1506   } while (pIterator->NextLine());
1507 }
1508 
RefreshWordRange(const CPVT_WordRange & wr)1509 void CFX_Edit::RefreshWordRange(const CPVT_WordRange& wr) {
1510   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1511   CPVT_WordRange wrTemp = wr;
1512 
1513   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1514   m_pVT->UpdateWordPlace(wrTemp.EndPos);
1515   pIterator->SetAt(wrTemp.BeginPos);
1516 
1517   CPVT_Word wordinfo;
1518   CPVT_Line lineinfo;
1519   CPVT_WordPlace place;
1520 
1521   while (pIterator->NextWord()) {
1522     place = pIterator->GetAt();
1523     if (place.WordCmp(wrTemp.EndPos) > 0)
1524       break;
1525 
1526     pIterator->GetWord(wordinfo);
1527     pIterator->GetLine(lineinfo);
1528 
1529     if (place.LineCmp(wrTemp.BeginPos) == 0 ||
1530         place.LineCmp(wrTemp.EndPos) == 0) {
1531       CFX_FloatRect rcWord(wordinfo.ptWord.x,
1532                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1533                            wordinfo.ptWord.x + wordinfo.fWidth,
1534                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1535 
1536       if (m_pNotify) {
1537         if (!m_bNotifyFlag) {
1538           m_bNotifyFlag = true;
1539           CFX_FloatRect rcRefresh = VTToEdit(rcWord);
1540           m_pNotify->IOnInvalidateRect(&rcRefresh);
1541           m_bNotifyFlag = false;
1542         }
1543       }
1544     } else {
1545       CFX_FloatRect rcLine(lineinfo.ptLine.x,
1546                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1547                            lineinfo.ptLine.x + lineinfo.fLineWidth,
1548                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1549 
1550       if (m_pNotify) {
1551         if (!m_bNotifyFlag) {
1552           m_bNotifyFlag = true;
1553           CFX_FloatRect rcRefresh = VTToEdit(rcLine);
1554           m_pNotify->IOnInvalidateRect(&rcRefresh);
1555           m_bNotifyFlag = false;
1556         }
1557       }
1558 
1559       pIterator->NextLine();
1560     }
1561   }
1562 }
1563 
SetCaret(const CPVT_WordPlace & place)1564 void CFX_Edit::SetCaret(const CPVT_WordPlace& place) {
1565   m_wpOldCaret = m_wpCaret;
1566   m_wpCaret = place;
1567 }
1568 
SetCaretInfo()1569 void CFX_Edit::SetCaretInfo() {
1570   if (m_pNotify) {
1571     if (!m_bNotifyFlag) {
1572       CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1573       pIterator->SetAt(m_wpCaret);
1574 
1575       CFX_PointF ptHead;
1576       CFX_PointF ptFoot;
1577       CPVT_Word word;
1578       CPVT_Line line;
1579       if (pIterator->GetWord(word)) {
1580         ptHead.x = word.ptWord.x + word.fWidth;
1581         ptHead.y = word.ptWord.y + word.fAscent;
1582         ptFoot.x = word.ptWord.x + word.fWidth;
1583         ptFoot.y = word.ptWord.y + word.fDescent;
1584       } else if (pIterator->GetLine(line)) {
1585         ptHead.x = line.ptLine.x;
1586         ptHead.y = line.ptLine.y + line.fLineAscent;
1587         ptFoot.x = line.ptLine.x;
1588         ptFoot.y = line.ptLine.y + line.fLineDescent;
1589       }
1590 
1591       m_bNotifyFlag = true;
1592       m_pNotify->IOnSetCaret(!m_SelState.IsExist(), VTToEdit(ptHead),
1593                              VTToEdit(ptFoot), m_wpCaret);
1594       m_bNotifyFlag = false;
1595     }
1596   }
1597 }
1598 
SetCaret(int32_t nPos)1599 void CFX_Edit::SetCaret(int32_t nPos) {
1600   if (m_pVT->IsValid()) {
1601     SelectNone();
1602     SetCaret(m_pVT->WordIndexToWordPlace(nPos));
1603     m_SelState.Set(m_wpCaret, m_wpCaret);
1604 
1605     ScrollToCaret();
1606     SetCaretOrigin();
1607     SetCaretInfo();
1608   }
1609 }
1610 
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)1611 void CFX_Edit::OnMouseDown(const CFX_PointF& point, bool bShift, bool bCtrl) {
1612   if (m_pVT->IsValid()) {
1613     SelectNone();
1614     SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1615     m_SelState.Set(m_wpCaret, m_wpCaret);
1616 
1617     ScrollToCaret();
1618     SetCaretOrigin();
1619     SetCaretInfo();
1620   }
1621 }
1622 
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)1623 void CFX_Edit::OnMouseMove(const CFX_PointF& point, bool bShift, bool bCtrl) {
1624   if (m_pVT->IsValid()) {
1625     SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1626 
1627     if (m_wpCaret != m_wpOldCaret) {
1628       m_SelState.SetEndPos(m_wpCaret);
1629 
1630       ScrollToCaret();
1631       Refresh();
1632       SetCaretOrigin();
1633       SetCaretInfo();
1634     }
1635   }
1636 }
1637 
OnVK_UP(bool bShift,bool bCtrl)1638 void CFX_Edit::OnVK_UP(bool bShift, bool bCtrl) {
1639   if (m_pVT->IsValid()) {
1640     SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
1641 
1642     if (bShift) {
1643       if (m_SelState.IsExist())
1644         m_SelState.SetEndPos(m_wpCaret);
1645       else
1646         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1647 
1648       if (m_wpOldCaret != m_wpCaret) {
1649         ScrollToCaret();
1650         Refresh();
1651         SetCaretInfo();
1652       }
1653     } else {
1654       SelectNone();
1655 
1656       ScrollToCaret();
1657       SetCaretInfo();
1658     }
1659   }
1660 }
1661 
OnVK_DOWN(bool bShift,bool bCtrl)1662 void CFX_Edit::OnVK_DOWN(bool bShift, bool bCtrl) {
1663   if (m_pVT->IsValid()) {
1664     SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
1665 
1666     if (bShift) {
1667       if (m_SelState.IsExist())
1668         m_SelState.SetEndPos(m_wpCaret);
1669       else
1670         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1671 
1672       if (m_wpOldCaret != m_wpCaret) {
1673         ScrollToCaret();
1674         Refresh();
1675         SetCaretInfo();
1676       }
1677     } else {
1678       SelectNone();
1679 
1680       ScrollToCaret();
1681       SetCaretInfo();
1682     }
1683   }
1684 }
1685 
OnVK_LEFT(bool bShift,bool bCtrl)1686 void CFX_Edit::OnVK_LEFT(bool bShift, bool bCtrl) {
1687   if (m_pVT->IsValid()) {
1688     if (bShift) {
1689       if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1690           m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
1691         SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1692 
1693       SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1694 
1695       if (m_SelState.IsExist())
1696         m_SelState.SetEndPos(m_wpCaret);
1697       else
1698         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1699 
1700       if (m_wpOldCaret != m_wpCaret) {
1701         ScrollToCaret();
1702         Refresh();
1703         SetCaretInfo();
1704       }
1705     } else {
1706       if (m_SelState.IsExist()) {
1707         if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
1708           SetCaret(m_SelState.BeginPos);
1709         else
1710           SetCaret(m_SelState.EndPos);
1711 
1712         SelectNone();
1713         ScrollToCaret();
1714         SetCaretInfo();
1715       } else {
1716         if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1717             m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
1718           SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1719 
1720         SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1721 
1722         ScrollToCaret();
1723         SetCaretOrigin();
1724         SetCaretInfo();
1725       }
1726     }
1727   }
1728 }
1729 
OnVK_RIGHT(bool bShift,bool bCtrl)1730 void CFX_Edit::OnVK_RIGHT(bool bShift, bool bCtrl) {
1731   if (m_pVT->IsValid()) {
1732     if (bShift) {
1733       SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1734 
1735       if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1736           m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
1737         SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1738 
1739       if (m_SelState.IsExist())
1740         m_SelState.SetEndPos(m_wpCaret);
1741       else
1742         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1743 
1744       if (m_wpOldCaret != m_wpCaret) {
1745         ScrollToCaret();
1746         Refresh();
1747         SetCaretInfo();
1748       }
1749     } else {
1750       if (m_SelState.IsExist()) {
1751         if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
1752           SetCaret(m_SelState.BeginPos);
1753         else
1754           SetCaret(m_SelState.EndPos);
1755 
1756         SelectNone();
1757         ScrollToCaret();
1758         SetCaretInfo();
1759       } else {
1760         SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1761 
1762         if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1763             m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
1764           SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1765 
1766         ScrollToCaret();
1767         SetCaretOrigin();
1768         SetCaretInfo();
1769       }
1770     }
1771   }
1772 }
1773 
OnVK_HOME(bool bShift,bool bCtrl)1774 void CFX_Edit::OnVK_HOME(bool bShift, bool bCtrl) {
1775   if (m_pVT->IsValid()) {
1776     if (bShift) {
1777       if (bCtrl)
1778         SetCaret(m_pVT->GetBeginWordPlace());
1779       else
1780         SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1781 
1782       if (m_SelState.IsExist())
1783         m_SelState.SetEndPos(m_wpCaret);
1784       else
1785         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1786 
1787       ScrollToCaret();
1788       Refresh();
1789       SetCaretInfo();
1790     } else {
1791       if (m_SelState.IsExist()) {
1792         if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
1793           SetCaret(m_SelState.BeginPos);
1794         else
1795           SetCaret(m_SelState.EndPos);
1796 
1797         SelectNone();
1798         ScrollToCaret();
1799         SetCaretInfo();
1800       } else {
1801         if (bCtrl)
1802           SetCaret(m_pVT->GetBeginWordPlace());
1803         else
1804           SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1805 
1806         ScrollToCaret();
1807         SetCaretOrigin();
1808         SetCaretInfo();
1809       }
1810     }
1811   }
1812 }
1813 
OnVK_END(bool bShift,bool bCtrl)1814 void CFX_Edit::OnVK_END(bool bShift, bool bCtrl) {
1815   if (m_pVT->IsValid()) {
1816     if (bShift) {
1817       if (bCtrl)
1818         SetCaret(m_pVT->GetEndWordPlace());
1819       else
1820         SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1821 
1822       if (m_SelState.IsExist())
1823         m_SelState.SetEndPos(m_wpCaret);
1824       else
1825         m_SelState.Set(m_wpOldCaret, m_wpCaret);
1826 
1827       ScrollToCaret();
1828       Refresh();
1829       SetCaretInfo();
1830     } else {
1831       if (m_SelState.IsExist()) {
1832         if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
1833           SetCaret(m_SelState.BeginPos);
1834         else
1835           SetCaret(m_SelState.EndPos);
1836 
1837         SelectNone();
1838         ScrollToCaret();
1839         SetCaretInfo();
1840       } else {
1841         if (bCtrl)
1842           SetCaret(m_pVT->GetEndWordPlace());
1843         else
1844           SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1845 
1846         ScrollToCaret();
1847         SetCaretOrigin();
1848         SetCaretInfo();
1849       }
1850     }
1851   }
1852 }
1853 
InsertWord(uint16_t word,int32_t charset,const CPVT_WordProps * pWordProps,bool bAddUndo,bool bPaint)1854 bool CFX_Edit::InsertWord(uint16_t word,
1855                           int32_t charset,
1856                           const CPVT_WordProps* pWordProps,
1857                           bool bAddUndo,
1858                           bool bPaint) {
1859   if (IsTextOverflow() || !m_pVT->IsValid())
1860     return false;
1861 
1862   m_pVT->UpdateWordPlace(m_wpCaret);
1863   SetCaret(m_pVT->InsertWord(m_wpCaret, word,
1864                              GetCharSetFromUnicode(word, charset), pWordProps));
1865   m_SelState.Set(m_wpCaret, m_wpCaret);
1866   if (m_wpCaret == m_wpOldCaret)
1867     return false;
1868 
1869   if (bAddUndo && m_bEnableUndo) {
1870     AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertWord>(
1871         this, m_wpOldCaret, m_wpCaret, word, charset, pWordProps));
1872   }
1873   if (bPaint)
1874     PaintInsertText(m_wpOldCaret, m_wpCaret);
1875 
1876   if (m_bOprNotify && m_pOprNotify)
1877     m_pOprNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
1878 
1879   return true;
1880 }
1881 
InsertReturn(const CPVT_SecProps * pSecProps,const CPVT_WordProps * pWordProps,bool bAddUndo,bool bPaint)1882 bool CFX_Edit::InsertReturn(const CPVT_SecProps* pSecProps,
1883                             const CPVT_WordProps* pWordProps,
1884                             bool bAddUndo,
1885                             bool bPaint) {
1886   if (IsTextOverflow() || !m_pVT->IsValid())
1887     return false;
1888 
1889   m_pVT->UpdateWordPlace(m_wpCaret);
1890   SetCaret(m_pVT->InsertSection(m_wpCaret, pSecProps, pWordProps));
1891   m_SelState.Set(m_wpCaret, m_wpCaret);
1892   if (m_wpCaret == m_wpOldCaret)
1893     return false;
1894 
1895   if (bAddUndo && m_bEnableUndo) {
1896     AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertReturn>(
1897         this, m_wpOldCaret, m_wpCaret, pSecProps, pWordProps));
1898   }
1899   if (bPaint) {
1900     RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1901     ScrollToCaret();
1902     Refresh();
1903     SetCaretOrigin();
1904     SetCaretInfo();
1905   }
1906   if (m_bOprNotify && m_pOprNotify)
1907     m_pOprNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
1908 
1909   return true;
1910 }
1911 
Backspace(bool bAddUndo,bool bPaint)1912 bool CFX_Edit::Backspace(bool bAddUndo, bool bPaint) {
1913   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
1914     return false;
1915 
1916   CPVT_Section section;
1917   CPVT_Word word;
1918   if (bAddUndo) {
1919     CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1920     pIterator->SetAt(m_wpCaret);
1921     pIterator->GetSection(section);
1922     pIterator->GetWord(word);
1923   }
1924   m_pVT->UpdateWordPlace(m_wpCaret);
1925   SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
1926   m_SelState.Set(m_wpCaret, m_wpCaret);
1927   if (m_wpCaret == m_wpOldCaret)
1928     return false;
1929 
1930   if (bAddUndo && m_bEnableUndo) {
1931     if (m_wpCaret.SecCmp(m_wpOldCaret) != 0) {
1932       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
1933           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
1934           section.SecProps, section.WordProps));
1935     } else {
1936       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Backspace>(
1937           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
1938           section.SecProps, word.WordProps));
1939     }
1940   }
1941   if (bPaint) {
1942     RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
1943     ScrollToCaret();
1944     Refresh();
1945     SetCaretOrigin();
1946     SetCaretInfo();
1947   }
1948   if (m_bOprNotify && m_pOprNotify)
1949     m_pOprNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
1950 
1951   return true;
1952 }
1953 
Delete(bool bAddUndo,bool bPaint)1954 bool CFX_Edit::Delete(bool bAddUndo, bool bPaint) {
1955   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace())
1956     return false;
1957 
1958   CPVT_Section section;
1959   CPVT_Word word;
1960   if (bAddUndo) {
1961     CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1962     pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
1963     pIterator->GetSection(section);
1964     pIterator->GetWord(word);
1965   }
1966   m_pVT->UpdateWordPlace(m_wpCaret);
1967   bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
1968   SetCaret(m_pVT->DeleteWord(m_wpCaret));
1969   m_SelState.Set(m_wpCaret, m_wpCaret);
1970   if (bAddUndo && m_bEnableUndo) {
1971     if (bSecEnd) {
1972       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
1973           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
1974           section.SecProps, section.WordProps, bSecEnd));
1975     } else {
1976       AddEditUndoItem(pdfium::MakeUnique<CFXEU_Delete>(
1977           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
1978           section.SecProps, word.WordProps, bSecEnd));
1979     }
1980   }
1981   if (bPaint) {
1982     RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1983     ScrollToCaret();
1984     Refresh();
1985     SetCaretOrigin();
1986     SetCaretInfo();
1987   }
1988   if (m_bOprNotify && m_pOprNotify)
1989     m_pOprNotify->OnDelete(m_wpCaret, m_wpOldCaret);
1990 
1991   return true;
1992 }
1993 
Empty()1994 bool CFX_Edit::Empty() {
1995   if (m_pVT->IsValid()) {
1996     m_pVT->DeleteWords(GetWholeWordRange());
1997     SetCaret(m_pVT->GetBeginWordPlace());
1998 
1999     return true;
2000   }
2001 
2002   return false;
2003 }
2004 
Clear(bool bAddUndo,bool bPaint)2005 bool CFX_Edit::Clear(bool bAddUndo, bool bPaint) {
2006   if (!m_pVT->IsValid() || !m_SelState.IsExist())
2007     return false;
2008 
2009   CPVT_WordRange range = m_SelState.ConvertToWordRange();
2010   if (bAddUndo && m_bEnableUndo)
2011     AddEditUndoItem(pdfium::MakeUnique<CFXEU_Clear>(this, range, GetSelText()));
2012 
2013   SelectNone();
2014   SetCaret(m_pVT->DeleteWords(range));
2015   m_SelState.Set(m_wpCaret, m_wpCaret);
2016   if (bPaint) {
2017     RearrangePart(range);
2018     ScrollToCaret();
2019     Refresh();
2020     SetCaretOrigin();
2021     SetCaretInfo();
2022   }
2023   if (m_bOprNotify && m_pOprNotify)
2024     m_pOprNotify->OnClear(m_wpCaret, m_wpOldCaret);
2025 
2026   return true;
2027 }
2028 
InsertText(const CFX_WideString & sText,int32_t charset,bool bAddUndo,bool bPaint)2029 bool CFX_Edit::InsertText(const CFX_WideString& sText,
2030                           int32_t charset,
2031                           bool bAddUndo,
2032                           bool bPaint) {
2033   if (IsTextOverflow())
2034     return false;
2035 
2036   m_pVT->UpdateWordPlace(m_wpCaret);
2037   SetCaret(DoInsertText(m_wpCaret, sText, charset));
2038   m_SelState.Set(m_wpCaret, m_wpCaret);
2039   if (m_wpCaret == m_wpOldCaret)
2040     return false;
2041 
2042   if (bAddUndo && m_bEnableUndo) {
2043     AddEditUndoItem(pdfium::MakeUnique<CFXEU_InsertText>(
2044         this, m_wpOldCaret, m_wpCaret, sText, charset));
2045   }
2046   if (bPaint)
2047     PaintInsertText(m_wpOldCaret, m_wpCaret);
2048 
2049   if (m_bOprNotify && m_pOprNotify)
2050     m_pOprNotify->OnInsertText(m_wpCaret, m_wpOldCaret);
2051 
2052   return true;
2053 }
2054 
PaintInsertText(const CPVT_WordPlace & wpOld,const CPVT_WordPlace & wpNew)2055 void CFX_Edit::PaintInsertText(const CPVT_WordPlace& wpOld,
2056                                const CPVT_WordPlace& wpNew) {
2057   if (m_pVT->IsValid()) {
2058     RearrangePart(CPVT_WordRange(wpOld, wpNew));
2059     ScrollToCaret();
2060     Refresh();
2061     SetCaretOrigin();
2062     SetCaretInfo();
2063   }
2064 }
2065 
Redo()2066 bool CFX_Edit::Redo() {
2067   if (m_bEnableUndo) {
2068     if (m_Undo.CanRedo()) {
2069       m_Undo.Redo();
2070       return true;
2071     }
2072   }
2073 
2074   return false;
2075 }
2076 
Undo()2077 bool CFX_Edit::Undo() {
2078   if (m_bEnableUndo) {
2079     if (m_Undo.CanUndo()) {
2080       m_Undo.Undo();
2081       return true;
2082     }
2083   }
2084 
2085   return false;
2086 }
2087 
SetCaretOrigin()2088 void CFX_Edit::SetCaretOrigin() {
2089   if (!m_pVT->IsValid())
2090     return;
2091 
2092   CPDF_VariableText::Iterator* pIterator = m_pVT->GetIterator();
2093   pIterator->SetAt(m_wpCaret);
2094   CPVT_Word word;
2095   CPVT_Line line;
2096   if (pIterator->GetWord(word)) {
2097     m_ptCaret.x = word.ptWord.x + word.fWidth;
2098     m_ptCaret.y = word.ptWord.y;
2099   } else if (pIterator->GetLine(line)) {
2100     m_ptCaret.x = line.ptLine.x;
2101     m_ptCaret.y = line.ptLine.y;
2102   }
2103 }
2104 
WordPlaceToWordIndex(const CPVT_WordPlace & place) const2105 int32_t CFX_Edit::WordPlaceToWordIndex(const CPVT_WordPlace& place) const {
2106   if (m_pVT->IsValid())
2107     return m_pVT->WordPlaceToWordIndex(place);
2108 
2109   return -1;
2110 }
2111 
WordIndexToWordPlace(int32_t index) const2112 CPVT_WordPlace CFX_Edit::WordIndexToWordPlace(int32_t index) const {
2113   if (m_pVT->IsValid())
2114     return m_pVT->WordIndexToWordPlace(index);
2115 
2116   return CPVT_WordPlace();
2117 }
2118 
IsTextFull() const2119 bool CFX_Edit::IsTextFull() const {
2120   int32_t nTotalWords = m_pVT->GetTotalWords();
2121   int32_t nLimitChar = m_pVT->GetLimitChar();
2122   int32_t nCharArray = m_pVT->GetCharArray();
2123 
2124   return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
2125          (nCharArray > 0 && nTotalWords >= nCharArray);
2126 }
2127 
IsTextOverflow() const2128 bool CFX_Edit::IsTextOverflow() const {
2129   if (!m_bEnableScroll && !m_bEnableOverflow) {
2130     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
2131     CFX_FloatRect rcContent = m_pVT->GetContentRect();
2132 
2133     if (m_pVT->IsMultiLine() && GetTotalLines() > 1 &&
2134         IsFloatBigger(rcContent.Height(), rcPlate.Height())) {
2135       return true;
2136     }
2137 
2138     if (IsFloatBigger(rcContent.Width(), rcPlate.Width()))
2139       return true;
2140   }
2141 
2142   return false;
2143 }
2144 
CanUndo() const2145 bool CFX_Edit::CanUndo() const {
2146   if (m_bEnableUndo) {
2147     return m_Undo.CanUndo();
2148   }
2149 
2150   return false;
2151 }
2152 
CanRedo() const2153 bool CFX_Edit::CanRedo() const {
2154   if (m_bEnableUndo) {
2155     return m_Undo.CanRedo();
2156   }
2157 
2158   return false;
2159 }
2160 
EnableRefresh(bool bRefresh)2161 void CFX_Edit::EnableRefresh(bool bRefresh) {
2162   m_bEnableRefresh = bRefresh;
2163 }
2164 
EnableUndo(bool bUndo)2165 void CFX_Edit::EnableUndo(bool bUndo) {
2166   m_bEnableUndo = bUndo;
2167 }
2168 
EnableOprNotify(bool bNotify)2169 void CFX_Edit::EnableOprNotify(bool bNotify) {
2170   m_bOprNotify = bNotify;
2171 }
2172 
DoInsertText(const CPVT_WordPlace & place,const CFX_WideString & sText,int32_t charset)2173 CPVT_WordPlace CFX_Edit::DoInsertText(const CPVT_WordPlace& place,
2174                                       const CFX_WideString& sText,
2175                                       int32_t charset) {
2176   CPVT_WordPlace wp = place;
2177 
2178   if (m_pVT->IsValid()) {
2179     for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) {
2180       uint16_t word = sText[i];
2181       switch (word) {
2182         case 0x0D:
2183           wp = m_pVT->InsertSection(wp, nullptr, nullptr);
2184           if (sText[i + 1] == 0x0A)
2185             i++;
2186           break;
2187         case 0x0A:
2188           wp = m_pVT->InsertSection(wp, nullptr, nullptr);
2189           if (sText[i + 1] == 0x0D)
2190             i++;
2191           break;
2192         case 0x09:
2193           word = 0x20;
2194         default:
2195           wp = m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset),
2196                                  nullptr);
2197           break;
2198       }
2199     }
2200   }
2201 
2202   return wp;
2203 }
2204 
GetCharSetFromUnicode(uint16_t word,int32_t nOldCharset)2205 int32_t CFX_Edit::GetCharSetFromUnicode(uint16_t word, int32_t nOldCharset) {
2206   if (IPVT_FontMap* pFontMap = GetFontMap())
2207     return pFontMap->CharSetFromUnicode(word, nOldCharset);
2208   return nOldCharset;
2209 }
2210 
AddEditUndoItem(std::unique_ptr<CFX_Edit_UndoItem> pEditUndoItem)2211 void CFX_Edit::AddEditUndoItem(
2212     std::unique_ptr<CFX_Edit_UndoItem> pEditUndoItem) {
2213   if (m_pGroupUndoItem)
2214     m_pGroupUndoItem->AddUndoItem(std::move(pEditUndoItem));
2215   else
2216     m_Undo.AddItem(std::move(pEditUndoItem));
2217 }
2218 
CFX_Edit_LineRectArray()2219 CFX_Edit_LineRectArray::CFX_Edit_LineRectArray() {}
2220 
~CFX_Edit_LineRectArray()2221 CFX_Edit_LineRectArray::~CFX_Edit_LineRectArray() {}
2222 
operator =(CFX_Edit_LineRectArray && that)2223 void CFX_Edit_LineRectArray::operator=(CFX_Edit_LineRectArray&& that) {
2224   m_LineRects = std::move(that.m_LineRects);
2225 }
2226 
Add(const CPVT_WordRange & wrLine,const CFX_FloatRect & rcLine)2227 void CFX_Edit_LineRectArray::Add(const CPVT_WordRange& wrLine,
2228                                  const CFX_FloatRect& rcLine) {
2229   m_LineRects.push_back(pdfium::MakeUnique<CFX_Edit_LineRect>(wrLine, rcLine));
2230 }
2231 
GetSize() const2232 int32_t CFX_Edit_LineRectArray::GetSize() const {
2233   return pdfium::CollectionSize<int32_t>(m_LineRects);
2234 }
2235 
GetAt(int32_t nIndex) const2236 CFX_Edit_LineRect* CFX_Edit_LineRectArray::GetAt(int32_t nIndex) const {
2237   if (nIndex < 0 || nIndex >= GetSize())
2238     return nullptr;
2239 
2240   return m_LineRects[nIndex].get();
2241 }
2242 
CFX_Edit_Select()2243 CFX_Edit_Select::CFX_Edit_Select() {}
2244 
CFX_Edit_Select(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)2245 CFX_Edit_Select::CFX_Edit_Select(const CPVT_WordPlace& begin,
2246                                  const CPVT_WordPlace& end) {
2247   Set(begin, end);
2248 }
2249 
CFX_Edit_Select(const CPVT_WordRange & range)2250 CFX_Edit_Select::CFX_Edit_Select(const CPVT_WordRange& range) {
2251   Set(range.BeginPos, range.EndPos);
2252 }
2253 
ConvertToWordRange() const2254 CPVT_WordRange CFX_Edit_Select::ConvertToWordRange() const {
2255   return CPVT_WordRange(BeginPos, EndPos);
2256 }
2257 
Default()2258 void CFX_Edit_Select::Default() {
2259   BeginPos.Default();
2260   EndPos.Default();
2261 }
2262 
Set(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)2263 void CFX_Edit_Select::Set(const CPVT_WordPlace& begin,
2264                           const CPVT_WordPlace& end) {
2265   BeginPos = begin;
2266   EndPos = end;
2267 }
2268 
SetBeginPos(const CPVT_WordPlace & begin)2269 void CFX_Edit_Select::SetBeginPos(const CPVT_WordPlace& begin) {
2270   BeginPos = begin;
2271 }
2272 
SetEndPos(const CPVT_WordPlace & end)2273 void CFX_Edit_Select::SetEndPos(const CPVT_WordPlace& end) {
2274   EndPos = end;
2275 }
2276 
IsExist() const2277 bool CFX_Edit_Select::IsExist() const {
2278   return BeginPos != EndPos;
2279 }
2280 
CFX_Edit_RectArray()2281 CFX_Edit_RectArray::CFX_Edit_RectArray() {}
2282 
~CFX_Edit_RectArray()2283 CFX_Edit_RectArray::~CFX_Edit_RectArray() {}
2284 
Clear()2285 void CFX_Edit_RectArray::Clear() {
2286   m_Rects.clear();
2287 }
2288 
Add(const CFX_FloatRect & rect)2289 void CFX_Edit_RectArray::Add(const CFX_FloatRect& rect) {
2290   // check for overlapped area
2291   for (const auto& pRect : m_Rects) {
2292     if (pRect && pRect->Contains(rect))
2293       return;
2294   }
2295   m_Rects.push_back(pdfium::MakeUnique<CFX_FloatRect>(rect));
2296 }
2297 
GetSize() const2298 int32_t CFX_Edit_RectArray::GetSize() const {
2299   return pdfium::CollectionSize<int32_t>(m_Rects);
2300 }
2301 
GetAt(int32_t nIndex) const2302 CFX_FloatRect* CFX_Edit_RectArray::GetAt(int32_t nIndex) const {
2303   if (nIndex < 0 || nIndex >= GetSize())
2304     return nullptr;
2305 
2306   return m_Rects[nIndex].get();
2307 }
2308