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/pwl/cpwl_caret.h"
8
9 #include <sstream>
10 #include <utility>
11
12 #include "core/fxge/cfx_graphstatedata.h"
13 #include "core/fxge/cfx_pathdata.h"
14 #include "core/fxge/cfx_renderdevice.h"
15 #include "third_party/base/ptr_util.h"
16
CPWL_Caret(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)17 CPWL_Caret::CPWL_Caret(
18 const CreateParams& cp,
19 std::unique_ptr<IPWL_SystemHandler::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 CFX_PathData path;
32
33 float fCaretX = rcRect.left + m_fWidth * 0.5f;
34 float fCaretTop = rcRect.top;
35 float fCaretBottom = rcRect.bottom;
36 if (!rcClip.IsEmpty()) {
37 rcRect.Intersect(rcClip);
38 if (rcRect.IsEmpty())
39 return;
40
41 fCaretTop = rcRect.top;
42 fCaretBottom = rcRect.bottom;
43 }
44
45 path.AppendPoint(CFX_PointF(fCaretX, fCaretBottom), FXPT_TYPE::MoveTo, false);
46 path.AppendPoint(CFX_PointF(fCaretX, fCaretTop), FXPT_TYPE::LineTo, false);
47
48 CFX_GraphStateData gsd;
49 gsd.m_LineWidth = m_fWidth;
50 pDevice->DrawPath(&path, &mtUser2Device, &gsd, 0, ArgbEncode(255, 0, 0, 0),
51 FXFILL_ALTERNATE);
52 }
53
OnTimerFired()54 void CPWL_Caret::OnTimerFired() {
55 m_bFlash = !m_bFlash;
56 InvalidateRect(nullptr);
57 // Note, |this| may no longer be viable at this point. If more work needs
58 // to be done, add an observer.
59 }
60
GetCaretRect() const61 CFX_FloatRect CPWL_Caret::GetCaretRect() const {
62 return CFX_FloatRect(m_ptFoot.x, m_ptFoot.y, m_ptHead.x + m_fWidth,
63 m_ptHead.y);
64 }
65
SetCaret(bool bVisible,const CFX_PointF & ptHead,const CFX_PointF & ptFoot)66 void CPWL_Caret::SetCaret(bool bVisible,
67 const CFX_PointF& ptHead,
68 const CFX_PointF& ptFoot) {
69 if (!bVisible) {
70 m_ptHead = CFX_PointF();
71 m_ptFoot = CFX_PointF();
72 m_bFlash = false;
73 if (!IsVisible())
74 return;
75
76 m_pTimer.reset();
77 CPWL_Wnd::SetVisible(false);
78 // Note, |this| may no longer be viable at this point. If more work needs
79 // to be done, check the return value of SetVisible().
80 return;
81 }
82
83 if (!IsVisible()) {
84 static constexpr int32_t kCaretFlashIntervalMs = 500;
85
86 m_ptHead = ptHead;
87 m_ptFoot = ptFoot;
88 m_pTimer = pdfium::MakeUnique<CFX_Timer>(GetTimerHandler(), this,
89 kCaretFlashIntervalMs);
90
91 if (!CPWL_Wnd::SetVisible(true))
92 return;
93
94 m_bFlash = true;
95 Move(m_rcInvalid, false, true);
96 // Note, |this| may no longer be viable at this point. If more work needs
97 // to be done, check the return value of Move().
98 return;
99 }
100
101 if (m_ptHead == ptHead && m_ptFoot == ptFoot)
102 return;
103
104 m_ptHead = ptHead;
105 m_ptFoot = ptFoot;
106 m_bFlash = true;
107 Move(m_rcInvalid, false, true);
108 // Note, |this| may no longer be viable at this point. If more work
109 // needs to be done, check the return value of Move().
110 }
111
InvalidateRect(CFX_FloatRect * pRect)112 bool CPWL_Caret::InvalidateRect(CFX_FloatRect* pRect) {
113 if (!pRect) {
114 return CPWL_Wnd::InvalidateRect(nullptr);
115 }
116
117 CFX_FloatRect rcRefresh = *pRect;
118 if (!rcRefresh.IsEmpty()) {
119 rcRefresh.Inflate(0.5f, 0.5f);
120 rcRefresh.Normalize();
121 }
122 rcRefresh.top += 1;
123 rcRefresh.bottom -= 1;
124 return CPWL_Wnd::InvalidateRect(&rcRefresh);
125 }
126
SetVisible(bool bVisible)127 bool CPWL_Caret::SetVisible(bool bVisible) {
128 return true;
129 }
130