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