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