xref: /aosp_15_r20/external/pdfium/fpdfsdk/pwl/cpwl_caret.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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_caret.h"
8 
9 #include <sstream>
10 #include <utility>
11 
12 #include "core/fxge/cfx_fillrenderoptions.h"
13 #include "core/fxge/cfx_graphstatedata.h"
14 #include "core/fxge/cfx_path.h"
15 #include "core/fxge/cfx_renderdevice.h"
16 
CPWL_Caret(const CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)17 CPWL_Caret::CPWL_Caret(
18     const CreateParams& cp,
19     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)
20     : CPWL_Wnd(cp, std::move(pAttachedData)) {}
21 
22 CPWL_Caret::~CPWL_Caret() = default;
23 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)24 void CPWL_Caret::DrawThisAppearance(CFX_RenderDevice* pDevice,
25                                     const CFX_Matrix& mtUser2Device) {
26   if (!IsVisible() || !m_bFlash)
27     return;
28 
29   CFX_FloatRect rcRect = GetCaretRect();
30   CFX_FloatRect rcClip = GetClipRect();
31 
32   float fCaretX = rcRect.left + m_fWidth * 0.5f;
33   float fCaretTop = rcRect.top;
34   float fCaretBottom = rcRect.bottom;
35   if (!rcClip.IsEmpty()) {
36     rcRect.Intersect(rcClip);
37     if (rcRect.IsEmpty())
38       return;
39 
40     fCaretTop = rcRect.top;
41     fCaretBottom = rcRect.bottom;
42   }
43 
44   CFX_Path path;
45   path.AppendPoint(CFX_PointF(fCaretX, fCaretBottom),
46                    CFX_Path::Point::Type::kMove);
47   path.AppendPoint(CFX_PointF(fCaretX, fCaretTop),
48                    CFX_Path::Point::Type::kLine);
49 
50   CFX_GraphStateData gsd;
51   gsd.m_LineWidth = m_fWidth;
52   pDevice->DrawPath(path, &mtUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
53                     CFX_FillRenderOptions::EvenOddOptions());
54 }
55 
OnTimerFired()56 void CPWL_Caret::OnTimerFired() {
57   m_bFlash = !m_bFlash;
58   InvalidateRect(nullptr);
59   // Note, |this| may no longer be viable at this point. If more work needs
60   // to be done, add an observer.
61 }
62 
GetCaretRect() const63 CFX_FloatRect CPWL_Caret::GetCaretRect() const {
64   return CFX_FloatRect(m_ptFoot.x, m_ptFoot.y, m_ptHead.x + m_fWidth,
65                        m_ptHead.y);
66 }
67 
SetCaret(bool bVisible,const CFX_PointF & ptHead,const CFX_PointF & ptFoot)68 void CPWL_Caret::SetCaret(bool bVisible,
69                           const CFX_PointF& ptHead,
70                           const CFX_PointF& ptFoot) {
71   if (!bVisible) {
72     m_ptHead = CFX_PointF();
73     m_ptFoot = CFX_PointF();
74     m_bFlash = false;
75     if (!IsVisible())
76       return;
77 
78     m_pTimer.reset();
79     (void)CPWL_Wnd::SetVisible(false);
80     // Note, |this| may no longer be viable at this point. If more work needs
81     // to be done, check the return value of SetVisible().
82     return;
83   }
84 
85   if (!IsVisible()) {
86     static constexpr int32_t kCaretFlashIntervalMs = 500;
87 
88     m_ptHead = ptHead;
89     m_ptFoot = ptFoot;
90     m_pTimer = std::make_unique<CFX_Timer>(GetTimerHandler(), this,
91                                            kCaretFlashIntervalMs);
92 
93     if (!CPWL_Wnd::SetVisible(true))
94       return;
95 
96     m_bFlash = true;
97     Move(m_rcInvalid, false, true);
98     // Note, |this| may no longer be viable at this point. If more work needs
99     // to be done, check the return value of Move().
100     return;
101   }
102 
103   if (m_ptHead == ptHead && m_ptFoot == ptFoot)
104     return;
105 
106   m_ptHead = ptHead;
107   m_ptFoot = ptFoot;
108   m_bFlash = true;
109   Move(m_rcInvalid, false, true);
110   // Note, |this| may no longer be viable at this point. If more work
111   // needs to be done, check the return value of Move().
112 }
113 
InvalidateRect(const CFX_FloatRect * pRect)114 bool CPWL_Caret::InvalidateRect(const CFX_FloatRect* pRect) {
115   if (!pRect)
116     return CPWL_Wnd::InvalidateRect(nullptr);
117 
118   CFX_FloatRect rcRefresh = *pRect;
119   if (!rcRefresh.IsEmpty()) {
120     rcRefresh.Inflate(0.5f, 0.5f);
121     rcRefresh.Normalize();
122   }
123   rcRefresh.top += 1;
124   rcRefresh.bottom -= 1;
125   return CPWL_Wnd::InvalidateRect(&rcRefresh);
126 }
127 
SetVisible(bool bVisible)128 bool CPWL_Caret::SetVisible(bool bVisible) {
129   return true;
130 }
131