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