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_Caret.h"
      8 #include "fpdfsdk/include/pdfwindow/PWL_Utils.h"
      9 #include "fpdfsdk/include/pdfwindow/PWL_Wnd.h"
     10 
     11 #define PWL_CARET_FLASHINTERVAL 500
     12 
     13 CPWL_Caret::CPWL_Caret()
     14     : m_bFlash(FALSE),
     15       m_ptHead(0, 0),
     16       m_ptFoot(0, 0),
     17       m_fWidth(0.4f),
     18       m_nDelay(0) {}
     19 
     20 CPWL_Caret::~CPWL_Caret() {}
     21 
     22 CFX_ByteString CPWL_Caret::GetClassName() const {
     23   return "CPWL_Caret";
     24 }
     25 
     26 void CPWL_Caret::GetThisAppearanceStream(CFX_ByteTextBuf& sAppStream) {
     27   GetCaretApp(sAppStream, CPDF_Point(0.0f, 0.0f));
     28 }
     29 
     30 void CPWL_Caret::DrawThisAppearance(CFX_RenderDevice* pDevice,
     31                                     CFX_Matrix* pUser2Device) {
     32   if (IsVisible() && m_bFlash) {
     33     CPDF_Rect rcRect = GetCaretRect();
     34     CPDF_Rect rcClip = GetClipRect();
     35 
     36     CFX_PathData path;
     37 
     38     path.SetPointCount(2);
     39 
     40     FX_FLOAT fCaretX = rcRect.left + m_fWidth * 0.5f;
     41     FX_FLOAT fCaretTop = rcRect.top;
     42     FX_FLOAT fCaretBottom = rcRect.bottom;
     43 
     44     if (!rcClip.IsEmpty()) {
     45       rcRect.Intersect(rcClip);
     46       if (!rcRect.IsEmpty()) {
     47         fCaretTop = rcRect.top;
     48         fCaretBottom = rcRect.bottom;
     49         path.SetPoint(0, fCaretX, fCaretBottom, FXPT_MOVETO);
     50         path.SetPoint(1, fCaretX, fCaretTop, FXPT_LINETO);
     51       } else {
     52         return;
     53       }
     54     } else {
     55       path.SetPoint(0, fCaretX, fCaretBottom, FXPT_MOVETO);
     56       path.SetPoint(1, fCaretX, fCaretTop, FXPT_LINETO);
     57     }
     58 
     59     CFX_GraphStateData gsd;
     60     gsd.m_LineWidth = m_fWidth;
     61 
     62     pDevice->DrawPath(&path, pUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
     63                       FXFILL_ALTERNATE);
     64   }
     65 }
     66 
     67 void CPWL_Caret::GetCaretApp(CFX_ByteTextBuf& sAppStream,
     68                              const CPDF_Point& ptOffset) {
     69   if (IsVisible() && m_bFlash) {
     70     CFX_ByteTextBuf sCaret;
     71 
     72     CPDF_Rect rcRect = GetCaretRect();
     73     CPDF_Rect rcClip = GetClipRect();
     74 
     75     rcRect = CPWL_Utils::OffsetRect(rcRect, ptOffset.x, ptOffset.y);
     76     rcClip = CPWL_Utils::OffsetRect(rcClip, ptOffset.x, ptOffset.y);
     77 
     78     sCaret << "q\n";
     79     if (!rcClip.IsEmpty()) {
     80       sCaret << rcClip.left << " " << rcClip.bottom + 2.5f << " "
     81              << rcClip.right - rcClip.left << " "
     82              << rcClip.top - rcClip.bottom - 4.5f << " re W n\n";
     83     }
     84     sCaret << m_fWidth << " w\n0 G\n";
     85     sCaret << rcRect.left + m_fWidth / 2 << " " << rcRect.bottom << " m\n";
     86     sCaret << rcRect.left + m_fWidth / 2 << " " << rcRect.top << " l S\nQ\n";
     87 
     88     sAppStream << sCaret;
     89   }
     90 }
     91 
     92 CFX_ByteString CPWL_Caret::GetCaretAppearanceStream(
     93     const CPDF_Point& ptOffset) {
     94   CFX_ByteTextBuf sCaret;
     95   GetCaretApp(sCaret, ptOffset);
     96   return sCaret.GetByteString();
     97 }
     98 
     99 void CPWL_Caret::TimerProc() {
    100   if (m_nDelay > 0) {
    101     m_nDelay--;
    102   } else {
    103     m_bFlash = !m_bFlash;
    104     InvalidateRect();
    105   }
    106 }
    107 
    108 CPDF_Rect CPWL_Caret::GetCaretRect() const {
    109   return CPDF_Rect(m_ptFoot.x, m_ptFoot.y, m_ptHead.x + m_fWidth, m_ptHead.y);
    110 }
    111 
    112 void CPWL_Caret::SetCaret(FX_BOOL bVisible,
    113                           const CPDF_Point& ptHead,
    114                           const CPDF_Point& ptFoot) {
    115   if (bVisible) {
    116     if (IsVisible()) {
    117       if (m_ptHead.x != ptHead.x || m_ptHead.y != ptHead.y ||
    118           m_ptFoot.x != ptFoot.x || m_ptFoot.y != ptFoot.y) {
    119         m_ptHead = ptHead;
    120         m_ptFoot = ptFoot;
    121 
    122         m_bFlash = TRUE;
    123         Move(m_rcInvalid, FALSE, TRUE);
    124       }
    125     } else {
    126       m_ptHead = ptHead;
    127       m_ptFoot = ptFoot;
    128 
    129       EndTimer();
    130       BeginTimer(PWL_CARET_FLASHINTERVAL);
    131 
    132       CPWL_Wnd::SetVisible(TRUE);
    133       m_bFlash = TRUE;
    134 
    135       Move(m_rcInvalid, FALSE, TRUE);
    136     }
    137   } else {
    138     m_ptHead = CPDF_Point(0, 0);
    139     m_ptFoot = CPDF_Point(0, 0);
    140 
    141     m_bFlash = FALSE;
    142     if (IsVisible()) {
    143       EndTimer();
    144       CPWL_Wnd::SetVisible(FALSE);
    145     }
    146   }
    147 }
    148 
    149 void CPWL_Caret::InvalidateRect(CPDF_Rect* pRect) {
    150   if (pRect) {
    151     CPDF_Rect rcRefresh = CPWL_Utils::InflateRect(*pRect, 0.5f);
    152     rcRefresh.top += 1;
    153     rcRefresh.bottom -= 1;
    154 
    155     CPWL_Wnd::InvalidateRect(&rcRefresh);
    156   } else {
    157     CPWL_Wnd::InvalidateRect(pRect);
    158   }
    159 }
    160