blob: 86c4938c10a15a0261a191aec92313d6ef2f3d1b [file] [log] [blame]
// 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 "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<Item>(
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);
for (auto& item : m_mapWidgetItem)
visitor->Trace(item.second);
}
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<Item>(
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<Item>::Trace(visitor);
visitor->Trace(pWidget);
}