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 };