summaryrefslogtreecommitdiff
path: root/xfa/fwl/cfwl_widgetmgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fwl/cfwl_widgetmgr.cpp')
-rw-r--r--xfa/fwl/cfwl_widgetmgr.cpp732
1 files changed, 732 insertions, 0 deletions
diff --git a/xfa/fwl/cfwl_widgetmgr.cpp b/xfa/fwl/cfwl_widgetmgr.cpp
new file mode 100644
index 0000000000..825de0e14e
--- /dev/null
+++ b/xfa/fwl/cfwl_widgetmgr.cpp
@@ -0,0 +1,732 @@
+// 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 "third_party/base/ptr_util.h"
+#include "xfa/fwl/cfwl_app.h"
+#include "xfa/fwl/cfwl_form.h"
+#include "xfa/fwl/cfwl_notedriver.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
+
+bool FWL_UseOffscreen(CFWL_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_pAdapter(pAdapterNative->GetWidgetMgr(this)) {
+ ASSERT(m_pAdapter);
+ m_mapWidgetItem[nullptr] = pdfium::MakeUnique<Item>();
+#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
+ m_rtScreen.Reset();
+#endif
+}
+
+CFWL_WidgetMgr::~CFWL_WidgetMgr() {}
+
+CFWL_Widget* CFWL_WidgetMgr::GetParentWidget(CFWL_Widget* pWidget) const {
+ Item* pItem = GetWidgetMgrItem(pWidget);
+ return pItem && pItem->pParent ? pItem->pParent->pWidget : nullptr;
+}
+
+CFWL_Widget* CFWL_WidgetMgr::GetOwnerWidget(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* pRect) {
+ if (!m_pAdapter)
+ return;
+
+ CFWL_Widget* pNative = pWidget;
+ CFX_RectF rect(*pRect);
+ if (IsFormDisabled()) {
+ CFWL_Widget* pOuter = pWidget->GetOuter();
+ while (pOuter) {
+ CFX_RectF rtTemp = pNative->GetWidgetRect();
+ rect.left += rtTemp.left;
+ rect.top += rtTemp.top;
+ pNative = pOuter;
+ pOuter = pOuter->GetOuter();
+ }
+ } else if (!IsAbleNative(pWidget)) {
+ pNative = GetSystemFormWidget(pWidget);
+ if (!pNative)
+ return;
+
+ pWidget->TransformTo(pNative, rect.left, rect.top);
+ }
+ AddRedrawCounts(pNative);
+ m_pAdapter->RepaintWidget(pNative, &rect);
+}
+
+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);
+}
+
+void CFWL_WidgetMgr::SetWidgetRect_Native(CFWL_Widget* pWidget,
+ const CFX_RectF& rect) {
+ if (!FWL_UseOffscreen(pWidget))
+ return;
+
+ Item* 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
+}
+
+CFWL_Widget* CFWL_WidgetMgr::GetWidgetAtPoint(CFWL_Widget* parent,
+ FX_FLOAT x,
+ FX_FLOAT y) {
+ if (!parent)
+ return nullptr;
+
+ FX_FLOAT x1;
+ FX_FLOAT y1;
+ CFWL_Widget* child = GetLastChildWidget(parent);
+ while (child) {
+ if ((child->GetStates() & FWL_WGTSTATE_Invisible) == 0) {
+ x1 = x;
+ y1 = y;
+ CFX_Matrix matrixOnParent;
+ child->GetMatrix(matrixOnParent, false);
+ CFX_Matrix m;
+ m.SetIdentity();
+ m.SetReverse(matrixOnParent);
+ m.TransformPoint(x1, y1);
+ CFX_RectF bounds = child->GetWidgetRect();
+ 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(CFWL_Widget* pForm,
+ FX_FLOAT fx,
+ FX_FLOAT fy) {
+ if (FWL_UseOffscreen(pForm))
+ GetWidgetMgrItem(pForm)->pOffscreen.reset();
+}
+
+CFWL_Widget* CFWL_WidgetMgr::NextTab(CFWL_Widget* parent,
+ CFWL_Widget* focus,
+ bool& bFind) {
+ CFWL_WidgetMgr* pMgr = parent->GetOwnerApp()->GetWidgetMgr();
+ CFWL_Widget* child = pMgr->GetFirstChildWidget(parent);
+ while (child) {
+ if (focus == child)
+ bFind = true;
+
+ if ((child->GetStyles() & FWL_WGTSTYLE_TabStop) &&
+ (!focus || (focus != child && bFind))) {
+ return child;
+ }
+ CFWL_Widget* bRet = NextTab(child, focus, bFind);
+ if (bRet)
+ return bRet;
+
+ child = pMgr->GetNextSiblingWidget(child);
+ }
+ return nullptr;
+}
+
+int32_t CFWL_WidgetMgr::CountRadioButtonGroup(CFWL_Widget* pFirst) const {
+ int32_t iRet = 0;
+ CFWL_Widget* pChild = pFirst;
+ while (pChild) {
+ pChild = GetNextSiblingWidget(pChild);
+ ++iRet;
+ }
+ return iRet;
+}
+
+CFWL_Widget* CFWL_WidgetMgr::GetRadioButtonGroupHeader(
+ CFWL_Widget* pRadioButton) const {
+ CFWL_Widget* pNext = pRadioButton;
+ if (pNext && (pNext->GetStyles() & FWL_WGTSTYLE_Group))
+ return pNext;
+ return nullptr;
+}
+
+void CFWL_WidgetMgr::GetSameGroupRadioButton(
+ CFWL_Widget* pRadioButton,
+ CFX_ArrayTemplate<CFWL_Widget*>& group) const {
+ CFWL_Widget* pFirst = GetFirstSiblingWidget(pRadioButton);
+ if (!pFirst)
+ pFirst = pRadioButton;
+
+ int32_t iGroup = CountRadioButtonGroup(pFirst);
+ if (iGroup < 2)
+ return;
+ group.Add(GetRadioButtonGroupHeader(pRadioButton));
+}
+
+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(
+ CFWL_Widget* pWidget) const {
+ auto it = m_mapWidgetItem.find(pWidget);
+ return it != m_mapWidgetItem.end() ? static_cast<Item*>(it->second.get())
+ : nullptr;
+}
+
+bool CFWL_WidgetMgr::IsAbleNative(CFWL_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);
+}
+
+void CFWL_WidgetMgr::GetAdapterPopupPos(CFWL_Widget* pWidget,
+ FX_FLOAT fMinHeight,
+ FX_FLOAT fMaxHeight,
+ const CFX_RectF& rtAnchor,
+ CFX_RectF& rtPopup) const {
+ m_pAdapter->GetPopupPos(pWidget, fMinHeight, fMaxHeight, rtAnchor, rtPopup);
+}
+
+void CFWL_WidgetMgr::OnSetCapability(uint32_t dwCapability) {
+ m_dwCapability = dwCapability;
+}
+
+void CFWL_WidgetMgr::OnProcessMessageToForm(CFWL_Message* pMessage) {
+ if (!pMessage)
+ return;
+ if (!pMessage->m_pDstTarget)
+ return;
+
+ CFWL_Widget* pDstWidget = pMessage->m_pDstTarget;
+ const CFWL_App* pApp = pDstWidget->GetOwnerApp();
+ if (!pApp)
+ return;
+
+ CFWL_NoteDriver* pNoteDriver =
+ static_cast<CFWL_NoteDriver*>(pApp->GetNoteDriver());
+ if (!pNoteDriver)
+ return;
+
+ std::unique_ptr<CFWL_Message> pClonedMessage = pMessage->Clone();
+ if (IsFormDisabled())
+ pNoteDriver->ProcessMessage(pClonedMessage.get());
+ else
+ pNoteDriver->QueueMessage(std::move(pClonedMessage));
+
+#if (_FX_OS_ == _FX_MACOSX_)
+ CFWL_NoteLoop* pTopLoop = pNoteDriver->GetTopLoop();
+ if (pTopLoop)
+ pNoteDriver->UnqueueMessage(pTopLoop);
+#endif
+}
+
+void CFWL_WidgetMgr::OnDrawWidget(CFWL_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.left = clipCopy.top = 0;
+
+ if (UseOffscreenDirect(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 (IsFormDisabled()) {
+ pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix);
+ pGraphics->GetClipRect(clipBounds);
+ clipCopy = clipBounds;
+ } else {
+ clipBounds.Set(pMatrix->a, pMatrix->b, pMatrix->c, pMatrix->d);
+ const_cast<CFX_Matrix*>(pMatrix)->SetIdentity(); // FIXME: const cast.
+ pWidget->GetDelegate()->OnDrawWidget(pTemp, pMatrix);
+ }
+#endif // _FX_OS_ == _FX_MACOSX_
+
+ if (!IsFormDisabled()) {
+ CFX_RectF rtClient;
+ pWidget->GetClientRect(rtClient);
+ clipBounds.Intersect(rtClient);
+ }
+ if (!clipBounds.IsEmpty())
+ DrawChild(pWidget, clipBounds, pTemp, pMatrix);
+
+ DrawWidgetAfter(pWidget, pGraphics, clipCopy, pMatrix);
+ ResetRedrawCounts(pWidget);
+}
+
+void CFWL_WidgetMgr::DrawChild(CFWL_Widget* parent,
+ const CFX_RectF& rtClip,
+ CFX_Graphics* pGraphics,
+ const CFX_Matrix* pMatrix) {
+ if (!parent)
+ return;
+
+ bool bFormDisable = IsFormDisabled();
+ CFWL_Widget* pNextChild = GetFirstChildWidget(parent);
+ while (pNextChild) {
+ CFWL_Widget* child = pNextChild;
+ pNextChild = GetNextSiblingWidget(child);
+ if (child->GetStates() & FWL_WGTSTATE_Invisible)
+ continue;
+
+ CFX_RectF rtWidget = child->GetWidgetRect();
+ 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 (IsFormDisabled() || IsNeedRepaint(child, &widgetMatrix, rtClip))
+ pDelegate->OnDrawWidget(pGraphics, &widgetMatrix);
+ }
+ if (!bFormDisable)
+ pGraphics->RestoreGraphState();
+
+ DrawChild(child, clipBounds, pGraphics,
+ bFormDisable ? &widgetMatrix : pMatrix);
+ child = GetNextSiblingWidget(child);
+ }
+}
+
+CFX_Graphics* CFWL_WidgetMgr::DrawWidgetBefore(CFWL_Widget* pWidget,
+ CFX_Graphics* pGraphics,
+ const CFX_Matrix* pMatrix) {
+ if (!FWL_UseOffscreen(pWidget))
+ return pGraphics;
+
+ Item* pItem = GetWidgetMgrItem(pWidget);
+ if (!pItem->pOffscreen) {
+ pItem->pOffscreen.reset(new CFX_Graphics);
+ CFX_RectF rect = pWidget->GetWidgetRect();
+ 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_WidgetMgr::DrawWidgetAfter(CFWL_Widget* pWidget,
+ CFX_Graphics* pGraphics,
+ CFX_RectF& rtClip,
+ const CFX_Matrix* pMatrix) {
+ if (FWL_UseOffscreen(pWidget)) {
+ Item* pItem = GetWidgetMgrItem(pWidget);
+ pGraphics->Transfer(pItem->pOffscreen.get(), rtClip.left, rtClip.top,
+ rtClip, pMatrix);
+#ifdef _WIN32
+ pItem->pOffscreen->ClearClip();
+#endif
+ }
+ Item* pItem = GetWidgetMgrItem(pWidget);
+ pItem->iRedrawCounter = 0;
+}
+
+bool CFWL_WidgetMgr::IsNeedRepaint(CFWL_Widget* pWidget,
+ CFX_Matrix* pMatrix,
+ const CFX_RectF& rtDirty) {
+ Item* pItem = GetWidgetMgrItem(pWidget);
+ if (pItem && pItem->iRedrawCounter > 0) {
+ pItem->iRedrawCounter = 0;
+ return true;
+ }
+
+ CFX_RectF rtWidget = pWidget->GetWidgetRect();
+ rtWidget.left = rtWidget.top = 0;
+ pMatrix->TransformRect(rtWidget);
+ if (!rtWidget.IntersectWith(rtDirty))
+ return false;
+
+ CFWL_Widget* pChild =
+ pWidget->GetOwnerApp()->GetWidgetMgr()->GetFirstChildWidget(pWidget);
+ if (!pChild)
+ return true;
+
+ CFX_RectF rtChilds;
+ rtChilds.Empty();
+ bool bChildIntersectWithDirty = false;
+ bool bOrginPtIntersectWidthChild = false;
+ 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();
+ 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;
+}
+
+bool CFWL_WidgetMgr::UseOffscreenDirect(CFWL_Widget* pWidget) const {
+ Item* pItem = 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();
+ CFX_RectF temp(m_rtScreen);
+ temp.Deflate(50, 50);
+ if (!temp.Contains(r))
+ return false;
+
+ pItem->bOutsideChanged = false;
+ }
+#endif
+
+ return pItem->iRedrawCounter == 0;
+}
+
+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)
+#if (_FX_OS_ == _FX_WIN32_DESKTOP_) || (_FX_OS_ == _FX_WIN64_)
+ ,
+ bOutsideChanged(false)
+#endif
+{
+}
+
+CFWL_WidgetMgr::Item::~Item() {}