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