Home | History | Annotate | Download | only in fwl
      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 "xfa/fwl/cfwl_widget.h"
      8 
      9 #include <algorithm>
     10 #include <utility>
     11 #include <vector>
     12 
     13 #include "third_party/base/stl_util.h"
     14 #include "xfa/fde/tto/fde_textout.h"
     15 #include "xfa/fwl/cfwl_app.h"
     16 #include "xfa/fwl/cfwl_combobox.h"
     17 #include "xfa/fwl/cfwl_event.h"
     18 #include "xfa/fwl/cfwl_eventmouse.h"
     19 #include "xfa/fwl/cfwl_form.h"
     20 #include "xfa/fwl/cfwl_messagekey.h"
     21 #include "xfa/fwl/cfwl_messagekillfocus.h"
     22 #include "xfa/fwl/cfwl_messagemouse.h"
     23 #include "xfa/fwl/cfwl_messagemousewheel.h"
     24 #include "xfa/fwl/cfwl_messagesetfocus.h"
     25 #include "xfa/fwl/cfwl_notedriver.h"
     26 #include "xfa/fwl/cfwl_themebackground.h"
     27 #include "xfa/fwl/cfwl_themepart.h"
     28 #include "xfa/fwl/cfwl_themetext.h"
     29 #include "xfa/fwl/cfwl_widgetmgr.h"
     30 #include "xfa/fwl/ifwl_themeprovider.h"
     31 #include "xfa/fxfa/xfa_ffapp.h"
     32 
     33 #define FWL_STYLEEXT_MNU_Vert (1L << 0)
     34 #define FWL_WGT_CalcHeight 2048
     35 #define FWL_WGT_CalcWidth 2048
     36 #define FWL_WGT_CalcMultiLineDefWidth 120.0f
     37 
     38 CFWL_Widget::CFWL_Widget(const CFWL_App* app,
     39                          std::unique_ptr<CFWL_WidgetProperties> properties,
     40                          CFWL_Widget* pOuter)
     41     : m_pOwnerApp(app),
     42       m_pWidgetMgr(app->GetWidgetMgr()),
     43       m_pProperties(std::move(properties)),
     44       m_pOuter(pOuter),
     45       m_iLock(0),
     46       m_pLayoutItem(nullptr),
     47       m_nEventKey(0),
     48       m_pDelegate(nullptr) {
     49   ASSERT(m_pWidgetMgr);
     50 
     51   CFWL_Widget* pParent = m_pProperties->m_pParent;
     52   m_pWidgetMgr->InsertWidget(pParent, this);
     53   if (IsChild())
     54     return;
     55 
     56   CFWL_Widget* pOwner = m_pProperties->m_pOwner;
     57   if (pOwner)
     58     m_pWidgetMgr->SetOwner(pOwner, this);
     59 }
     60 
     61 CFWL_Widget::~CFWL_Widget() {
     62   NotifyDriver();
     63   m_pWidgetMgr->RemoveWidget(this);
     64 }
     65 
     66 bool CFWL_Widget::IsInstance(const CFX_WideStringC& wsClass) const {
     67   return false;
     68 }
     69 
     70 CFX_RectF CFWL_Widget::GetAutosizedWidgetRect() {
     71   return CFX_RectF();
     72 }
     73 
     74 CFX_RectF CFWL_Widget::GetWidgetRect() {
     75   return m_pProperties->m_rtWidget;
     76 }
     77 
     78 void CFWL_Widget::InflateWidgetRect(CFX_RectF& rect) {
     79   if (HasBorder()) {
     80     FX_FLOAT fBorder = GetBorderSize(true);
     81     rect.Inflate(fBorder, fBorder);
     82   }
     83 }
     84 
     85 void CFWL_Widget::SetWidgetRect(const CFX_RectF& rect) {
     86   m_pProperties->m_rtWidget = rect;
     87 }
     88 
     89 CFX_RectF CFWL_Widget::GetClientRect() {
     90   return GetEdgeRect();
     91 }
     92 
     93 void CFWL_Widget::SetParent(CFWL_Widget* pParent) {
     94   m_pProperties->m_pParent = pParent;
     95   m_pWidgetMgr->SetParent(pParent, this);
     96 }
     97 
     98 uint32_t CFWL_Widget::GetStyles() const {
     99   return m_pProperties->m_dwStyles;
    100 }
    101 
    102 void CFWL_Widget::ModifyStyles(uint32_t dwStylesAdded,
    103                                uint32_t dwStylesRemoved) {
    104   m_pProperties->m_dwStyles =
    105       (m_pProperties->m_dwStyles & ~dwStylesRemoved) | dwStylesAdded;
    106 }
    107 
    108 uint32_t CFWL_Widget::GetStylesEx() const {
    109   return m_pProperties->m_dwStyleExes;
    110 }
    111 uint32_t CFWL_Widget::GetStates() const {
    112   return m_pProperties->m_dwStates;
    113 }
    114 
    115 void CFWL_Widget::ModifyStylesEx(uint32_t dwStylesExAdded,
    116                                  uint32_t dwStylesExRemoved) {
    117   m_pProperties->m_dwStyleExes =
    118       (m_pProperties->m_dwStyleExes & ~dwStylesExRemoved) | dwStylesExAdded;
    119 }
    120 
    121 static void NotifyHideChildWidget(CFWL_WidgetMgr* widgetMgr,
    122                                   CFWL_Widget* widget,
    123                                   CFWL_NoteDriver* noteDriver) {
    124   CFWL_Widget* child = widgetMgr->GetFirstChildWidget(widget);
    125   while (child) {
    126     noteDriver->NotifyTargetHide(child);
    127     NotifyHideChildWidget(widgetMgr, child, noteDriver);
    128     child = widgetMgr->GetNextSiblingWidget(child);
    129   }
    130 }
    131 
    132 void CFWL_Widget::SetStates(uint32_t dwStates) {
    133   m_pProperties->m_dwStates |= dwStates;
    134   if (!(dwStates & FWL_WGTSTATE_Invisible))
    135     return;
    136 
    137   CFWL_NoteDriver* noteDriver =
    138       static_cast<CFWL_NoteDriver*>(GetOwnerApp()->GetNoteDriver());
    139   CFWL_WidgetMgr* widgetMgr = GetOwnerApp()->GetWidgetMgr();
    140   noteDriver->NotifyTargetHide(this);
    141   CFWL_Widget* child = widgetMgr->GetFirstChildWidget(this);
    142   while (child) {
    143     noteDriver->NotifyTargetHide(child);
    144     NotifyHideChildWidget(widgetMgr, child, noteDriver);
    145     child = widgetMgr->GetNextSiblingWidget(child);
    146   }
    147   return;
    148 }
    149 
    150 void CFWL_Widget::RemoveStates(uint32_t dwStates) {
    151   m_pProperties->m_dwStates &= ~dwStates;
    152 }
    153 
    154 FWL_WidgetHit CFWL_Widget::HitTest(const CFX_PointF& point) {
    155   if (GetClientRect().Contains(point))
    156     return FWL_WidgetHit::Client;
    157   if (HasBorder() && GetRelativeRect().Contains(point))
    158     return FWL_WidgetHit::Border;
    159   return FWL_WidgetHit::Unknown;
    160 }
    161 
    162 CFX_PointF CFWL_Widget::TransformTo(CFWL_Widget* pWidget,
    163                                     const CFX_PointF& point) {
    164   if (m_pWidgetMgr->IsFormDisabled()) {
    165     CFX_SizeF szOffset;
    166     if (IsParent(pWidget)) {
    167       szOffset = GetOffsetFromParent(pWidget);
    168     } else {
    169       szOffset = pWidget->GetOffsetFromParent(this);
    170       szOffset.width = -szOffset.width;
    171       szOffset.height = -szOffset.height;
    172     }
    173     return point + CFX_PointF(szOffset.width, szOffset.height);
    174   }
    175 
    176   CFX_PointF ret = point;
    177   CFWL_Widget* parent = GetParent();
    178   if (parent)
    179     ret = GetMatrix().Transform(ret + GetWidgetRect().TopLeft());
    180 
    181   CFWL_Widget* form1 = m_pWidgetMgr->GetSystemFormWidget(this);
    182   if (!form1)
    183     return ret;
    184 
    185   if (!pWidget)
    186     return ret + form1->GetWidgetRect().TopLeft();
    187 
    188   CFWL_Widget* form2 = m_pWidgetMgr->GetSystemFormWidget(pWidget);
    189   if (!form2)
    190     return ret;
    191   if (form1 != form2) {
    192     ret += form1->GetWidgetRect().TopLeft();
    193     ret -= form2->GetWidgetRect().TopLeft();
    194   }
    195 
    196   parent = pWidget->GetParent();
    197   if (!parent)
    198     return ret;
    199 
    200   CFX_Matrix m;
    201   m.SetReverse(pWidget->GetMatrix());
    202   return m.Transform(ret) - pWidget->GetWidgetRect().TopLeft();
    203 }
    204 
    205 CFX_Matrix CFWL_Widget::GetMatrix() {
    206   if (!m_pProperties)
    207     return CFX_Matrix();
    208 
    209   CFWL_Widget* parent = GetParent();
    210   std::vector<CFWL_Widget*> parents;
    211   while (parent) {
    212     parents.push_back(parent);
    213     parent = parent->GetParent();
    214   }
    215 
    216   CFX_Matrix matrix;
    217   CFX_Matrix ctmOnParent;
    218   CFX_RectF rect;
    219   int32_t count = pdfium::CollectionSize<int32_t>(parents);
    220   for (int32_t i = count - 2; i >= 0; i--) {
    221     parent = parents[i];
    222     if (parent->m_pProperties)
    223       ctmOnParent.SetIdentity();
    224     rect = parent->GetWidgetRect();
    225     matrix.Concat(ctmOnParent, true);
    226     matrix.Translate(rect.left, rect.top, true);
    227   }
    228   CFX_Matrix m;
    229   m.SetIdentity();
    230   matrix.Concat(m, true);
    231   parents.clear();
    232   return matrix;
    233 }
    234 
    235 IFWL_ThemeProvider* CFWL_Widget::GetThemeProvider() const {
    236   return m_pProperties->m_pThemeProvider;
    237 }
    238 
    239 void CFWL_Widget::SetThemeProvider(IFWL_ThemeProvider* pThemeProvider) {
    240   m_pProperties->m_pThemeProvider = pThemeProvider;
    241 }
    242 
    243 bool CFWL_Widget::IsEnabled() const {
    244   return (m_pProperties->m_dwStates & FWL_WGTSTATE_Disabled) == 0;
    245 }
    246 
    247 bool CFWL_Widget::HasBorder() const {
    248   return !!(m_pProperties->m_dwStyles & FWL_WGTSTYLE_Border);
    249 }
    250 
    251 bool CFWL_Widget::IsVisible() const {
    252   return (m_pProperties->m_dwStates & FWL_WGTSTATE_Invisible) == 0;
    253 }
    254 
    255 bool CFWL_Widget::IsOverLapper() const {
    256   return (m_pProperties->m_dwStyles & FWL_WGTSTYLE_WindowTypeMask) ==
    257          FWL_WGTSTYLE_OverLapper;
    258 }
    259 
    260 bool CFWL_Widget::IsPopup() const {
    261   return !!(m_pProperties->m_dwStyles & FWL_WGTSTYLE_Popup);
    262 }
    263 
    264 bool CFWL_Widget::IsChild() const {
    265   return !!(m_pProperties->m_dwStyles & FWL_WGTSTYLE_Child);
    266 }
    267 
    268 CFX_RectF CFWL_Widget::GetEdgeRect() {
    269   CFX_RectF rtEdge(0, 0, m_pProperties->m_rtWidget.width,
    270                    m_pProperties->m_rtWidget.height);
    271   if (HasBorder()) {
    272     FX_FLOAT fCX = GetBorderSize(true);
    273     FX_FLOAT fCY = GetBorderSize(false);
    274     rtEdge.Deflate(fCX, fCY);
    275   }
    276   return rtEdge;
    277 }
    278 
    279 FX_FLOAT CFWL_Widget::GetBorderSize(bool bCX) {
    280   IFWL_ThemeProvider* theme = GetAvailableTheme();
    281   if (!theme)
    282     return 0.0f;
    283   return bCX ? theme->GetCXBorderSize() : theme->GetCYBorderSize();
    284 }
    285 
    286 CFX_RectF CFWL_Widget::GetRelativeRect() {
    287   return CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
    288                    m_pProperties->m_rtWidget.height);
    289 }
    290 
    291 IFWL_ThemeProvider* CFWL_Widget::GetAvailableTheme() {
    292   if (m_pProperties->m_pThemeProvider)
    293     return m_pProperties->m_pThemeProvider;
    294 
    295   CFWL_Widget* pUp = this;
    296   do {
    297     pUp = (pUp->GetStyles() & FWL_WGTSTYLE_Popup)
    298               ? m_pWidgetMgr->GetOwnerWidget(pUp)
    299               : m_pWidgetMgr->GetParentWidget(pUp);
    300     if (pUp) {
    301       IFWL_ThemeProvider* pRet = pUp->GetThemeProvider();
    302       if (pRet)
    303         return pRet;
    304     }
    305   } while (pUp);
    306   return nullptr;
    307 }
    308 
    309 CFWL_Widget* CFWL_Widget::GetRootOuter() {
    310   CFWL_Widget* pRet = m_pOuter;
    311   if (!pRet)
    312     return nullptr;
    313 
    314   while (CFWL_Widget* pOuter = pRet->GetOuter())
    315     pRet = pOuter;
    316   return pRet;
    317 }
    318 
    319 CFX_SizeF CFWL_Widget::CalcTextSize(const CFX_WideString& wsText,
    320                                     IFWL_ThemeProvider* pTheme,
    321                                     bool bMultiLine) {
    322   if (!pTheme)
    323     return CFX_SizeF();
    324 
    325   CFWL_ThemeText calPart;
    326   calPart.m_pWidget = this;
    327   calPart.m_wsText = wsText;
    328   calPart.m_dwTTOStyles =
    329       bMultiLine ? FDE_TTOSTYLE_LineWrap : FDE_TTOSTYLE_SingleLine;
    330   calPart.m_iTTOAlign = FDE_TTOALIGNMENT_TopLeft;
    331   FX_FLOAT fWidth =
    332       bMultiLine ? FWL_WGT_CalcMultiLineDefWidth : FWL_WGT_CalcWidth;
    333   CFX_RectF rect(0, 0, fWidth, FWL_WGT_CalcHeight);
    334   pTheme->CalcTextRect(&calPart, rect);
    335   return CFX_SizeF(rect.width, rect.height);
    336 }
    337 
    338 void CFWL_Widget::CalcTextRect(const CFX_WideString& wsText,
    339                                IFWL_ThemeProvider* pTheme,
    340                                uint32_t dwTTOStyles,
    341                                int32_t iTTOAlign,
    342                                CFX_RectF& rect) {
    343   CFWL_ThemeText calPart;
    344   calPart.m_pWidget = this;
    345   calPart.m_wsText = wsText;
    346   calPart.m_dwTTOStyles = dwTTOStyles;
    347   calPart.m_iTTOAlign = iTTOAlign;
    348   pTheme->CalcTextRect(&calPart, rect);
    349 }
    350 
    351 void CFWL_Widget::SetFocus(bool bFocus) {
    352   if (m_pWidgetMgr->IsFormDisabled())
    353     return;
    354 
    355   const CFWL_App* pApp = GetOwnerApp();
    356   if (!pApp)
    357     return;
    358 
    359   CFWL_NoteDriver* pDriver =
    360       static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
    361   if (!pDriver)
    362     return;
    363 
    364   CFWL_Widget* curFocus = pDriver->GetFocus();
    365   if (bFocus && curFocus != this)
    366     pDriver->SetFocus(this);
    367   else if (!bFocus && curFocus == this)
    368     pDriver->SetFocus(nullptr);
    369 }
    370 
    371 void CFWL_Widget::SetGrab(bool bSet) {
    372   const CFWL_App* pApp = GetOwnerApp();
    373   if (!pApp)
    374     return;
    375 
    376   CFWL_NoteDriver* pDriver =
    377       static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
    378   pDriver->SetGrab(this, bSet);
    379 }
    380 
    381 void CFWL_Widget::GetPopupPos(FX_FLOAT fMinHeight,
    382                               FX_FLOAT fMaxHeight,
    383                               const CFX_RectF& rtAnchor,
    384                               CFX_RectF& rtPopup) {
    385   if (GetClassID() == FWL_Type::ComboBox) {
    386     if (m_pWidgetMgr->IsFormDisabled()) {
    387       m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
    388                                        rtPopup);
    389       return;
    390     }
    391     GetPopupPosComboBox(fMinHeight, fMaxHeight, rtAnchor, rtPopup);
    392     return;
    393   }
    394   if (GetClassID() == FWL_Type::DateTimePicker &&
    395       m_pWidgetMgr->IsFormDisabled()) {
    396     m_pWidgetMgr->GetAdapterPopupPos(this, fMinHeight, fMaxHeight, rtAnchor,
    397                                      rtPopup);
    398     return;
    399   }
    400   GetPopupPosGeneral(fMinHeight, fMaxHeight, rtAnchor, rtPopup);
    401 }
    402 
    403 bool CFWL_Widget::GetPopupPosMenu(FX_FLOAT fMinHeight,
    404                                   FX_FLOAT fMaxHeight,
    405                                   const CFX_RectF& rtAnchor,
    406                                   CFX_RectF& rtPopup) {
    407   if (GetStylesEx() & FWL_STYLEEXT_MNU_Vert) {
    408     bool bLeft = m_pProperties->m_rtWidget.left < 0;
    409     FX_FLOAT fRight = rtAnchor.right() + rtPopup.width;
    410     CFX_PointF point = TransformTo(nullptr, CFX_PointF());
    411     if (fRight + point.x > 0.0f || bLeft) {
    412       rtPopup = CFX_RectF(rtAnchor.left - rtPopup.width, rtAnchor.top,
    413                           rtPopup.width, rtPopup.height);
    414     } else {
    415       rtPopup = CFX_RectF(rtAnchor.right(), rtAnchor.top, rtPopup.width,
    416                           rtPopup.height);
    417     }
    418     rtPopup.Offset(point.x, point.y);
    419     return true;
    420   }
    421 
    422   FX_FLOAT fBottom = rtAnchor.bottom() + rtPopup.height;
    423   CFX_PointF point = TransformTo(nullptr, point);
    424   if (fBottom + point.y > 0.0f) {
    425     rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.top - rtPopup.height,
    426                         rtPopup.width, rtPopup.height);
    427   } else {
    428     rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
    429                         rtPopup.height);
    430   }
    431   rtPopup.Offset(point.x, point.y);
    432   return true;
    433 }
    434 
    435 bool CFWL_Widget::GetPopupPosComboBox(FX_FLOAT fMinHeight,
    436                                       FX_FLOAT fMaxHeight,
    437                                       const CFX_RectF& rtAnchor,
    438                                       CFX_RectF& rtPopup) {
    439   FX_FLOAT fPopHeight = rtPopup.height;
    440   if (rtPopup.height > fMaxHeight)
    441     fPopHeight = fMaxHeight;
    442   else if (rtPopup.height < fMinHeight)
    443     fPopHeight = fMinHeight;
    444 
    445   FX_FLOAT fWidth = std::max(rtAnchor.width, rtPopup.width);
    446   FX_FLOAT fBottom = rtAnchor.bottom() + fPopHeight;
    447   CFX_PointF point = TransformTo(nullptr, CFX_PointF());
    448   if (fBottom + point.y > 0.0f) {
    449     rtPopup =
    450         CFX_RectF(rtAnchor.left, rtAnchor.top - fPopHeight, fWidth, fPopHeight);
    451   } else {
    452     rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), fWidth, fPopHeight);
    453   }
    454 
    455   rtPopup.Offset(point.x, point.y);
    456   return true;
    457 }
    458 
    459 bool CFWL_Widget::GetPopupPosGeneral(FX_FLOAT fMinHeight,
    460                                      FX_FLOAT fMaxHeight,
    461                                      const CFX_RectF& rtAnchor,
    462                                      CFX_RectF& rtPopup) {
    463   CFX_PointF point = TransformTo(nullptr, CFX_PointF());
    464   if (rtAnchor.bottom() + point.y > 0.0f) {
    465     rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.top - rtPopup.height,
    466                         rtPopup.width, rtPopup.height);
    467   } else {
    468     rtPopup = CFX_RectF(rtAnchor.left, rtAnchor.bottom(), rtPopup.width,
    469                         rtPopup.height);
    470   }
    471   rtPopup.Offset(point.x, point.y);
    472   return true;
    473 }
    474 
    475 void CFWL_Widget::RegisterEventTarget(CFWL_Widget* pEventSource) {
    476   const CFWL_App* pApp = GetOwnerApp();
    477   if (!pApp)
    478     return;
    479 
    480   CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
    481   if (!pNoteDriver)
    482     return;
    483 
    484   pNoteDriver->RegisterEventTarget(this, pEventSource);
    485 }
    486 
    487 void CFWL_Widget::UnregisterEventTarget() {
    488   const CFWL_App* pApp = GetOwnerApp();
    489   if (!pApp)
    490     return;
    491 
    492   CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
    493   if (!pNoteDriver)
    494     return;
    495 
    496   pNoteDriver->UnregisterEventTarget(this);
    497 }
    498 
    499 void CFWL_Widget::DispatchEvent(CFWL_Event* pEvent) {
    500   if (m_pOuter) {
    501     m_pOuter->GetDelegate()->OnProcessEvent(pEvent);
    502     return;
    503   }
    504   const CFWL_App* pApp = GetOwnerApp();
    505   if (!pApp)
    506     return;
    507 
    508   CFWL_NoteDriver* pNoteDriver = pApp->GetNoteDriver();
    509   if (!pNoteDriver)
    510     return;
    511   pNoteDriver->SendEvent(pEvent);
    512 }
    513 
    514 void CFWL_Widget::Repaint() {
    515   RepaintRect(CFX_RectF(0, 0, m_pProperties->m_rtWidget.width,
    516                         m_pProperties->m_rtWidget.height));
    517 }
    518 
    519 void CFWL_Widget::RepaintRect(const CFX_RectF& pRect) {
    520   m_pWidgetMgr->RepaintWidget(this, pRect);
    521 }
    522 
    523 void CFWL_Widget::DrawBackground(CFX_Graphics* pGraphics,
    524                                  CFWL_Part iPartBk,
    525                                  IFWL_ThemeProvider* pTheme,
    526                                  const CFX_Matrix* pMatrix) {
    527   CFWL_ThemeBackground param;
    528   param.m_pWidget = this;
    529   param.m_iPart = iPartBk;
    530   param.m_pGraphics = pGraphics;
    531   if (pMatrix)
    532     param.m_matrix.Concat(*pMatrix, true);
    533   param.m_rtPart = GetRelativeRect();
    534   pTheme->DrawBackground(&param);
    535 }
    536 
    537 void CFWL_Widget::DrawBorder(CFX_Graphics* pGraphics,
    538                              CFWL_Part iPartBorder,
    539                              IFWL_ThemeProvider* pTheme,
    540                              const CFX_Matrix* pMatrix) {
    541   CFWL_ThemeBackground param;
    542   param.m_pWidget = this;
    543   param.m_iPart = iPartBorder;
    544   param.m_pGraphics = pGraphics;
    545   if (pMatrix)
    546     param.m_matrix.Concat(*pMatrix, true);
    547   param.m_rtPart = GetRelativeRect();
    548   pTheme->DrawBackground(&param);
    549 }
    550 
    551 void CFWL_Widget::NotifyDriver() {
    552   const CFWL_App* pApp = GetOwnerApp();
    553   if (!pApp)
    554     return;
    555 
    556   CFWL_NoteDriver* pDriver =
    557       static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
    558   if (!pDriver)
    559     return;
    560 
    561   pDriver->NotifyTargetDestroy(this);
    562 }
    563 
    564 CFX_SizeF CFWL_Widget::GetOffsetFromParent(CFWL_Widget* pParent) {
    565   if (pParent == this)
    566     return CFX_SizeF();
    567 
    568   CFWL_WidgetMgr* pWidgetMgr = GetOwnerApp()->GetWidgetMgr();
    569   if (!pWidgetMgr)
    570     return CFX_SizeF();
    571 
    572   CFX_SizeF szRet(m_pProperties->m_rtWidget.left,
    573                   m_pProperties->m_rtWidget.top);
    574 
    575   CFWL_Widget* pDstWidget = GetParent();
    576   while (pDstWidget && pDstWidget != pParent) {
    577     CFX_RectF rtDst = pDstWidget->GetWidgetRect();
    578     szRet += CFX_SizeF(rtDst.left, rtDst.top);
    579     pDstWidget = pWidgetMgr->GetParentWidget(pDstWidget);
    580   }
    581   return szRet;
    582 }
    583 
    584 bool CFWL_Widget::IsParent(CFWL_Widget* pParent) {
    585   CFWL_Widget* pUpWidget = GetParent();
    586   while (pUpWidget) {
    587     if (pUpWidget == pParent)
    588       return true;
    589     pUpWidget = pUpWidget->GetParent();
    590   }
    591   return false;
    592 }
    593 
    594 void CFWL_Widget::OnProcessMessage(CFWL_Message* pMessage) {
    595   if (!pMessage->m_pDstTarget)
    596     return;
    597 
    598   CFWL_Widget* pWidget = pMessage->m_pDstTarget;
    599   switch (pMessage->GetType()) {
    600     case CFWL_Message::Type::Mouse: {
    601       CFWL_MessageMouse* pMsgMouse = static_cast<CFWL_MessageMouse*>(pMessage);
    602 
    603       CFWL_EventMouse evt(pWidget, pWidget);
    604       evt.m_dwCmd = pMsgMouse->m_dwCmd;
    605       pWidget->DispatchEvent(&evt);
    606       break;
    607     }
    608     default:
    609       break;
    610   }
    611 }
    612 
    613 void CFWL_Widget::OnProcessEvent(CFWL_Event* pEvent) {}
    614 
    615 void CFWL_Widget::OnDrawWidget(CFX_Graphics* pGraphics,
    616                                const CFX_Matrix* pMatrix) {}
    617