// Copyright 2014 The PDFium Authors // 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 "build/build_config.h" #include "fxjs/gc/container_trace.h" #include "third_party/base/check.h" #include "xfa/fwl/cfwl_app.h" #include "xfa/fwl/cfwl_message.h" #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fwl/cfwl_pushbutton.h" CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapter, CFWL_App* pApp) : m_pAdapter(pAdapter), m_pApp(pApp) { DCHECK(m_pAdapter); m_mapWidgetItem[nullptr] = cppgc::MakeGarbageCollected( pApp->GetHeap()->GetAllocationHandle(), nullptr); } CFWL_WidgetMgr::~CFWL_WidgetMgr() = default; void CFWL_WidgetMgr::Trace(cppgc::Visitor* visitor) const { visitor->Trace(m_pApp); visitor->Trace(m_pAdapter); ContainerTrace(visitor, m_mapWidgetItem); } CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(const CFWL_Widget* pWidget) const { Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return nullptr; Item* pParent = pItem->GetParent(); return pParent ? pParent->pWidget : nullptr; } CFWL_Widget* CFWL_WidgetMgr::GetPriorSiblingWidget(CFWL_Widget* pWidget) const { Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return nullptr; Item* pSibling = pItem->GetPrevSibling(); return pSibling ? pSibling->pWidget : nullptr; } CFWL_Widget* CFWL_WidgetMgr::GetNextSiblingWidget(CFWL_Widget* pWidget) const { Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return nullptr; Item* pSibling = pItem->GetNextSibling(); return pSibling ? pSibling->pWidget : nullptr; } CFWL_Widget* CFWL_WidgetMgr::GetFirstChildWidget(CFWL_Widget* pWidget) const { Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return nullptr; Item* pChild = pItem->GetFirstChild(); return pChild ? pChild->pWidget : nullptr; } CFWL_Widget* CFWL_WidgetMgr::GetLastChildWidget(CFWL_Widget* pWidget) const { Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return nullptr; Item* pChild = pItem->GetLastChild(); return pChild ? pChild->pWidget : 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(); } m_pAdapter->RepaintWidget(pNative); } void CFWL_WidgetMgr::InsertWidget(CFWL_Widget* pParent, CFWL_Widget* pChild) { Item* pParentItem = GetWidgetMgrItem(pParent); if (!pParentItem) { pParentItem = CreateWidgetMgrItem(pParent); GetWidgetMgrRootItem()->AppendLastChild(pParentItem); } Item* pChildItem = GetWidgetMgrItem(pChild); if (!pChildItem) pChildItem = CreateWidgetMgrItem(pChild); pParentItem->AppendLastChild(pChildItem); } void CFWL_WidgetMgr::RemoveWidget(CFWL_Widget* pWidget) { DCHECK(pWidget); Item* pItem = GetWidgetMgrItem(pWidget); if (!pItem) return; while (pItem->GetFirstChild()) RemoveWidget(pItem->GetFirstChild()->pWidget); pItem->RemoveSelfIfParented(); m_mapWidgetItem.erase(pWidget); } 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() & FWL_STATE_PSB_Default)) { return pParent; } CFWL_Widget* child = GetFirstChildWidget(pParent); while (child) { if (child->GetClassID() == FWL_Type::PushButton && (child->GetStates() & FWL_STATE_PSB_Default)) { return child; } if (CFWL_Widget* find = GetDefaultButton(child)) return find; child = GetNextSiblingWidget(child); } return nullptr; } CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrRootItem() const { return GetWidgetMgrItem(nullptr); } CFWL_WidgetMgr::Item* CFWL_WidgetMgr::GetWidgetMgrItem( const CFWL_Widget* pWidget) const { auto it = m_mapWidgetItem.find(pWidget); return it != m_mapWidgetItem.end() ? it->second : nullptr; } CFWL_WidgetMgr::Item* CFWL_WidgetMgr::CreateWidgetMgrItem( CFWL_Widget* pWidget) { auto* pItem = cppgc::MakeGarbageCollected( m_pApp->GetHeap()->GetAllocationHandle(), pWidget); m_mapWidgetItem[pWidget] = pItem; return pItem; } 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(CFWL_Message* pMessage) { CFWL_Widget* pDstWidget = pMessage->GetDstTarget(); if (!pDstWidget) return; CFWL_NoteDriver* pNoteDriver = pDstWidget->GetFWLApp()->GetNoteDriver(); pNoteDriver->ProcessMessage(pMessage); } void CFWL_WidgetMgr::OnDrawWidget(CFWL_Widget* pWidget, CFGAS_GEGraphics* pGraphics, const CFX_Matrix& matrix) { if (!pWidget || !pGraphics) return; pWidget->GetDelegate()->OnDrawWidget(pGraphics, matrix); CFX_RectF clipBounds = pGraphics->GetClipRect(); if (!clipBounds.IsEmpty()) DrawChildren(pWidget, clipBounds, pGraphics, matrix); } void CFWL_WidgetMgr::DrawChildren(CFWL_Widget* parent, const CFX_RectF& rtClip, CFGAS_GEGraphics* pGraphics, const CFX_Matrix& mtMatrix) { 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); widgetMatrix.Concat(mtMatrix); widgetMatrix.TranslatePrepend(rtWidget.left, rtWidget.top); if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) pDelegate->OnDrawWidget(pGraphics, widgetMatrix); DrawChildren(child, clipBounds, pGraphics, widgetMatrix); } } CFWL_WidgetMgr::Item::Item(CFWL_Widget* widget) : pWidget(widget) {} CFWL_WidgetMgr::Item::~Item() = default; void CFWL_WidgetMgr::Item::Trace(cppgc::Visitor* visitor) const { GCedTreeNode::Trace(visitor); visitor->Trace(pWidget); }