Home | History | Annotate | Download | only in pdfwindow
      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/include/pdfwindow/PWL_Edit.h"
      8 
      9 #include "core/include/fxcrt/fx_safe_types.h"
     10 #include "core/include/fxcrt/fx_xml.h"
     11 #include "fpdfsdk/include/pdfwindow/PWL_Caret.h"
     12 #include "fpdfsdk/include/pdfwindow/PWL_EditCtrl.h"
     13 #include "fpdfsdk/include/pdfwindow/PWL_FontMap.h"
     14 #include "fpdfsdk/include/pdfwindow/PWL_ScrollBar.h"
     15 #include "fpdfsdk/include/pdfwindow/PWL_Utils.h"
     16 #include "fpdfsdk/include/pdfwindow/PWL_Wnd.h"
     17 #include "public/fpdf_fwlevent.h"
     18 
     19 CPWL_Edit::CPWL_Edit()
     20     : m_pFillerNotify(NULL), m_pSpellCheck(NULL), m_bFocus(FALSE) {
     21   m_pFormFiller = NULL;
     22 }
     23 
     24 CPWL_Edit::~CPWL_Edit() {
     25   ASSERT(m_bFocus == FALSE);
     26 }
     27 
     28 CFX_ByteString CPWL_Edit::GetClassName() const {
     29   return PWL_CLASSNAME_EDIT;
     30 }
     31 
     32 void CPWL_Edit::OnDestroy() {}
     33 
     34 void CPWL_Edit::SetText(const FX_WCHAR* csText) {
     35   CFX_WideString swText = csText;
     36 
     37   if (HasFlag(PES_RICH)) {
     38     CFX_ByteString sValue = CFX_ByteString::FromUnicode(swText);
     39 
     40     if (CXML_Element* pXML =
     41             CXML_Element::Parse(sValue.c_str(), sValue.GetLength())) {
     42       int32_t nCount = pXML->CountChildren();
     43       FX_BOOL bFirst = TRUE;
     44 
     45       swText.Empty();
     46 
     47       for (int32_t i = 0; i < nCount; i++) {
     48         if (CXML_Element* pSubElement = pXML->GetElement(i)) {
     49           CFX_ByteString tag = pSubElement->GetTagName();
     50           if (tag.EqualNoCase("p")) {
     51             int nChild = pSubElement->CountChildren();
     52             CFX_WideString swSection;
     53             for (int32_t j = 0; j < nChild; j++) {
     54               swSection += pSubElement->GetContent(j);
     55             }
     56 
     57             if (bFirst)
     58               bFirst = FALSE;
     59             else
     60               swText += FWL_VKEY_Return;
     61             swText += swSection;
     62           }
     63         }
     64       }
     65 
     66       delete pXML;
     67     }
     68   }
     69 
     70   m_pEdit->SetText(swText.c_str());
     71 }
     72 
     73 void CPWL_Edit::RePosChildWnd() {
     74   if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
     75     CPDF_Rect rcWindow = m_rcOldWindow;
     76     CPDF_Rect rcVScroll =
     77         CPDF_Rect(rcWindow.right, rcWindow.bottom,
     78                   rcWindow.right + PWL_SCROLLBAR_WIDTH, rcWindow.top);
     79     pVSB->Move(rcVScroll, TRUE, FALSE);
     80   }
     81 
     82   if (m_pEditCaret && !HasFlag(PES_TEXTOVERFLOW))
     83     m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect(
     84         GetClientRect(), 1.0f));  //+1 for caret beside border
     85 
     86   CPWL_EditCtrl::RePosChildWnd();
     87 }
     88 
     89 CPDF_Rect CPWL_Edit::GetClientRect() const {
     90   CPDF_Rect rcClient = CPWL_Utils::DeflateRect(
     91       GetWindowRect(), (FX_FLOAT)(GetBorderWidth() + GetInnerBorderWidth()));
     92 
     93   if (CPWL_ScrollBar* pVSB = GetVScrollBar()) {
     94     if (pVSB->IsVisible()) {
     95       rcClient.right -= PWL_SCROLLBAR_WIDTH;
     96     }
     97   }
     98 
     99   return rcClient;
    100 }
    101 
    102 void CPWL_Edit::SetAlignFormatH(PWL_EDIT_ALIGNFORMAT_H nFormat,
    103                                 FX_BOOL bPaint) {
    104   m_pEdit->SetAlignmentH((int32_t)nFormat, bPaint);
    105 }
    106 
    107 void CPWL_Edit::SetAlignFormatV(PWL_EDIT_ALIGNFORMAT_V nFormat,
    108                                 FX_BOOL bPaint) {
    109   m_pEdit->SetAlignmentV((int32_t)nFormat, bPaint);
    110 }
    111 
    112 FX_BOOL CPWL_Edit::CanSelectAll() const {
    113   return GetSelectWordRange() != m_pEdit->GetWholeWordRange();
    114 }
    115 
    116 FX_BOOL CPWL_Edit::CanClear() const {
    117   return !IsReadOnly() && m_pEdit->IsSelected();
    118 }
    119 
    120 FX_BOOL CPWL_Edit::CanCopy() const {
    121   return !HasFlag(PES_PASSWORD) && !HasFlag(PES_NOREAD) &&
    122          m_pEdit->IsSelected();
    123 }
    124 
    125 FX_BOOL CPWL_Edit::CanCut() const {
    126   return CanCopy() && !IsReadOnly();
    127 }
    128 
    129 FX_BOOL CPWL_Edit::CanPaste() const {
    130   if (IsReadOnly())
    131     return FALSE;
    132 
    133   CFX_WideString swClipboard;
    134   if (IFX_SystemHandler* pSH = GetSystemHandler())
    135     swClipboard = pSH->GetClipboardText(GetAttachedHWnd());
    136 
    137   return !swClipboard.IsEmpty();
    138 }
    139 
    140 void CPWL_Edit::CopyText() {
    141   if (!CanCopy())
    142     return;
    143 
    144   CFX_WideString str = m_pEdit->GetSelText();
    145 
    146   if (IFX_SystemHandler* pSH = GetSystemHandler())
    147     pSH->SetClipboardText(GetAttachedHWnd(), str);
    148 }
    149 
    150 void CPWL_Edit::PasteText() {
    151   if (!CanPaste())
    152     return;
    153 
    154   CFX_WideString swClipboard;
    155   if (IFX_SystemHandler* pSH = GetSystemHandler())
    156     swClipboard = pSH->GetClipboardText(GetAttachedHWnd());
    157 
    158   if (m_pFillerNotify) {
    159     FX_BOOL bRC = TRUE;
    160     FX_BOOL bExit = FALSE;
    161     CFX_WideString strChangeEx;
    162     int nSelStart = 0;
    163     int nSelEnd = 0;
    164     GetSel(nSelStart, nSelEnd);
    165     m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swClipboard,
    166                                        strChangeEx, nSelStart, nSelEnd, TRUE,
    167                                        bRC, bExit, 0);
    168     if (!bRC)
    169       return;
    170     if (bExit)
    171       return;
    172   }
    173 
    174   if (swClipboard.GetLength() > 0) {
    175     Clear();
    176     InsertText(swClipboard.c_str());
    177   }
    178 }
    179 
    180 void CPWL_Edit::CutText() {
    181   if (!CanCut())
    182     return;
    183 
    184   CFX_WideString str = m_pEdit->GetSelText();
    185 
    186   if (IFX_SystemHandler* pSH = GetSystemHandler())
    187     pSH->SetClipboardText(GetAttachedHWnd(), str);
    188 
    189   m_pEdit->Clear();
    190 }
    191 
    192 void CPWL_Edit::OnCreated() {
    193   CPWL_EditCtrl::OnCreated();
    194 
    195   if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
    196     pScroll->RemoveFlag(PWS_AUTOTRANSPARENT);
    197     pScroll->SetTransparency(255);
    198   }
    199 
    200   SetParamByFlag();
    201 
    202   m_rcOldWindow = GetWindowRect();
    203 
    204   m_pEdit->SetOprNotify(this);
    205   m_pEdit->EnableOprNotify(TRUE);
    206 }
    207 
    208 void CPWL_Edit::SetParamByFlag() {
    209   if (HasFlag(PES_RIGHT)) {
    210     m_pEdit->SetAlignmentH(2, FALSE);
    211   } else if (HasFlag(PES_MIDDLE)) {
    212     m_pEdit->SetAlignmentH(1, FALSE);
    213   } else {
    214     m_pEdit->SetAlignmentH(0, FALSE);
    215   }
    216 
    217   if (HasFlag(PES_BOTTOM)) {
    218     m_pEdit->SetAlignmentV(2, FALSE);
    219   } else if (HasFlag(PES_CENTER)) {
    220     m_pEdit->SetAlignmentV(1, FALSE);
    221   } else {
    222     m_pEdit->SetAlignmentV(0, FALSE);
    223   }
    224 
    225   if (HasFlag(PES_PASSWORD)) {
    226     m_pEdit->SetPasswordChar('*', FALSE);
    227   }
    228 
    229   m_pEdit->SetMultiLine(HasFlag(PES_MULTILINE), FALSE);
    230   m_pEdit->SetAutoReturn(HasFlag(PES_AUTORETURN), FALSE);
    231   m_pEdit->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE), FALSE);
    232   m_pEdit->SetAutoScroll(HasFlag(PES_AUTOSCROLL), FALSE);
    233   m_pEdit->EnableUndo(HasFlag(PES_UNDO));
    234 
    235   if (HasFlag(PES_TEXTOVERFLOW)) {
    236     SetClipRect(CPDF_Rect(0.0f, 0.0f, 0.0f, 0.0f));
    237     m_pEdit->SetTextOverflow(TRUE, FALSE);
    238   } else {
    239     if (m_pEditCaret) {
    240       m_pEditCaret->SetClipRect(CPWL_Utils::InflateRect(
    241           GetClientRect(), 1.0f));  //+1 for caret beside border
    242     }
    243   }
    244 
    245   if (HasFlag(PES_SPELLCHECK)) {
    246     m_pSpellCheck = GetCreationParam().pSpellCheck;
    247   }
    248 }
    249 
    250 void CPWL_Edit::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
    251   CPWL_Wnd::GetThisAppearanceStream(sAppStream);
    252 
    253   CPDF_Rect rcClient = GetClientRect();
    254   CFX_ByteTextBuf sLine;
    255 
    256   int32_t nCharArray = m_pEdit->GetCharArray();
    257 
    258   if (nCharArray > 0) {
    259     switch (GetBorderStyle()) {
    260       case PBS_SOLID: {
    261         sLine << "q\n" << GetBorderWidth() << " w\n"
    262               << CPWL_Utils::GetColorAppStream(GetBorderColor(), FALSE)
    263               << " 2 J 0 j\n";
    264 
    265         for (int32_t i = 1; i < nCharArray; i++) {
    266           sLine << rcClient.left +
    267                        ((rcClient.right - rcClient.left) / nCharArray) * i
    268                 << " " << rcClient.bottom << " m\n"
    269                 << rcClient.left +
    270                        ((rcClient.right - rcClient.left) / nCharArray) * i
    271                 << " " << rcClient.top << " l S\n";
    272         }
    273 
    274         sLine << "Q\n";
    275       } break;
    276       case PBS_DASH: {
    277         sLine << "q\n" << GetBorderWidth() << " w\n"
    278               << CPWL_Utils::GetColorAppStream(GetBorderColor(), FALSE)
    279               << " 2 J 0 j\n"
    280               << "[" << GetBorderDash().nDash << " " << GetBorderDash().nGap
    281               << "] " << GetBorderDash().nPhase << " d\n";
    282 
    283         for (int32_t i = 1; i < nCharArray; i++) {
    284           sLine << rcClient.left +
    285                        ((rcClient.right - rcClient.left) / nCharArray) * i
    286                 << " " << rcClient.bottom << " m\n"
    287                 << rcClient.left +
    288                        ((rcClient.right - rcClient.left) / nCharArray) * i
    289                 << " " << rcClient.top << " l S\n";
    290         }
    291 
    292         sLine << "Q\n";
    293       } break;
    294     }
    295   }
    296 
    297   sAppStream << sLine;
    298 
    299   CFX_ByteTextBuf sText;
    300 
    301   CPDF_Point ptOffset = CPDF_Point(0.0f, 0.0f);
    302 
    303   CPVT_WordRange wrWhole = m_pEdit->GetWholeWordRange();
    304   CPVT_WordRange wrSelect = GetSelectWordRange();
    305   CPVT_WordRange wrVisible =
    306       (HasFlag(PES_TEXTOVERFLOW) ? wrWhole : m_pEdit->GetVisibleWordRange());
    307   CPVT_WordRange wrSelBefore(wrWhole.BeginPos, wrSelect.BeginPos);
    308   CPVT_WordRange wrSelAfter(wrSelect.EndPos, wrWhole.EndPos);
    309 
    310   CPVT_WordRange wrTemp =
    311       CPWL_Utils::OverlapWordRange(GetSelectWordRange(), wrVisible);
    312   CFX_ByteString sEditSel =
    313       CPWL_Utils::GetEditSelAppStream(m_pEdit, ptOffset, &wrTemp);
    314 
    315   if (sEditSel.GetLength() > 0)
    316     sText << CPWL_Utils::GetColorAppStream(PWL_DEFAULT_SELBACKCOLOR)
    317           << sEditSel;
    318 
    319   wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelBefore);
    320   CFX_ByteString sEditBefore = CPWL_Utils::GetEditAppStream(
    321       m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
    322       m_pEdit->GetPasswordChar());
    323 
    324   if (sEditBefore.GetLength() > 0)
    325     sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor())
    326           << sEditBefore << "ET\n";
    327 
    328   wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelect);
    329   CFX_ByteString sEditMid = CPWL_Utils::GetEditAppStream(
    330       m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
    331       m_pEdit->GetPasswordChar());
    332 
    333   if (sEditMid.GetLength() > 0)
    334     sText << "BT\n"
    335           << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_GRAY, 1))
    336           << sEditMid << "ET\n";
    337 
    338   wrTemp = CPWL_Utils::OverlapWordRange(wrVisible, wrSelAfter);
    339   CFX_ByteString sEditAfter = CPWL_Utils::GetEditAppStream(
    340       m_pEdit, ptOffset, &wrTemp, !HasFlag(PES_CHARARRAY),
    341       m_pEdit->GetPasswordChar());
    342 
    343   if (sEditAfter.GetLength() > 0)
    344     sText << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor())
    345           << sEditAfter << "ET\n";
    346 
    347   if (HasFlag(PES_SPELLCHECK)) {
    348     CFX_ByteString sSpellCheck = CPWL_Utils::GetSpellCheckAppStream(
    349         m_pEdit, m_pSpellCheck, ptOffset, &wrVisible);
    350     if (sSpellCheck.GetLength() > 0)
    351       sText << CPWL_Utils::GetColorAppStream(CPWL_Color(COLORTYPE_RGB, 1, 0, 0),
    352                                              FALSE)
    353             << sSpellCheck;
    354   }
    355 
    356   if (sText.GetLength() > 0) {
    357     CPDF_Rect rcClient = GetClientRect();
    358     sAppStream << "q\n/Tx BMC\n";
    359 
    360     if (!HasFlag(PES_TEXTOVERFLOW))
    361       sAppStream << rcClient.left << " " << rcClient.bottom << " "
    362                  << rcClient.right - rcClient.left << " "
    363                  << rcClient.top - rcClient.bottom << " re W n\n";
    364 
    365     sAppStream << sText;
    366 
    367     sAppStream << "EMC\nQ\n";
    368   }
    369 }
    370 
    371 void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice,
    372                                    CFX_Matrix* pUser2Device) {
    373   CPWL_Wnd::DrawThisAppearance(pDevice, pUser2Device);
    374 
    375   CPDF_Rect rcClient = GetClientRect();
    376   CFX_ByteTextBuf sLine;
    377 
    378   int32_t nCharArray = m_pEdit->GetCharArray();
    379   FX_SAFE_INT32 nCharArraySafe = nCharArray;
    380   nCharArraySafe -= 1;
    381   nCharArraySafe *= 2;
    382 
    383   if (nCharArray > 0 && nCharArraySafe.IsValid()) {
    384     switch (GetBorderStyle()) {
    385       case PBS_SOLID: {
    386         CFX_GraphStateData gsd;
    387         gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth();
    388 
    389         CFX_PathData path;
    390         path.SetPointCount(nCharArraySafe.ValueOrDie());
    391 
    392         for (int32_t i = 0; i < nCharArray - 1; i++) {
    393           path.SetPoint(
    394               i * 2,
    395               rcClient.left +
    396                   ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
    397               rcClient.bottom, FXPT_MOVETO);
    398           path.SetPoint(
    399               i * 2 + 1,
    400               rcClient.left +
    401                   ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
    402               rcClient.top, FXPT_LINETO);
    403         }
    404         if (path.GetPointCount() > 0)
    405           pDevice->DrawPath(
    406               &path, pUser2Device, &gsd, 0,
    407               CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255),
    408               FXFILL_ALTERNATE);
    409       } break;
    410       case PBS_DASH: {
    411         CFX_GraphStateData gsd;
    412         gsd.m_LineWidth = (FX_FLOAT)GetBorderWidth();
    413 
    414         gsd.SetDashCount(2);
    415         gsd.m_DashArray[0] = (FX_FLOAT)GetBorderDash().nDash;
    416         gsd.m_DashArray[1] = (FX_FLOAT)GetBorderDash().nGap;
    417         gsd.m_DashPhase = (FX_FLOAT)GetBorderDash().nPhase;
    418 
    419         CFX_PathData path;
    420         path.SetPointCount(nCharArraySafe.ValueOrDie());
    421 
    422         for (int32_t i = 0; i < nCharArray - 1; i++) {
    423           path.SetPoint(
    424               i * 2,
    425               rcClient.left +
    426                   ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
    427               rcClient.bottom, FXPT_MOVETO);
    428           path.SetPoint(
    429               i * 2 + 1,
    430               rcClient.left +
    431                   ((rcClient.right - rcClient.left) / nCharArray) * (i + 1),
    432               rcClient.top, FXPT_LINETO);
    433         }
    434         if (path.GetPointCount() > 0)
    435           pDevice->DrawPath(
    436               &path, pUser2Device, &gsd, 0,
    437               CPWL_Utils::PWLColorToFXColor(GetBorderColor(), 255),
    438               FXFILL_ALTERNATE);
    439       } break;
    440     }
    441   }
    442 
    443   CPDF_Rect rcClip;
    444   CPVT_WordRange wrRange = m_pEdit->GetVisibleWordRange();
    445   CPVT_WordRange* pRange = NULL;
    446 
    447   if (!HasFlag(PES_TEXTOVERFLOW)) {
    448     rcClip = GetClientRect();
    449     pRange = &wrRange;
    450   }
    451   IFX_SystemHandler* pSysHandler = GetSystemHandler();
    452   IFX_Edit::DrawEdit(
    453       pDevice, pUser2Device, m_pEdit,
    454       CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
    455       CPWL_Utils::PWLColorToFXColor(GetTextStrokeColor(), GetTransparency()),
    456       rcClip, CPDF_Point(0.0f, 0.0f), pRange, pSysHandler, m_pFormFiller);
    457 
    458   if (HasFlag(PES_SPELLCHECK)) {
    459     CPWL_Utils::DrawEditSpellCheck(pDevice, pUser2Device, m_pEdit, rcClip,
    460                                    CPDF_Point(0.0f, 0.0f), pRange,
    461                                    GetCreationParam().pSpellCheck);
    462   }
    463 }
    464 
    465 FX_BOOL CPWL_Edit::OnLButtonDown(const CPDF_Point& point, FX_DWORD nFlag) {
    466   CPWL_Wnd::OnLButtonDown(point, nFlag);
    467 
    468   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
    469     if (m_bMouseDown)
    470       InvalidateRect();
    471 
    472     m_bMouseDown = TRUE;
    473     SetCapture();
    474 
    475     m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
    476   }
    477 
    478   return TRUE;
    479 }
    480 
    481 FX_BOOL CPWL_Edit::OnLButtonDblClk(const CPDF_Point& point, FX_DWORD nFlag) {
    482   CPWL_Wnd::OnLButtonDblClk(point, nFlag);
    483 
    484   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
    485     m_pEdit->SelectAll();
    486   }
    487 
    488   return TRUE;
    489 }
    490 
    491 #define WM_PWLEDIT_UNDO 0x01
    492 #define WM_PWLEDIT_REDO 0x02
    493 #define WM_PWLEDIT_CUT 0x03
    494 #define WM_PWLEDIT_COPY 0x04
    495 #define WM_PWLEDIT_PASTE 0x05
    496 #define WM_PWLEDIT_DELETE 0x06
    497 #define WM_PWLEDIT_SELECTALL 0x07
    498 #define WM_PWLEDIT_SUGGEST 0x08
    499 
    500 FX_BOOL CPWL_Edit::OnRButtonUp(const CPDF_Point& point, FX_DWORD nFlag) {
    501   if (m_bMouseDown)
    502     return FALSE;
    503 
    504   CPWL_Wnd::OnRButtonUp(point, nFlag);
    505 
    506   if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point))
    507     return TRUE;
    508 
    509   IFX_SystemHandler* pSH = GetSystemHandler();
    510   if (!pSH)
    511     return FALSE;
    512 
    513   SetFocus();
    514 
    515   CPVT_WordRange wrLatin = GetLatinWordsRange(point);
    516   CFX_WideString swLatin = m_pEdit->GetRangeText(wrLatin);
    517 
    518   FX_HMENU hPopup = pSH->CreatePopupMenu();
    519   if (!hPopup)
    520     return FALSE;
    521 
    522   CFX_ByteStringArray sSuggestWords;
    523   CPDF_Point ptPopup = point;
    524 
    525   if (!IsReadOnly()) {
    526     if (HasFlag(PES_SPELLCHECK) && !swLatin.IsEmpty()) {
    527       if (m_pSpellCheck) {
    528         CFX_ByteString sLatin = CFX_ByteString::FromUnicode(swLatin);
    529 
    530         if (!m_pSpellCheck->CheckWord(sLatin)) {
    531           m_pSpellCheck->SuggestWords(sLatin, sSuggestWords);
    532 
    533           int32_t nSuggest = sSuggestWords.GetSize();
    534 
    535           for (int32_t nWord = 0; nWord < nSuggest; nWord++) {
    536             pSH->AppendMenuItem(hPopup, WM_PWLEDIT_SUGGEST + nWord,
    537                                 sSuggestWords[nWord].UTF8Decode());
    538           }
    539 
    540           if (nSuggest > 0)
    541             pSH->AppendMenuItem(hPopup, 0, L"");
    542 
    543           ptPopup = GetWordRightBottomPoint(wrLatin.EndPos);
    544         }
    545       }
    546     }
    547   }
    548 
    549   IPWL_Provider* pProvider = GetProvider();
    550 
    551   if (HasFlag(PES_UNDO)) {
    552     pSH->AppendMenuItem(
    553         hPopup, WM_PWLEDIT_UNDO,
    554         pProvider ? pProvider->LoadPopupMenuString(0) : L"&Undo");
    555     pSH->AppendMenuItem(
    556         hPopup, WM_PWLEDIT_REDO,
    557         pProvider ? pProvider->LoadPopupMenuString(1) : L"&Redo");
    558     pSH->AppendMenuItem(hPopup, 0, L"");
    559 
    560     if (!m_pEdit->CanUndo())
    561       pSH->EnableMenuItem(hPopup, WM_PWLEDIT_UNDO, FALSE);
    562     if (!m_pEdit->CanRedo())
    563       pSH->EnableMenuItem(hPopup, WM_PWLEDIT_REDO, FALSE);
    564   }
    565 
    566   pSH->AppendMenuItem(hPopup, WM_PWLEDIT_CUT,
    567                       pProvider ? pProvider->LoadPopupMenuString(2) : L"Cu&t");
    568   pSH->AppendMenuItem(hPopup, WM_PWLEDIT_COPY,
    569                       pProvider ? pProvider->LoadPopupMenuString(3) : L"&Copy");
    570   pSH->AppendMenuItem(
    571       hPopup, WM_PWLEDIT_PASTE,
    572       pProvider ? pProvider->LoadPopupMenuString(4) : L"&Paste");
    573   pSH->AppendMenuItem(
    574       hPopup, WM_PWLEDIT_DELETE,
    575       pProvider ? pProvider->LoadPopupMenuString(5) : L"&Delete");
    576 
    577   CFX_WideString swText = pSH->GetClipboardText(GetAttachedHWnd());
    578   if (swText.IsEmpty())
    579     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_PASTE, FALSE);
    580 
    581   if (!m_pEdit->IsSelected()) {
    582     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE);
    583     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE);
    584     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_DELETE, FALSE);
    585   }
    586 
    587   if (IsReadOnly()) {
    588     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE);
    589     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_DELETE, FALSE);
    590     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_PASTE, FALSE);
    591   }
    592 
    593   if (HasFlag(PES_PASSWORD)) {
    594     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE);
    595     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE);
    596   }
    597 
    598   if (HasFlag(PES_NOREAD)) {
    599     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_CUT, FALSE);
    600     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_COPY, FALSE);
    601   }
    602 
    603   pSH->AppendMenuItem(hPopup, 0, L"");
    604   pSH->AppendMenuItem(
    605       hPopup, WM_PWLEDIT_SELECTALL,
    606       pProvider ? pProvider->LoadPopupMenuString(6) : L"&Select All");
    607 
    608   if (m_pEdit->GetTotalWords() == 0) {
    609     pSH->EnableMenuItem(hPopup, WM_PWLEDIT_SELECTALL, FALSE);
    610   }
    611 
    612   int32_t x, y;
    613   PWLtoWnd(ptPopup, x, y);
    614   pSH->ClientToScreen(GetAttachedHWnd(), x, y);
    615   pSH->SetCursor(FXCT_ARROW);
    616   int32_t nCmd = pSH->TrackPopupMenu(hPopup, x, y, GetAttachedHWnd());
    617 
    618   switch (nCmd) {
    619     case WM_PWLEDIT_UNDO:
    620       Undo();
    621       break;
    622     case WM_PWLEDIT_REDO:
    623       Redo();
    624       break;
    625     case WM_PWLEDIT_CUT:
    626       CutText();
    627       break;
    628     case WM_PWLEDIT_COPY:
    629       CopyText();
    630       break;
    631     case WM_PWLEDIT_PASTE:
    632       PasteText();
    633       break;
    634     case WM_PWLEDIT_DELETE:
    635       Clear();
    636       break;
    637     case WM_PWLEDIT_SELECTALL:
    638       SelectAll();
    639       break;
    640     case WM_PWLEDIT_SUGGEST + 0:
    641       SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos),
    642              m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos));
    643       ReplaceSel(sSuggestWords[0].UTF8Decode().c_str());
    644       break;
    645     case WM_PWLEDIT_SUGGEST + 1:
    646       SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos),
    647              m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos));
    648       ReplaceSel(sSuggestWords[1].UTF8Decode().c_str());
    649       break;
    650     case WM_PWLEDIT_SUGGEST + 2:
    651       SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos),
    652              m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos));
    653       ReplaceSel(sSuggestWords[2].UTF8Decode().c_str());
    654       break;
    655     case WM_PWLEDIT_SUGGEST + 3:
    656       SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos),
    657              m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos));
    658       ReplaceSel(sSuggestWords[3].UTF8Decode().c_str());
    659       break;
    660     case WM_PWLEDIT_SUGGEST + 4:
    661       SetSel(m_pEdit->WordPlaceToWordIndex(wrLatin.BeginPos),
    662              m_pEdit->WordPlaceToWordIndex(wrLatin.EndPos));
    663       ReplaceSel(sSuggestWords[4].UTF8Decode().c_str());
    664       break;
    665     default:
    666       break;
    667   }
    668 
    669   pSH->DestroyMenu(hPopup);
    670 
    671   return TRUE;
    672 }
    673 
    674 void CPWL_Edit::OnSetFocus() {
    675   SetEditCaret(TRUE);
    676 
    677   if (!IsReadOnly()) {
    678     if (IPWL_FocusHandler* pFocusHandler = GetFocusHandler())
    679       pFocusHandler->OnSetFocus(this);
    680   }
    681 
    682   m_bFocus = TRUE;
    683 }
    684 
    685 void CPWL_Edit::OnKillFocus() {
    686   ShowVScrollBar(FALSE);
    687 
    688   m_pEdit->SelectNone();
    689   SetCaret(FALSE, CPDF_Point(0.0f, 0.0f), CPDF_Point(0.0f, 0.0f));
    690 
    691   SetCharSet(0);
    692 
    693   if (!IsReadOnly()) {
    694     if (IPWL_FocusHandler* pFocusHandler = GetFocusHandler())
    695       pFocusHandler->OnKillFocus(this);
    696   }
    697 
    698   m_bFocus = FALSE;
    699 }
    700 
    701 void CPWL_Edit::SetHorzScale(int32_t nHorzScale, FX_BOOL bPaint /* = TRUE*/) {
    702   m_pEdit->SetHorzScale(nHorzScale, bPaint);
    703 }
    704 
    705 void CPWL_Edit::SetCharSpace(FX_FLOAT fCharSpace, FX_BOOL bPaint /* = TRUE*/) {
    706   m_pEdit->SetCharSpace(fCharSpace, bPaint);
    707 }
    708 
    709 void CPWL_Edit::SetLineLeading(FX_FLOAT fLineLeading,
    710                                FX_BOOL bPaint /* = TRUE*/) {
    711   m_pEdit->SetLineLeading(fLineLeading, bPaint);
    712 }
    713 
    714 CFX_ByteString CPWL_Edit::GetSelectAppearanceStream(
    715     const CPDF_Point& ptOffset) const {
    716   CPVT_WordRange wr = GetSelectWordRange();
    717   return CPWL_Utils::GetEditSelAppStream(m_pEdit, ptOffset, &wr);
    718 }
    719 
    720 CPVT_WordRange CPWL_Edit::GetSelectWordRange() const {
    721   if (m_pEdit->IsSelected()) {
    722     int32_t nStart = -1;
    723     int32_t nEnd = -1;
    724 
    725     m_pEdit->GetSel(nStart, nEnd);
    726 
    727     CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStart);
    728     CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEnd);
    729 
    730     return CPVT_WordRange(wpStart, wpEnd);
    731   }
    732 
    733   return CPVT_WordRange();
    734 }
    735 
    736 CFX_ByteString CPWL_Edit::GetTextAppearanceStream(
    737     const CPDF_Point& ptOffset) const {
    738   CFX_ByteTextBuf sRet;
    739   CFX_ByteString sEdit = CPWL_Utils::GetEditAppStream(m_pEdit, ptOffset);
    740 
    741   if (sEdit.GetLength() > 0) {
    742     sRet << "BT\n" << CPWL_Utils::GetColorAppStream(GetTextColor()) << sEdit
    743          << "ET\n";
    744   }
    745 
    746   return sRet.GetByteString();
    747 }
    748 
    749 CFX_ByteString CPWL_Edit::GetCaretAppearanceStream(
    750     const CPDF_Point& ptOffset) const {
    751   if (m_pEditCaret)
    752     return m_pEditCaret->GetCaretAppearanceStream(ptOffset);
    753 
    754   return CFX_ByteString();
    755 }
    756 
    757 CPDF_Point CPWL_Edit::GetWordRightBottomPoint(const CPVT_WordPlace& wpWord) {
    758   CPDF_Point pt(0.0f, 0.0f);
    759 
    760   if (IFX_Edit_Iterator* pIterator = m_pEdit->GetIterator()) {
    761     CPVT_WordPlace wpOld = pIterator->GetAt();
    762     pIterator->SetAt(wpWord);
    763     CPVT_Word word;
    764     if (pIterator->GetWord(word)) {
    765       pt = CPDF_Point(word.ptWord.x + word.fWidth,
    766                       word.ptWord.y + word.fDescent);
    767     }
    768 
    769     pIterator->SetAt(wpOld);
    770   }
    771 
    772   return pt;
    773 }
    774 
    775 FX_BOOL CPWL_Edit::IsTextFull() const {
    776   return m_pEdit->IsTextFull();
    777 }
    778 
    779 FX_FLOAT CPWL_Edit::GetCharArrayAutoFontSize(CPDF_Font* pFont,
    780                                              const CPDF_Rect& rcPlate,
    781                                              int32_t nCharArray) {
    782   if (pFont && !pFont->IsStandardFont()) {
    783     FX_RECT rcBBox;
    784     pFont->GetFontBBox(rcBBox);
    785 
    786     CPDF_Rect rcCell = rcPlate;
    787     FX_FLOAT xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width();
    788     FX_FLOAT ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height();
    789 
    790     return xdiv < ydiv ? xdiv : ydiv;
    791   }
    792 
    793   return 0.0f;
    794 }
    795 
    796 void CPWL_Edit::SetCharArray(int32_t nCharArray) {
    797   if (HasFlag(PES_CHARARRAY) && nCharArray > 0) {
    798     m_pEdit->SetCharArray(nCharArray);
    799     m_pEdit->SetTextOverflow(TRUE);
    800 
    801     if (HasFlag(PWS_AUTOFONTSIZE)) {
    802       if (IFX_Edit_FontMap* pFontMap = GetFontMap()) {
    803         FX_FLOAT fFontSize = GetCharArrayAutoFontSize(
    804             pFontMap->GetPDFFont(0), GetClientRect(), nCharArray);
    805         if (fFontSize > 0.0f) {
    806           m_pEdit->SetAutoFontSize(FALSE);
    807           m_pEdit->SetFontSize(fFontSize);
    808         }
    809       }
    810     }
    811   }
    812 }
    813 
    814 void CPWL_Edit::SetLimitChar(int32_t nLimitChar) {
    815   m_pEdit->SetLimitChar(nLimitChar);
    816 }
    817 
    818 void CPWL_Edit::ReplaceSel(const FX_WCHAR* csText) {
    819   m_pEdit->Clear();
    820   m_pEdit->InsertText(csText);
    821 }
    822 
    823 CPDF_Rect CPWL_Edit::GetFocusRect() const {
    824   return CPDF_Rect();
    825 }
    826 
    827 void CPWL_Edit::ShowVScrollBar(FX_BOOL bShow) {
    828   if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
    829     if (bShow) {
    830       if (!pScroll->IsVisible()) {
    831         pScroll->SetVisible(TRUE);
    832         CPDF_Rect rcWindow = GetWindowRect();
    833         m_rcOldWindow = rcWindow;
    834         rcWindow.right += PWL_SCROLLBAR_WIDTH;
    835         Move(rcWindow, TRUE, TRUE);
    836       }
    837     } else {
    838       if (pScroll->IsVisible()) {
    839         pScroll->SetVisible(FALSE);
    840         Move(m_rcOldWindow, TRUE, TRUE);
    841       }
    842     }
    843   }
    844 }
    845 
    846 FX_BOOL CPWL_Edit::IsVScrollBarVisible() const {
    847   if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
    848     return pScroll->IsVisible();
    849   }
    850 
    851   return FALSE;
    852 }
    853 
    854 void CPWL_Edit::EnableSpellCheck(FX_BOOL bEnabled) {
    855   if (bEnabled)
    856     AddFlag(PES_SPELLCHECK);
    857   else
    858     RemoveFlag(PES_SPELLCHECK);
    859 }
    860 
    861 FX_BOOL CPWL_Edit::OnKeyDown(FX_WORD nChar, FX_DWORD nFlag) {
    862   if (m_bMouseDown)
    863     return TRUE;
    864 
    865   if (nChar == FWL_VKEY_Delete) {
    866     if (m_pFillerNotify) {
    867       FX_BOOL bRC = TRUE;
    868       FX_BOOL bExit = FALSE;
    869       CFX_WideString strChange;
    870       CFX_WideString strChangeEx;
    871 
    872       int nSelStart = 0;
    873       int nSelEnd = 0;
    874       GetSel(nSelStart, nSelEnd);
    875 
    876       if (nSelStart == nSelEnd)
    877         nSelEnd = nSelStart + 1;
    878       m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), strChange,
    879                                          strChangeEx, nSelStart, nSelEnd, TRUE,
    880                                          bRC, bExit, nFlag);
    881       if (!bRC)
    882         return FALSE;
    883       if (bExit)
    884         return FALSE;
    885     }
    886   }
    887 
    888   FX_BOOL bRet = CPWL_EditCtrl::OnKeyDown(nChar, nFlag);
    889 
    890   // In case of implementation swallow the OnKeyDown event.
    891   if (IsProceedtoOnChar(nChar, nFlag))
    892     return TRUE;
    893 
    894   return bRet;
    895 }
    896 
    897 /**
    898 *In case of implementation swallow the OnKeyDown event.
    899 *If the event is swallowed, implementation may do other unexpected things, which
    900 *is not the control means to do.
    901 */
    902 FX_BOOL CPWL_Edit::IsProceedtoOnChar(FX_WORD nKeyCode, FX_DWORD nFlag) {
    903   FX_BOOL bCtrl = IsCTRLpressed(nFlag);
    904   FX_BOOL bAlt = IsALTpressed(nFlag);
    905   if (bCtrl && !bAlt) {
    906     // hot keys for edit control.
    907     switch (nKeyCode) {
    908       case 'C':
    909       case 'V':
    910       case 'X':
    911       case 'A':
    912       case 'Z':
    913         return TRUE;
    914       default:
    915         break;
    916     }
    917   }
    918   // control characters.
    919   switch (nKeyCode) {
    920     case FWL_VKEY_Escape:
    921     case FWL_VKEY_Back:
    922     case FWL_VKEY_Return:
    923     case FWL_VKEY_Space:
    924       return TRUE;
    925     default:
    926       return FALSE;
    927   }
    928 }
    929 
    930 FX_BOOL CPWL_Edit::OnChar(FX_WORD nChar, FX_DWORD nFlag) {
    931   if (m_bMouseDown)
    932     return TRUE;
    933 
    934   FX_BOOL bRC = TRUE;
    935   FX_BOOL bExit = FALSE;
    936 
    937   if (!IsCTRLpressed(nFlag)) {
    938     if (m_pFillerNotify) {
    939       CFX_WideString swChange;
    940 
    941       int nSelStart = 0;
    942       int nSelEnd = 0;
    943       GetSel(nSelStart, nSelEnd);
    944 
    945       switch (nChar) {
    946         case FWL_VKEY_Back:
    947           if (nSelStart == nSelEnd)
    948             nSelStart = nSelEnd - 1;
    949           break;
    950         case FWL_VKEY_Return:
    951           break;
    952         default:
    953           swChange += nChar;
    954           break;
    955       }
    956 
    957       CFX_WideString strChangeEx;
    958       m_pFillerNotify->OnBeforeKeyStroke(GetAttachedData(), swChange,
    959                                          strChangeEx, nSelStart, nSelEnd, TRUE,
    960                                          bRC, bExit, nFlag);
    961     }
    962   }
    963 
    964   if (!bRC)
    965     return TRUE;
    966   if (bExit)
    967     return FALSE;
    968 
    969   if (IFX_Edit_FontMap* pFontMap = GetFontMap()) {
    970     int32_t nOldCharSet = GetCharSet();
    971     int32_t nNewCharSet = pFontMap->CharSetFromUnicode(nChar, DEFAULT_CHARSET);
    972     if (nOldCharSet != nNewCharSet) {
    973       SetCharSet(nNewCharSet);
    974     }
    975   }
    976 
    977   return CPWL_EditCtrl::OnChar(nChar, nFlag);
    978 }
    979 
    980 FX_BOOL CPWL_Edit::OnMouseWheel(short zDelta,
    981                                 const CPDF_Point& point,
    982                                 FX_DWORD nFlag) {
    983   if (HasFlag(PES_MULTILINE)) {
    984     CPDF_Point ptScroll = GetScrollPos();
    985 
    986     if (zDelta > 0) {
    987       ptScroll.y += GetFontSize();
    988     } else {
    989       ptScroll.y -= GetFontSize();
    990     }
    991     SetScrollPos(ptScroll);
    992 
    993     return TRUE;
    994   }
    995 
    996   return FALSE;
    997 }
    998 
    999 void CPWL_Edit::OnInsertReturn(const CPVT_WordPlace& place,
   1000                                const CPVT_WordPlace& oldplace) {
   1001   if (HasFlag(PES_SPELLCHECK)) {
   1002     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1003                                                GetLatinWordsRange(place)));
   1004   }
   1005 
   1006   if (m_pEditNotify) {
   1007     m_pEditNotify->OnInsertReturn(place, oldplace);
   1008   }
   1009 }
   1010 
   1011 void CPWL_Edit::OnBackSpace(const CPVT_WordPlace& place,
   1012                             const CPVT_WordPlace& oldplace) {
   1013   if (HasFlag(PES_SPELLCHECK)) {
   1014     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1015                                                GetLatinWordsRange(place)));
   1016   }
   1017 
   1018   if (m_pEditNotify) {
   1019     m_pEditNotify->OnBackSpace(place, oldplace);
   1020   }
   1021 }
   1022 
   1023 void CPWL_Edit::OnDelete(const CPVT_WordPlace& place,
   1024                          const CPVT_WordPlace& oldplace) {
   1025   if (HasFlag(PES_SPELLCHECK)) {
   1026     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1027                                                GetLatinWordsRange(place)));
   1028   }
   1029 
   1030   if (m_pEditNotify) {
   1031     m_pEditNotify->OnDelete(place, oldplace);
   1032   }
   1033 }
   1034 
   1035 void CPWL_Edit::OnClear(const CPVT_WordPlace& place,
   1036                         const CPVT_WordPlace& oldplace) {
   1037   if (HasFlag(PES_SPELLCHECK)) {
   1038     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1039                                                GetLatinWordsRange(place)));
   1040   }
   1041 
   1042   if (m_pEditNotify) {
   1043     m_pEditNotify->OnClear(place, oldplace);
   1044   }
   1045 }
   1046 
   1047 void CPWL_Edit::OnInsertWord(const CPVT_WordPlace& place,
   1048                              const CPVT_WordPlace& oldplace) {
   1049   if (HasFlag(PES_SPELLCHECK)) {
   1050     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1051                                                GetLatinWordsRange(place)));
   1052   }
   1053 
   1054   if (m_pEditNotify) {
   1055     m_pEditNotify->OnInsertWord(place, oldplace);
   1056   }
   1057 }
   1058 
   1059 void CPWL_Edit::OnSetText(const CPVT_WordPlace& place,
   1060                           const CPVT_WordPlace& oldplace) {}
   1061 
   1062 void CPWL_Edit::OnInsertText(const CPVT_WordPlace& place,
   1063                              const CPVT_WordPlace& oldplace) {
   1064   if (HasFlag(PES_SPELLCHECK)) {
   1065     m_pEdit->RefreshWordRange(CombineWordRange(GetLatinWordsRange(oldplace),
   1066                                                GetLatinWordsRange(place)));
   1067   }
   1068 
   1069   if (m_pEditNotify) {
   1070     m_pEditNotify->OnInsertText(place, oldplace);
   1071   }
   1072 }
   1073 
   1074 void CPWL_Edit::OnAddUndo(IFX_Edit_UndoItem* pUndoItem) {
   1075   if (m_pEditNotify) {
   1076     m_pEditNotify->OnAddUndo(this);
   1077   }
   1078 }
   1079 
   1080 CPVT_WordRange CPWL_Edit::CombineWordRange(const CPVT_WordRange& wr1,
   1081                                            const CPVT_WordRange& wr2) {
   1082   CPVT_WordRange wrRet;
   1083 
   1084   if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) {
   1085     wrRet.BeginPos = wr1.BeginPos;
   1086   } else {
   1087     wrRet.BeginPos = wr2.BeginPos;
   1088   }
   1089 
   1090   if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) {
   1091     wrRet.EndPos = wr2.EndPos;
   1092   } else {
   1093     wrRet.EndPos = wr1.EndPos;
   1094   }
   1095 
   1096   return wrRet;
   1097 }
   1098 
   1099 CPVT_WordRange CPWL_Edit::GetLatinWordsRange(const CPDF_Point& point) const {
   1100   return GetSameWordsRange(m_pEdit->SearchWordPlace(point), TRUE, FALSE);
   1101 }
   1102 
   1103 CPVT_WordRange CPWL_Edit::GetLatinWordsRange(
   1104     const CPVT_WordPlace& place) const {
   1105   return GetSameWordsRange(place, TRUE, FALSE);
   1106 }
   1107 
   1108 CPVT_WordRange CPWL_Edit::GetArabicWordsRange(
   1109     const CPVT_WordPlace& place) const {
   1110   return GetSameWordsRange(place, FALSE, TRUE);
   1111 }
   1112 
   1113 #define PWL_ISARABICWORD(word) \
   1114   ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
   1115 
   1116 CPVT_WordRange CPWL_Edit::GetSameWordsRange(const CPVT_WordPlace& place,
   1117                                             FX_BOOL bLatin,
   1118                                             FX_BOOL bArabic) const {
   1119   CPVT_WordRange range;
   1120 
   1121   if (IFX_Edit_Iterator* pIterator = m_pEdit->GetIterator()) {
   1122     CPVT_Word wordinfo;
   1123     CPVT_WordPlace wpStart(place), wpEnd(place);
   1124     pIterator->SetAt(place);
   1125 
   1126     if (bLatin) {
   1127       while (pIterator->NextWord()) {
   1128         if (!pIterator->GetWord(wordinfo) ||
   1129             !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
   1130           break;
   1131         }
   1132 
   1133         wpEnd = pIterator->GetAt();
   1134       }
   1135     } else if (bArabic) {
   1136       while (pIterator->NextWord()) {
   1137         if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
   1138           break;
   1139 
   1140         wpEnd = pIterator->GetAt();
   1141       }
   1142     }
   1143 
   1144     pIterator->SetAt(place);
   1145 
   1146     if (bLatin) {
   1147       do {
   1148         if (!pIterator->GetWord(wordinfo) ||
   1149             !FX_EDIT_ISLATINWORD(wordinfo.Word)) {
   1150           break;
   1151         }
   1152 
   1153         wpStart = pIterator->GetAt();
   1154       } while (pIterator->PrevWord());
   1155     } else if (bArabic) {
   1156       do {
   1157         if (!pIterator->GetWord(wordinfo) || !PWL_ISARABICWORD(wordinfo.Word))
   1158           break;
   1159 
   1160         wpStart = pIterator->GetAt();
   1161       } while (pIterator->PrevWord());
   1162     }
   1163 
   1164     range.Set(wpStart, wpEnd);
   1165   }
   1166 
   1167   return range;
   1168 }
   1169 
   1170 void CPWL_Edit::GeneratePageObjects(
   1171     CPDF_PageObjects* pPageObjects,
   1172     const CPDF_Point& ptOffset,
   1173     CFX_ArrayTemplate<CPDF_TextObject*>& ObjArray) {
   1174   IFX_Edit::GeneratePageObjects(
   1175       pPageObjects, m_pEdit, ptOffset, NULL,
   1176       CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
   1177       ObjArray);
   1178 }
   1179 
   1180 void CPWL_Edit::GeneratePageObjects(CPDF_PageObjects* pPageObjects,
   1181                                     const CPDF_Point& ptOffset) {
   1182   CFX_ArrayTemplate<CPDF_TextObject*> ObjArray;
   1183   IFX_Edit::GeneratePageObjects(
   1184       pPageObjects, m_pEdit, ptOffset, NULL,
   1185       CPWL_Utils::PWLColorToFXColor(GetTextColor(), GetTransparency()),
   1186       ObjArray);
   1187 }
   1188