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/pdfwindow/PWL_EditCtrl.h"
      8 
      9 #include "core/fpdfdoc/cpvt_section.h"
     10 #include "core/fpdfdoc/cpvt_word.h"
     11 #include "core/fxge/fx_font.h"
     12 #include "fpdfsdk/fxedit/fxet_edit.h"
     13 #include "fpdfsdk/pdfwindow/PWL_Caret.h"
     14 #include "fpdfsdk/pdfwindow/PWL_FontMap.h"
     15 #include "fpdfsdk/pdfwindow/PWL_ScrollBar.h"
     16 #include "fpdfsdk/pdfwindow/PWL_Utils.h"
     17 #include "fpdfsdk/pdfwindow/PWL_Wnd.h"
     18 #include "public/fpdf_fwlevent.h"
     19 
     20 CPWL_EditCtrl::CPWL_EditCtrl()
     21     : m_pEdit(new CFX_Edit),
     22       m_pEditCaret(nullptr),
     23       m_bMouseDown(false),
     24       m_nCharSet(FXFONT_DEFAULT_CHARSET),
     25       m_nCodePage(0) {}
     26 
     27 CPWL_EditCtrl::~CPWL_EditCtrl() {}
     28 
     29 void CPWL_EditCtrl::OnCreate(PWL_CREATEPARAM& cp) {
     30   cp.eCursorType = FXCT_VBEAM;
     31 }
     32 
     33 void CPWL_EditCtrl::OnCreated() {
     34   SetFontSize(GetCreationParam().fFontSize);
     35 
     36   m_pEdit->SetFontMap(GetFontMap());
     37   m_pEdit->SetNotify(this);
     38   m_pEdit->Initialize();
     39 }
     40 
     41 bool CPWL_EditCtrl::IsWndHorV() {
     42   CFX_Matrix mt = GetWindowMatrix();
     43   return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
     44 }
     45 
     46 void CPWL_EditCtrl::SetCursor() {
     47   if (IsValid()) {
     48     if (CFX_SystemHandler* pSH = GetSystemHandler()) {
     49       if (IsWndHorV())
     50         pSH->SetCursor(FXCT_VBEAM);
     51       else
     52         pSH->SetCursor(FXCT_HBEAM);
     53     }
     54   }
     55 }
     56 
     57 void CPWL_EditCtrl::RePosChildWnd() {
     58   m_pEdit->SetPlateRect(GetClientRect());
     59 }
     60 
     61 void CPWL_EditCtrl::OnNotify(CPWL_Wnd* pWnd,
     62                              uint32_t msg,
     63                              intptr_t wParam,
     64                              intptr_t lParam) {
     65   CPWL_Wnd::OnNotify(pWnd, msg, wParam, lParam);
     66 
     67   switch (msg) {
     68     case PNM_SETSCROLLINFO:
     69       switch (wParam) {
     70         case SBT_VSCROLL:
     71           if (CPWL_Wnd* pChild = GetVScrollBar()) {
     72             pChild->OnNotify(pWnd, PNM_SETSCROLLINFO, wParam, lParam);
     73           }
     74           break;
     75       }
     76       break;
     77     case PNM_SETSCROLLPOS:
     78       switch (wParam) {
     79         case SBT_VSCROLL:
     80           if (CPWL_Wnd* pChild = GetVScrollBar()) {
     81             pChild->OnNotify(pWnd, PNM_SETSCROLLPOS, wParam, lParam);
     82           }
     83           break;
     84       }
     85       break;
     86     case PNM_SCROLLWINDOW: {
     87       FX_FLOAT fPos = *(FX_FLOAT*)lParam;
     88       switch (wParam) {
     89         case SBT_VSCROLL:
     90           m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, fPos));
     91           break;
     92       }
     93     } break;
     94     case PNM_SETCARETINFO: {
     95       if (PWL_CARET_INFO* pCaretInfo = (PWL_CARET_INFO*)wParam) {
     96         SetCaret(pCaretInfo->bVisible, pCaretInfo->ptHead, pCaretInfo->ptFoot);
     97       }
     98     } break;
     99   }
    100 }
    101 
    102 void CPWL_EditCtrl::CreateChildWnd(const PWL_CREATEPARAM& cp) {
    103   if (!IsReadOnly())
    104     CreateEditCaret(cp);
    105 }
    106 
    107 void CPWL_EditCtrl::CreateEditCaret(const PWL_CREATEPARAM& cp) {
    108   if (m_pEditCaret)
    109     return;
    110 
    111   m_pEditCaret = new CPWL_Caret;
    112   m_pEditCaret->SetInvalidRect(GetClientRect());
    113 
    114   PWL_CREATEPARAM ecp = cp;
    115   ecp.pParentWnd = this;
    116   ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP;
    117   ecp.dwBorderWidth = 0;
    118   ecp.nBorderStyle = BorderStyle::SOLID;
    119   ecp.rcRectWnd = CFX_FloatRect(0, 0, 0, 0);
    120 
    121   m_pEditCaret->Create(ecp);
    122 }
    123 
    124 void CPWL_EditCtrl::SetFontSize(FX_FLOAT fFontSize) {
    125   m_pEdit->SetFontSize(fFontSize);
    126 }
    127 
    128 FX_FLOAT CPWL_EditCtrl::GetFontSize() const {
    129   return m_pEdit->GetFontSize();
    130 }
    131 
    132 bool CPWL_EditCtrl::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
    133   if (m_bMouseDown)
    134     return true;
    135 
    136   bool bRet = CPWL_Wnd::OnKeyDown(nChar, nFlag);
    137 
    138   // FILTER
    139   switch (nChar) {
    140     default:
    141       return false;
    142     case FWL_VKEY_Delete:
    143     case FWL_VKEY_Up:
    144     case FWL_VKEY_Down:
    145     case FWL_VKEY_Left:
    146     case FWL_VKEY_Right:
    147     case FWL_VKEY_Home:
    148     case FWL_VKEY_End:
    149     case FWL_VKEY_Insert:
    150     case 'C':
    151     case 'V':
    152     case 'X':
    153     case 'A':
    154     case 'Z':
    155     case 'c':
    156     case 'v':
    157     case 'x':
    158     case 'a':
    159     case 'z':
    160       break;
    161   }
    162 
    163   if (nChar == FWL_VKEY_Delete && m_pEdit->IsSelected())
    164     nChar = FWL_VKEY_Unknown;
    165 
    166   switch (nChar) {
    167     case FWL_VKEY_Delete:
    168       Delete();
    169       return true;
    170     case FWL_VKEY_Insert:
    171       if (IsSHIFTpressed(nFlag))
    172         PasteText();
    173       return true;
    174     case FWL_VKEY_Up:
    175       m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag), false);
    176       return true;
    177     case FWL_VKEY_Down:
    178       m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag), false);
    179       return true;
    180     case FWL_VKEY_Left:
    181       m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag), false);
    182       return true;
    183     case FWL_VKEY_Right:
    184       m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag), false);
    185       return true;
    186     case FWL_VKEY_Home:
    187       m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
    188       return true;
    189     case FWL_VKEY_End:
    190       m_pEdit->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
    191       return true;
    192     case FWL_VKEY_Unknown:
    193       if (!IsSHIFTpressed(nFlag))
    194         Clear();
    195       else
    196         CutText();
    197       return true;
    198     default:
    199       break;
    200   }
    201 
    202   return bRet;
    203 }
    204 
    205 bool CPWL_EditCtrl::OnChar(uint16_t nChar, uint32_t nFlag) {
    206   if (m_bMouseDown)
    207     return true;
    208 
    209   CPWL_Wnd::OnChar(nChar, nFlag);
    210 
    211   // FILTER
    212   switch (nChar) {
    213     case 0x0A:
    214     case 0x1B:
    215       return false;
    216     default:
    217       break;
    218   }
    219 
    220   bool bCtrl = IsCTRLpressed(nFlag);
    221   bool bAlt = IsALTpressed(nFlag);
    222   bool bShift = IsSHIFTpressed(nFlag);
    223 
    224   uint16_t word = nChar;
    225 
    226   if (bCtrl && !bAlt) {
    227     switch (nChar) {
    228       case 'C' - 'A' + 1:
    229         CopyText();
    230         return true;
    231       case 'V' - 'A' + 1:
    232         PasteText();
    233         return true;
    234       case 'X' - 'A' + 1:
    235         CutText();
    236         return true;
    237       case 'A' - 'A' + 1:
    238         SelectAll();
    239         return true;
    240       case 'Z' - 'A' + 1:
    241         if (bShift)
    242           Redo();
    243         else
    244           Undo();
    245         return true;
    246       default:
    247         if (nChar < 32)
    248           return false;
    249     }
    250   }
    251 
    252   if (IsReadOnly())
    253     return true;
    254 
    255   if (m_pEdit->IsSelected() && word == FWL_VKEY_Back)
    256     word = FWL_VKEY_Unknown;
    257 
    258   Clear();
    259 
    260   switch (word) {
    261     case FWL_VKEY_Back:
    262       Backspace();
    263       break;
    264     case FWL_VKEY_Return:
    265       InsertReturn();
    266       break;
    267     case FWL_VKEY_Unknown:
    268       break;
    269     default:
    270       InsertWord(word, GetCharSet());
    271       break;
    272   }
    273 
    274   return true;
    275 }
    276 
    277 bool CPWL_EditCtrl::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
    278   CPWL_Wnd::OnLButtonDown(point, nFlag);
    279 
    280   if (ClientHitTest(point)) {
    281     if (m_bMouseDown)
    282       InvalidateRect();
    283 
    284     m_bMouseDown = true;
    285     SetCapture();
    286 
    287     m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
    288   }
    289 
    290   return true;
    291 }
    292 
    293 bool CPWL_EditCtrl::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
    294   CPWL_Wnd::OnLButtonUp(point, nFlag);
    295 
    296   if (m_bMouseDown) {
    297     // can receive keybord message
    298     if (ClientHitTest(point) && !IsFocused())
    299       SetFocus();
    300 
    301     ReleaseCapture();
    302     m_bMouseDown = false;
    303   }
    304 
    305   return true;
    306 }
    307 
    308 bool CPWL_EditCtrl::OnMouseMove(const CFX_PointF& point, uint32_t nFlag) {
    309   CPWL_Wnd::OnMouseMove(point, nFlag);
    310 
    311   if (m_bMouseDown)
    312     m_pEdit->OnMouseMove(point, false, false);
    313 
    314   return true;
    315 }
    316 
    317 CFX_FloatRect CPWL_EditCtrl::GetContentRect() const {
    318   return m_pEdit->GetContentRect();
    319 }
    320 
    321 void CPWL_EditCtrl::SetEditCaret(bool bVisible) {
    322   CFX_PointF ptHead;
    323   CFX_PointF ptFoot;
    324   if (bVisible)
    325     GetCaretInfo(&ptHead, &ptFoot);
    326 
    327   CPVT_WordPlace wpTemp = m_pEdit->GetCaretWordPlace();
    328   IOnSetCaret(bVisible, ptHead, ptFoot, wpTemp);
    329 }
    330 
    331 void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const {
    332   CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
    333   pIterator->SetAt(m_pEdit->GetCaret());
    334   CPVT_Word word;
    335   CPVT_Line line;
    336   if (pIterator->GetWord(word)) {
    337     ptHead->x = word.ptWord.x + word.fWidth;
    338     ptHead->y = word.ptWord.y + word.fAscent;
    339     ptFoot->x = word.ptWord.x + word.fWidth;
    340     ptFoot->y = word.ptWord.y + word.fDescent;
    341   } else if (pIterator->GetLine(line)) {
    342     ptHead->x = line.ptLine.x;
    343     ptHead->y = line.ptLine.y + line.fLineAscent;
    344     ptFoot->x = line.ptLine.x;
    345     ptFoot->y = line.ptLine.y + line.fLineDescent;
    346   }
    347 }
    348 
    349 void CPWL_EditCtrl::SetCaret(bool bVisible,
    350                              const CFX_PointF& ptHead,
    351                              const CFX_PointF& ptFoot) {
    352   if (m_pEditCaret) {
    353     if (!IsFocused() || m_pEdit->IsSelected())
    354       bVisible = false;
    355 
    356     m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot);
    357   }
    358 }
    359 
    360 CFX_WideString CPWL_EditCtrl::GetText() const {
    361   return m_pEdit->GetText();
    362 }
    363 
    364 void CPWL_EditCtrl::SetSel(int32_t nStartChar, int32_t nEndChar) {
    365   m_pEdit->SetSel(nStartChar, nEndChar);
    366 }
    367 
    368 void CPWL_EditCtrl::GetSel(int32_t& nStartChar, int32_t& nEndChar) const {
    369   m_pEdit->GetSel(nStartChar, nEndChar);
    370 }
    371 
    372 void CPWL_EditCtrl::Clear() {
    373   if (!IsReadOnly())
    374     m_pEdit->Clear();
    375 }
    376 
    377 void CPWL_EditCtrl::SelectAll() {
    378   m_pEdit->SelectAll();
    379 }
    380 
    381 void CPWL_EditCtrl::Paint() {
    382   m_pEdit->Paint();
    383 }
    384 
    385 void CPWL_EditCtrl::EnableRefresh(bool bRefresh) {
    386   m_pEdit->EnableRefresh(bRefresh);
    387 }
    388 
    389 int32_t CPWL_EditCtrl::GetCaret() const {
    390   return m_pEdit->GetCaret();
    391 }
    392 
    393 void CPWL_EditCtrl::SetCaret(int32_t nPos) {
    394   m_pEdit->SetCaret(nPos);
    395 }
    396 
    397 int32_t CPWL_EditCtrl::GetTotalWords() const {
    398   return m_pEdit->GetTotalWords();
    399 }
    400 
    401 void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
    402   m_pEdit->SetScrollPos(point);
    403 }
    404 
    405 CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
    406   return m_pEdit->GetScrollPos();
    407 }
    408 
    409 CPDF_Font* CPWL_EditCtrl::GetCaretFont() const {
    410   int32_t nFontIndex = 0;
    411 
    412   CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
    413   pIterator->SetAt(m_pEdit->GetCaret());
    414   CPVT_Word word;
    415   CPVT_Section section;
    416   if (pIterator->GetWord(word)) {
    417     nFontIndex = word.nFontIndex;
    418   } else if (HasFlag(PES_RICH)) {
    419     if (pIterator->GetSection(section)) {
    420       nFontIndex = section.WordProps.nFontIndex;
    421     }
    422   }
    423 
    424   if (IPVT_FontMap* pFontMap = GetFontMap())
    425     return pFontMap->GetPDFFont(nFontIndex);
    426 
    427   return nullptr;
    428 }
    429 
    430 FX_FLOAT CPWL_EditCtrl::GetCaretFontSize() const {
    431   FX_FLOAT fFontSize = GetFontSize();
    432 
    433   CFX_Edit_Iterator* pIterator = m_pEdit->GetIterator();
    434   pIterator->SetAt(m_pEdit->GetCaret());
    435   CPVT_Word word;
    436   CPVT_Section section;
    437   if (pIterator->GetWord(word)) {
    438     fFontSize = word.fFontSize;
    439   } else if (HasFlag(PES_RICH)) {
    440     if (pIterator->GetSection(section)) {
    441       fFontSize = section.WordProps.fFontSize;
    442     }
    443   }
    444 
    445   return fFontSize;
    446 }
    447 
    448 void CPWL_EditCtrl::SetText(const CFX_WideString& wsText) {
    449   m_pEdit->SetText(wsText);
    450 }
    451 
    452 void CPWL_EditCtrl::CopyText() {}
    453 
    454 void CPWL_EditCtrl::PasteText() {}
    455 
    456 void CPWL_EditCtrl::CutText() {}
    457 
    458 void CPWL_EditCtrl::ShowVScrollBar(bool bShow) {}
    459 
    460 void CPWL_EditCtrl::InsertText(const CFX_WideString& wsText) {
    461   if (!IsReadOnly())
    462     m_pEdit->InsertText(wsText, FXFONT_DEFAULT_CHARSET);
    463 }
    464 
    465 void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) {
    466   if (!IsReadOnly())
    467     m_pEdit->InsertWord(word, nCharset);
    468 }
    469 
    470 void CPWL_EditCtrl::InsertReturn() {
    471   if (!IsReadOnly())
    472     m_pEdit->InsertReturn();
    473 }
    474 
    475 void CPWL_EditCtrl::Delete() {
    476   if (!IsReadOnly())
    477     m_pEdit->Delete();
    478 }
    479 
    480 void CPWL_EditCtrl::Backspace() {
    481   if (!IsReadOnly())
    482     m_pEdit->Backspace();
    483 }
    484 
    485 bool CPWL_EditCtrl::CanUndo() const {
    486   return !IsReadOnly() && m_pEdit->CanUndo();
    487 }
    488 
    489 bool CPWL_EditCtrl::CanRedo() const {
    490   return !IsReadOnly() && m_pEdit->CanRedo();
    491 }
    492 
    493 void CPWL_EditCtrl::Redo() {
    494   if (CanRedo())
    495     m_pEdit->Redo();
    496 }
    497 
    498 void CPWL_EditCtrl::Undo() {
    499   if (CanUndo())
    500     m_pEdit->Undo();
    501 }
    502 
    503 void CPWL_EditCtrl::IOnSetScrollInfoY(FX_FLOAT fPlateMin,
    504                                       FX_FLOAT fPlateMax,
    505                                       FX_FLOAT fContentMin,
    506                                       FX_FLOAT fContentMax,
    507                                       FX_FLOAT fSmallStep,
    508                                       FX_FLOAT fBigStep) {
    509   PWL_SCROLL_INFO Info;
    510 
    511   Info.fPlateWidth = fPlateMax - fPlateMin;
    512   Info.fContentMin = fContentMin;
    513   Info.fContentMax = fContentMax;
    514   Info.fSmallStep = fSmallStep;
    515   Info.fBigStep = fBigStep;
    516 
    517   OnNotify(this, PNM_SETSCROLLINFO, SBT_VSCROLL, (intptr_t)&Info);
    518 
    519   if (IsFloatBigger(Info.fPlateWidth, Info.fContentMax - Info.fContentMin) ||
    520       IsFloatEqual(Info.fPlateWidth, Info.fContentMax - Info.fContentMin)) {
    521     ShowVScrollBar(false);
    522   } else {
    523     ShowVScrollBar(true);
    524   }
    525 }
    526 
    527 void CPWL_EditCtrl::IOnSetScrollPosY(FX_FLOAT fy) {
    528   OnNotify(this, PNM_SETSCROLLPOS, SBT_VSCROLL, (intptr_t)&fy);
    529 }
    530 
    531 void CPWL_EditCtrl::IOnSetCaret(bool bVisible,
    532                                 const CFX_PointF& ptHead,
    533                                 const CFX_PointF& ptFoot,
    534                                 const CPVT_WordPlace& place) {
    535   PWL_CARET_INFO cInfo;
    536   cInfo.bVisible = bVisible;
    537   cInfo.ptHead = ptHead;
    538   cInfo.ptFoot = ptFoot;
    539 
    540   OnNotify(this, PNM_SETCARETINFO, (intptr_t)&cInfo, (intptr_t) nullptr);
    541 }
    542 
    543 void CPWL_EditCtrl::IOnCaretChange(const CPVT_SecProps& secProps,
    544                                    const CPVT_WordProps& wordProps) {}
    545 
    546 void CPWL_EditCtrl::IOnContentChange(const CFX_FloatRect& rcContent) {}
    547 
    548 void CPWL_EditCtrl::IOnInvalidateRect(CFX_FloatRect* pRect) {
    549   InvalidateRect(pRect);
    550 }
    551 
    552 int32_t CPWL_EditCtrl::GetCharSet() const {
    553   return m_nCharSet < 0 ? FXFONT_DEFAULT_CHARSET : m_nCharSet;
    554 }
    555 
    556 void CPWL_EditCtrl::GetTextRange(const CFX_FloatRect& rect,
    557                                  int32_t& nStartChar,
    558                                  int32_t& nEndChar) const {
    559   nStartChar = m_pEdit->WordPlaceToWordIndex(
    560       m_pEdit->SearchWordPlace(CFX_PointF(rect.left, rect.top)));
    561   nEndChar = m_pEdit->WordPlaceToWordIndex(
    562       m_pEdit->SearchWordPlace(CFX_PointF(rect.right, rect.bottom)));
    563 }
    564 
    565 CFX_WideString CPWL_EditCtrl::GetText(int32_t& nStartChar,
    566                                       int32_t& nEndChar) const {
    567   CPVT_WordPlace wpStart = m_pEdit->WordIndexToWordPlace(nStartChar);
    568   CPVT_WordPlace wpEnd = m_pEdit->WordIndexToWordPlace(nEndChar);
    569   return m_pEdit->GetRangeText(CPVT_WordRange(wpStart, wpEnd));
    570 }
    571 
    572 void CPWL_EditCtrl::SetReadyToInput() {
    573   if (m_bMouseDown) {
    574     ReleaseCapture();
    575     m_bMouseDown = false;
    576   }
    577 }
    578