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