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