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