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