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