xref: /aosp_15_r20/external/pdfium/fxjs/xfa/cjx_node.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "fxjs/xfa/cjx_node.h"
8 
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "core/fxcrt/cfx_memorystream.h"
14 #include "core/fxcrt/cfx_read_only_string_stream.h"
15 #include "core/fxcrt/fx_codepage.h"
16 #include "core/fxcrt/xml/cfx_xmldocument.h"
17 #include "core/fxcrt/xml/cfx_xmlelement.h"
18 #include "core/fxcrt/xml/cfx_xmlparser.h"
19 #include "fxjs/fxv8.h"
20 #include "fxjs/js_resources.h"
21 #include "fxjs/xfa/cfxjse_engine.h"
22 #include "v8/include/v8-object.h"
23 #include "xfa/fxfa/cxfa_eventparam.h"
24 #include "xfa/fxfa/cxfa_ffdoc.h"
25 #include "xfa/fxfa/cxfa_ffnotify.h"
26 #include "xfa/fxfa/parser/cxfa_document.h"
27 #include "xfa/fxfa/parser/cxfa_document_builder.h"
28 #include "xfa/fxfa/parser/cxfa_node.h"
29 #include "xfa/fxfa/parser/xfa_basic_data.h"
30 #include "xfa/fxfa/parser/xfa_utils.h"
31 
32 namespace {
33 
34 enum class EventAppliesTo : uint8_t {
35   kNone = 0,
36   kAll = 1,
37   kAllNonRecursive = 2,
38   kSubform = 3,
39   kFieldOrExclusion = 4,
40   kField = 5,
41   kSignature = 6,
42   kChoiceList = 7
43 };
44 
45 struct ExecEventParaInfo {
46   uint32_t m_uHash;  // hashed as wide string.
47   XFA_EVENTTYPE m_eventType;
48   EventAppliesTo m_validFlags;
49 };
50 
51 #undef PARA
52 #define PARA(a, b, c, d) a, c, EventAppliesTo::d
53 const ExecEventParaInfo kExecEventParaInfoTable[] = {
54     {PARA(0x109d7ce7, "mouseEnter", XFA_EVENT_MouseEnter, kField)},
55     {PARA(0x1bfc72d9, "preOpen", XFA_EVENT_PreOpen, kChoiceList)},
56     {PARA(0x2196a452, "initialize", XFA_EVENT_Initialize, kAll)},
57     {PARA(0x27410f03, "mouseExit", XFA_EVENT_MouseExit, kField)},
58     {PARA(0x36f1c6d8, "preSign", XFA_EVENT_PreSign, kSignature)},
59     {PARA(0x4731d6ba, "exit", XFA_EVENT_Exit, kAllNonRecursive)},
60     {PARA(0x7233018a, "validate", XFA_EVENT_Validate, kAll)},
61     {PARA(0x8808385e, "indexChange", XFA_EVENT_IndexChange, kSubform)},
62     {PARA(0x891f4606, "change", XFA_EVENT_Change, kFieldOrExclusion)},
63     {PARA(0x9f693b21, "mouseDown", XFA_EVENT_MouseDown, kField)},
64     {PARA(0xcdce56b3, "full", XFA_EVENT_Full, kFieldOrExclusion)},
65     {PARA(0xd576d08e, "mouseUp", XFA_EVENT_MouseUp, kField)},
66     {PARA(0xd95657a6, "click", XFA_EVENT_Click, kFieldOrExclusion)},
67     {PARA(0xdbfbe02e, "calculate", XFA_EVENT_Calculate, kAll)},
68     {PARA(0xe25fa7b8, "postOpen", XFA_EVENT_PostOpen, kChoiceList)},
69     {PARA(0xe28dce7e, "enter", XFA_EVENT_Enter, kAllNonRecursive)},
70     {PARA(0xfd54fbb7, "postSign", XFA_EVENT_PostSign, kSignature)},
71 };
72 #undef PARA
73 
GetExecEventParaInfoByName(WideStringView wsEventName)74 const ExecEventParaInfo* GetExecEventParaInfoByName(
75     WideStringView wsEventName) {
76   if (wsEventName.IsEmpty())
77     return nullptr;
78 
79   uint32_t uHash = FX_HashCode_GetW(wsEventName);
80   auto* result = std::lower_bound(
81       std::begin(kExecEventParaInfoTable), std::end(kExecEventParaInfoTable),
82       uHash, [](const ExecEventParaInfo& iter, const uint16_t& hash) {
83         return iter.m_uHash < hash;
84       });
85   if (result != std::end(kExecEventParaInfoTable) && result->m_uHash == uHash)
86     return result;
87   return nullptr;
88 }
89 
90 }  // namespace
91 
92 const CJX_MethodSpec CJX_Node::MethodSpecs[] = {
93     {"applyXSL", applyXSL_static},
94     {"assignNode", assignNode_static},
95     {"clone", clone_static},
96     {"getAttribute", getAttribute_static},
97     {"getElement", getElement_static},
98     {"isPropertySpecified", isPropertySpecified_static},
99     {"loadXML", loadXML_static},
100     {"saveFilteredXML", saveFilteredXML_static},
101     {"saveXML", saveXML_static},
102     {"setAttribute", setAttribute_static},
103     {"setElement", setElement_static}};
104 
CJX_Node(CXFA_Node * node)105 CJX_Node::CJX_Node(CXFA_Node* node) : CJX_Tree(node) {
106   DefineMethods(MethodSpecs);
107 }
108 
109 CJX_Node::~CJX_Node() = default;
110 
DynamicTypeIs(TypeTag eType) const111 bool CJX_Node::DynamicTypeIs(TypeTag eType) const {
112   return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
113 }
114 
applyXSL(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)115 CJS_Result CJX_Node::applyXSL(CFXJSE_Engine* runtime,
116                               const std::vector<v8::Local<v8::Value>>& params) {
117   if (params.size() != 1)
118     return CJS_Result::Failure(JSMessage::kParamError);
119 
120   // TODO(weili): check whether we need to implement this, pdfium:501.
121   return CJS_Result::Success();
122 }
123 
assignNode(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)124 CJS_Result CJX_Node::assignNode(
125     CFXJSE_Engine* runtime,
126     const std::vector<v8::Local<v8::Value>>& params) {
127   if (params.empty() || params.size() > 3)
128     return CJS_Result::Failure(JSMessage::kParamError);
129 
130   // TODO(weili): check whether we need to implement this, pdfium:501.
131   return CJS_Result::Success();
132 }
133 
clone(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)134 CJS_Result CJX_Node::clone(CFXJSE_Engine* runtime,
135                            const std::vector<v8::Local<v8::Value>>& params) {
136   if (params.size() != 1)
137     return CJS_Result::Failure(JSMessage::kParamError);
138 
139   CXFA_Node* pCloneNode = GetXFANode()->Clone(runtime->ToBoolean(params[0]));
140   return CJS_Result::Success(runtime->GetOrCreateJSBindingFromMap(pCloneNode));
141 }
142 
getAttribute(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)143 CJS_Result CJX_Node::getAttribute(
144     CFXJSE_Engine* runtime,
145     const std::vector<v8::Local<v8::Value>>& params) {
146   if (params.size() != 1)
147     return CJS_Result::Failure(JSMessage::kParamError);
148 
149   WideString expression = runtime->ToWideString(params[0]);
150   return CJS_Result::Success(runtime->NewString(
151       GetAttributeByString(expression.AsStringView()).ToUTF8().AsStringView()));
152 }
153 
getElement(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)154 CJS_Result CJX_Node::getElement(
155     CFXJSE_Engine* runtime,
156     const std::vector<v8::Local<v8::Value>>& params) {
157   if (params.empty() || params.size() > 2)
158     return CJS_Result::Failure(JSMessage::kParamError);
159 
160   WideString expression = runtime->ToWideString(params[0]);
161   int32_t iValue = params.size() >= 2 ? runtime->ToInt32(params[1]) : 0;
162   XFA_Element eElement = XFA_GetElementByName(expression.AsStringView());
163   if (eElement == XFA_Element::Unknown)
164     return CJS_Result::Success(runtime->NewNull());
165 
166   CXFA_Node* pNode = GetOrCreateProperty<CXFA_Node>(iValue, eElement);
167   if (!pNode)
168     return CJS_Result::Success(runtime->NewNull());
169 
170   return CJS_Result::Success(runtime->GetOrCreateJSBindingFromMap(pNode));
171 }
172 
isPropertySpecified(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)173 CJS_Result CJX_Node::isPropertySpecified(
174     CFXJSE_Engine* runtime,
175     const std::vector<v8::Local<v8::Value>>& params) {
176   if (params.empty() || params.size() > 3)
177     return CJS_Result::Failure(JSMessage::kParamError);
178 
179   WideString expression = runtime->ToWideString(params[0]);
180   absl::optional<XFA_ATTRIBUTEINFO> attr =
181       XFA_GetAttributeByName(expression.AsStringView());
182   if (attr.has_value() && HasAttribute(attr.value().attribute))
183     return CJS_Result::Success(runtime->NewBoolean(true));
184 
185   XFA_Element eType = XFA_GetElementByName(expression.AsStringView());
186   if (eType == XFA_Element::Unknown)
187     return CJS_Result::Success(runtime->NewBoolean(false));
188 
189   bool bParent = params.size() < 2 || runtime->ToBoolean(params[1]);
190   int32_t iIndex = params.size() == 3 ? runtime->ToInt32(params[2]) : 0;
191   bool bHas = !!GetOrCreateProperty<CXFA_Node>(iIndex, eType);
192   if (!bHas && bParent && GetXFANode()->GetParent()) {
193     // Also check on the parent.
194     auto* jsnode = GetXFANode()->GetParent()->JSObject();
195     bHas = jsnode->HasAttribute(attr.value().attribute) ||
196            !!jsnode->GetOrCreateProperty<CXFA_Node>(iIndex, eType);
197   }
198   return CJS_Result::Success(runtime->NewBoolean(bHas));
199 }
200 
loadXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)201 CJS_Result CJX_Node::loadXML(CFXJSE_Engine* runtime,
202                              const std::vector<v8::Local<v8::Value>>& params) {
203   if (params.empty() || params.size() > 3)
204     return CJS_Result::Failure(JSMessage::kParamError);
205 
206   ByteString expression = runtime->ToByteString(params[0]);
207   if (expression.IsEmpty())
208     return CJS_Result::Success();
209 
210   bool bIgnoreRoot = true;
211   if (params.size() >= 2)
212     bIgnoreRoot = runtime->ToBoolean(params[1]);
213 
214   bool bOverwrite = false;
215   if (params.size() >= 3)
216     bOverwrite = runtime->ToBoolean(params[2]);
217 
218   auto stream =
219       pdfium::MakeRetain<CFX_ReadOnlyStringStream>(std::move(expression));
220 
221   CFX_XMLParser parser(stream);
222   std::unique_ptr<CFX_XMLDocument> xml_doc = parser.Parse();
223   CXFA_DocumentBuilder builder(GetDocument());
224   CFX_XMLNode* pXMLNode = builder.Build(xml_doc.get());
225   if (!pXMLNode)
226     return CJS_Result::Success();
227 
228   CFX_XMLDocument* top_xml_doc =
229       GetXFANode()->GetDocument()->GetNotify()->GetFFDoc()->GetXMLDocument();
230   top_xml_doc->AppendNodesFrom(xml_doc.get());
231 
232   if (bIgnoreRoot &&
233       (pXMLNode->GetType() != CFX_XMLNode::Type::kElement ||
234        XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLNode)))) {
235     bIgnoreRoot = false;
236   }
237 
238   CXFA_Node* pFakeRoot = GetXFANode()->Clone(false);
239   WideString wsContentType = GetCData(XFA_Attribute::ContentType);
240   if (!wsContentType.IsEmpty()) {
241     pFakeRoot->JSObject()->SetCData(XFA_Attribute::ContentType,
242                                     WideString(wsContentType));
243   }
244 
245   CFX_XMLNode* pFakeXMLRoot = pFakeRoot->GetXMLMappingNode();
246   if (!pFakeXMLRoot) {
247     CFX_XMLNode* pThisXMLRoot = GetXFANode()->GetXMLMappingNode();
248     CFX_XMLNode* clone;
249     if (pThisXMLRoot) {
250       clone = pThisXMLRoot->Clone(top_xml_doc);
251     } else {
252       clone = top_xml_doc->CreateNode<CFX_XMLElement>(
253           WideString::FromASCII(GetXFANode()->GetClassName()));
254     }
255     pFakeXMLRoot = clone;
256   }
257 
258   if (bIgnoreRoot) {
259     CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild();
260     while (pXMLChild) {
261       CFX_XMLNode* pXMLSibling = pXMLChild->GetNextSibling();
262       pXMLNode->RemoveChild(pXMLChild);
263       pFakeXMLRoot->AppendLastChild(pXMLChild);
264       pXMLChild = pXMLSibling;
265     }
266   } else {
267     pXMLNode->RemoveSelfIfParented();
268     pFakeXMLRoot->AppendLastChild(pXMLNode);
269   }
270 
271   builder.ConstructXFANode(pFakeRoot, pFakeXMLRoot);
272   pFakeRoot = builder.GetRootNode();
273   if (!pFakeRoot)
274     return CJS_Result::Success();
275 
276   if (bOverwrite) {
277     CXFA_Node* pChild = GetXFANode()->GetFirstChild();
278     CXFA_Node* pNewChild = pFakeRoot->GetFirstChild();
279     int32_t index = 0;
280     while (pNewChild) {
281       CXFA_Node* pItem = pNewChild->GetNextSibling();
282       pFakeRoot->RemoveChildAndNotify(pNewChild, true);
283       GetXFANode()->InsertChildAndNotify(index++, pNewChild);
284       pNewChild->SetInitializedFlagAndNotify();
285       pNewChild = pItem;
286     }
287 
288     while (pChild) {
289       CXFA_Node* pItem = pChild->GetNextSibling();
290       GetXFANode()->RemoveChildAndNotify(pChild, true);
291       pFakeRoot->InsertChildAndNotify(pChild, nullptr);
292       pChild = pItem;
293     }
294 
295     if (GetXFANode()->GetPacketType() == XFA_PacketType::Form &&
296         GetXFANode()->GetElementType() == XFA_Element::ExData) {
297       CFX_XMLNode* pTempXMLNode = GetXFANode()->GetXMLMappingNode();
298       GetXFANode()->SetXMLMappingNode(pFakeXMLRoot);
299 
300       if (pTempXMLNode && !pTempXMLNode->GetParent())
301         pFakeXMLRoot = pTempXMLNode;
302       else
303         pFakeXMLRoot = nullptr;
304     }
305     MoveBufferMapData(pFakeRoot, GetXFANode());
306   } else {
307     CXFA_Node* pChild = pFakeRoot->GetFirstChild();
308     while (pChild) {
309       CXFA_Node* pItem = pChild->GetNextSibling();
310       pFakeRoot->RemoveChildAndNotify(pChild, true);
311       GetXFANode()->InsertChildAndNotify(pChild, nullptr);
312       pChild->SetInitializedFlagAndNotify();
313       pChild = pItem;
314     }
315   }
316 
317   if (pFakeXMLRoot) {
318     pFakeRoot->SetXMLMappingNode(std::move(pFakeXMLRoot));
319   }
320   pFakeRoot->SetFlag(XFA_NodeFlag::kHasRemovedChildren);
321 
322   return CJS_Result::Success();
323 }
324 
saveFilteredXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)325 CJS_Result CJX_Node::saveFilteredXML(
326     CFXJSE_Engine* runtime,
327     const std::vector<v8::Local<v8::Value>>& params) {
328   // TODO(weili): Check whether we need to implement this, pdfium:501.
329   return CJS_Result::Success();
330 }
331 
saveXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)332 CJS_Result CJX_Node::saveXML(CFXJSE_Engine* runtime,
333                              const std::vector<v8::Local<v8::Value>>& params) {
334   if (params.size() > 1)
335     return CJS_Result::Failure(JSMessage::kParamError);
336 
337   if (params.size() == 1 &&
338       !runtime->ToWideString(params[0]).EqualsASCII("pretty")) {
339     return CJS_Result::Failure(JSMessage::kValueError);
340   }
341 
342   // TODO(weili): Check whether we need to save pretty print XML, pdfium:501.
343 
344   ByteString bsXMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
345   if (GetXFANode()->GetPacketType() != XFA_PacketType::Form &&
346       GetXFANode()->GetPacketType() != XFA_PacketType::Datasets) {
347     return CJS_Result::Success(runtime->NewString(""));
348   }
349 
350   CFX_XMLNode* pElement = nullptr;
351   if (GetXFANode()->GetPacketType() == XFA_PacketType::Datasets) {
352     pElement = GetXFANode()->GetXMLMappingNode();
353     if (!pElement || pElement->GetType() != CFX_XMLNode::Type::kElement) {
354       return CJS_Result::Success(
355           runtime->NewString(bsXMLHeader.AsStringView()));
356     }
357 
358     XFA_DataExporter_DealWithDataGroupNode(GetXFANode());
359   }
360 
361   auto pMemoryStream = pdfium::MakeRetain<CFX_MemoryStream>();
362   pMemoryStream->WriteString(bsXMLHeader.AsStringView());
363 
364   if (GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
365     XFA_DataExporter_RegenerateFormFile(GetXFANode(), pMemoryStream, true);
366   } else {
367     pElement->Save(pMemoryStream);
368   }
369 
370   return CJS_Result::Success(
371       runtime->NewString(ByteStringView(pMemoryStream->GetSpan())));
372 }
373 
setAttribute(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)374 CJS_Result CJX_Node::setAttribute(
375     CFXJSE_Engine* runtime,
376     const std::vector<v8::Local<v8::Value>>& params) {
377   if (params.size() != 2)
378     return CJS_Result::Failure(JSMessage::kParamError);
379 
380   // Note: yes, arglist is spec'd absolutely backwards from what any sane
381   // person would do, namely value first, attribute second.
382   WideString attributeValue = runtime->ToWideString(params[0]);
383   WideString attribute = runtime->ToWideString(params[1]);
384 
385   // Pass them to our method, however, in the more usual manner.
386   SetAttributeByString(attribute.AsStringView(), attributeValue);
387   return CJS_Result::Success();
388 }
389 
setElement(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)390 CJS_Result CJX_Node::setElement(
391     CFXJSE_Engine* runtime,
392     const std::vector<v8::Local<v8::Value>>& params) {
393   if (params.size() != 1 && params.size() != 2)
394     return CJS_Result::Failure(JSMessage::kParamError);
395 
396   // TODO(weili): check whether we need to implement this, pdfium:501.
397   return CJS_Result::Success();
398 }
399 
ns(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)400 void CJX_Node::ns(v8::Isolate* pIsolate,
401                   v8::Local<v8::Value>* pValue,
402                   bool bSetting,
403                   XFA_Attribute eAttribute) {
404   if (bSetting) {
405     ThrowInvalidPropertyException(pIsolate);
406     return;
407   }
408   *pValue = fxv8::NewStringHelper(
409       pIsolate, TryNamespace().value_or(WideString()).ToUTF8().AsStringView());
410 }
411 
model(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)412 void CJX_Node::model(v8::Isolate* pIsolate,
413                      v8::Local<v8::Value>* pValue,
414                      bool bSetting,
415                      XFA_Attribute eAttribute) {
416   if (bSetting) {
417     ThrowInvalidPropertyException(pIsolate);
418     return;
419   }
420   CXFA_Node* pModel = GetXFANode()->GetModelNode();
421   if (!pModel) {
422     *pValue = fxv8::NewNullHelper(pIsolate);
423     return;
424   }
425   *pValue =
426       GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pModel);
427 }
428 
isContainer(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)429 void CJX_Node::isContainer(v8::Isolate* pIsolate,
430                            v8::Local<v8::Value>* pValue,
431                            bool bSetting,
432                            XFA_Attribute eAttribute) {
433   if (bSetting) {
434     ThrowInvalidPropertyException(pIsolate);
435     return;
436   }
437   *pValue = fxv8::NewBooleanHelper(pIsolate, GetXFANode()->IsContainerNode());
438 }
439 
isNull(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)440 void CJX_Node::isNull(v8::Isolate* pIsolate,
441                       v8::Local<v8::Value>* pValue,
442                       bool bSetting,
443                       XFA_Attribute eAttribute) {
444   if (bSetting) {
445     ThrowInvalidPropertyException(pIsolate);
446     return;
447   }
448   if (GetXFANode()->GetElementType() == XFA_Element::Subform) {
449     *pValue = fxv8::NewBooleanHelper(pIsolate, false);
450     return;
451   }
452   *pValue = fxv8::NewBooleanHelper(pIsolate, GetContent(false).IsEmpty());
453 }
454 
oneOfChild(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)455 void CJX_Node::oneOfChild(v8::Isolate* pIsolate,
456                           v8::Local<v8::Value>* pValue,
457                           bool bSetting,
458                           XFA_Attribute eAttribute) {
459   if (bSetting) {
460     ThrowInvalidPropertyException(pIsolate);
461     return;
462   }
463 
464   std::vector<CXFA_Node*> properties =
465       GetXFANode()->GetNodeListWithFilter(XFA_NodeFilter::kOneOfProperty);
466   if (!properties.empty()) {
467     *pValue = GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
468         properties.front());
469   }
470 }
471 
execSingleEventByName(WideStringView wsEventName,XFA_Element eType)472 XFA_EventError CJX_Node::execSingleEventByName(WideStringView wsEventName,
473                                                XFA_Element eType) {
474   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
475   if (!pNotify)
476     return XFA_EventError::kNotExist;
477 
478   const ExecEventParaInfo* eventParaInfo =
479       GetExecEventParaInfoByName(wsEventName);
480   if (!eventParaInfo)
481     return XFA_EventError::kNotExist;
482 
483   switch (eventParaInfo->m_validFlags) {
484     case EventAppliesTo::kNone:
485       return XFA_EventError::kNotExist;
486     case EventAppliesTo::kAll:
487     case EventAppliesTo::kAllNonRecursive:
488       return pNotify->ExecEventByDeepFirst(
489           GetXFANode(), eventParaInfo->m_eventType, false,
490           eventParaInfo->m_validFlags == EventAppliesTo::kAll);
491     case EventAppliesTo::kSubform:
492       if (eType != XFA_Element::Subform)
493         return XFA_EventError::kNotExist;
494 
495       return pNotify->ExecEventByDeepFirst(
496           GetXFANode(), eventParaInfo->m_eventType, false, false);
497     case EventAppliesTo::kFieldOrExclusion: {
498       if (eType != XFA_Element::ExclGroup && eType != XFA_Element::Field)
499         return XFA_EventError::kNotExist;
500 
501       CXFA_Node* pParentNode = GetXFANode()->GetParent();
502       if (pParentNode &&
503           pParentNode->GetElementType() == XFA_Element::ExclGroup) {
504         // TODO(dsinclair): This seems like a bug, we do the same work twice?
505         pNotify->ExecEventByDeepFirst(GetXFANode(), eventParaInfo->m_eventType,
506                                       false, false);
507       }
508       return pNotify->ExecEventByDeepFirst(
509           GetXFANode(), eventParaInfo->m_eventType, false, false);
510     }
511     case EventAppliesTo::kField:
512       if (eType != XFA_Element::Field)
513         return XFA_EventError::kNotExist;
514 
515       return pNotify->ExecEventByDeepFirst(
516           GetXFANode(), eventParaInfo->m_eventType, false, false);
517     case EventAppliesTo::kSignature: {
518       if (!GetXFANode()->IsWidgetReady())
519         return XFA_EventError::kNotExist;
520       if (GetXFANode()->GetUIChildNode()->GetElementType() !=
521           XFA_Element::Signature) {
522         return XFA_EventError::kNotExist;
523       }
524       return pNotify->ExecEventByDeepFirst(
525           GetXFANode(), eventParaInfo->m_eventType, false, false);
526     }
527     case EventAppliesTo::kChoiceList: {
528       if (!GetXFANode()->IsWidgetReady())
529         return XFA_EventError::kNotExist;
530       if (GetXFANode()->GetUIChildNode()->GetElementType() !=
531           XFA_Element::ChoiceList) {
532         return XFA_EventError::kNotExist;
533       }
534       return pNotify->ExecEventByDeepFirst(
535           GetXFANode(), eventParaInfo->m_eventType, false, false);
536     }
537   }
538   return XFA_EventError::kNotExist;
539 }
540