xref: /aosp_15_r20/external/pdfium/fpdfsdk/pwl/cpwl_wnd.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_wnd.h"
8 
9 #include <sstream>
10 #include <utility>
11 #include <vector>
12 
13 #include "build/build_config.h"
14 #include "core/fxcrt/stl_util.h"
15 #include "core/fxge/cfx_renderdevice.h"
16 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
17 #include "public/fpdf_fwlevent.h"
18 #include "third_party/base/check.h"
19 #include "third_party/base/check_op.h"
20 #include "third_party/base/containers/contains.h"
21 
22 namespace {
23 
24 constexpr float kDefaultFontSize = 9.0f;
25 
26 }  // namespace
27 
28 // static
29 const CFX_Color CPWL_Wnd::kDefaultBlackColor =
30     CFX_Color(CFX_Color::Type::kGray, 0);
31 
32 // static
33 const CFX_Color CPWL_Wnd::kDefaultWhiteColor =
34     CFX_Color(CFX_Color::Type::kGray, 1);
35 
CreateParams(CFX_Timer::HandlerIface * timer_handler,IPWL_FillerNotify * filler_notify,ProviderIface * provider)36 CPWL_Wnd::CreateParams::CreateParams(CFX_Timer::HandlerIface* timer_handler,
37                                      IPWL_FillerNotify* filler_notify,
38                                      ProviderIface* provider)
39     : pTimerHandler(timer_handler),
40       pFillerNotify(filler_notify),
41       pProvider(provider),
42       fFontSize(kDefaultFontSize),
43       sDash(3, 0, 0) {}
44 
45 CPWL_Wnd::CreateParams::CreateParams(const CreateParams& other) = default;
46 
47 CPWL_Wnd::CreateParams::~CreateParams() = default;
48 
49 // For a compound window (a window containing a child window as occurs in a
50 // list box, combo box, or even a scroll bar), this class contains information
51 // shared amongst the parent and children.
52 class CPWL_Wnd::SharedCaptureFocusState final : public Observable {
53  public:
SharedCaptureFocusState(const CPWL_Wnd * pOwnerWnd)54   explicit SharedCaptureFocusState(const CPWL_Wnd* pOwnerWnd)
55       : m_pOwnerWnd(pOwnerWnd) {}
56   ~SharedCaptureFocusState() = default;
57 
IsOwnedByWnd(const CPWL_Wnd * pWnd) const58   bool IsOwnedByWnd(const CPWL_Wnd* pWnd) const { return m_pOwnerWnd == pWnd; }
59 
IsWndCaptureMouse(const CPWL_Wnd * pWnd) const60   bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
61     return pWnd && pdfium::Contains(m_MousePaths, pWnd);
62   }
63 
IsMainCaptureKeyboard(const CPWL_Wnd * pWnd) const64   bool IsMainCaptureKeyboard(const CPWL_Wnd* pWnd) const {
65     return pWnd == m_pMainKeyboardWnd;
66   }
67 
IsWndCaptureKeyboard(const CPWL_Wnd * pWnd) const68   bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
69     return pWnd && pdfium::Contains(m_KeyboardPaths, pWnd);
70   }
71 
SetCapture(CPWL_Wnd * pWnd)72   void SetCapture(CPWL_Wnd* pWnd) { m_MousePaths = pWnd->GetAncestors(); }
ReleaseCapture()73   void ReleaseCapture() { m_MousePaths.clear(); }
74 
SetFocus(CPWL_Wnd * pWnd)75   void SetFocus(CPWL_Wnd* pWnd) {
76     m_KeyboardPaths = pWnd->GetAncestors();
77     m_pMainKeyboardWnd = pWnd;
78 
79     // Note, pWnd may get destroyed in the OnSetFocus call.
80     pWnd->OnSetFocus();
81   }
82 
ReleaseFocus()83   void ReleaseFocus() {
84     ObservedPtr<SharedCaptureFocusState> observed_ptr(this);
85     if (!m_KeyboardPaths.empty()) {
86       CPWL_Wnd* pWnd = m_KeyboardPaths.front();
87       if (pWnd)
88         pWnd->OnKillFocus();
89     }
90     if (!observed_ptr)
91       return;
92 
93     m_pMainKeyboardWnd = nullptr;
94     m_KeyboardPaths.clear();
95   }
96 
RemoveWnd(CPWL_Wnd * pWnd)97   void RemoveWnd(CPWL_Wnd* pWnd) {
98     if (pWnd == m_pOwnerWnd) {
99       m_pOwnerWnd = nullptr;
100     }
101     if (pWnd == m_pMainKeyboardWnd) {
102       m_pMainKeyboardWnd = nullptr;
103     }
104     auto mouse_it = std::find(m_MousePaths.begin(), m_MousePaths.end(), pWnd);
105     if (mouse_it != m_MousePaths.end()) {
106       m_MousePaths.erase(mouse_it);
107     }
108     auto keyboard_it =
109         std::find(m_KeyboardPaths.begin(), m_KeyboardPaths.end(), pWnd);
110     if (keyboard_it != m_KeyboardPaths.end()) {
111       m_KeyboardPaths.erase(keyboard_it);
112     }
113   }
114 
115  private:
116   UnownedPtr<const CPWL_Wnd> m_pOwnerWnd;
117   UnownedPtr<const CPWL_Wnd> m_pMainKeyboardWnd;
118   std::vector<UnownedPtr<CPWL_Wnd>> m_MousePaths;
119   std::vector<UnownedPtr<CPWL_Wnd>> m_KeyboardPaths;
120 };
121 
122 // static
IsSHIFTKeyDown(Mask<FWL_EVENTFLAG> nFlag)123 bool CPWL_Wnd::IsSHIFTKeyDown(Mask<FWL_EVENTFLAG> nFlag) {
124   return !!(nFlag & FWL_EVENTFLAG_ShiftKey);
125 }
126 
127 // static
IsCTRLKeyDown(Mask<FWL_EVENTFLAG> nFlag)128 bool CPWL_Wnd::IsCTRLKeyDown(Mask<FWL_EVENTFLAG> nFlag) {
129   return !!(nFlag & FWL_EVENTFLAG_ControlKey);
130 }
131 
132 // static
IsALTKeyDown(Mask<FWL_EVENTFLAG> nFlag)133 bool CPWL_Wnd::IsALTKeyDown(Mask<FWL_EVENTFLAG> nFlag) {
134   return !!(nFlag & FWL_EVENTFLAG_AltKey);
135 }
136 
137 // static
IsMETAKeyDown(Mask<FWL_EVENTFLAG> nFlag)138 bool CPWL_Wnd::IsMETAKeyDown(Mask<FWL_EVENTFLAG> nFlag) {
139   return !!(nFlag & FWL_EVENTFLAG_MetaKey);
140 }
141 
142 // static
IsPlatformShortcutKey(Mask<FWL_EVENTFLAG> nFlag)143 bool CPWL_Wnd::IsPlatformShortcutKey(Mask<FWL_EVENTFLAG> nFlag) {
144 #if BUILDFLAG(IS_APPLE)
145   return IsMETAKeyDown(nFlag);
146 #else
147   return IsCTRLKeyDown(nFlag);
148 #endif
149 }
150 
CPWL_Wnd(const CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)151 CPWL_Wnd::CPWL_Wnd(
152     const CreateParams& cp,
153     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)
154     : m_CreationParams(cp), m_pAttachedData(std::move(pAttachedData)) {}
155 
~CPWL_Wnd()156 CPWL_Wnd::~CPWL_Wnd() {
157   DCHECK(!m_bCreated);
158 }
159 
Realize()160 void CPWL_Wnd::Realize() {
161   DCHECK(!m_bCreated);
162 
163   m_CreationParams.rcRectWnd.Normalize();
164   m_rcWindow = m_CreationParams.rcRectWnd;
165   m_rcClip = m_rcWindow;
166   if (!m_rcClip.IsEmpty()) {
167     m_rcClip.Inflate(1.0f, 1.0f);
168     m_rcClip.Normalize();
169   }
170   CreateSharedCaptureFocusState();
171 
172   CreateParams ccp = m_CreationParams;
173   ccp.dwFlags &= 0xFFFF0000L;  // remove sub styles
174   CreateVScrollBar(ccp);
175   CreateChildWnd(ccp);
176   m_bVisible = HasFlag(PWS_VISIBLE);
177   OnCreated();
178   if (!RepositionChildWnd()) {
179     return;
180   }
181 
182   m_bCreated = true;
183 }
184 
OnCreated()185 void CPWL_Wnd::OnCreated() {}
186 
OnDestroy()187 void CPWL_Wnd::OnDestroy() {}
188 
InvalidateProvider(ProviderIface * provider)189 void CPWL_Wnd::InvalidateProvider(ProviderIface* provider) {
190   if (m_CreationParams.pProvider.Get() == provider)
191     m_CreationParams.pProvider.Reset();
192 }
193 
Destroy()194 void CPWL_Wnd::Destroy() {
195   KillFocus();
196   OnDestroy();
197   if (m_bCreated) {
198     m_pVScrollBar = nullptr;
199     while (!m_Children.empty()) {
200       std::unique_ptr<CPWL_Wnd> pChild = std::move(m_Children.back());
201       m_Children.pop_back();
202       pChild->Destroy();
203     }
204     if (m_pParent)
205       m_pParent->RemoveChild(this);
206     m_bCreated = false;
207   }
208   DestroySharedCaptureFocusState();
209 }
210 
Move(const CFX_FloatRect & rcNew,bool bReset,bool bRefresh)211 bool CPWL_Wnd::Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh) {
212   if (!IsValid())
213     return true;
214 
215   CFX_FloatRect rcOld = GetWindowRect();
216   m_rcWindow = rcNew;
217   m_rcWindow.Normalize();
218 
219   if (bReset) {
220     if (rcOld.left != rcNew.left || rcOld.right != rcNew.right ||
221         rcOld.top != rcNew.top || rcOld.bottom != rcNew.bottom) {
222       if (!RepositionChildWnd()) {
223         return false;
224       }
225     }
226   }
227   if (bRefresh && !InvalidateRectMove(rcOld, rcNew))
228     return false;
229 
230   m_CreationParams.rcRectWnd = m_rcWindow;
231   return true;
232 }
233 
InvalidateRectMove(const CFX_FloatRect & rcOld,const CFX_FloatRect & rcNew)234 bool CPWL_Wnd::InvalidateRectMove(const CFX_FloatRect& rcOld,
235                                   const CFX_FloatRect& rcNew) {
236   CFX_FloatRect rcUnion = rcOld;
237   rcUnion.Union(rcNew);
238 
239   return InvalidateRect(&rcUnion);
240 }
241 
DrawAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)242 void CPWL_Wnd::DrawAppearance(CFX_RenderDevice* pDevice,
243                               const CFX_Matrix& mtUser2Device) {
244   if (IsValid() && IsVisible()) {
245     DrawThisAppearance(pDevice, mtUser2Device);
246     DrawChildAppearance(pDevice, mtUser2Device);
247   }
248 }
249 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)250 void CPWL_Wnd::DrawThisAppearance(CFX_RenderDevice* pDevice,
251                                   const CFX_Matrix& mtUser2Device) {
252   CFX_FloatRect rectWnd = GetWindowRect();
253   if (rectWnd.IsEmpty())
254     return;
255 
256   if (HasFlag(PWS_BACKGROUND)) {
257     float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
258     pDevice->DrawFillRect(&mtUser2Device, rectWnd.GetDeflated(width, width),
259                           GetBackgroundColor(), GetTransparency());
260   }
261 
262   if (HasFlag(PWS_BORDER)) {
263     pDevice->DrawBorder(&mtUser2Device, rectWnd,
264                         static_cast<float>(GetBorderWidth()), GetBorderColor(),
265                         GetBorderLeftTopColor(GetBorderStyle()),
266                         GetBorderRightBottomColor(GetBorderStyle()),
267                         GetBorderStyle(), GetTransparency());
268   }
269 }
270 
DrawChildAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)271 void CPWL_Wnd::DrawChildAppearance(CFX_RenderDevice* pDevice,
272                                    const CFX_Matrix& mtUser2Device) {
273   for (const auto& pChild : m_Children) {
274     pChild->DrawAppearance(pDevice, mtUser2Device);
275   }
276 }
277 
InvalidateRect(const CFX_FloatRect * pRect)278 bool CPWL_Wnd::InvalidateRect(const CFX_FloatRect* pRect) {
279   if (!IsValid())
280     return true;
281 
282   ObservedPtr<CPWL_Wnd> this_observed(this);
283   CFX_FloatRect rcRefresh = pRect ? *pRect : GetWindowRect();
284   if (!HasFlag(PWS_NOREFRESHCLIP)) {
285     CFX_FloatRect rcClip = GetClipRect();
286     if (!rcClip.IsEmpty())
287       rcRefresh.Intersect(rcClip);
288   }
289 
290   CFX_FloatRect rcWin = PWLtoWnd(rcRefresh);
291   rcWin.Inflate(1, 1);
292   rcWin.Normalize();
293   GetFillerNotify()->InvalidateRect(m_pAttachedData.get(), rcWin);
294   return !!this_observed;
295 }
296 
OnKeyDown(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlag)297 bool CPWL_Wnd::OnKeyDown(FWL_VKEYCODE nKeyCode, Mask<FWL_EVENTFLAG> nFlag) {
298   if (!IsValid() || !IsVisible())
299     return false;
300   if (!IsWndCaptureKeyboard(this))
301     return false;
302   for (const auto& pChild : m_Children) {
303     if (IsWndCaptureKeyboard(pChild.get()))
304       return pChild->OnKeyDown(nKeyCode, nFlag);
305   }
306   return false;
307 }
308 
OnChar(uint16_t nChar,Mask<FWL_EVENTFLAG> nFlag)309 bool CPWL_Wnd::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
310   if (!IsValid() || !IsVisible())
311     return false;
312   if (!IsWndCaptureKeyboard(this))
313     return false;
314   for (const auto& pChild : m_Children) {
315     if (IsWndCaptureKeyboard(pChild.get()))
316       return pChild->OnChar(nChar, nFlag);
317   }
318   return false;
319 }
320 
321 #define PWL_IMPLEMENT_MOUSE_METHOD(mouse_method_name)         \
322   bool CPWL_Wnd::mouse_method_name(Mask<FWL_EVENTFLAG> nFlag, \
323                                    const CFX_PointF& point) { \
324     if (!IsValid() || !IsVisible())                           \
325       return false;                                           \
326     if (IsWndCaptureMouse(this)) {                            \
327       for (const auto& pChild : m_Children) {                 \
328         if (IsWndCaptureMouse(pChild.get())) {                \
329           return pChild->mouse_method_name(nFlag, point);     \
330         }                                                     \
331       }                                                       \
332       SetCursor();                                            \
333       return false;                                           \
334     }                                                         \
335     for (const auto& pChild : m_Children) {                   \
336       if (pChild->WndHitTest(point)) {                        \
337         return pChild->mouse_method_name(nFlag, point);       \
338       }                                                       \
339     }                                                         \
340     if (WndHitTest(point))                                    \
341       SetCursor();                                            \
342     return false;                                             \
343   }
344 
345 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDblClk)
PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)346 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)
347 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonUp)
348 PWL_IMPLEMENT_MOUSE_METHOD(OnMouseMove)
349 #undef PWL_IMPLEMENT_MOUSE_METHOD
350 
351 // Unlike their FWL counterparts, PWL windows don't handle right clicks.
352 bool CPWL_Wnd::OnRButtonDown(Mask<FWL_EVENTFLAG> nFlag,
353                              const CFX_PointF& point) {
354   return false;
355 }
356 
OnRButtonUp(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)357 bool CPWL_Wnd::OnRButtonUp(Mask<FWL_EVENTFLAG> nFlag, const CFX_PointF& point) {
358   return false;
359 }
360 
GetText()361 WideString CPWL_Wnd::GetText() {
362   return WideString();
363 }
364 
GetSelectedText()365 WideString CPWL_Wnd::GetSelectedText() {
366   return WideString();
367 }
368 
ReplaceAndKeepSelection(const WideString & text)369 void CPWL_Wnd::ReplaceAndKeepSelection(const WideString& text) {}
370 
ReplaceSelection(const WideString & text)371 void CPWL_Wnd::ReplaceSelection(const WideString& text) {}
372 
SelectAllText()373 bool CPWL_Wnd::SelectAllText() {
374   return false;
375 }
376 
CanUndo()377 bool CPWL_Wnd::CanUndo() {
378   return false;
379 }
380 
CanRedo()381 bool CPWL_Wnd::CanRedo() {
382   return false;
383 }
384 
Undo()385 bool CPWL_Wnd::Undo() {
386   return false;
387 }
388 
Redo()389 bool CPWL_Wnd::Redo() {
390   return false;
391 }
392 
OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point,const CFX_Vector & delta)393 bool CPWL_Wnd::OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,
394                             const CFX_PointF& point,
395                             const CFX_Vector& delta) {
396   if (!IsValid() || !IsVisible())
397     return false;
398 
399   SetCursor();
400   if (!IsWndCaptureKeyboard(this))
401     return false;
402 
403   for (const auto& pChild : m_Children) {
404     if (IsWndCaptureKeyboard(pChild.get()))
405       return pChild->OnMouseWheel(nFlag, point, delta);
406   }
407   return false;
408 }
409 
AddChild(std::unique_ptr<CPWL_Wnd> pWnd)410 void CPWL_Wnd::AddChild(std::unique_ptr<CPWL_Wnd> pWnd) {
411   DCHECK(!pWnd->m_pParent);
412   pWnd->m_pParent = this;
413   m_Children.push_back(std::move(pWnd));
414 }
415 
RemoveChild(CPWL_Wnd * pWnd)416 void CPWL_Wnd::RemoveChild(CPWL_Wnd* pWnd) {
417   DCHECK_EQ(pWnd->m_pParent, this);
418   auto it =
419       std::find(m_Children.begin(), m_Children.end(), MakeFakeUniquePtr(pWnd));
420   if (it == m_Children.end())
421     return;
422 
423   // TODO(tsepez): murky ownership.
424   it->release();
425   m_Children.erase(it);
426 }
427 
SetScrollInfo(const PWL_SCROLL_INFO & info)428 void CPWL_Wnd::SetScrollInfo(const PWL_SCROLL_INFO& info) {}
429 
SetScrollPosition(float pos)430 void CPWL_Wnd::SetScrollPosition(float pos) {}
431 
ScrollWindowVertically(float pos)432 void CPWL_Wnd::ScrollWindowVertically(float pos) {}
433 
NotifyLButtonDown(CPWL_Wnd * child,const CFX_PointF & pos)434 void CPWL_Wnd::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {}
435 
NotifyLButtonUp(CPWL_Wnd * child,const CFX_PointF & pos)436 void CPWL_Wnd::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {}
437 
NotifyMouseMove(CPWL_Wnd * child,const CFX_PointF & pos)438 void CPWL_Wnd::NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos) {}
439 
GetWindowRect() const440 CFX_FloatRect CPWL_Wnd::GetWindowRect() const {
441   return m_rcWindow;
442 }
443 
GetClientRect() const444 CFX_FloatRect CPWL_Wnd::GetClientRect() const {
445   CFX_FloatRect rcWindow = GetWindowRect();
446 
447   float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
448   CFX_FloatRect rcClient = rcWindow.GetDeflated(width, width);
449   if (CPWL_ScrollBar* pVSB = GetVScrollBar())
450     rcClient.right -= pVSB->GetScrollBarWidth();
451 
452   rcClient.Normalize();
453   return rcWindow.Contains(rcClient) ? rcClient : CFX_FloatRect();
454 }
455 
GetCenterPoint() const456 CFX_PointF CPWL_Wnd::GetCenterPoint() const {
457   CFX_FloatRect rcClient = GetClientRect();
458   return CFX_PointF((rcClient.left + rcClient.right) * 0.5f,
459                     (rcClient.top + rcClient.bottom) * 0.5f);
460 }
461 
HasFlag(uint32_t dwFlags) const462 bool CPWL_Wnd::HasFlag(uint32_t dwFlags) const {
463   return (m_CreationParams.dwFlags & dwFlags) != 0;
464 }
465 
RemoveFlag(uint32_t dwFlags)466 void CPWL_Wnd::RemoveFlag(uint32_t dwFlags) {
467   m_CreationParams.dwFlags &= ~dwFlags;
468 }
469 
GetBackgroundColor() const470 CFX_Color CPWL_Wnd::GetBackgroundColor() const {
471   return m_CreationParams.sBackgroundColor;
472 }
473 
GetTextColor() const474 CFX_Color CPWL_Wnd::GetTextColor() const {
475   return m_CreationParams.sTextColor;
476 }
477 
GetBorderStyle() const478 BorderStyle CPWL_Wnd::GetBorderStyle() const {
479   return m_CreationParams.nBorderStyle;
480 }
481 
GetBorderWidth() const482 int32_t CPWL_Wnd::GetBorderWidth() const {
483   return HasFlag(PWS_BORDER) ? m_CreationParams.dwBorderWidth : 0;
484 }
485 
GetInnerBorderWidth() const486 int32_t CPWL_Wnd::GetInnerBorderWidth() const {
487   return 0;
488 }
489 
GetBorderColor() const490 CFX_Color CPWL_Wnd::GetBorderColor() const {
491   return HasFlag(PWS_BORDER) ? m_CreationParams.sBorderColor : CFX_Color();
492 }
493 
GetBorderDash() const494 const CPWL_Dash& CPWL_Wnd::GetBorderDash() const {
495   return m_CreationParams.sDash;
496 }
497 
GetVScrollBar() const498 CPWL_ScrollBar* CPWL_Wnd::GetVScrollBar() const {
499   return HasFlag(PWS_VSCROLL) ? m_pVScrollBar : nullptr;
500 }
501 
CreateVScrollBar(const CreateParams & cp)502 void CPWL_Wnd::CreateVScrollBar(const CreateParams& cp) {
503   if (m_pVScrollBar || !HasFlag(PWS_VSCROLL))
504     return;
505 
506   CreateParams scp = cp;
507   scp.dwFlags = PWS_BACKGROUND | PWS_AUTOTRANSPARENT | PWS_NOREFRESHCLIP;
508   scp.sBackgroundColor = kDefaultWhiteColor;
509   scp.eCursorType = IPWL_FillerNotify::CursorStyle::kArrow;
510   scp.nTransparency = CPWL_ScrollBar::kTransparency;
511 
512   auto pBar = std::make_unique<CPWL_ScrollBar>(scp, CloneAttachedData());
513   m_pVScrollBar = pBar.get();
514   AddChild(std::move(pBar));
515   m_pVScrollBar->Realize();
516 }
517 
SetCapture()518 void CPWL_Wnd::SetCapture() {
519   if (SharedCaptureFocusState* pSharedState = GetSharedCaptureFocusState()) {
520     pSharedState->SetCapture(this);
521   }
522 }
523 
ReleaseCapture()524 void CPWL_Wnd::ReleaseCapture() {
525   for (const auto& pChild : m_Children)
526     pChild->ReleaseCapture();
527 
528   if (SharedCaptureFocusState* pSharedState = GetSharedCaptureFocusState()) {
529     pSharedState->ReleaseCapture();
530   }
531 }
532 
SetFocus()533 void CPWL_Wnd::SetFocus() {
534   if (SharedCaptureFocusState* pSharedState = GetSharedCaptureFocusState()) {
535     if (!pSharedState->IsMainCaptureKeyboard(this)) {
536       pSharedState->ReleaseFocus();
537     }
538     pSharedState->SetFocus(this);
539   }
540 }
541 
KillFocus()542 void CPWL_Wnd::KillFocus() {
543   if (SharedCaptureFocusState* pSharedState = GetSharedCaptureFocusState()) {
544     if (pSharedState->IsWndCaptureKeyboard(this)) {
545       pSharedState->ReleaseFocus();
546     }
547   }
548 }
549 
OnSetFocus()550 void CPWL_Wnd::OnSetFocus() {}
551 
OnKillFocus()552 void CPWL_Wnd::OnKillFocus() {}
553 
CloneAttachedData() const554 std::unique_ptr<IPWL_FillerNotify::PerWindowData> CPWL_Wnd::CloneAttachedData()
555     const {
556   return m_pAttachedData ? m_pAttachedData->Clone() : nullptr;
557 }
558 
GetAncestors()559 std::vector<UnownedPtr<CPWL_Wnd>> CPWL_Wnd::GetAncestors() {
560   std::vector<UnownedPtr<CPWL_Wnd>> results;
561   for (CPWL_Wnd* pWnd = this; pWnd; pWnd = pWnd->GetParentWindow()) {
562     results.emplace_back(pWnd);
563   }
564   return results;
565 }
566 
WndHitTest(const CFX_PointF & point) const567 bool CPWL_Wnd::WndHitTest(const CFX_PointF& point) const {
568   return IsValid() && IsVisible() && GetWindowRect().Contains(point);
569 }
570 
ClientHitTest(const CFX_PointF & point) const571 bool CPWL_Wnd::ClientHitTest(const CFX_PointF& point) const {
572   return IsValid() && IsVisible() && GetClientRect().Contains(point);
573 }
574 
SetVisible(bool bVisible)575 bool CPWL_Wnd::SetVisible(bool bVisible) {
576   if (!IsValid())
577     return true;
578 
579   ObservedPtr<CPWL_Wnd> this_observed(this);
580   for (const auto& pChild : m_Children) {
581     if (!pChild->SetVisible(bVisible)) {
582       return false;
583     }
584     if (!this_observed) {
585       return false;
586     }
587   }
588 
589   if (bVisible != m_bVisible) {
590     m_bVisible = bVisible;
591     if (!RepositionChildWnd()) {
592       return false;
593     }
594 
595     if (!InvalidateRect(nullptr))
596       return false;
597   }
598   return true;
599 }
600 
SetClipRect(const CFX_FloatRect & rect)601 void CPWL_Wnd::SetClipRect(const CFX_FloatRect& rect) {
602   m_rcClip = rect;
603   m_rcClip.Normalize();
604 }
605 
GetClipRect() const606 const CFX_FloatRect& CPWL_Wnd::GetClipRect() const {
607   return m_rcClip;
608 }
609 
IsReadOnly() const610 bool CPWL_Wnd::IsReadOnly() const {
611   return HasFlag(PWS_READONLY);
612 }
613 
RepositionChildWnd()614 bool CPWL_Wnd::RepositionChildWnd() {
615   CPWL_ScrollBar* pVSB = GetVScrollBar();
616   if (!pVSB)
617     return true;
618 
619   CFX_FloatRect rcContent = GetWindowRect();
620   if (!rcContent.IsEmpty()) {
621     float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
622     rcContent.Deflate(width, width);
623     rcContent.Normalize();
624   }
625   CFX_FloatRect rcVScroll =
626       CFX_FloatRect(rcContent.right - CPWL_ScrollBar::kWidth, rcContent.bottom,
627                     rcContent.right - 1.0f, rcContent.top);
628 
629   ObservedPtr<CPWL_Wnd> this_observed(this);
630   pVSB->Move(rcVScroll, true, false);
631   if (!this_observed) {
632     return false;
633   }
634 
635   return true;
636 }
637 
CreateChildWnd(const CreateParams & cp)638 void CPWL_Wnd::CreateChildWnd(const CreateParams& cp) {}
639 
SetCursor()640 void CPWL_Wnd::SetCursor() {
641   if (IsValid())
642     GetFillerNotify()->SetCursor(GetCreationParams()->eCursorType);
643 }
644 
CreateSharedCaptureFocusState()645 void CPWL_Wnd::CreateSharedCaptureFocusState() {
646   if (!m_CreationParams.pSharedCaptureFocusState) {
647     m_CreationParams.pSharedCaptureFocusState =
648         new SharedCaptureFocusState(this);
649   }
650 }
651 
DestroySharedCaptureFocusState()652 void CPWL_Wnd::DestroySharedCaptureFocusState() {
653   SharedCaptureFocusState* pSharedCaptureFocusState =
654       GetSharedCaptureFocusState();
655   if (!pSharedCaptureFocusState) {
656     return;
657   }
658   const bool owned = pSharedCaptureFocusState->IsOwnedByWnd(this);
659   pSharedCaptureFocusState->RemoveWnd(this);
660   if (owned) {
661     delete pSharedCaptureFocusState;
662   }
663 }
664 
GetSharedCaptureFocusState() const665 CPWL_Wnd::SharedCaptureFocusState* CPWL_Wnd::GetSharedCaptureFocusState()
666     const {
667   return m_CreationParams.pSharedCaptureFocusState;
668 }
669 
IsCaptureMouse() const670 bool CPWL_Wnd::IsCaptureMouse() const {
671   return IsWndCaptureMouse(this);
672 }
673 
IsWndCaptureMouse(const CPWL_Wnd * pWnd) const674 bool CPWL_Wnd::IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
675   SharedCaptureFocusState* pCtrl = GetSharedCaptureFocusState();
676   return pCtrl && pCtrl->IsWndCaptureMouse(pWnd);
677 }
678 
IsWndCaptureKeyboard(const CPWL_Wnd * pWnd) const679 bool CPWL_Wnd::IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
680   SharedCaptureFocusState* pCtrl = GetSharedCaptureFocusState();
681   return pCtrl && pCtrl->IsWndCaptureKeyboard(pWnd);
682 }
683 
IsFocused() const684 bool CPWL_Wnd::IsFocused() const {
685   SharedCaptureFocusState* pCtrl = GetSharedCaptureFocusState();
686   return pCtrl && pCtrl->IsMainCaptureKeyboard(this);
687 }
688 
GetFocusRect() const689 CFX_FloatRect CPWL_Wnd::GetFocusRect() const {
690   CFX_FloatRect rect = GetWindowRect();
691   if (!rect.IsEmpty()) {
692     rect.Inflate(1.0f, 1.0f);
693     rect.Normalize();
694   }
695   return rect;
696 }
697 
GetFontSize() const698 float CPWL_Wnd::GetFontSize() const {
699   return m_CreationParams.fFontSize;
700 }
701 
SetFontSize(float fFontSize)702 void CPWL_Wnd::SetFontSize(float fFontSize) {
703   m_CreationParams.fFontSize = fFontSize;
704 }
705 
GetBorderLeftTopColor(BorderStyle nBorderStyle) const706 CFX_Color CPWL_Wnd::GetBorderLeftTopColor(BorderStyle nBorderStyle) const {
707   switch (nBorderStyle) {
708     case BorderStyle::kBeveled:
709       return CFX_Color(CFX_Color::Type::kGray, 1);
710     case BorderStyle::kInset:
711       return CFX_Color(CFX_Color::Type::kGray, 0.5f);
712     default:
713       return CFX_Color();
714   }
715 }
716 
GetBorderRightBottomColor(BorderStyle nBorderStyle) const717 CFX_Color CPWL_Wnd::GetBorderRightBottomColor(BorderStyle nBorderStyle) const {
718   switch (nBorderStyle) {
719     case BorderStyle::kBeveled:
720       return GetBackgroundColor() / 2.0f;
721     case BorderStyle::kInset:
722       return CFX_Color(CFX_Color::Type::kGray, 0.75f);
723     default:
724       return CFX_Color();
725   }
726 }
727 
GetTransparency()728 int32_t CPWL_Wnd::GetTransparency() {
729   return m_CreationParams.nTransparency;
730 }
731 
SetTransparency(int32_t nTransparency)732 void CPWL_Wnd::SetTransparency(int32_t nTransparency) {
733   for (const auto& pChild : m_Children)
734     pChild->SetTransparency(nTransparency);
735 
736   m_CreationParams.nTransparency = nTransparency;
737 }
738 
GetWindowMatrix() const739 CFX_Matrix CPWL_Wnd::GetWindowMatrix() const {
740   CFX_Matrix mt;
741   if (ProviderIface* pProvider = GetProvider())
742     mt.Concat(pProvider->GetWindowMatrix(GetAttachedData()));
743   return mt;
744 }
745 
PWLtoWnd(const CFX_FloatRect & rect) const746 CFX_FloatRect CPWL_Wnd::PWLtoWnd(const CFX_FloatRect& rect) const {
747   CFX_Matrix mt = GetWindowMatrix();
748   return mt.TransformRect(rect);
749 }
750