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