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.h" 8 9 #include <algorithm> 10 #include <memory> 11 #include <sstream> 12 #include <vector> 13 14 #include "core/fpdfapi/font/cpdf_font.h" 15 #include "core/fpdfdoc/cpvt_word.h" 16 #include "core/fxcrt/fx_safe_types.h" 17 #include "core/fxcrt/xml/cxml_content.h" 18 #include "core/fxcrt/xml/cxml_element.h" 19 #include "core/fxge/cfx_graphstatedata.h" 20 #include "core/fxge/cfx_pathdata.h" 21 #include "core/fxge/cfx_renderdevice.h" 22 #include "core/fxge/fx_font.h" 23 #include "fpdfsdk/pwl/cpwl_caret.h" 24 #include "fpdfsdk/pwl/cpwl_edit_ctrl.h" 25 #include "fpdfsdk/pwl/cpwl_edit_impl.h" 26 #include "fpdfsdk/pwl/cpwl_font_map.h" 27 #include "fpdfsdk/pwl/cpwl_scroll_bar.h" 28 #include "fpdfsdk/pwl/cpwl_wnd.h" 29 #include "public/fpdf_fwlevent.h" 30 #include "third_party/base/stl_util.h" 31 32 CPWL_Edit::CPWL_Edit() : m_bFocus(false) {} 33 34 CPWL_Edit::~CPWL_Edit() { 35 ASSERT(!m_bFocus); 36 } 37 38 ByteString CPWL_Edit::GetClassName() const { 39 return PWL_CLASSNAME_EDIT; 40 } 41 42 void CPWL_Edit::SetText(const WideString& csText) { 43 WideString swText = csText; 44 if (!HasFlag(PES_RICH)) { 45 m_pEdit->SetText(swText); 46 return; 47 } 48 49 ByteString sValue = ByteString::FromUnicode(swText); 50 std::unique_ptr<CXML_Element> pXML( 51 CXML_Element::Parse(sValue.c_str(), sValue.GetLength())); 52 if (!pXML) { 53 m_pEdit->SetText(swText); 54 return; 55 } 56 swText.clear(); 57 58 bool bFirst = true; 59 size_t nCount = pXML->CountChildren(); 60 for (size_t i = 0; i < nCount; ++i) { 61 CXML_Element* pSubElement = ToElement(pXML->GetChild(i)); 62 if (!pSubElement || !pSubElement->GetTagName().EqualNoCase("p")) 63 continue; 64 65 WideString swSection; 66 size_t nSubChild = pSubElement->CountChildren(); 67 for (size_t j = 0; j < nSubChild; ++j) { 68 CXML_Content* pSubContent = ToContent(pSubElement->GetChild(j)); 69 if (pSubContent) 70 swSection += pSubContent->m_Content; 71 } 72 if (bFirst) 73 bFirst = false; 74 else 75 swText += FWL_VKEY_Return; 76 swText += swSection; 77 } 78 79 m_pEdit->SetText(swText); 80 } 81 82 bool CPWL_Edit::RePosChildWnd() { 83 if (CPWL_ScrollBar* pVSB = GetVScrollBar()) { 84 CFX_FloatRect rcWindow = m_rcOldWindow; 85 CFX_FloatRect rcVScroll = 86 CFX_FloatRect(rcWindow.right, rcWindow.bottom, 87 rcWindow.right + PWL_SCROLLBAR_WIDTH, rcWindow.top); 88 89 ObservedPtr thisObserved(this); 90 91 pVSB->Move(rcVScroll, true, false); 92 if (!thisObserved) 93 return false; 94 } 95 96 if (m_pEditCaret && !HasFlag(PES_TEXTOVERFLOW)) { 97 CFX_FloatRect rect = GetClientRect(); 98 if (!rect.IsEmpty()) { 99 // +1 for caret beside border 100 rect.Inflate(1.0f, 1.0f); 101 rect.Normalize(); 102 } 103 m_pEditCaret->SetClipRect(rect); 104 } 105 106 return CPWL_EditCtrl::RePosChildWnd(); 107 } 108 109 CFX_FloatRect CPWL_Edit::GetClientRect() const { 110 float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth()); 111 CFX_FloatRect rcClient = GetWindowRect().GetDeflated(width, width); 112 if (CPWL_ScrollBar* pVSB = GetVScrollBar()) { 113 if (pVSB->IsVisible()) { 114 rcClient.right -= PWL_SCROLLBAR_WIDTH; 115 } 116 } 117 118 return rcClient; 119 } 120 121 void CPWL_Edit::SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat, bool bPaint) { 122 m_pEdit->SetAlignmentV((int32_t)nFormat, bPaint); 123 } 124 125 bool CPWL_Edit::CanSelectAll() const { 126 return GetSelectWordRange() != m_pEdit->GetWholeWordRange(); 127 } 128 129 bool CPWL_Edit::CanCopy() const { 130 return !HasFlag(PES_PASSWORD) && !HasFlag(PES_NOREAD) && 131 m_pEdit->IsSelected(); 132 } 133 134 bool CPWL_Edit::CanCut() const { 135 return CanCopy() && !IsReadOnly(); 136 } 137 void CPWL_Edit::CutText() { 138 if (!CanCut()) 139 return; 140 m_pEdit->ClearSelection(); 141 } 142 143 void CPWL_Edit::OnCreated() { 144 CPWL_EditCtrl::OnCreated(); 145 146 if (CPWL_ScrollBar* pScroll = GetVScrollBar()) { 147 pScroll->RemoveFlag(PWS_AUTOTRANSPARENT); 148 pScroll->SetTransparency(255); 149 } 150 151 SetParamByFlag(); 152 153 m_rcOldWindow = GetWindowRect(); 154 155 m_pEdit->SetOperationNotify(this); 156 } 157 158 void CPWL_Edit::SetParamByFlag() { 159 if (HasFlag(PES_RIGHT)) { 160 m_pEdit->SetAlignmentH(2, false); 161 } else if (HasFlag(PES_MIDDLE)) { 162 m_pEdit->SetAlignmentH(1, false); 163 } else { 164 m_pEdit->SetAlignmentH(0, false); 165 } 166 167 if (HasFlag(PES_BOTTOM)) { 168 m_pEdit->SetAlignmentV(2, false); 169 } else if (HasFlag(PES_CENTER)) { 170 m_pEdit->SetAlignmentV(1, false); 171 } else { 172 m_pEdit->SetAlignmentV(0, false); 173 } 174 175 if (HasFlag(PES_PASSWORD)) { 176 m_pEdit->SetPasswordChar('*', false); 177 } 178 179 m_pEdit->SetMultiLine(HasFlag(PES_MULTILINE), false); 180 m_pEdit->SetAutoReturn(HasFlag(PES_AUTORETURN), false); 181 m_pEdit->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE), false); 182 m_pEdit->SetAutoScroll(HasFlag(PES_AUTOSCROLL), false); 183 m_pEdit->EnableUndo(HasFlag(PES_UNDO)); 184 185 if (HasFlag(PES_TEXTOVERFLOW)) { 186 SetClipRect(CFX_FloatRect()); 187 m_pEdit->SetTextOverflow(true, false); 188 } else { 189 if (m_pEditCaret) { 190 CFX_FloatRect rect = GetClientRect(); 191 if (!rect.IsEmpty()) { 192 // +1 for caret beside border 193 rect.Inflate(1.0f, 1.0f); 194 rect.Normalize(); 195 } 196 m_pEditCaret->SetClipRect(rect); 197 } 198 } 199 } 200 201 void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice, 202 const CFX_Matrix& mtUser2Device) { 203 CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device); 204 205 CFX_FloatRect rcClient = GetClientRect(); 206 207 int32_t nCharArray = m_pEdit->GetCharArray(); 208 FX_SAFE_INT32 nCharArraySafe = nCharArray; 209 nCharArraySafe -= 1; 210 nCharArraySafe *= 2; 211 212 if (nCharArray > 0 && nCharArraySafe.IsValid()) { 213 switch (GetBorderStyle()) { 214 case BorderStyle::SOLID: { 215 CFX_GraphStateData gsd; 216 gsd.m_LineWidth = (float)GetBorderWidth(); 217 218 CFX_PathData path; 219 220 for (int32_t i = 0; i < nCharArray - 1; i++) { 221 path.AppendPoint( 222 CFX_PointF( 223 rcClient.left + 224 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 225 rcClient.bottom), 226 FXPT_TYPE::MoveTo, false); 227 path.AppendPoint( 228 CFX_PointF( 229 rcClient.left + 230 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 231 rcClient.top), 232 FXPT_TYPE::LineTo, false); 233 } 234 if (!path.GetPoints().empty()) { 235 pDevice->DrawPath(&path, &mtUser2Device, &gsd, 0, 236 GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE); 237 } 238 break; 239 } 240 case BorderStyle::DASH: { 241 CFX_GraphStateData gsd; 242 gsd.m_LineWidth = (float)GetBorderWidth(); 243 244 gsd.SetDashCount(2); 245 gsd.m_DashArray[0] = (float)GetBorderDash().nDash; 246 gsd.m_DashArray[1] = (float)GetBorderDash().nGap; 247 gsd.m_DashPhase = (float)GetBorderDash().nPhase; 248 249 CFX_PathData path; 250 for (int32_t i = 0; i < nCharArray - 1; i++) { 251 path.AppendPoint( 252 CFX_PointF( 253 rcClient.left + 254 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 255 rcClient.bottom), 256 FXPT_TYPE::MoveTo, false); 257 path.AppendPoint( 258 CFX_PointF( 259 rcClient.left + 260 ((rcClient.right - rcClient.left) / nCharArray) * (i + 1), 261 rcClient.top), 262 FXPT_TYPE::LineTo, false); 263 } 264 if (!path.GetPoints().empty()) { 265 pDevice->DrawPath(&path, &mtUser2Device, &gsd, 0, 266 GetBorderColor().ToFXColor(255), FXFILL_ALTERNATE); 267 } 268 break; 269 } 270 default: 271 break; 272 } 273 } 274 275 CFX_FloatRect rcClip; 276 CPVT_WordRange wrRange = m_pEdit->GetVisibleWordRange(); 277 CPVT_WordRange* pRange = nullptr; 278 if (!HasFlag(PES_TEXTOVERFLOW)) { 279 rcClip = GetClientRect(); 280 pRange = &wrRange; 281 } 282 283 CFX_SystemHandler* pSysHandler = GetSystemHandler(); 284 CPWL_EditImpl::DrawEdit(pDevice, mtUser2Device, m_pEdit.get(), 285 GetTextColor().ToFXColor(GetTransparency()), rcClip, 286 CFX_PointF(), pRange, pSysHandler, 287 m_pFormFiller.Get()); 288 } 289 290 bool CPWL_Edit::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) { 291 CPWL_Wnd::OnLButtonDown(point, nFlag); 292 293 if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) { 294 if (m_bMouseDown && !InvalidateRect(nullptr)) 295 return true; 296 297 m_bMouseDown = true; 298 SetCapture(); 299 300 m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag)); 301 } 302 303 return true; 304 } 305 306 bool CPWL_Edit::OnLButtonDblClk(const CFX_PointF& point, uint32_t nFlag) { 307 CPWL_Wnd::OnLButtonDblClk(point, nFlag); 308 309 if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) { 310 m_pEdit->SelectAll(); 311 } 312 313 return true; 314 } 315 316 bool CPWL_Edit::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) { 317 if (m_bMouseDown) 318 return false; 319 320 CPWL_Wnd::OnRButtonUp(point, nFlag); 321 322 if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point)) 323 return true; 324 325 CFX_SystemHandler* pSH = GetSystemHandler(); 326 if (!pSH) 327 return false; 328 329 SetFocus(); 330 331 return false; 332 } 333 334 void CPWL_Edit::OnSetFocus() { 335 ObservedPtr observed_ptr(this); 336 SetEditCaret(true); 337 if (!observed_ptr) 338 return; 339 340 if (!IsReadOnly()) { 341 if (CPWL_Wnd::FocusHandlerIface* pFocusHandler = GetFocusHandler()) { 342 pFocusHandler->OnSetFocus(this); 343 if (!observed_ptr) 344 return; 345 } 346 } 347 m_bFocus = true; 348 } 349 350 void CPWL_Edit::OnKillFocus() { 351 ObservedPtr observed_ptr(this); 352 353 CPWL_ScrollBar* pScroll = GetVScrollBar(); 354 if (pScroll && pScroll->IsVisible()) { 355 pScroll->SetVisible(false); 356 if (!observed_ptr) 357 return; 358 359 if (!Move(m_rcOldWindow, true, true)) 360 return; 361 } 362 363 m_pEdit->SelectNone(); 364 if (!observed_ptr) 365 return; 366 367 if (!SetCaret(false, CFX_PointF(), CFX_PointF())) 368 return; 369 370 SetCharSet(FX_CHARSET_ANSI); 371 m_bFocus = false; 372 } 373 374 void CPWL_Edit::SetCharSpace(float fCharSpace) { 375 m_pEdit->SetCharSpace(fCharSpace); 376 } 377 378 CPVT_WordRange CPWL_Edit::GetSelectWordRange() const { 379 if (!m_pEdit->IsSelected()) 380 return CPVT_WordRange(); 381 382 int32_t nStart = -1; 383 int32_t nEnd = -1; 384 385 m_pEdit->GetSelection(nStart, nEnd); 386 387 CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStart); 388 CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEnd); 389 390 return CPVT_WordRange(wpStart, wpEnd); 391 } 392 393 CFX_PointF CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) { 394 CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); 395 CPVT_WordPlace wpOld = pIterator->GetAt(); 396 pIterator->SetAt(wpWord); 397 398 CFX_PointF pt; 399 CPVT_Word word; 400 if (pIterator->GetWord(word)) 401 pt = CFX_PointF(word.ptWord.x + word.fWidth, word.ptWord.y + word.fDescent); 402 pIterator->SetAt(wpOld); 403 return pt; 404 } 405 406 bool CPWL_Edit::IsTextFull() const { 407 return m_pEdit->IsTextFull(); 408 } 409 410 float CPWL_Edit::GetCharArrayAutoFontSize(CPDF_Font* pFont, 411 const CFX_FloatRect& rcPlate, 412 int32_t nCharArray) { 413 if (!pFont || pFont->IsStandardFont()) 414 return 0.0f; 415 416 FX_RECT rcBBox; 417 pFont->GetFontBBox(rcBBox); 418 419 CFX_FloatRect rcCell = rcPlate; 420 float xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width(); 421 float ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height(); 422 423 return xdiv < ydiv ? xdiv : ydiv; 424 } 425 426 void CPWL_Edit::SetCharArray(int32_t nCharArray) { 427 if (!HasFlag(PES_CHARARRAY) || nCharArray <= 0) 428 return; 429 430 m_pEdit->SetCharArray(nCharArray); 431 m_pEdit->SetTextOverflow(true, true); 432 433 if (!HasFlag(PWS_AUTOFONTSIZE)) 434 return; 435 436 IPVT_FontMap* pFontMap = GetFontMap(); 437 if (!pFontMap) 438 return; 439 440 float fFontSize = GetCharArrayAutoFontSize(pFontMap->GetPDFFont(0), 441 GetClientRect(), nCharArray); 442 if (fFontSize <= 0.0f) 443 return; 444 445 m_pEdit->SetAutoFontSize(false, true); 446 m_pEdit->SetFontSize(fFontSize); 447 } 448 449 void CPWL_Edit::SetLimitChar(int32_t nLimitChar) { 450 m_pEdit->SetLimitChar(nLimitChar); 451 } 452 453 void CPWL_Edit::ReplaceSel(const WideString& wsText) { 454 m_pEdit->ClearSelection(); 455 m_pEdit->InsertText(wsText, FX_CHARSET_Default); 456 } 457 458 CFX_FloatRect CPWL_Edit::GetFocusRect() const { 459 return CFX_FloatRect(); 460 } 461 462 bool CPWL_Edit::IsVScrollBarVisible() const { 463 CPWL_ScrollBar* pScroll = GetVScrollBar(); 464 return pScroll && pScroll->IsVisible(); 465 } 466 467 bool CPWL_Edit::OnKeyDown(uint16_t nChar, uint32_t nFlag) { 468 if (m_bMouseDown) 469 return true; 470 471 if (nChar == FWL_VKEY_Delete) { 472 if (m_pFillerNotify) { 473 WideString strChange; 474 WideString strChangeEx; 475 476 int nSelStart = 0; 477 int nSelEnd = 0; 478 GetSelection(nSelStart, nSelEnd); 479 480 if (nSelStart == nSelEnd) 481 nSelEnd = nSelStart + 1; 482 483 CPWL_Wnd::ObservedPtr thisObserved(this); 484 485 bool bRC; 486 bool bExit; 487 std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke( 488 GetAttachedData(), strChange, strChangeEx, nSelStart, nSelEnd, true, 489 nFlag); 490 491 if (!thisObserved) 492 return false; 493 494 if (!bRC) 495 return false; 496 if (bExit) 497 return false; 498 } 499 } 500 501 bool bRet = CPWL_EditCtrl::OnKeyDown(nChar, nFlag); 502 503 // In case of implementation swallow the OnKeyDown event. 504 if (IsProceedtoOnChar(nChar, nFlag)) 505 return true; 506 507 return bRet; 508 } 509 510 // static 511 bool CPWL_Edit::IsProceedtoOnChar(uint16_t nKeyCode, uint32_t nFlag) { 512 bool bCtrl = IsCTRLpressed(nFlag); 513 bool bAlt = IsALTpressed(nFlag); 514 if (bCtrl && !bAlt) { 515 // hot keys for edit control. 516 switch (nKeyCode) { 517 case 'C': 518 case 'V': 519 case 'X': 520 case 'A': 521 case 'Z': 522 return true; 523 default: 524 break; 525 } 526 } 527 // control characters. 528 switch (nKeyCode) { 529 case FWL_VKEY_Escape: 530 case FWL_VKEY_Back: 531 case FWL_VKEY_Return: 532 case FWL_VKEY_Space: 533 return true; 534 default: 535 return false; 536 } 537 } 538 539 bool CPWL_Edit::OnChar(uint16_t nChar, uint32_t nFlag) { 540 if (m_bMouseDown) 541 return true; 542 543 bool bRC = true; 544 bool bExit = false; 545 546 if (!IsCTRLpressed(nFlag)) { 547 if (m_pFillerNotify) { 548 WideString swChange; 549 550 int nSelStart = 0; 551 int nSelEnd = 0; 552 GetSelection(nSelStart, nSelEnd); 553 554 switch (nChar) { 555 case FWL_VKEY_Back: 556 if (nSelStart == nSelEnd) 557 nSelStart = nSelEnd - 1; 558 break; 559 case FWL_VKEY_Return: 560 break; 561 default: 562 swChange += nChar; 563 break; 564 } 565 566 CPWL_Wnd::ObservedPtr thisObserved(this); 567 568 WideString strChangeEx; 569 std::tie(bRC, bExit) = m_pFillerNotify->OnBeforeKeyStroke( 570 GetAttachedData(), swChange, strChangeEx, nSelStart, nSelEnd, true, 571 nFlag); 572 573 if (!thisObserved) 574 return false; 575 } 576 } 577 578 if (!bRC) 579 return true; 580 if (bExit) 581 return false; 582 583 if (IPVT_FontMap* pFontMap = GetFontMap()) { 584 int32_t nOldCharSet = GetCharSet(); 585 int32_t nNewCharSet = 586 pFontMap->CharSetFromUnicode(nChar, FX_CHARSET_Default); 587 if (nOldCharSet != nNewCharSet) { 588 SetCharSet(nNewCharSet); 589 } 590 } 591 592 return CPWL_EditCtrl::OnChar(nChar, nFlag); 593 } 594 595 bool CPWL_Edit::OnMouseWheel(short zDelta, 596 const CFX_PointF& point, 597 uint32_t nFlag) { 598 if (!HasFlag(PES_MULTILINE)) 599 return false; 600 601 CFX_PointF ptScroll = GetScrollPos(); 602 if (zDelta > 0) 603 ptScroll.y += GetFontSize(); 604 else 605 ptScroll.y -= GetFontSize(); 606 SetScrollPos(ptScroll); 607 return true; 608 } 609 610 void CPWL_Edit::OnInsertReturn(const CPVT_WordPlace& place, 611 const CPVT_WordPlace& oldplace) { 612 if (HasFlag(PES_SPELLCHECK)) { 613 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 614 GetLatinWordsRange(place))); 615 } 616 } 617 618 void CPWL_Edit::OnBackSpace(const CPVT_WordPlace& place, 619 const CPVT_WordPlace& oldplace) { 620 if (HasFlag(PES_SPELLCHECK)) { 621 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 622 GetLatinWordsRange(place))); 623 } 624 } 625 626 void CPWL_Edit::OnDelete(const CPVT_WordPlace& place, 627 const CPVT_WordPlace& oldplace) { 628 if (HasFlag(PES_SPELLCHECK)) { 629 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 630 GetLatinWordsRange(place))); 631 } 632 } 633 634 void CPWL_Edit::OnClear(const CPVT_WordPlace& place, 635 const CPVT_WordPlace& oldplace) { 636 if (HasFlag(PES_SPELLCHECK)) { 637 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 638 GetLatinWordsRange(place))); 639 } 640 } 641 642 void CPWL_Edit::OnInsertWord(const CPVT_WordPlace& place, 643 const CPVT_WordPlace& oldplace) { 644 if (HasFlag(PES_SPELLCHECK)) { 645 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 646 GetLatinWordsRange(place))); 647 } 648 } 649 650 void CPWL_Edit::OnInsertText(const CPVT_WordPlace& place, 651 const CPVT_WordPlace& oldplace) { 652 if (HasFlag(PES_SPELLCHECK)) { 653 m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace), 654 GetLatinWordsRange(place))); 655 } 656 } 657 658 CPVT_WordRange CPWL_Edit::CombineWordRange(const CPVT_WordRange& wr1, 659 const CPVT_WordRange& wr2) { 660 return CPVT_WordRange(std::min(wr1.BeginPos, wr2.BeginPos), 661 std::max(wr1.EndPos, wr2.EndPos)); 662 } 663 664 CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CFX_PointF& point) const { 665 return GetSameWordsRange(m_pEdit->SearchWordPlace(point), true, false); 666 } 667 668 CPVT_WordRange CPWL_Edit::GetLatinWordsRange( 669 const CPVT_WordPlace& place) const { 670 return GetSameWordsRange(place, true, false); 671 } 672 673 #define PWL_ISARABICWORD(word) \ 674 ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC)) 675 676 CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place, 677 bool bLatin, 678 bool bArabic) const { 679 CPVT_WordRange range; 680 681 CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator(); 682 CPVT_Word wordinfo; 683 CPVT_WordPlace wpStart(place), wpEnd(place); 684 pIterator->SetAt(place); 685 686 if (bLatin) { 687 while (pIterator->NextWord()) { 688 if (!pIterator->GetWord(wordinfo) || 689 !FX_EDIT_ISLATINWORD(wordinfo.Word)) { 690 break; 691 } 692 693 wpEnd = pIterator->GetAt(); 694 } 695 } else if (bArabic) { 696 while (pIterator->NextWord()) { 697 if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word)) 698 break; 699 700 wpEnd = pIterator->GetAt(); 701 } 702 } 703 704 pIterator->SetAt(place); 705 706 if (bLatin) { 707 do { 708 if (!pIterator->GetWord(wordinfo) || 709 !FX_EDIT_ISLATINWORD(wordinfo.Word)) { 710 break; 711 } 712 713 wpStart = pIterator->GetAt(); 714 } while (pIterator->PrevWord()); 715 } else if (bArabic) { 716 do { 717 if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word)) 718 break; 719 720 wpStart = pIterator->GetAt(); 721 } while (pIterator->PrevWord()); 722 } 723 724 range.Set(wpStart, wpEnd); 725 return range; 726 } 727