Observe CXFA_FFWidgets across OnSetFocus() events.
Although ObservedPtrs are computationally expensive, the
distance between the free and the stale pointer includes a round
trip through JS and back to C++, so returning status through all
the intervening layers would be cumbersome.
Bug: chromium:978575
Change-Id: Id4dcb40fab3bddb9ede58b986569c7cfa91c4b87
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/57110
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/cxfa_ffdocview.cpp b/xfa/fxfa/cxfa_ffdocview.cpp
index 59bc5fe..3308722 100644
--- a/xfa/fxfa/cxfa_ffdocview.cpp
+++ b/xfa/fxfa/cxfa_ffdocview.cpp
@@ -280,17 +280,22 @@
!pItem->TestStatusBits(XFA_WidgetStatus_Focused)) {
if (!pOldFocus->IsLoaded())
pOldFocus->LoadWidget();
- pOldFocus->OnSetFocus(pOldFocus);
+ if (!pOldFocus->OnSetFocus(pOldFocus))
+ pOldFocus = nullptr;
}
- pOldFocus->OnKillFocus(pNewFocus);
}
+ if (pOldFocus)
+ pOldFocus->OnKillFocus(pNewFocus);
if (pNewFocus) {
if (pNewFocus->GetLayoutItem()->TestStatusBits(XFA_WidgetStatus_Visible)) {
if (!pNewFocus->IsLoaded())
pNewFocus->LoadWidget();
- pNewFocus->OnSetFocus(pOldFocus);
+ if (!pNewFocus->OnSetFocus(pOldFocus))
+ pNewFocus = nullptr;
}
+ }
+ if (pNewFocus) {
CXFA_Node* node = pNewFocus->GetNode();
m_pFocusNode = node->IsWidgetReady() ? node : nullptr;
m_pFocusWidget = pNewFocus;
diff --git a/xfa/fxfa/cxfa_fffield.cpp b/xfa/fxfa/cxfa_fffield.cpp
index 6176b3b..b43fafc 100644
--- a/xfa/fxfa/cxfa_fffield.cpp
+++ b/xfa/fxfa/cxfa_fffield.cpp
@@ -499,7 +499,9 @@
}
bool CXFA_FFField::OnSetFocus(CXFA_FFWidget* pOldWidget) {
- CXFA_FFWidget::OnSetFocus(pOldWidget);
+ if (!CXFA_FFWidget::OnSetFocus(pOldWidget))
+ return false;
+
if (!m_pNormalWidget)
return false;
diff --git a/xfa/fxfa/cxfa_ffwidget.cpp b/xfa/fxfa/cxfa_ffwidget.cpp
index eb50185..ebcac99 100644
--- a/xfa/fxfa/cxfa_ffwidget.cpp
+++ b/xfa/fxfa/cxfa_ffwidget.cpp
@@ -394,16 +394,24 @@
}
bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) {
+ // OnSetFocus event may remove this widget.
+ ObservedPtr<CXFA_FFWidget> pWatched(this);
CXFA_FFWidget* pParent = GetFFWidget(ToContentLayoutItem(GetParent()));
if (pParent && !pParent->IsAncestorOf(pOldWidget))
pParent->OnSetFocus(pOldWidget);
+ if (!pWatched)
+ return false;
+
GetLayoutItem()->SetStatusBits(XFA_WidgetStatus_Focused);
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_Enter;
eParam.m_pTarget = m_pNode.Get();
m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Enter, &eParam);
+ if (!pWatched)
+ return false;
+
return true;
}
diff --git a/xfa/fxfa/cxfa_ffwidget.h b/xfa/fxfa/cxfa_ffwidget.h
index 48d9eed..ed868e2 100644
--- a/xfa/fxfa/cxfa_ffwidget.h
+++ b/xfa/fxfa/cxfa_ffwidget.h
@@ -11,6 +11,7 @@
#include "core/fpdfdoc/cpdf_formfield.h"
#include "core/fxcodec/fx_codec_def.h"
+#include "core/fxcrt/observed_ptr.h"
#include "core/fxge/cfx_graphstatedata.h"
#include "xfa/fwl/cfwl_app.h"
#include "xfa/fwl/cfwl_messagemouse.h"
@@ -62,7 +63,7 @@
int32_t m_iRefCount;
};
-class CXFA_FFWidget : public CFWL_Widget::AdapterIface {
+class CXFA_FFWidget : public Observable, public CFWL_Widget::AdapterIface {
public:
enum FocusOption { kDoNotDrawFocus = 0, kDrawFocus };
enum HighlightOption { kNoHighlight = 0, kHighlight };