// 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_noteimp.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/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 } 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 = nullptr; pItem->pPrevious = nullptr; 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 = nullptr; return TRUE; } i = 0; while (i < nIndex && pChild->pNext) { pChild = pChild->pNext; ++i; } if (!pChild->pNext) { pChild->pNext = pItem; pItem->pPrevious = pChild; pItem->pNext = nullptr; 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 = nullptr; pItem->pNext = nullptr; } 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(nullptr); 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 = nullptr; pItem->pPrevious = nullptr; } 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 nullptr; 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 = parent->GetOwnerApp()->GetWidgetMgr(); 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& 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)) != nullptr) { 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 = pParent->GetOwnerApp()->GetWidgetMgr()->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 = child->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(child); } return nullptr; } 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(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; const IFWL_App* pApp = pDstWidget->GetOwnerApp(); if (!pApp) return; CFWL_NoteDriver* pNoteDriver = static_cast(pApp->GetNoteDriver()); if (!pNoteDriver) return; if (m_pWidgetMgr->IsThreadEnabled()) pMessage = static_cast(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_ pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); pGraphics->GetClipRect(clipBounds); clipCopy = clipBounds; #elif _FX_OS_ == _FX_MACOSX_ if (m_pWidgetMgr->IsFormDisabled()) { pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix); pGraphics->GetClipRect(clipBounds); clipCopy = clipBounds; } else { clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d); const_cast(pMatrix)->SetIdentity(); // FIXME: const cast. pWidget->GetDelegate()->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); if (IFWL_WidgetDelegate* pDelegate = child->GetDelegate()) { 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 = pWidget->GetOwnerApp()->GetWidgetMgr()->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]; FXSYS_memset(hitPoint, 0, sizeof(hitPoint)); 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; } pChild = pChild->GetOwnerApp()->GetWidgetMgr()->GetNextSiblingWidget(pChild); } while (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; } CFWL_WidgetMgrItem::CFWL_WidgetMgrItem() : CFWL_WidgetMgrItem(nullptr) {} CFWL_WidgetMgrItem::CFWL_WidgetMgrItem(IFWL_Widget* widget) : pParent(nullptr), pOwner(nullptr), pChild(nullptr), pPrevious(nullptr), pNext(nullptr), pWidget(widget), iRedrawCounter(0) #if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_) , bOutsideChanged(FALSE) #endif { } CFWL_WidgetMgrItem::~CFWL_WidgetMgrItem() {}