| // 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/cfwl_widgetmgr.h" | |
| #include <utility> | |
| #include "build/build_config.h" | |
| #include "third_party/base/ptr_util.h" | |
| #include "xfa/fwl/cfwl_app.h" | |
| #include "xfa/fwl/cfwl_message.h" | |
| #include "xfa/fwl/cfwl_notedriver.h" | |
| CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapterNative) | |
| : m_pAdapter(pAdapterNative) { | |
| m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>(); | |
| } | |
| CFWL_WidgetMgr::~CFWL_WidgetMgr() = default; | |
| // static | |
| CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent, CFWL_Widget* focus) { | |
| CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr(); | |
| CFWL_Widget* child = pMgr->GetFirstChildWidget(parent); | |
| while (child) { | |
| CFWL_Widget* bRet = NextTab(child, focus); | |
| if (bRet) | |
| return bRet; | |
| child = pMgr->GetNextSiblingWidget(child); | |
| } | |
| return nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(const CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| return pItem && pItem->pOwner ? pItem->pOwner->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetFirstSiblingWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| if (!pItem) | |
| return nullptr; | |
| pItem = pItem->pPrevious; | |
| while (pItem && pItem->pPrevious) | |
| pItem = pItem->pPrevious; | |
| return pItem ? pItem->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| return pItem && pItem->pPrevious ? pItem->pPrevious->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| return pItem && pItem->pNext ? pItem->pNext->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| return pItem && pItem->pChild ? pItem->pChild->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| if (!pItem) | |
| return nullptr; | |
| pItem = pItem->pChild; | |
| while (pItem && pItem->pNext) | |
| pItem = pItem->pNext; | |
| return pItem ? pItem->pWidget : nullptr; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetSystemFormWidget(CFWL_Widget* pWidget) const { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| while (pItem) { | |
| if (IsAbleNative(pItem->pWidget)) | |
| return pItem->pWidget; | |
| pItem = pItem->pParent; | |
| } | |
| return nullptr; | |
| } | |
| void CFWL_WidgetMgr::AppendWidget(CFWL_Widget* pWidget) { | |
| Item* pItem = GetWidgetMgrItem(pWidget); | |
| if (!pItem) | |
| return; | |
| if (!pItem->pParent) | |
| return; | |
| Item* pChild = pItem->pParent->pChild; | |
| int32_t i = 0; | |
| while (pChild) { | |
| if (pChild == pItem) { | |
| 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 = nullptr; | |
| pItem->pPrevious = nullptr; | |
| break; | |
| } | |
| if (!pChild->pNext) | |
| break; | |
| pChild = pChild->pNext; | |
| ++i; | |
| } | |
| pChild = pItem->pParent->pChild; | |
| if (pChild) { | |
| while (pChild->pNext) | |
| pChild = pChild->pNext; | |
| pChild->pNext = pItem; | |
| pItem->pPrevious = pChild; | |
| } else { | |
| pItem->pParent->pChild = pItem; | |
| pItem->pPrevious = nullptr; | |
| } | |
| pItem->pNext = nullptr; | |
| } | |
| void CFWL_WidgetMgr::RepaintWidget(CFWL_Widget* pWidget, | |
| const CFX_RectF& rect) { | |
| CFWL_Widget* pNative = pWidget; | |
| CFX_RectF transformedRect = rect; | |
| CFWL_Widget* pOuter = pWidget->GetOuter(); | |
| while (pOuter) { | |
| CFX_RectF rtTemp = pNative->GetWidgetRect(); | |
| transformedRect.left += rtTemp.left; | |
| transformedRect.top += rtTemp.top; | |
| pNative = pOuter; | |
| pOuter = pOuter->GetOuter(); | |
| } | |
| AddRedrawCounts(pNative); | |
| m_pAdapter->RepaintWidget(pNative); | |
| } | |
| void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
| Item* pParentItem = GetWidgetMgrItem(pParent); | |
| if (!pParentItem) { | |
| auto item = pdfium::MakeUnique<Item>(pParent); | |
| pParentItem = item.get(); | |
| m_mapWidgetItem[pParent] = std::move(item); | |
| pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
| AppendWidget(pParent); | |
| } | |
| Item* pItem = GetWidgetMgrItem(pChild); | |
| if (!pItem) { | |
| auto item = pdfium::MakeUnique<Item>(pChild); | |
| pItem = item.get(); | |
| m_mapWidgetItem[pChild] = std::move(item); | |
| } | |
| 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; | |
| AppendWidget(pChild); | |
| } | |
| void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) { | |
| Item* 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; | |
| Item* pChild = pItem->pChild; | |
| while (pChild) { | |
| Item* pNext = pChild->pNext; | |
| RemoveWidget(pChild->pWidget); | |
| pChild = pNext; | |
| } | |
| m_mapWidgetItem.erase(pWidget); | |
| } | |
| void CFWL_WidgetMgr::SetOwner(CFWL_Widget* pOwner, CFWL_Widget* pOwned) { | |
| Item* pParentItem = GetWidgetMgrItem(pOwner); | |
| if (!pParentItem) { | |
| auto item = pdfium::MakeUnique<Item>(pOwner); | |
| pParentItem = item.get(); | |
| m_mapWidgetItem[pOwner] = std::move(item); | |
| pParentItem->pParent = GetWidgetMgrItem(nullptr); | |
| AppendWidget(pOwner); | |
| } | |
| Item* pItem = GetWidgetMgrItem(pOwned); | |
| if (!pItem) { | |
| auto item = pdfium::MakeUnique<Item>(pOwned); | |
| pItem = item.get(); | |
| m_mapWidgetItem[pOwned] = std::move(item); | |
| } | |
| pItem->pOwner = pParentItem; | |
| } | |
| void CFWL_WidgetMgr::SetParent(CFWL_Widget* pParent, CFWL_Widget* pChild) { | |
| Item* pParentItem = GetWidgetMgrItem(pParent); | |
| Item* 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 = nullptr; | |
| pItem->pPrevious = nullptr; | |
| } | |
| pItem->pParent = pParentItem; | |
| AppendWidget(pChild); | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent, | |
| const CFX_PointF& point) const { | |
| if (!parent) | |
| return nullptr; | |
| CFWL_Widget* child = GetLastChildWidget(parent); | |
| while (child) { | |
| if (child->IsVisible()) { | |
| CFX_PointF pos = parent->GetMatrix().GetInverse().Transform(point); | |
| CFX_RectF bounds = child->GetWidgetRect(); | |
| if (bounds.Contains(pos)) { | |
| pos -= bounds.TopLeft(); | |
| return GetWidgetAtPoint(child, pos); | |
| } | |
| } | |
| child = GetPriorSiblingWidget(child); | |
| } | |
| return parent; | |
| } | |
| CFWL_Widget* CFWL_WidgetMgr::GetDefaultButton(CFWL_Widget* pParent) const { | |
| if ((pParent->GetClassID() == FWL_Type::PushButton) && | |
| (pParent->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
| return pParent; | |
| } | |
| CFWL_Widget* child = | |
| pParent->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pParent); | |
| while (child) { | |
| if ((child->GetClassID() == FWL_Type::PushButton) && | |
| (child->GetStates() & (1 << (FWL_WGTSTATE_MAX + 2)))) { | |
| return child; | |
| } | |
| if (CFWL_Widget* find = GetDefaultButton(child)) | |
| return find; | |
| child = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child); | |
| } | |
| return nullptr; | |
| } | |
| void CFWL_WidgetMgr::AddRedrawCounts(CFWL_Widget* pWidget) { | |
| GetWidgetMgrItem(pWidget)->iRedrawCounter++; | |
| } | |
| void CFWL_WidgetMgr::ResetRedrawCounts(CFWL_Widget* pWidget) { | |
| GetWidgetMgrItem(pWidget)->iRedrawCounter = 0; | |
| } | |
| CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem( | |
| const CFWL_Widget* pWidget) const { | |
| auto it = m_mapWidgetItem.find(pWidget); | |
| return it != m_mapWidgetItem.end() ? it->second.get() : nullptr; | |
| } | |
| bool CFWL_WidgetMgr::IsAbleNative(CFWL_Widget* pWidget) const { | |
| if (!pWidget || !pWidget->IsForm()) | |
| return false; | |
| return pWidget->IsOverLapper() || pWidget->IsPopup(); | |
| } | |
| void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget, | |
| float fMinHeight, | |
| float fMaxHeight, | |
| const CFX_RectF& rtAnchor, | |
| CFX_RectF* pPopupRect) const { | |
| m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, | |
| pPopupRect); | |
| } | |
| void CFWL_WidgetMgr::OnProcessMessageToForm( | |
| std::unique_ptr<CFWL_Message> pMessage) { | |
| CFWL_Widget* pDstWidget = pMessage->GetDstTarget(); | |
| if (!pDstWidget) | |
| return; | |
| CFWL_NoteDriver* pNoteDriver = pDstWidget->GetOwnerApp()->GetNoteDriver(); | |
| pNoteDriver->ProcessMessage(std::move(pMessage)); | |
| } | |
| void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget, | |
| CXFA_Graphics* pGraphics, | |
| const CFX_Matrix& matrix) { | |
| if (!pWidget || !pGraphics) | |
| return; | |
| CFX_RectF clipCopy(0, 0, pWidget->GetWidgetRect().Size()); | |
| CFX_RectF clipBounds; | |
| pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix); | |
| clipBounds = pGraphics->GetClipRect(); | |
| clipCopy = clipBounds; | |
| if (!clipBounds.IsEmpty()) | |
| DrawChild(pWidget, clipBounds, pGraphics, &matrix); | |
| GetWidgetMgrItem(pWidget)->iRedrawCounter = 0; | |
| ResetRedrawCounts(pWidget); | |
| } | |
| void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent, | |
| const CFX_RectF& rtClip, | |
| CXFA_Graphics* pGraphics, | |
| const CFX_Matrix* pMatrix) { | |
| if (!parent) | |
| return; | |
| CFWL_Widget* pNextChild = GetFirstChildWidget(parent); | |
| while (pNextChild) { | |
| CFWL_Widget* child = pNextChild; | |
| pNextChild = GetNextSiblingWidget(child); | |
| if (!child->IsVisible()) | |
| continue; | |
| CFX_RectF rtWidget = child->GetWidgetRect(); | |
| if (rtWidget.IsEmpty()) | |
| continue; | |
| CFX_Matrix widgetMatrix; | |
| CFX_RectF clipBounds(rtWidget); | |
| if (pMatrix) | |
| widgetMatrix.Concat(*pMatrix); | |
| widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top); | |
| if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) | |
| pDelegate->OnDrawWidget(pGraphics, widgetMatrix); | |
| DrawChild(child, clipBounds, pGraphics, &widgetMatrix); | |
| } | |
| } | |
| CFWL_WidgetMgr::Item::Item() : CFWL_WidgetMgr::Item(nullptr) {} | |
| CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget) | |
| : pParent(nullptr), | |
| pOwner(nullptr), | |
| pChild(nullptr), | |
| pPrevious(nullptr), | |
| pNext(nullptr), | |
| pWidget(widget), | |
| iRedrawCounter(0) {} | |
| CFWL_WidgetMgr::Item::~Item() {} |