summaryrefslogtreecommitdiff
path: root/xfa/fwl/core/cfwl_widgetmgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fwl/core/cfwl_widgetmgr.cpp')
-rw-r--r--xfa/fwl/core/cfwl_widgetmgr.cpp862
1 files changed, 862 insertions, 0 deletions
diff --git a/xfa/fwl/core/cfwl_widgetmgr.cpp b/xfa/fwl/core/cfwl_widgetmgr.cpp
new file mode 100644
index 0000000000..760be7107b
--- /dev/null
+++ b/xfa/fwl/core/cfwl_widgetmgr.cpp
@@ -0,0 +1,862 @@
+// Copyright 2014 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "xfa/fwl/core/cfwl_widgetmgr.h"
+
+#include "xfa/fwl/core/cfwl_message.h"
+#include "xfa/fwl/core/fwl_appimp.h"
+#include "xfa/fwl/core/fwl_noteimp.h"
+#include "xfa/fwl/core/fwl_widgetimp.h"
+#include "xfa/fwl/core/ifwl_app.h"
+#include "xfa/fwl/core/ifwl_form.h"
+#include "xfa/fxfa/app/xfa_fwladapter.h"
+#include "xfa/fxfa/include/xfa_ffapp.h"
+
+namespace {
+
+const int kNeedRepaintHitPoints = 12;
+const int kNeedRepaintHitPiece = 3;
+
+struct FWL_NEEDREPAINTHITDATA {
+ CFX_PointF hitPoint;
+ bool bNotNeedRepaint;
+ bool bNotContainByDirty;
+};
+
+} // namespace
+
+FX_BOOL FWL_UseOffscreen(IFWL_Widget* pWidget) {
+#if (_FX_OS_ == _FX_MACOSX_)
+ return FALSE;
+#else
+ return pWidget->GetStyles() & FWL_WGTSTYLE_Offscreen;
+#endif
+}
+
+// static
+CFWL_WidgetMgr* CFWL_WidgetMgr::GetInstance() {
+ IFWL_App* pApp = FWL_GetApp();
+ return pApp ? pApp->GetWidgetMgr() : nullptr;
+}
+
+CFWL_WidgetMgr::CFWL_WidgetMgr(CXFA_FFApp* pAdapterNative)
+ : m_dwCapability(0),
+ m_pDelegate(new CFWL_WidgetMgrDelegate(this)),
+ m_pAdapter(pAdapterNative->GetWidgetMgr(m_pDelegate.get())) {
+ ASSERT(m_pAdapter);
+ m_mapWidgetItem[nullptr].reset(new CFWL_WidgetMgrItem);
+#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
+ m_rtScreen.Reset();
+#endif
+}
+
+CFWL_WidgetMgr::~CFWL_WidgetMgr() {}
+
+IFWL_Widget* CFWL_WidgetMgr::GetParentWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ pItem = pItem ? pItem->pPrevious : nullptr; // Not self.
+ while (pItem && pItem->pPrevious)
+ pItem = pItem->pPrevious;
+
+ return pItem ? pItem->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetLastSiblingWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ pItem = pItem ? pItem->pNext : nullptr; // Not self.
+ while (pItem && pItem->pNext)
+ pItem = pItem->pNext;
+
+ return pItem ? pItem->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ pItem = pItem ? pItem->pChild : nullptr;
+ while (pItem && pItem->pNext)
+ pItem = pItem->pNext;
+
+ return pItem ? pItem->pWidget : nullptr;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(IFWL_Widget* pWidget) const {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ while (pItem) {
+ if (IsAbleNative(pItem->pWidget))
+ return pItem->pWidget;
+ pItem = pItem->pParent;
+ }
+ return nullptr;
+}
+
+FX_BOOL CFWL_WidgetMgr::SetWidgetIndex(IFWL_Widget* pWidget, int32_t nIndex) {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ if (!pItem)
+ return FALSE;
+ if (!pItem->pParent)
+ return FALSE;
+ CFWL_WidgetMgrItem* pChild = pItem->pParent->pChild;
+ int32_t i = 0;
+ while (pChild) {
+ if (pChild == pItem) {
+ if (i == nIndex) {
+ return TRUE;
+ }
+ if (pChild->pPrevious) {
+ pChild->pPrevious->pNext = pChild->pNext;
+ }
+ if (pChild->pNext) {
+ pChild->pNext->pPrevious = pChild->pPrevious;
+ }
+ if (pItem->pParent->pChild == pItem) {
+ pItem->pParent->pChild = pItem->pNext;
+ }
+ pItem->pNext = NULL;
+ pItem->pPrevious = NULL;
+ break;
+ }
+ if (!pChild->pNext) {
+ break;
+ }
+ pChild = pChild->pNext;
+ ++i;
+ }
+ pChild = pItem->pParent->pChild;
+ if (pChild) {
+ if (nIndex < 0) {
+ while (pChild->pNext) {
+ pChild = pChild->pNext;
+ }
+ pChild->pNext = pItem;
+ pItem->pPrevious = pChild;
+ pItem->pNext = NULL;
+ return TRUE;
+ }
+ i = 0;
+ while (i < nIndex && pChild->pNext) {
+ pChild = pChild->pNext;
+ ++i;
+ }
+ if (!pChild->pNext) {
+ pChild->pNext = pItem;
+ pItem->pPrevious = pChild;
+ pItem->pNext = NULL;
+ return TRUE;
+ }
+ if (pChild->pPrevious) {
+ pItem->pPrevious = pChild->pPrevious;
+ pChild->pPrevious->pNext = pItem;
+ }
+ pChild->pPrevious = pItem;
+ pItem->pNext = pChild;
+ if (pItem->pParent->pChild == pChild) {
+ pItem->pParent->pChild = pItem;
+ }
+ } else {
+ pItem->pParent->pChild = pItem;
+ pItem->pPrevious = NULL;
+ pItem->pNext = NULL;
+ }
+ return TRUE;
+}
+FWL_Error CFWL_WidgetMgr::RepaintWidget(IFWL_Widget* pWidget,
+ const CFX_RectF* pRect) {
+ if (!m_pAdapter)
+ return FWL_Error::Indefinite;
+ IFWL_Widget* pNative = pWidget;
+ CFX_RectF rect(*pRect);
+ if (IsFormDisabled()) {
+ IFWL_Widget* pOuter = pWidget->GetOuter();
+ while (pOuter) {
+ CFX_RectF rtTemp;
+ pNative->GetWidgetRect(rtTemp);
+ rect.left += rtTemp.left;
+ rect.top += rtTemp.top;
+ pNative = pOuter;
+ pOuter = pOuter->GetOuter();
+ }
+ } else if (!IsAbleNative(pWidget)) {
+ pNative = GetSystemFormWidget(pWidget);
+ if (!pNative)
+ return FWL_Error::Indefinite;
+ pWidget->TransformTo(pNative, rect.left, rect.top);
+ }
+ AddRedrawCounts(pNative);
+ return m_pAdapter->RepaintWidget(pNative, &rect);
+}
+void CFWL_WidgetMgr::AddWidget(IFWL_Widget* pWidget) {
+ CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(NULL);
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ if (!pItem) {
+ pItem = new CFWL_WidgetMgrItem(pWidget);
+ m_mapWidgetItem[pWidget].reset(pItem);
+ }
+ if (pItem->pParent && pItem->pParent != pParentItem) {
+ if (pItem->pPrevious) {
+ pItem->pPrevious->pNext = pItem->pNext;
+ }
+ if (pItem->pNext) {
+ pItem->pNext->pPrevious = pItem->pPrevious;
+ }
+ if (pItem->pParent->pChild == pItem) {
+ pItem->pParent->pChild = pItem->pNext;
+ }
+ }
+ pItem->pParent = pParentItem;
+ SetWidgetIndex(pWidget, -1);
+}
+void CFWL_WidgetMgr::InsertWidget(IFWL_Widget* pParent,
+ IFWL_Widget* pChild,
+ int32_t nIndex) {
+ CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent);
+ if (!pParentItem) {
+ pParentItem = new CFWL_WidgetMgrItem(pParent);
+ m_mapWidgetItem[pParent].reset(pParentItem);
+ pParentItem->pParent = GetWidgetMgrItem(nullptr);
+ SetWidgetIndex(pParent, -1);
+ }
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pChild);
+ if (!pItem) {
+ pItem = new CFWL_WidgetMgrItem(pChild);
+ m_mapWidgetItem[pChild].reset(pItem);
+ }
+ if (pItem->pParent && pItem->pParent != pParentItem) {
+ if (pItem->pPrevious) {
+ pItem->pPrevious->pNext = pItem->pNext;
+ }
+ if (pItem->pNext) {
+ pItem->pNext->pPrevious = pItem->pPrevious;
+ }
+ if (pItem->pParent->pChild == pItem) {
+ pItem->pParent->pChild = pItem->pNext;
+ }
+ }
+ pItem->pParent = pParentItem;
+ SetWidgetIndex(pChild, nIndex);
+}
+void CFWL_WidgetMgr::RemoveWidget(IFWL_Widget* pWidget) {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ if (!pItem) {
+ return;
+ }
+ if (pItem->pPrevious) {
+ pItem->pPrevious->pNext = pItem->pNext;
+ }
+ if (pItem->pNext) {
+ pItem->pNext->pPrevious = pItem->pPrevious;
+ }
+ if (pItem->pParent && pItem->pParent->pChild == pItem) {
+ pItem->pParent->pChild = pItem->pNext;
+ }
+ CFWL_WidgetMgrItem* pChild = pItem->pChild;
+ while (pChild) {
+ CFWL_WidgetMgrItem* pNext = pChild->pNext;
+ RemoveWidget(pChild->pWidget);
+ pChild = pNext;
+ }
+ m_mapWidgetItem.erase(pWidget);
+}
+void CFWL_WidgetMgr::SetOwner(IFWL_Widget* pOwner, IFWL_Widget* pOwned) {
+ CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pOwner);
+ if (!pParentItem) {
+ pParentItem = new CFWL_WidgetMgrItem(pOwner);
+ m_mapWidgetItem[pOwner].reset(pParentItem);
+ pParentItem->pParent = GetWidgetMgrItem(nullptr);
+ SetWidgetIndex(pOwner, -1);
+ }
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pOwned);
+ if (!pItem) {
+ pItem = new CFWL_WidgetMgrItem(pOwned);
+ m_mapWidgetItem[pOwned].reset(pItem);
+ }
+ pItem->pOwner = pParentItem;
+}
+void CFWL_WidgetMgr::SetParent(IFWL_Widget* pParent, IFWL_Widget* pChild) {
+ CFWL_WidgetMgrItem* pParentItem = GetWidgetMgrItem(pParent);
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pChild);
+ if (!pItem)
+ return;
+ if (pItem->pParent && pItem->pParent != pParentItem) {
+ if (pItem->pPrevious) {
+ pItem->pPrevious->pNext = pItem->pNext;
+ }
+ if (pItem->pNext) {
+ pItem->pNext->pPrevious = pItem->pPrevious;
+ }
+ if (pItem->pParent->pChild == pItem) {
+ pItem->pParent->pChild = pItem->pNext;
+ }
+ pItem->pNext = NULL;
+ pItem->pPrevious = NULL;
+ }
+ pItem->pParent = pParentItem;
+ SetWidgetIndex(pChild, -1);
+}
+
+FX_BOOL CFWL_WidgetMgr::IsChild(IFWL_Widget* pChild, IFWL_Widget* pParent) {
+ IFWL_Widget* pTemp = pChild;
+ do {
+ if (pTemp == pParent)
+ return TRUE;
+ pTemp = GetParentWidget(pTemp);
+ } while (pTemp);
+ return FALSE;
+}
+
+FWL_Error CFWL_WidgetMgr::SetWidgetRect_Native(IFWL_Widget* pWidget,
+ const CFX_RectF& rect) {
+ if (FWL_UseOffscreen(pWidget)) {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ pItem->iRedrawCounter++;
+ if (pItem->pOffscreen) {
+ CFX_RenderDevice* pDevice = pItem->pOffscreen->GetRenderDevice();
+ if (pDevice && pDevice->GetBitmap()) {
+ CFX_DIBitmap* pBitmap = pDevice->GetBitmap();
+ if (pBitmap->GetWidth() - rect.width > 1 ||
+ pBitmap->GetHeight() - rect.height > 1) {
+ pItem->pOffscreen.reset();
+ }
+ }
+ }
+#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
+ pItem->bOutsideChanged = !m_rtScreen.Contains(rect);
+#endif
+ }
+ return FWL_Error::Succeeded;
+}
+
+IFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(IFWL_Widget* parent,
+ FX_FLOAT x,
+ FX_FLOAT y) {
+ if (!parent)
+ return NULL;
+ FX_FLOAT x1;
+ FX_FLOAT y1;
+ IFWL_Widget* child = GetLastChildWidget(parent);
+ while (child) {
+ if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {
+ x1 = x;
+ y1 = y;
+ CFX_Matrix matrixOnParent;
+ child->GetMatrix(matrixOnParent);
+ CFX_Matrix m;
+ m.SetIdentity();
+ m.SetReverse(matrixOnParent);
+ m.TransformPoint(x1, y1);
+ CFX_RectF bounds;
+ child->GetWidgetRect(bounds);
+ if (bounds.Contains(x1, y1)) {
+ x1 -= bounds.left;
+ y1 -= bounds.top;
+ return GetWidgetAtPoint(child, x1, y1);
+ }
+ }
+ child = GetPriorSiblingWidget(child);
+ }
+ return parent;
+}
+
+void CFWL_WidgetMgr::NotifySizeChanged(IFWL_Widget* pForm,
+ FX_FLOAT fx,
+ FX_FLOAT fy) {
+ if (FWL_UseOffscreen(pForm))
+ GetWidgetMgrItem(pForm)->pOffscreen.reset();
+}
+
+IFWL_Widget* CFWL_WidgetMgr::nextTab(IFWL_Widget* parent,
+ IFWL_Widget* focus,
+ FX_BOOL& bFind) {
+ CFWL_WidgetMgr* pMgr = CFWL_WidgetMgr::GetInstance();
+ IFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
+ while (child) {
+ if (focus == child)
+ bFind = TRUE;
+
+ if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) &&
+ (!focus || (focus != child && bFind))) {
+ return child;
+ }
+ IFWL_Widget* bRet = nextTab(child, focus, bFind);
+ if (bRet)
+ return bRet;
+
+ child = pMgr->GetNextSiblingWidget(child);
+ }
+ return nullptr;
+}
+
+int32_t CFWL_WidgetMgr::CountRadioButtonGroup(IFWL_Widget* pFirst) {
+ int32_t iRet = 0;
+ IFWL_Widget* pChild = pFirst;
+ while (pChild) {
+ pChild = GetNextSiblingWidget(pChild);
+ ++iRet;
+ }
+ return iRet;
+}
+IFWL_Widget* CFWL_WidgetMgr::GetSiblingRadioButton(IFWL_Widget* pWidget,
+ FX_BOOL bNext) {
+ return nullptr;
+}
+IFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(
+ IFWL_Widget* pRadioButton) {
+ IFWL_Widget* pNext = pRadioButton;
+ while (pNext) {
+ if (pNext->GetStyles() & FWL_WGTSTYLE_Group)
+ return pNext;
+ pNext = GetSiblingRadioButton(pNext, FALSE);
+ }
+ pNext = GetLastSiblingWidget(pRadioButton);
+ while ((pNext = GetSiblingRadioButton(pNext, FALSE)) != nullptr &&
+ pNext != pRadioButton) {
+ if (pNext->GetStyles() & FWL_WGTSTYLE_Group)
+ return pNext;
+ }
+ pNext = GetFirstSiblingWidget(pRadioButton);
+ return GetSiblingRadioButton(pNext, TRUE);
+}
+void CFWL_WidgetMgr::GetSameGroupRadioButton(
+ IFWL_Widget* pRadioButton,
+ CFX_ArrayTemplate<IFWL_Widget*>& group) {
+ IFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton);
+ if (!pFirst) {
+ pFirst = pRadioButton;
+ }
+ int32_t iGroup = CountRadioButtonGroup(pFirst);
+ if (iGroup < 2) {
+ IFWL_Widget* pNext = pFirst;
+ while ((pNext = GetSiblingRadioButton(pNext, TRUE)) != NULL) {
+ group.Add(pNext);
+ }
+ return;
+ }
+ IFWL_Widget* pNext = GetRadioButtonGroupHeader(pRadioButton);
+ do {
+ group.Add(pNext);
+ pNext = GetSiblingRadioButton(pNext, TRUE);
+ if (!pNext)
+ pNext = GetSiblingRadioButton(pFirst, TRUE);
+ } while (pNext && ((pNext->GetStyles() & FWL_WGTSTYLE_Group) == 0));
+}
+IFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(IFWL_Widget* pParent) {
+ if ((pParent->GetClassID() == FWL_Type::PushButton) &&
+ (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
+ return pParent;
+ }
+ IFWL_Widget* child =
+ CFWL_WidgetMgr::GetInstance()->GetFirstChildWidget(pParent);
+ while (child) {
+ if ((child->GetClassID() == FWL_Type::PushButton) &&
+ (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) {
+ return child;
+ }
+ IFWL_Widget* find = GetDefaultButton(child);
+ if (find) {
+ return find;
+ }
+ child = CFWL_WidgetMgr::GetInstance()->GetNextSiblingWidget(child);
+ }
+ return NULL;
+}
+void CFWL_WidgetMgr::AddRedrawCounts(IFWL_Widget* pWidget) {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ (pItem->iRedrawCounter)++;
+}
+void CFWL_WidgetMgr::ResetRedrawCounts(IFWL_Widget* pWidget) {
+ CFWL_WidgetMgrItem* pItem = GetWidgetMgrItem(pWidget);
+ pItem->iRedrawCounter = 0;
+}
+CFWL_WidgetMgrItem* CFWL_WidgetMgr::GetWidgetMgrItem(
+ IFWL_Widget* pWidget) const {
+ auto it = m_mapWidgetItem.find(pWidget);
+ return it != m_mapWidgetItem.end()
+ ? static_cast<CFWL_WidgetMgrItem*>(it->second.get())
+ : nullptr;
+}
+int32_t CFWL_WidgetMgr::TravelWidgetMgr(CFWL_WidgetMgrItem* pParent,
+ int32_t* pIndex,
+ CFWL_WidgetMgrItem* pItem,
+ IFWL_Widget** pWidget) {
+ if (!pParent) {
+ return 0;
+ }
+ int32_t iCount = 0;
+ CFWL_WidgetMgrItem* pChild = pParent->pChild;
+ while (pChild) {
+ iCount++;
+ if (pIndex) {
+ if (*pIndex == 0) {
+ *pWidget = pChild->pWidget;
+ return iCount;
+ }
+ pIndex--;
+ }
+ if (pItem && pItem == pChild) {
+ return iCount - 1;
+ }
+ pChild = pChild->pNext;
+ }
+ if (pIndex) {
+ return 0;
+ } else if (pItem) {
+ return -1;
+ }
+ return iCount - 1;
+}
+
+FX_BOOL CFWL_WidgetMgr::IsAbleNative(IFWL_Widget* pWidget) const {
+ if (!pWidget)
+ return FALSE;
+ if (!pWidget->IsInstance(FX_WSTRC(FWL_CLASS_Form))) {
+ return FALSE;
+ }
+ uint32_t dwStyles = pWidget->GetStyles();
+ return ((dwStyles & FWL_WGTSTYLE_WindowTypeMask) ==
+ FWL_WGTSTYLE_OverLapper) ||
+ (dwStyles & FWL_WGTSTYLE_Popup);
+}
+
+bool CFWL_WidgetMgr::IsThreadEnabled() {
+ return !(m_dwCapability & FWL_WGTMGR_DisableThread);
+}
+
+bool CFWL_WidgetMgr::IsFormDisabled() {
+ return !!(m_dwCapability & FWL_WGTMGR_DisableForm);
+}
+
+FX_BOOL CFWL_WidgetMgr::GetAdapterPopupPos(IFWL_Widget* pWidget,
+ FX_FLOAT fMinHeight,
+ FX_FLOAT fMaxHeight,
+ const CFX_RectF& rtAnchor,
+ CFX_RectF& rtPopup) {
+ CXFA_FWLAdapterWidgetMgr* pSDApapter = GetAdapterWidgetMgr();
+ return pSDApapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor,
+ rtPopup);
+}
+CFWL_WidgetMgrDelegate::CFWL_WidgetMgrDelegate(CFWL_WidgetMgr* pWidgetMgr)
+ : m_pWidgetMgr(pWidgetMgr) {}
+FWL_Error CFWL_WidgetMgrDelegate::OnSetCapability(uint32_t dwCapability) {
+ m_pWidgetMgr->m_dwCapability = dwCapability;
+ return FWL_Error::Succeeded;
+}
+
+void CFWL_WidgetMgrDelegate::OnProcessMessageToForm(CFWL_Message* pMessage) {
+ if (!pMessage)
+ return;
+ if (!pMessage->m_pDstTarget)
+ return;
+
+ IFWL_Widget* pDstWidget = pMessage->m_pDstTarget;
+ IFWL_App* pApp = pDstWidget->GetOwnerApp();
+ if (!pApp)
+ return;
+
+ CFWL_NoteDriver* pNoteDriver =
+ static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
+ if (!pNoteDriver)
+ return;
+
+ if (m_pWidgetMgr->IsThreadEnabled())
+ pMessage = static_cast<CFWL_Message*>(pMessage->Clone());
+ if (m_pWidgetMgr->IsFormDisabled())
+ pNoteDriver->ProcessMessage(pMessage);
+ else
+ pNoteDriver->QueueMessage(pMessage);
+
+#if (_FX_OS_ == _FX_MACOSX_)
+ CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop();
+ if (pTopLoop)
+ pNoteDriver->UnqueueMessage(pTopLoop);
+#endif
+
+ if (m_pWidgetMgr->IsThreadEnabled())
+ pMessage->Release();
+
+ return;
+}
+
+void CFWL_WidgetMgrDelegate::OnDrawWidget(IFWL_Widget* pWidget,
+ CFX_Graphics* pGraphics,
+ const CFX_Matrix* pMatrix) {
+ if (!pWidget || !pGraphics)
+ return;
+
+ CFX_Graphics* pTemp = DrawWidgetBefore(pWidget, pGraphics, pMatrix);
+ CFX_RectF clipCopy;
+ pWidget->GetWidgetRect(clipCopy);
+ clipCopy.left = clipCopy.top = 0;
+ if (bUseOffscreenDirect(pWidget)) {
+ DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);
+ return;
+ }
+ CFX_RectF clipBounds;
+
+#if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN64_ || \
+ _FX_OS_ == _FX_LINUX_DESKTOP_ || _FX_OS_ == _FX_ANDROID_
+ IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL);
+ pDelegate->OnDrawWidget(pTemp, pMatrix);
+ pGraphics->GetClipRect(clipBounds);
+ clipCopy = clipBounds;
+#elif _FX_OS_ == _FX_MACOSX_
+ if (m_pWidgetMgr->IsFormDisabled()) {
+ IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL);
+ pDelegate->OnDrawWidget(pTemp, pMatrix);
+ pGraphics->GetClipRect(clipBounds);
+ clipCopy = clipBounds;
+ } else {
+ clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);
+ const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast.
+ IFWL_WidgetDelegate* pDelegate = pWidget->SetDelegate(NULL);
+ pDelegate->OnDrawWidget(pTemp, pMatrix);
+ }
+#endif // _FX_OS_ == _FX_MACOSX_
+
+ if (!m_pWidgetMgr->IsFormDisabled()) {
+ CFX_RectF rtClient;
+ pWidget->GetClientRect(rtClient);
+ clipBounds.Intersect(rtClient);
+ }
+ if (!clipBounds.IsEmpty())
+ DrawChild(pWidget, clipBounds, pTemp, pMatrix);
+
+ DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);
+ m_pWidgetMgr->ResetRedrawCounts(pWidget);
+}
+
+void CFWL_WidgetMgrDelegate::DrawChild(IFWL_Widget* parent,
+ const CFX_RectF& rtClip,
+ CFX_Graphics* pGraphics,
+ const CFX_Matrix* pMatrix) {
+ if (!parent)
+ return;
+
+ FX_BOOL bFormDisable = m_pWidgetMgr->IsFormDisabled();
+ IFWL_Widget* pNextChild = m_pWidgetMgr->GetFirstChildWidget(parent);
+ while (pNextChild) {
+ IFWL_Widget* child = pNextChild;
+ pNextChild = m_pWidgetMgr->GetNextSiblingWidget(child);
+ if (child->GetStates() & FWL_WGTSTATE_Invisible)
+ continue;
+
+ CFX_RectF rtWidget;
+ child->GetWidgetRect(rtWidget);
+ if (rtWidget.IsEmpty())
+ continue;
+
+ CFX_Matrix widgetMatrix;
+ CFX_RectF clipBounds(rtWidget);
+ if (!bFormDisable)
+ child->GetMatrix(widgetMatrix, TRUE);
+ if (pMatrix)
+ widgetMatrix.Concat(*pMatrix);
+
+ if (!bFormDisable) {
+ widgetMatrix.TransformPoint(clipBounds.left, clipBounds.top);
+ clipBounds.Intersect(rtClip);
+ if (clipBounds.IsEmpty())
+ continue;
+
+ pGraphics->SaveGraphState();
+ pGraphics->SetClipRect(clipBounds);
+ }
+ widgetMatrix.Translate(rtWidget.left, rtWidget.top, TRUE);
+ IFWL_WidgetDelegate* pDelegate = child->SetDelegate(NULL);
+ if (pDelegate) {
+ if (m_pWidgetMgr->IsFormDisabled() ||
+ IsNeedRepaint(child, &widgetMatrix, rtClip)) {
+ pDelegate->OnDrawWidget(pGraphics, &widgetMatrix);
+ }
+ }
+ if (!bFormDisable)
+ pGraphics->RestoreGraphState();
+
+ DrawChild(child, clipBounds, pGraphics,
+ bFormDisable ? &widgetMatrix : pMatrix);
+ child = m_pWidgetMgr->GetNextSiblingWidget(child);
+ }
+}
+
+CFX_Graphics* CFWL_WidgetMgrDelegate::DrawWidgetBefore(
+ IFWL_Widget* pWidget,
+ CFX_Graphics* pGraphics,
+ const CFX_Matrix* pMatrix) {
+ if (!FWL_UseOffscreen(pWidget))
+ return pGraphics;
+
+ CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
+ if (!pItem->pOffscreen) {
+ pItem->pOffscreen.reset(new CFX_Graphics);
+ CFX_RectF rect;
+ pWidget->GetWidgetRect(rect);
+ pItem->pOffscreen->Create((int32_t)rect.width, (int32_t)rect.height,
+ FXDIB_Argb);
+ }
+ CFX_RectF rect;
+ pGraphics->GetClipRect(rect);
+ pItem->pOffscreen->SetClipRect(rect);
+ return pItem->pOffscreen.get();
+}
+
+void CFWL_WidgetMgrDelegate::DrawWidgetAfter(IFWL_Widget* pWidget,
+ CFX_Graphics* pGraphics,
+ CFX_RectF& rtClip,
+ const CFX_Matrix* pMatrix) {
+ if (FWL_UseOffscreen(pWidget)) {
+ CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
+ pGraphics->Transfer(pItem->pOffscreen.get(), rtClip.left, rtClip.top,
+ rtClip, pMatrix);
+#ifdef _WIN32
+ pItem->pOffscreen->ClearClip();
+#endif
+ }
+ CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
+ pItem->iRedrawCounter = 0;
+}
+
+FX_BOOL CFWL_WidgetMgrDelegate::IsNeedRepaint(IFWL_Widget* pWidget,
+ CFX_Matrix* pMatrix,
+ const CFX_RectF& rtDirty) {
+ CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
+ if (pItem && pItem->iRedrawCounter > 0) {
+ pItem->iRedrawCounter = 0;
+ return TRUE;
+ }
+ CFX_RectF rtWidget;
+ pWidget->GetWidgetRect(rtWidget);
+ rtWidget.left = rtWidget.top = 0;
+ pMatrix->TransformRect(rtWidget);
+ if (!rtWidget.IntersectWith(rtDirty))
+ return FALSE;
+
+ IFWL_Widget* pChild =
+ CFWL_WidgetMgr::GetInstance()->GetFirstChildWidget(pWidget);
+ if (!pChild)
+ return TRUE;
+
+ CFX_RectF rtChilds;
+ rtChilds.Empty();
+ FX_BOOL bChildIntersectWithDirty = FALSE;
+ FX_BOOL bOrginPtIntersectWidthChild = FALSE;
+ FX_BOOL bOrginPtIntersectWidthDirty =
+ rtDirty.Contains(rtWidget.left, rtWidget.top);
+ static FWL_NEEDREPAINTHITDATA hitPoint[kNeedRepaintHitPoints];
+ int32_t iSize = sizeof(FWL_NEEDREPAINTHITDATA);
+ FXSYS_memset(hitPoint, 0, iSize);
+ FX_FLOAT fxPiece = rtWidget.width / kNeedRepaintHitPiece;
+ FX_FLOAT fyPiece = rtWidget.height / kNeedRepaintHitPiece;
+ hitPoint[2].hitPoint.x = hitPoint[6].hitPoint.x = rtWidget.left;
+ hitPoint[0].hitPoint.x = hitPoint[3].hitPoint.x = hitPoint[7].hitPoint.x =
+ hitPoint[10].hitPoint.x = fxPiece + rtWidget.left;
+ hitPoint[1].hitPoint.x = hitPoint[4].hitPoint.x = hitPoint[8].hitPoint.x =
+ hitPoint[11].hitPoint.x = fxPiece * 2 + rtWidget.left;
+ hitPoint[5].hitPoint.x = hitPoint[9].hitPoint.x =
+ rtWidget.width + rtWidget.left;
+ hitPoint[0].hitPoint.y = hitPoint[1].hitPoint.y = rtWidget.top;
+ hitPoint[2].hitPoint.y = hitPoint[3].hitPoint.y = hitPoint[4].hitPoint.y =
+ hitPoint[5].hitPoint.y = fyPiece + rtWidget.top;
+ hitPoint[6].hitPoint.y = hitPoint[7].hitPoint.y = hitPoint[8].hitPoint.y =
+ hitPoint[9].hitPoint.y = fyPiece * 2 + rtWidget.top;
+ hitPoint[10].hitPoint.y = hitPoint[11].hitPoint.y =
+ rtWidget.height + rtWidget.top;
+ do {
+ CFX_RectF rect;
+ pChild->GetWidgetRect(rect);
+ CFX_RectF r = rect;
+ r.left += rtWidget.left;
+ r.top += rtWidget.top;
+ if (r.IsEmpty())
+ continue;
+ if (r.Contains(rtDirty))
+ return FALSE;
+ if (!bChildIntersectWithDirty && r.IntersectWith(rtDirty))
+ bChildIntersectWithDirty = TRUE;
+ if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
+ bOrginPtIntersectWidthChild = rect.Contains(0, 0);
+
+ if (rtChilds.IsEmpty())
+ rtChilds = rect;
+ else if (!(pChild->GetStates() & FWL_WGTSTATE_Invisible))
+ rtChilds.Union(rect);
+
+ for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
+ if (hitPoint[i].bNotContainByDirty || hitPoint[i].bNotNeedRepaint)
+ continue;
+ if (!rtDirty.Contains(hitPoint[i].hitPoint)) {
+ hitPoint[i].bNotContainByDirty = true;
+ continue;
+ }
+ if (r.Contains(hitPoint[i].hitPoint))
+ hitPoint[i].bNotNeedRepaint = true;
+ }
+ } while (
+ (pChild = CFWL_WidgetMgr::GetInstance()->GetNextSiblingWidget(pChild)));
+
+ if (!bChildIntersectWithDirty)
+ return TRUE;
+ if (bOrginPtIntersectWidthDirty && !bOrginPtIntersectWidthChild)
+ return TRUE;
+ if (rtChilds.IsEmpty())
+ return TRUE;
+
+ int32_t repaintPoint = kNeedRepaintHitPoints;
+ for (int32_t i = 0; i < kNeedRepaintHitPoints; i++) {
+ if (hitPoint[i].bNotNeedRepaint)
+ repaintPoint--;
+ }
+ if (repaintPoint > 0)
+ return TRUE;
+
+ pMatrix->TransformRect(rtChilds);
+ if (rtChilds.Contains(rtDirty) || rtChilds.Contains(rtWidget))
+ return FALSE;
+ return TRUE;
+}
+
+FX_BOOL CFWL_WidgetMgrDelegate::bUseOffscreenDirect(IFWL_Widget* pWidget) {
+ CFWL_WidgetMgrItem* pItem = m_pWidgetMgr->GetWidgetMgrItem(pWidget);
+ if (!FWL_UseOffscreen(pWidget) || !(pItem->pOffscreen))
+ return FALSE;
+
+#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
+ if (pItem->bOutsideChanged) {
+ CFX_RectF r;
+ pWidget->GetWidgetRect(r);
+ CFX_RectF temp(m_pWidgetMgr->m_rtScreen);
+ temp.Deflate(50, 50);
+ if (!temp.Contains(r))
+ return FALSE;
+
+ pItem->bOutsideChanged = FALSE;
+ }
+#endif
+
+ return pItem->iRedrawCounter == 0;
+}