|  | // 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 "core/fxcrt/check.h" | 
|  | #include "fxjs/gc/container_trace.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" | 
|  |  | 
|  | namespace pdfium { | 
|  |  | 
|  | CFWL_WidgetMgr::CFWL_WidgetMgr(AdapterIface* pAdapter, CFWL_App* pApp) | 
|  | : adapter_(pAdapter), app_(pApp) { | 
|  | DCHECK(adapter_); | 
|  | map_widget_item_[nullptr] = cppgc::MakeGarbageCollected<Item>( | 
|  | pApp->GetHeap()->GetAllocationHandle(), nullptr); | 
|  | } | 
|  |  | 
|  | CFWL_WidgetMgr::~CFWL_WidgetMgr() = default; | 
|  |  | 
|  | void CFWL_WidgetMgr::Trace(cppgc::Visitor* visitor) const { | 
|  | visitor->Trace(app_); | 
|  | visitor->Trace(adapter_); | 
|  | ContainerTrace(visitor, map_widget_item_); | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | } | 
|  | adapter_->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(); | 
|  | map_widget_item_.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 = map_widget_item_.find(pWidget); | 
|  | return it != map_widget_item_.end() ? it->second : nullptr; | 
|  | } | 
|  |  | 
|  | CFWL_WidgetMgr::Item* CFWL_WidgetMgr::CreateWidgetMgrItem( | 
|  | CFWL_Widget* pWidget) { | 
|  | auto* pItem = cppgc::MakeGarbageCollected<Item>( | 
|  | app_->GetHeap()->GetAllocationHandle(), pWidget); | 
|  | map_widget_item_[pWidget] = pItem; | 
|  | return pItem; | 
|  | } | 
|  |  | 
|  | void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget, | 
|  | float fMinHeight, | 
|  | float fMaxHeight, | 
|  | const CFX_RectF& rtAnchor, | 
|  | CFX_RectF* pPopupRect) const { | 
|  | adapter_->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<Item>::Trace(visitor); | 
|  | visitor->Trace(pWidget); | 
|  | } | 
|  |  | 
|  | }  // namespace pdfium |