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