• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(
141       GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
142           pCloneNode));
143 }
144 
getAttribute(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)145 CJS_Result CJX_Node::getAttribute(
146     CFXJSE_Engine* runtime,
147     const std::vector<v8::Local<v8::Value>>& params) {
148   if (params.size() != 1)
149     return CJS_Result::Failure(JSMessage::kParamError);
150 
151   WideString expression = runtime->ToWideString(params[0]);
152   return CJS_Result::Success(runtime->NewString(
153       GetAttributeByString(expression.AsStringView()).ToUTF8().AsStringView()));
154 }
155 
getElement(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)156 CJS_Result CJX_Node::getElement(
157     CFXJSE_Engine* runtime,
158     const std::vector<v8::Local<v8::Value>>& params) {
159   if (params.empty() || params.size() > 2)
160     return CJS_Result::Failure(JSMessage::kParamError);
161 
162   WideString expression = runtime->ToWideString(params[0]);
163   int32_t iValue = params.size() >= 2 ? runtime->ToInt32(params[1]) : 0;
164   XFA_Element eElement = XFA_GetElementByName(expression.AsStringView());
165   if (eElement == XFA_Element::Unknown)
166     return CJS_Result::Success(runtime->NewNull());
167 
168   CXFA_Node* pNode = GetOrCreateProperty<CXFA_Node>(iValue, eElement);
169   if (!pNode)
170     return CJS_Result::Success(runtime->NewNull());
171 
172   return CJS_Result::Success(
173       GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pNode));
174 }
175 
isPropertySpecified(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)176 CJS_Result CJX_Node::isPropertySpecified(
177     CFXJSE_Engine* runtime,
178     const std::vector<v8::Local<v8::Value>>& params) {
179   if (params.empty() || params.size() > 3)
180     return CJS_Result::Failure(JSMessage::kParamError);
181 
182   WideString expression = runtime->ToWideString(params[0]);
183   absl::optional<XFA_ATTRIBUTEINFO> attr =
184       XFA_GetAttributeByName(expression.AsStringView());
185   if (attr.has_value() && HasAttribute(attr.value().attribute))
186     return CJS_Result::Success(runtime->NewBoolean(true));
187 
188   XFA_Element eType = XFA_GetElementByName(expression.AsStringView());
189   if (eType == XFA_Element::Unknown)
190     return CJS_Result::Success(runtime->NewBoolean(false));
191 
192   bool bParent = params.size() < 2 || runtime->ToBoolean(params[1]);
193   int32_t iIndex = params.size() == 3 ? runtime->ToInt32(params[2]) : 0;
194   bool bHas = !!GetOrCreateProperty<CXFA_Node>(iIndex, eType);
195   if (!bHas && bParent && GetXFANode()->GetParent()) {
196     // Also check on the parent.
197     auto* jsnode = GetXFANode()->GetParent()->JSObject();
198     bHas = jsnode->HasAttribute(attr.value().attribute) ||
199            !!jsnode->GetOrCreateProperty<CXFA_Node>(iIndex, eType);
200   }
201   return CJS_Result::Success(runtime->NewBoolean(bHas));
202 }
203 
loadXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)204 CJS_Result CJX_Node::loadXML(CFXJSE_Engine* runtime,
205                              const std::vector<v8::Local<v8::Value>>& params) {
206   if (params.empty() || params.size() > 3)
207     return CJS_Result::Failure(JSMessage::kParamError);
208 
209   ByteString expression = runtime->ToByteString(params[0]);
210   if (expression.IsEmpty())
211     return CJS_Result::Success();
212 
213   bool bIgnoreRoot = true;
214   if (params.size() >= 2)
215     bIgnoreRoot = runtime->ToBoolean(params[1]);
216 
217   bool bOverwrite = false;
218   if (params.size() >= 3)
219     bOverwrite = runtime->ToBoolean(params[2]);
220 
221   auto stream =
222       pdfium::MakeRetain<CFX_ReadOnlyStringStream>(std::move(expression));
223 
224   CFX_XMLParser parser(stream);
225   std::unique_ptr<CFX_XMLDocument> xml_doc = parser.Parse();
226   CXFA_DocumentBuilder builder(GetDocument());
227   CFX_XMLNode* pXMLNode = builder.Build(xml_doc.get());
228   if (!pXMLNode)
229     return CJS_Result::Success();
230 
231   CFX_XMLDocument* top_xml_doc =
232       GetXFANode()->GetDocument()->GetNotify()->GetFFDoc()->GetXMLDocument();
233   top_xml_doc->AppendNodesFrom(xml_doc.get());
234 
235   if (bIgnoreRoot &&
236       (pXMLNode->GetType() != CFX_XMLNode::Type::kElement ||
237        XFA_RecognizeRichText(static_cast<CFX_XMLElement*>(pXMLNode)))) {
238     bIgnoreRoot = false;
239   }
240 
241   CXFA_Node* pFakeRoot = GetXFANode()->Clone(false);
242   WideString wsContentType = GetCData(XFA_Attribute::ContentType);
243   if (!wsContentType.IsEmpty()) {
244     pFakeRoot->JSObject()->SetCData(XFA_Attribute::ContentType,
245                                     WideString(wsContentType));
246   }
247 
248   CFX_XMLNode* pFakeXMLRoot = pFakeRoot->GetXMLMappingNode();
249   if (!pFakeXMLRoot) {
250     CFX_XMLNode* pThisXMLRoot = GetXFANode()->GetXMLMappingNode();
251     CFX_XMLNode* clone;
252     if (pThisXMLRoot) {
253       clone = pThisXMLRoot->Clone(top_xml_doc);
254     } else {
255       clone = top_xml_doc->CreateNode<CFX_XMLElement>(
256           WideString::FromASCII(GetXFANode()->GetClassName()));
257     }
258     pFakeXMLRoot = clone;
259   }
260 
261   if (bIgnoreRoot) {
262     CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild();
263     while (pXMLChild) {
264       CFX_XMLNode* pXMLSibling = pXMLChild->GetNextSibling();
265       pXMLNode->RemoveChild(pXMLChild);
266       pFakeXMLRoot->AppendLastChild(pXMLChild);
267       pXMLChild = pXMLSibling;
268     }
269   } else {
270     pXMLNode->RemoveSelfIfParented();
271     pFakeXMLRoot->AppendLastChild(pXMLNode);
272   }
273 
274   builder.ConstructXFANode(pFakeRoot, pFakeXMLRoot);
275   pFakeRoot = builder.GetRootNode();
276   if (!pFakeRoot)
277     return CJS_Result::Success();
278 
279   if (bOverwrite) {
280     CXFA_Node* pChild = GetXFANode()->GetFirstChild();
281     CXFA_Node* pNewChild = pFakeRoot->GetFirstChild();
282     int32_t index = 0;
283     while (pNewChild) {
284       CXFA_Node* pItem = pNewChild->GetNextSibling();
285       pFakeRoot->RemoveChildAndNotify(pNewChild, true);
286       GetXFANode()->InsertChildAndNotify(index++, pNewChild);
287       pNewChild->SetInitializedFlagAndNotify();
288       pNewChild = pItem;
289     }
290 
291     while (pChild) {
292       CXFA_Node* pItem = pChild->GetNextSibling();
293       GetXFANode()->RemoveChildAndNotify(pChild, true);
294       pFakeRoot->InsertChildAndNotify(pChild, nullptr);
295       pChild = pItem;
296     }
297 
298     if (GetXFANode()->GetPacketType() == XFA_PacketType::Form &&
299         GetXFANode()->GetElementType() == XFA_Element::ExData) {
300       CFX_XMLNode* pTempXMLNode = GetXFANode()->GetXMLMappingNode();
301       GetXFANode()->SetXMLMappingNode(pFakeXMLRoot);
302 
303       if (pTempXMLNode && !pTempXMLNode->GetParent())
304         pFakeXMLRoot = pTempXMLNode;
305       else
306         pFakeXMLRoot = nullptr;
307     }
308     MoveBufferMapData(pFakeRoot, GetXFANode());
309   } else {
310     CXFA_Node* pChild = pFakeRoot->GetFirstChild();
311     while (pChild) {
312       CXFA_Node* pItem = pChild->GetNextSibling();
313       pFakeRoot->RemoveChildAndNotify(pChild, true);
314       GetXFANode()->InsertChildAndNotify(pChild, nullptr);
315       pChild->SetInitializedFlagAndNotify();
316       pChild = pItem;
317     }
318   }
319 
320   if (pFakeXMLRoot) {
321     pFakeRoot->SetXMLMappingNode(std::move(pFakeXMLRoot));
322   }
323   pFakeRoot->SetFlag(XFA_NodeFlag::kHasRemovedChildren);
324 
325   return CJS_Result::Success();
326 }
327 
saveFilteredXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)328 CJS_Result CJX_Node::saveFilteredXML(
329     CFXJSE_Engine* runtime,
330     const std::vector<v8::Local<v8::Value>>& params) {
331   // TODO(weili): Check whether we need to implement this, pdfium:501.
332   return CJS_Result::Success();
333 }
334 
saveXML(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)335 CJS_Result CJX_Node::saveXML(CFXJSE_Engine* runtime,
336                              const std::vector<v8::Local<v8::Value>>& params) {
337   if (params.size() > 1)
338     return CJS_Result::Failure(JSMessage::kParamError);
339 
340   if (params.size() == 1 &&
341       !runtime->ToWideString(params[0]).EqualsASCII("pretty")) {
342     return CJS_Result::Failure(JSMessage::kValueError);
343   }
344 
345   // TODO(weili): Check whether we need to save pretty print XML, pdfium:501.
346 
347   ByteString bsXMLHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
348   if (GetXFANode()->GetPacketType() != XFA_PacketType::Form &&
349       GetXFANode()->GetPacketType() != XFA_PacketType::Datasets) {
350     return CJS_Result::Success(runtime->NewString(""));
351   }
352 
353   CFX_XMLNode* pElement = nullptr;
354   if (GetXFANode()->GetPacketType() == XFA_PacketType::Datasets) {
355     pElement = GetXFANode()->GetXMLMappingNode();
356     if (!pElement || pElement->GetType() != CFX_XMLNode::Type::kElement) {
357       return CJS_Result::Success(
358           runtime->NewString(bsXMLHeader.AsStringView()));
359     }
360 
361     XFA_DataExporter_DealWithDataGroupNode(GetXFANode());
362   }
363 
364   auto pMemoryStream = pdfium::MakeRetain<CFX_MemoryStream>();
365   pMemoryStream->WriteString(bsXMLHeader.AsStringView());
366 
367   if (GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
368     XFA_DataExporter_RegenerateFormFile(GetXFANode(), pMemoryStream, true);
369   } else {
370     pElement->Save(pMemoryStream);
371   }
372 
373   return CJS_Result::Success(
374       runtime->NewString(ByteStringView(pMemoryStream->GetSpan())));
375 }
376 
setAttribute(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)377 CJS_Result CJX_Node::setAttribute(
378     CFXJSE_Engine* runtime,
379     const std::vector<v8::Local<v8::Value>>& params) {
380   if (params.size() != 2)
381     return CJS_Result::Failure(JSMessage::kParamError);
382 
383   // Note: yes, arglist is spec'd absolutely backwards from what any sane
384   // person would do, namely value first, attribute second.
385   WideString attributeValue = runtime->ToWideString(params[0]);
386   WideString attribute = runtime->ToWideString(params[1]);
387 
388   // Pass them to our method, however, in the more usual manner.
389   SetAttributeByString(attribute.AsStringView(), attributeValue);
390   return CJS_Result::Success();
391 }
392 
setElement(CFXJSE_Engine * runtime,const std::vector<v8::Local<v8::Value>> & params)393 CJS_Result CJX_Node::setElement(
394     CFXJSE_Engine* runtime,
395     const std::vector<v8::Local<v8::Value>>& params) {
396   if (params.size() != 1 && params.size() != 2)
397     return CJS_Result::Failure(JSMessage::kParamError);
398 
399   // TODO(weili): check whether we need to implement this, pdfium:501.
400   return CJS_Result::Success();
401 }
402 
ns(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)403 void CJX_Node::ns(v8::Isolate* pIsolate,
404                   v8::Local<v8::Value>* pValue,
405                   bool bSetting,
406                   XFA_Attribute eAttribute) {
407   if (bSetting) {
408     ThrowInvalidPropertyException(pIsolate);
409     return;
410   }
411   *pValue = fxv8::NewStringHelper(
412       pIsolate, TryNamespace().value_or(WideString()).ToUTF8().AsStringView());
413 }
414 
model(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)415 void CJX_Node::model(v8::Isolate* pIsolate,
416                      v8::Local<v8::Value>* pValue,
417                      bool bSetting,
418                      XFA_Attribute eAttribute) {
419   if (bSetting) {
420     ThrowInvalidPropertyException(pIsolate);
421     return;
422   }
423   CXFA_Node* pModel = GetXFANode()->GetModelNode();
424   if (!pModel) {
425     *pValue = fxv8::NewNullHelper(pIsolate);
426     return;
427   }
428   *pValue =
429       GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pModel);
430 }
431 
isContainer(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)432 void CJX_Node::isContainer(v8::Isolate* pIsolate,
433                            v8::Local<v8::Value>* pValue,
434                            bool bSetting,
435                            XFA_Attribute eAttribute) {
436   if (bSetting) {
437     ThrowInvalidPropertyException(pIsolate);
438     return;
439   }
440   *pValue = fxv8::NewBooleanHelper(pIsolate, GetXFANode()->IsContainerNode());
441 }
442 
isNull(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)443 void CJX_Node::isNull(v8::Isolate* pIsolate,
444                       v8::Local<v8::Value>* pValue,
445                       bool bSetting,
446                       XFA_Attribute eAttribute) {
447   if (bSetting) {
448     ThrowInvalidPropertyException(pIsolate);
449     return;
450   }
451   if (GetXFANode()->GetElementType() == XFA_Element::Subform) {
452     *pValue = fxv8::NewBooleanHelper(pIsolate, false);
453     return;
454   }
455   *pValue = fxv8::NewBooleanHelper(pIsolate, GetContent(false).IsEmpty());
456 }
457 
oneOfChild(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)458 void CJX_Node::oneOfChild(v8::Isolate* pIsolate,
459                           v8::Local<v8::Value>* pValue,
460                           bool bSetting,
461                           XFA_Attribute eAttribute) {
462   if (bSetting) {
463     ThrowInvalidPropertyException(pIsolate);
464     return;
465   }
466 
467   std::vector<CXFA_Node*> properties =
468       GetXFANode()->GetNodeListWithFilter(XFA_NodeFilter::kOneOfProperty);
469   if (!properties.empty()) {
470     *pValue = GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
471         properties.front());
472   }
473 }
474 
execSingleEventByName(WideStringView wsEventName,XFA_Element eType)475 XFA_EventError CJX_Node::execSingleEventByName(WideStringView wsEventName,
476                                                XFA_Element eType) {
477   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
478   if (!pNotify)
479     return XFA_EventError::kNotExist;
480 
481   const ExecEventParaInfo* eventParaInfo =
482       GetExecEventParaInfoByName(wsEventName);
483   if (!eventParaInfo)
484     return XFA_EventError::kNotExist;
485 
486   switch (eventParaInfo->m_validFlags) {
487     case EventAppliesTo::kNone:
488       return XFA_EventError::kNotExist;
489     case EventAppliesTo::kAll:
490     case EventAppliesTo::kAllNonRecursive:
491       return pNotify->ExecEventByDeepFirst(
492           GetXFANode(), eventParaInfo->m_eventType, false,
493           eventParaInfo->m_validFlags == EventAppliesTo::kAll);
494     case EventAppliesTo::kSubform:
495       if (eType != XFA_Element::Subform)
496         return XFA_EventError::kNotExist;
497 
498       return pNotify->ExecEventByDeepFirst(
499           GetXFANode(), eventParaInfo->m_eventType, false, false);
500     case EventAppliesTo::kFieldOrExclusion: {
501       if (eType != XFA_Element::ExclGroup && eType != XFA_Element::Field)
502         return XFA_EventError::kNotExist;
503 
504       CXFA_Node* pParentNode = GetXFANode()->GetParent();
505       if (pParentNode &&
506           pParentNode->GetElementType() == XFA_Element::ExclGroup) {
507         // TODO(dsinclair): This seems like a bug, we do the same work twice?
508         pNotify->ExecEventByDeepFirst(GetXFANode(), eventParaInfo->m_eventType,
509                                       false, false);
510       }
511       return pNotify->ExecEventByDeepFirst(
512           GetXFANode(), eventParaInfo->m_eventType, false, false);
513     }
514     case EventAppliesTo::kField:
515       if (eType != XFA_Element::Field)
516         return XFA_EventError::kNotExist;
517 
518       return pNotify->ExecEventByDeepFirst(
519           GetXFANode(), eventParaInfo->m_eventType, false, false);
520     case EventAppliesTo::kSignature: {
521       if (!GetXFANode()->IsWidgetReady())
522         return XFA_EventError::kNotExist;
523       if (GetXFANode()->GetUIChildNode()->GetElementType() !=
524           XFA_Element::Signature) {
525         return XFA_EventError::kNotExist;
526       }
527       return pNotify->ExecEventByDeepFirst(
528           GetXFANode(), eventParaInfo->m_eventType, false, false);
529     }
530     case EventAppliesTo::kChoiceList: {
531       if (!GetXFANode()->IsWidgetReady())
532         return XFA_EventError::kNotExist;
533       if (GetXFANode()->GetUIChildNode()->GetElementType() !=
534           XFA_Element::ChoiceList) {
535         return XFA_EventError::kNotExist;
536       }
537       return pNotify->ExecEventByDeepFirst(
538           GetXFANode(), eventParaInfo->m_eventType, false, false);
539     }
540   }
541   return XFA_EventError::kNotExist;
542 }
543