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_wnd.h"
8 
9 #include <map>
10 #include <sstream>
11 #include <utility>
12 #include <vector>
13 
14 #include "core/fxge/cfx_renderdevice.h"
15 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
16 #include "public/fpdf_fwlevent.h"
17 #include "third_party/base/ptr_util.h"
18 #include "third_party/base/stl_util.h"
19 
20 namespace {
21 
22 constexpr float kDefaultFontSize = 9.0f;
23 
24 }  // namespace
25 
CreateParams()26 CPWL_Wnd::CreateParams::CreateParams()
27     : fFontSize(kDefaultFontSize), sDash(3, 0, 0) {}
28 
29 CPWL_Wnd::CreateParams::CreateParams(const CreateParams& other) = default;
30 
31 CPWL_Wnd::CreateParams::~CreateParams() = default;
32 
33 class CPWL_MsgControl final : public Observable {
34  public:
CPWL_MsgControl(CPWL_Wnd * pWnd)35   explicit CPWL_MsgControl(CPWL_Wnd* pWnd) : m_pCreatedWnd(pWnd) {}
~CPWL_MsgControl()36   ~CPWL_MsgControl() {}
37 
IsWndCreated(const CPWL_Wnd * pWnd) const38   bool IsWndCreated(const CPWL_Wnd* pWnd) const {
39     return m_pCreatedWnd == pWnd;
40   }
41 
IsWndCaptureMouse(const CPWL_Wnd * pWnd) const42   bool IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
43     return pWnd && pdfium::ContainsValue(m_aMousePath, pWnd);
44   }
45 
IsMainCaptureKeyboard(const CPWL_Wnd * pWnd) const46   bool IsMainCaptureKeyboard(const CPWL_Wnd* pWnd) const {
47     return pWnd == m_pMainKeyboardWnd;
48   }
49 
IsWndCaptureKeyboard(const CPWL_Wnd * pWnd) const50   bool IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
51     return pWnd && pdfium::ContainsValue(m_aKeyboardPath, pWnd);
52   }
53 
SetFocus(CPWL_Wnd * pWnd)54   void SetFocus(CPWL_Wnd* pWnd) {
55     m_aKeyboardPath.clear();
56     if (!pWnd)
57       return;
58 
59     m_pMainKeyboardWnd = pWnd;
60     CPWL_Wnd* pParent = pWnd;
61     while (pParent) {
62       m_aKeyboardPath.push_back(pParent);
63       pParent = pParent->GetParentWindow();
64     }
65     // Note, pWnd may get destroyed in the OnSetFocus call.
66     pWnd->OnSetFocus();
67   }
68 
KillFocus()69   void KillFocus() {
70     ObservedPtr<CPWL_MsgControl> observed_ptr(this);
71     if (!m_aKeyboardPath.empty())
72       if (CPWL_Wnd* pWnd = m_aKeyboardPath[0])
73         pWnd->OnKillFocus();
74     if (!observed_ptr)
75       return;
76 
77     m_pMainKeyboardWnd = nullptr;
78     m_aKeyboardPath.clear();
79   }
80 
SetCapture(CPWL_Wnd * pWnd)81   void SetCapture(CPWL_Wnd* pWnd) {
82     m_aMousePath.clear();
83     if (pWnd) {
84       CPWL_Wnd* pParent = pWnd;
85       while (pParent) {
86         m_aMousePath.push_back(pParent);
87         pParent = pParent->GetParentWindow();
88       }
89     }
90   }
91 
ReleaseCapture()92   void ReleaseCapture() { m_aMousePath.clear(); }
93 
GetFocusedWindow() const94   CPWL_Wnd* GetFocusedWindow() const { return m_pMainKeyboardWnd.Get(); }
95 
96  private:
97   std::vector<CPWL_Wnd*> m_aMousePath;
98   std::vector<CPWL_Wnd*> m_aKeyboardPath;
99   UnownedPtr<CPWL_Wnd> m_pCreatedWnd;
100   UnownedPtr<CPWL_Wnd> m_pMainKeyboardWnd;
101 };
102 
103 // static
IsSHIFTKeyDown(uint32_t nFlag)104 bool CPWL_Wnd::IsSHIFTKeyDown(uint32_t nFlag) {
105   return !!(nFlag & FWL_EVENTFLAG_ShiftKey);
106 }
107 
108 // static
IsCTRLKeyDown(uint32_t nFlag)109 bool CPWL_Wnd::IsCTRLKeyDown(uint32_t nFlag) {
110   return !!(nFlag & FWL_EVENTFLAG_ControlKey);
111 }
112 
113 // static
IsALTKeyDown(uint32_t nFlag)114 bool CPWL_Wnd::IsALTKeyDown(uint32_t nFlag) {
115   return !!(nFlag & FWL_EVENTFLAG_AltKey);
116 }
117 
CPWL_Wnd(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)118 CPWL_Wnd::CPWL_Wnd(
119     const CreateParams& cp,
120     std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)
121     : m_CreationParams(cp), m_pAttachedData(std::move(pAttachedData)) {}
122 
~CPWL_Wnd()123 CPWL_Wnd::~CPWL_Wnd() {
124   ASSERT(!m_bCreated);
125 }
126 
Realize()127 void CPWL_Wnd::Realize() {
128   ASSERT(!m_bCreated);
129 
130   m_CreationParams.rcRectWnd.Normalize();
131   m_rcWindow = m_CreationParams.rcRectWnd;
132   m_rcClip = m_rcWindow;
133   if (!m_rcClip.IsEmpty()) {
134     m_rcClip.Inflate(1.0f, 1.0f);
135     m_rcClip.Normalize();
136   }
137   CreateMsgControl();
138 
139   CreateParams ccp = m_CreationParams;
140   ccp.dwFlags &= 0xFFFF0000L;  // remove sub styles
141   CreateScrollBar(ccp);
142   CreateChildWnd(ccp);
143   m_bVisible = HasFlag(PWS_VISIBLE);
144   OnCreated();
145   if (!RePosChildWnd())
146     return;
147 
148   m_bCreated = true;
149 }
150 
OnCreated()151 void CPWL_Wnd::OnCreated() {}
152 
OnDestroy()153 void CPWL_Wnd::OnDestroy() {}
154 
InvalidateFocusHandler(FocusHandlerIface * handler)155 void CPWL_Wnd::InvalidateFocusHandler(FocusHandlerIface* handler) {
156   if (m_CreationParams.pFocusHandler == handler)
157     m_CreationParams.pFocusHandler = nullptr;
158 }
159 
InvalidateProvider(ProviderIface * provider)160 void CPWL_Wnd::InvalidateProvider(ProviderIface* provider) {
161   if (m_CreationParams.pProvider.Get() == provider)
162     m_CreationParams.pProvider.Reset();
163 }
164 
Destroy()165 void CPWL_Wnd::Destroy() {
166   KillFocus();
167   OnDestroy();
168   if (m_bCreated) {
169     m_pVScrollBar = nullptr;
170     while (!m_Children.empty()) {
171       std::unique_ptr<CPWL_Wnd> pChild = std::move(m_Children.back());
172       m_Children.pop_back();
173       pChild->Destroy();
174     }
175     if (m_pParent)
176       m_pParent->RemoveChild(this);
177     m_bCreated = false;
178   }
179   DestroyMsgControl();
180 }
181 
Move(const CFX_FloatRect & rcNew,bool bReset,bool bRefresh)182 bool CPWL_Wnd::Move(const CFX_FloatRect& rcNew, bool bReset, bool bRefresh) {
183   if (!IsValid())
184     return true;
185 
186   CFX_FloatRect rcOld = GetWindowRect();
187   m_rcWindow = rcNew;
188   m_rcWindow.Normalize();
189 
190   if (bReset) {
191     if (rcOld.left != rcNew.left || rcOld.right != rcNew.right ||
192         rcOld.top != rcNew.top || rcOld.bottom != rcNew.bottom) {
193       if (!RePosChildWnd())
194         return false;
195     }
196   }
197   if (bRefresh && !InvalidateRectMove(rcOld, rcNew))
198     return false;
199 
200   m_CreationParams.rcRectWnd = m_rcWindow;
201   return true;
202 }
203 
InvalidateRectMove(const CFX_FloatRect & rcOld,const CFX_FloatRect & rcNew)204 bool CPWL_Wnd::InvalidateRectMove(const CFX_FloatRect& rcOld,
205                                   const CFX_FloatRect& rcNew) {
206   CFX_FloatRect rcUnion = rcOld;
207   rcUnion.Union(rcNew);
208 
209   return InvalidateRect(&rcUnion);
210 }
211 
DrawAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)212 void CPWL_Wnd::DrawAppearance(CFX_RenderDevice* pDevice,
213                               const CFX_Matrix& mtUser2Device) {
214   if (IsValid() && IsVisible()) {
215     DrawThisAppearance(pDevice, mtUser2Device);
216     DrawChildAppearance(pDevice, mtUser2Device);
217   }
218 }
219 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)220 void CPWL_Wnd::DrawThisAppearance(CFX_RenderDevice* pDevice,
221                                   const CFX_Matrix& mtUser2Device) {
222   CFX_FloatRect rectWnd = GetWindowRect();
223   if (rectWnd.IsEmpty())
224     return;
225 
226   if (HasFlag(PWS_BACKGROUND)) {
227     float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
228     pDevice->DrawFillRect(&mtUser2Device, rectWnd.GetDeflated(width, width),
229                           GetBackgroundColor(), GetTransparency());
230   }
231 
232   if (HasFlag(PWS_BORDER)) {
233     pDevice->DrawBorder(&mtUser2Device, rectWnd,
234                         static_cast<float>(GetBorderWidth()), GetBorderColor(),
235                         GetBorderLeftTopColor(GetBorderStyle()),
236                         GetBorderRightBottomColor(GetBorderStyle()),
237                         GetBorderStyle(), GetTransparency());
238   }
239 }
240 
DrawChildAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)241 void CPWL_Wnd::DrawChildAppearance(CFX_RenderDevice* pDevice,
242                                    const CFX_Matrix& mtUser2Device) {
243   for (const auto& pChild : m_Children) {
244     CFX_Matrix mt = pChild->GetChildMatrix();
245     if (mt.IsIdentity()) {
246       pChild->DrawAppearance(pDevice, mtUser2Device);
247       continue;
248     }
249     mt.Concat(mtUser2Device);
250     pChild->DrawAppearance(pDevice, mt);
251   }
252 }
253 
InvalidateRect(CFX_FloatRect * pRect)254 bool CPWL_Wnd::InvalidateRect(CFX_FloatRect* pRect) {
255   if (!IsValid())
256     return true;
257 
258   ObservedPtr<CPWL_Wnd> thisObserved(this);
259   CFX_FloatRect rcRefresh = pRect ? *pRect : GetWindowRect();
260   if (!HasFlag(PWS_NOREFRESHCLIP)) {
261     CFX_FloatRect rcClip = GetClipRect();
262     if (!rcClip.IsEmpty())
263       rcRefresh.Intersect(rcClip);
264   }
265 
266   CFX_FloatRect rcWin = PWLtoWnd(rcRefresh);
267   rcWin.Inflate(1, 1);
268   rcWin.Normalize();
269   GetSystemHandler()->InvalidateRect(m_pAttachedData.get(), rcWin);
270   return !!thisObserved;
271 }
272 
273 #define PWL_IMPLEMENT_KEY_METHOD(key_method_name)                  \
274   bool CPWL_Wnd::key_method_name(uint16_t nChar, uint32_t nFlag) { \
275     if (!IsValid() || !IsVisible() || !IsEnabled())                \
276       return false;                                                \
277     if (!IsWndCaptureKeyboard(this))                               \
278       return false;                                                \
279     for (const auto& pChild : m_Children) {                        \
280       if (IsWndCaptureKeyboard(pChild.get()))                      \
281         return pChild->key_method_name(nChar, nFlag);              \
282     }                                                              \
283     return false;                                                  \
284   }
285 
286 PWL_IMPLEMENT_KEY_METHOD(OnKeyDown)
PWL_IMPLEMENT_KEY_METHOD(OnChar)287 PWL_IMPLEMENT_KEY_METHOD(OnChar)
288 #undef PWL_IMPLEMENT_KEY_METHOD
289 
290 #define PWL_IMPLEMENT_MOUSE_METHOD(mouse_method_name)                          \
291   bool CPWL_Wnd::mouse_method_name(const CFX_PointF& point, uint32_t nFlag) {  \
292     if (!IsValid() || !IsVisible() || !IsEnabled())                            \
293       return false;                                                            \
294     if (IsWndCaptureMouse(this)) {                                             \
295       for (const auto& pChild : m_Children) {                                  \
296         if (IsWndCaptureMouse(pChild.get())) {                                 \
297           return pChild->mouse_method_name(pChild->ParentToChild(point),       \
298                                            nFlag);                             \
299         }                                                                      \
300       }                                                                        \
301       SetCursor();                                                             \
302       return false;                                                            \
303     }                                                                          \
304     for (const auto& pChild : m_Children) {                                    \
305       if (pChild->WndHitTest(pChild->ParentToChild(point))) {                  \
306         return pChild->mouse_method_name(pChild->ParentToChild(point), nFlag); \
307       }                                                                        \
308     }                                                                          \
309     if (WndHitTest(point))                                                     \
310       SetCursor();                                                             \
311     return false;                                                              \
312   }
313 
314 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDblClk)
315 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonDown)
316 PWL_IMPLEMENT_MOUSE_METHOD(OnLButtonUp)
317 PWL_IMPLEMENT_MOUSE_METHOD(OnMouseMove)
318 #undef PWL_IMPLEMENT_MOUSE_METHOD
319 
320 // Unlike their FWL counterparts, PWL windows don't handle right clicks.
321 bool CPWL_Wnd::OnRButtonDown(const CFX_PointF& point, uint32_t nFlag) {
322   return false;
323 }
324 
OnRButtonUp(const CFX_PointF & point,uint32_t nFlag)325 bool CPWL_Wnd::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
326   return false;
327 }
328 
GetText()329 WideString CPWL_Wnd::GetText() {
330   return WideString();
331 }
332 
GetSelectedText()333 WideString CPWL_Wnd::GetSelectedText() {
334   return WideString();
335 }
336 
ReplaceSelection(const WideString & text)337 void CPWL_Wnd::ReplaceSelection(const WideString& text) {}
338 
CanUndo()339 bool CPWL_Wnd::CanUndo() {
340   return false;
341 }
342 
CanRedo()343 bool CPWL_Wnd::CanRedo() {
344   return false;
345 }
346 
Undo()347 bool CPWL_Wnd::Undo() {
348   return false;
349 }
350 
Redo()351 bool CPWL_Wnd::Redo() {
352   return false;
353 }
354 
OnMouseWheel(short zDelta,const CFX_PointF & point,uint32_t nFlag)355 bool CPWL_Wnd::OnMouseWheel(short zDelta,
356                             const CFX_PointF& point,
357                             uint32_t nFlag) {
358   if (!IsValid() || !IsVisible() || !IsEnabled())
359     return false;
360 
361   SetCursor();
362   if (!IsWndCaptureKeyboard(this))
363     return false;
364 
365   for (const auto& pChild : m_Children) {
366     if (IsWndCaptureKeyboard(pChild.get()))
367       return pChild->OnMouseWheel(zDelta, pChild->ParentToChild(point), nFlag);
368   }
369   return false;
370 }
371 
AddChild(std::unique_ptr<CPWL_Wnd> pWnd)372 void CPWL_Wnd::AddChild(std::unique_ptr<CPWL_Wnd> pWnd) {
373   ASSERT(!pWnd->m_pParent);
374   pWnd->m_pParent = this;
375   m_Children.push_back(std::move(pWnd));
376 }
377 
RemoveChild(CPWL_Wnd * pWnd)378 void CPWL_Wnd::RemoveChild(CPWL_Wnd* pWnd) {
379   ASSERT(pWnd->m_pParent == this);
380   auto it = std::find(m_Children.begin(), m_Children.end(),
381                       pdfium::FakeUniquePtr<CPWL_Wnd>(pWnd));
382   if (it == m_Children.end())
383     return;
384 
385   // TODO(tsepez): murky ownership.
386   it->release();
387   m_Children.erase(it);
388 }
389 
SetScrollInfo(const PWL_SCROLL_INFO & info)390 void CPWL_Wnd::SetScrollInfo(const PWL_SCROLL_INFO& info) {}
391 
SetScrollPosition(float pos)392 void CPWL_Wnd::SetScrollPosition(float pos) {}
393 
ScrollWindowVertically(float pos)394 void CPWL_Wnd::ScrollWindowVertically(float pos) {}
395 
NotifyLButtonDown(CPWL_Wnd * child,const CFX_PointF & pos)396 void CPWL_Wnd::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {}
397 
NotifyLButtonUp(CPWL_Wnd * child,const CFX_PointF & pos)398 void CPWL_Wnd::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {}
399 
NotifyMouseMove(CPWL_Wnd * child,const CFX_PointF & pos)400 void CPWL_Wnd::NotifyMouseMove(CPWL_Wnd* child, const CFX_PointF& pos) {}
401 
GetWindowRect() const402 CFX_FloatRect CPWL_Wnd::GetWindowRect() const {
403   return m_rcWindow;
404 }
405 
GetClientRect() const406 CFX_FloatRect CPWL_Wnd::GetClientRect() const {
407   CFX_FloatRect rcWindow = GetWindowRect();
408 
409   float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
410   CFX_FloatRect rcClient = rcWindow.GetDeflated(width, width);
411   if (CPWL_ScrollBar* pVSB = GetVScrollBar())
412     rcClient.right -= pVSB->GetScrollBarWidth();
413 
414   rcClient.Normalize();
415   return rcWindow.Contains(rcClient) ? rcClient : CFX_FloatRect();
416 }
417 
GetCenterPoint() const418 CFX_PointF CPWL_Wnd::GetCenterPoint() const {
419   CFX_FloatRect rcClient = GetClientRect();
420   return CFX_PointF((rcClient.left + rcClient.right) * 0.5f,
421                     (rcClient.top + rcClient.bottom) * 0.5f);
422 }
423 
HasFlag(uint32_t dwFlags) const424 bool CPWL_Wnd::HasFlag(uint32_t dwFlags) const {
425   return (m_CreationParams.dwFlags & dwFlags) != 0;
426 }
427 
RemoveFlag(uint32_t dwFlags)428 void CPWL_Wnd::RemoveFlag(uint32_t dwFlags) {
429   m_CreationParams.dwFlags &= ~dwFlags;
430 }
431 
AddFlag(uint32_t dwFlags)432 void CPWL_Wnd::AddFlag(uint32_t dwFlags) {
433   m_CreationParams.dwFlags |= dwFlags;
434 }
435 
GetBackgroundColor() const436 CFX_Color CPWL_Wnd::GetBackgroundColor() const {
437   return m_CreationParams.sBackgroundColor;
438 }
439 
SetBackgroundColor(const CFX_Color & color)440 void CPWL_Wnd::SetBackgroundColor(const CFX_Color& color) {
441   m_CreationParams.sBackgroundColor = color;
442 }
443 
GetTextColor() const444 CFX_Color CPWL_Wnd::GetTextColor() const {
445   return m_CreationParams.sTextColor;
446 }
447 
GetBorderStyle() const448 BorderStyle CPWL_Wnd::GetBorderStyle() const {
449   return m_CreationParams.nBorderStyle;
450 }
451 
SetBorderStyle(BorderStyle nBorderStyle)452 void CPWL_Wnd::SetBorderStyle(BorderStyle nBorderStyle) {
453   if (HasFlag(PWS_BORDER))
454     m_CreationParams.nBorderStyle = nBorderStyle;
455 }
456 
GetBorderWidth() const457 int32_t CPWL_Wnd::GetBorderWidth() const {
458   return HasFlag(PWS_BORDER) ? m_CreationParams.dwBorderWidth : 0;
459 }
460 
GetInnerBorderWidth() const461 int32_t CPWL_Wnd::GetInnerBorderWidth() const {
462   return 0;
463 }
464 
GetBorderColor() const465 CFX_Color CPWL_Wnd::GetBorderColor() const {
466   return HasFlag(PWS_BORDER) ? m_CreationParams.sBorderColor : CFX_Color();
467 }
468 
GetBorderDash() const469 const CPWL_Dash& CPWL_Wnd::GetBorderDash() const {
470   return m_CreationParams.sDash;
471 }
472 
GetVScrollBar() const473 CPWL_ScrollBar* CPWL_Wnd::GetVScrollBar() const {
474   return HasFlag(PWS_VSCROLL) ? m_pVScrollBar.Get() : nullptr;
475 }
476 
CreateScrollBar(const CreateParams & cp)477 void CPWL_Wnd::CreateScrollBar(const CreateParams& cp) {
478   CreateVScrollBar(cp);
479 }
480 
CreateVScrollBar(const CreateParams & cp)481 void CPWL_Wnd::CreateVScrollBar(const CreateParams& cp) {
482   if (m_pVScrollBar || !HasFlag(PWS_VSCROLL))
483     return;
484 
485   CreateParams scp = cp;
486   scp.dwFlags =
487       PWS_CHILD | PWS_BACKGROUND | PWS_AUTOTRANSPARENT | PWS_NOREFRESHCLIP;
488   scp.sBackgroundColor = PWL_DEFAULT_WHITECOLOR;
489   scp.eCursorType = FXCT_ARROW;
490   scp.nTransparency = PWL_SCROLLBAR_TRANSPARENCY;
491 
492   auto pBar =
493       pdfium::MakeUnique<CPWL_ScrollBar>(scp, CloneAttachedData(), SBT_VSCROLL);
494   m_pVScrollBar = pBar.get();
495   AddChild(std::move(pBar));
496   m_pVScrollBar->Realize();
497 }
498 
SetCapture()499 void CPWL_Wnd::SetCapture() {
500   if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
501     pMsgCtrl->SetCapture(this);
502 }
503 
ReleaseCapture()504 void CPWL_Wnd::ReleaseCapture() {
505   for (const auto& pChild : m_Children)
506     pChild->ReleaseCapture();
507 
508   if (CPWL_MsgControl* pMsgCtrl = GetMsgControl())
509     pMsgCtrl->ReleaseCapture();
510 }
511 
SetFocus()512 void CPWL_Wnd::SetFocus() {
513   if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
514     if (!pMsgCtrl->IsMainCaptureKeyboard(this))
515       pMsgCtrl->KillFocus();
516     pMsgCtrl->SetFocus(this);
517   }
518 }
519 
KillFocus()520 void CPWL_Wnd::KillFocus() {
521   if (CPWL_MsgControl* pMsgCtrl = GetMsgControl()) {
522     if (pMsgCtrl->IsWndCaptureKeyboard(this))
523       pMsgCtrl->KillFocus();
524   }
525 }
526 
OnSetFocus()527 void CPWL_Wnd::OnSetFocus() {}
528 
OnKillFocus()529 void CPWL_Wnd::OnKillFocus() {}
530 
CloneAttachedData() const531 std::unique_ptr<IPWL_SystemHandler::PerWindowData> CPWL_Wnd::CloneAttachedData()
532     const {
533   return m_pAttachedData ? m_pAttachedData->Clone() : nullptr;
534 }
535 
WndHitTest(const CFX_PointF & point) const536 bool CPWL_Wnd::WndHitTest(const CFX_PointF& point) const {
537   return IsValid() && IsVisible() && GetWindowRect().Contains(point);
538 }
539 
ClientHitTest(const CFX_PointF & point) const540 bool CPWL_Wnd::ClientHitTest(const CFX_PointF& point) const {
541   return IsValid() && IsVisible() && GetClientRect().Contains(point);
542 }
543 
SetVisible(bool bVisible)544 bool CPWL_Wnd::SetVisible(bool bVisible) {
545   if (!IsValid())
546     return true;
547 
548   ObservedPtr<CPWL_Wnd> thisObserved(this);
549   for (const auto& pChild : m_Children) {
550     pChild->SetVisible(bVisible);
551     if (!thisObserved)
552       return false;
553   }
554 
555   if (bVisible != m_bVisible) {
556     m_bVisible = bVisible;
557     if (!RePosChildWnd())
558       return false;
559 
560     if (!InvalidateRect(nullptr))
561       return false;
562   }
563   return true;
564 }
565 
SetClipRect(const CFX_FloatRect & rect)566 void CPWL_Wnd::SetClipRect(const CFX_FloatRect& rect) {
567   m_rcClip = rect;
568   m_rcClip.Normalize();
569 }
570 
GetClipRect() const571 const CFX_FloatRect& CPWL_Wnd::GetClipRect() const {
572   return m_rcClip;
573 }
574 
IsReadOnly() const575 bool CPWL_Wnd::IsReadOnly() const {
576   return HasFlag(PWS_READONLY);
577 }
578 
RePosChildWnd()579 bool CPWL_Wnd::RePosChildWnd() {
580   CPWL_ScrollBar* pVSB = GetVScrollBar();
581   if (!pVSB)
582     return true;
583 
584   CFX_FloatRect rcContent = GetWindowRect();
585   if (!rcContent.IsEmpty()) {
586     float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
587     rcContent.Deflate(width, width);
588     rcContent.Normalize();
589   }
590   CFX_FloatRect rcVScroll =
591       CFX_FloatRect(rcContent.right - PWL_SCROLLBAR_WIDTH, rcContent.bottom,
592                     rcContent.right - 1.0f, rcContent.top);
593 
594   ObservedPtr<CPWL_Wnd> thisObserved(this);
595   pVSB->Move(rcVScroll, true, false);
596   if (!thisObserved)
597     return false;
598 
599   return true;
600 }
601 
CreateChildWnd(const CreateParams & cp)602 void CPWL_Wnd::CreateChildWnd(const CreateParams& cp) {}
603 
SetCursor()604 void CPWL_Wnd::SetCursor() {
605   if (IsValid())
606     GetSystemHandler()->SetCursor(GetCreationParams()->eCursorType);
607 }
608 
CreateMsgControl()609 void CPWL_Wnd::CreateMsgControl() {
610   if (!m_CreationParams.pMsgControl)
611     m_CreationParams.pMsgControl = new CPWL_MsgControl(this);
612 }
613 
DestroyMsgControl()614 void CPWL_Wnd::DestroyMsgControl() {
615   CPWL_MsgControl* pMsgControl = GetMsgControl();
616   if (pMsgControl && pMsgControl->IsWndCreated(this))
617     delete pMsgControl;
618 }
619 
GetMsgControl() const620 CPWL_MsgControl* CPWL_Wnd::GetMsgControl() const {
621   return m_CreationParams.pMsgControl;
622 }
623 
IsCaptureMouse() const624 bool CPWL_Wnd::IsCaptureMouse() const {
625   return IsWndCaptureMouse(this);
626 }
627 
IsWndCaptureMouse(const CPWL_Wnd * pWnd) const628 bool CPWL_Wnd::IsWndCaptureMouse(const CPWL_Wnd* pWnd) const {
629   CPWL_MsgControl* pCtrl = GetMsgControl();
630   return pCtrl && pCtrl->IsWndCaptureMouse(pWnd);
631 }
632 
IsWndCaptureKeyboard(const CPWL_Wnd * pWnd) const633 bool CPWL_Wnd::IsWndCaptureKeyboard(const CPWL_Wnd* pWnd) const {
634   CPWL_MsgControl* pCtrl = GetMsgControl();
635   return pCtrl && pCtrl->IsWndCaptureKeyboard(pWnd);
636 }
637 
IsFocused() const638 bool CPWL_Wnd::IsFocused() const {
639   CPWL_MsgControl* pCtrl = GetMsgControl();
640   return pCtrl && pCtrl->IsMainCaptureKeyboard(this);
641 }
642 
GetFocusRect() const643 CFX_FloatRect CPWL_Wnd::GetFocusRect() const {
644   CFX_FloatRect rect = GetWindowRect();
645   if (!rect.IsEmpty()) {
646     rect.Inflate(1.0f, 1.0f);
647     rect.Normalize();
648   }
649   return rect;
650 }
651 
GetFontSize() const652 float CPWL_Wnd::GetFontSize() const {
653   return m_CreationParams.fFontSize;
654 }
655 
SetFontSize(float fFontSize)656 void CPWL_Wnd::SetFontSize(float fFontSize) {
657   m_CreationParams.fFontSize = fFontSize;
658 }
659 
GetBorderLeftTopColor(BorderStyle nBorderStyle) const660 CFX_Color CPWL_Wnd::GetBorderLeftTopColor(BorderStyle nBorderStyle) const {
661   switch (nBorderStyle) {
662     case BorderStyle::BEVELED:
663       return CFX_Color(CFX_Color::kGray, 1);
664     case BorderStyle::INSET:
665       return CFX_Color(CFX_Color::kGray, 0.5f);
666     default:
667       return CFX_Color();
668   }
669 }
670 
GetBorderRightBottomColor(BorderStyle nBorderStyle) const671 CFX_Color CPWL_Wnd::GetBorderRightBottomColor(BorderStyle nBorderStyle) const {
672   switch (nBorderStyle) {
673     case BorderStyle::BEVELED:
674       return GetBackgroundColor() / 2.0f;
675     case BorderStyle::INSET:
676       return CFX_Color(CFX_Color::kGray, 0.75f);
677     default:
678       return CFX_Color();
679   }
680 }
681 
GetTransparency()682 int32_t CPWL_Wnd::GetTransparency() {
683   return m_CreationParams.nTransparency;
684 }
685 
SetTransparency(int32_t nTransparency)686 void CPWL_Wnd::SetTransparency(int32_t nTransparency) {
687   for (const auto& pChild : m_Children)
688     pChild->SetTransparency(nTransparency);
689 
690   m_CreationParams.nTransparency = nTransparency;
691 }
692 
GetWindowMatrix() const693 CFX_Matrix CPWL_Wnd::GetWindowMatrix() const {
694   CFX_Matrix mt = GetChildToRoot();
695   if (ProviderIface* pProvider = GetProvider())
696     mt.Concat(pProvider->GetWindowMatrix(GetAttachedData()));
697   return mt;
698 }
699 
PWLtoWnd(const CFX_FloatRect & rect) const700 CFX_FloatRect CPWL_Wnd::PWLtoWnd(const CFX_FloatRect& rect) const {
701   CFX_Matrix mt = GetWindowMatrix();
702   return mt.TransformRect(rect);
703 }
704 
ParentToChild(const CFX_PointF & point) const705 CFX_PointF CPWL_Wnd::ParentToChild(const CFX_PointF& point) const {
706   CFX_Matrix mt = GetChildMatrix();
707   if (mt.IsIdentity())
708     return point;
709 
710   CFX_Matrix inverse = mt.GetInverse();
711   if (!inverse.IsIdentity())
712     mt = inverse;
713   return mt.Transform(point);
714 }
715 
ParentToChild(const CFX_FloatRect & rect) const716 CFX_FloatRect CPWL_Wnd::ParentToChild(const CFX_FloatRect& rect) const {
717   CFX_Matrix mt = GetChildMatrix();
718   if (mt.IsIdentity())
719     return rect;
720 
721   CFX_Matrix inverse = mt.GetInverse();
722   if (!inverse.IsIdentity())
723     mt = inverse;
724 
725   return mt.TransformRect(rect);
726 }
727 
GetChildToRoot() const728 CFX_Matrix CPWL_Wnd::GetChildToRoot() const {
729   CFX_Matrix mt;
730   if (HasFlag(PWS_CHILD)) {
731     const CPWL_Wnd* pParent = this;
732     while (pParent) {
733       mt.Concat(pParent->GetChildMatrix());
734       pParent = pParent->GetParentWindow();
735     }
736   }
737   return mt;
738 }
739 
GetChildMatrix() const740 CFX_Matrix CPWL_Wnd::GetChildMatrix() const {
741   return HasFlag(PWS_CHILD) ? m_CreationParams.mtChild : CFX_Matrix();
742 }
743 
SetChildMatrix(const CFX_Matrix & mt)744 void CPWL_Wnd::SetChildMatrix(const CFX_Matrix& mt) {
745   m_CreationParams.mtChild = mt;
746 }
747 
GetFocused() const748 const CPWL_Wnd* CPWL_Wnd::GetFocused() const {
749   CPWL_MsgControl* pMsgCtrl = GetMsgControl();
750   return pMsgCtrl ? pMsgCtrl->GetFocusedWindow() : nullptr;
751 }
752 
EnableWindow(bool bEnable)753 void CPWL_Wnd::EnableWindow(bool bEnable) {
754   if (m_bEnabled == bEnable)
755     return;
756 
757   for (const auto& pChild : m_Children)
758     pChild->EnableWindow(bEnable);
759 
760   m_bEnabled = bEnable;
761 }
762