1 // Copyright 2014 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 "xfa/fxfa/cxfa_textprovider.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <vector>
12 
13 #include "core/fxcrt/xml/cfx_xmlelement.h"
14 #include "core/fxcrt/xml/cfx_xmlnode.h"
15 #include "fxjs/xfa/cfxjse_engine.h"
16 #include "fxjs/xfa/cfxjse_value.h"
17 #include "fxjs/xfa/cjx_object.h"
18 #include "xfa/fde/cfde_textout.h"
19 #include "xfa/fxfa/cxfa_eventparam.h"
20 #include "xfa/fxfa/cxfa_ffapp.h"
21 #include "xfa/fxfa/cxfa_ffcheckbutton.h"
22 #include "xfa/fxfa/cxfa_ffdoc.h"
23 #include "xfa/fxfa/cxfa_ffdocview.h"
24 #include "xfa/fxfa/cxfa_fffield.h"
25 #include "xfa/fxfa/cxfa_ffpageview.h"
26 #include "xfa/fxfa/cxfa_ffwidget.h"
27 #include "xfa/fxfa/cxfa_fontmgr.h"
28 #include "xfa/fxfa/cxfa_fwladapterwidgetmgr.h"
29 #include "xfa/fxfa/parser/cxfa_caption.h"
30 #include "xfa/fxfa/parser/cxfa_font.h"
31 #include "xfa/fxfa/parser/cxfa_items.h"
32 #include "xfa/fxfa/parser/cxfa_localevalue.h"
33 #include "xfa/fxfa/parser/cxfa_node.h"
34 #include "xfa/fxfa/parser/cxfa_para.h"
35 #include "xfa/fxfa/parser/cxfa_value.h"
36 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
37 #include "xfa/fxfa/parser/xfa_utils.h"
38 
GetTextNode(bool * bRichText)39 CXFA_Node* CXFA_TextProvider::GetTextNode(bool* bRichText) {
40   *bRichText = false;
41   if (m_eType == XFA_TEXTPROVIDERTYPE_Text) {
42     CXFA_Value* pValueNode =
43         m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
44     if (!pValueNode)
45       return nullptr;
46 
47     CXFA_Node* pChildNode = pValueNode->GetFirstChild();
48     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
49       Optional<WideString> contentType = pChildNode->JSObject()->TryAttribute(
50           XFA_Attribute::ContentType, false);
51       if (contentType.has_value() &&
52           contentType.value().EqualsASCII("text/html")) {
53         *bRichText = true;
54       }
55     }
56     return pChildNode;
57   }
58 
59   if (m_eType == XFA_TEXTPROVIDERTYPE_Datasets) {
60     CXFA_Node* pBind = m_pNode->GetBindData();
61     CFX_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
62     for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
63          pXMLChild = pXMLChild->GetNextSibling()) {
64       CFX_XMLElement* pElement = ToXMLElement(pXMLChild);
65       if (pElement && XFA_RecognizeRichText(pElement)) {
66         *bRichText = true;
67         break;
68       }
69     }
70     return pBind;
71   }
72 
73   if (m_eType == XFA_TEXTPROVIDERTYPE_Caption) {
74     CXFA_Caption* pCaptionNode =
75         m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
76     if (!pCaptionNode)
77       return nullptr;
78 
79     CXFA_Value* pValueNode =
80         pCaptionNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
81     if (!pValueNode)
82       return nullptr;
83 
84     CXFA_Node* pChildNode = pValueNode->GetFirstChild();
85     if (pChildNode && pChildNode->GetElementType() == XFA_Element::ExData) {
86       Optional<WideString> contentType = pChildNode->JSObject()->TryAttribute(
87           XFA_Attribute::ContentType, false);
88       if (contentType.has_value() &&
89           contentType.value().EqualsASCII("text/html")) {
90         *bRichText = true;
91       }
92     }
93     return pChildNode;
94   }
95 
96   CXFA_Items* pItemNode =
97       m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
98   if (!pItemNode)
99     return nullptr;
100 
101   CXFA_Node* pNode = pItemNode->GetFirstChild();
102   while (pNode) {
103     WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
104     if (m_eType == XFA_TEXTPROVIDERTYPE_Rollover &&
105         wsName.EqualsASCII("rollover")) {
106       return pNode;
107     }
108     if (m_eType == XFA_TEXTPROVIDERTYPE_Down && wsName.EqualsASCII("down"))
109       return pNode;
110 
111     pNode = pNode->GetNextSibling();
112   }
113   return nullptr;
114 }
115 
GetParaIfExists()116 CXFA_Para* CXFA_TextProvider::GetParaIfExists() {
117   if (m_eType == XFA_TEXTPROVIDERTYPE_Text)
118     return m_pNode->GetParaIfExists();
119 
120   CXFA_Caption* pNode =
121       m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
122   return pNode->GetChild<CXFA_Para>(0, XFA_Element::Para, false);
123 }
124 
GetFontIfExists()125 CXFA_Font* CXFA_TextProvider::GetFontIfExists() {
126   if (m_eType == XFA_TEXTPROVIDERTYPE_Text)
127     return m_pNode->GetFontIfExists();
128 
129   CXFA_Caption* pNode =
130       m_pNode->GetChild<CXFA_Caption>(0, XFA_Element::Caption, false);
131   CXFA_Font* font = pNode->GetChild<CXFA_Font>(0, XFA_Element::Font, false);
132   return font ? font : m_pNode->GetFontIfExists();
133 }
134 
IsCheckButtonAndAutoWidth() const135 bool CXFA_TextProvider::IsCheckButtonAndAutoWidth() const {
136   if (m_pNode->GetFFWidgetType() != XFA_FFWidgetType::kCheckButton)
137     return false;
138   return !m_pNode->TryWidth();
139 }
140 
GetEmbeddedObj(const WideString & wsAttr) const141 Optional<WideString> CXFA_TextProvider::GetEmbeddedObj(
142     const WideString& wsAttr) const {
143   if (m_eType != XFA_TEXTPROVIDERTYPE_Text)
144     return {};
145 
146   CXFA_Node* pParent = m_pNode->GetParent();
147   CXFA_Document* pDocument = m_pNode->GetDocument();
148   CXFA_Node* pIDNode = nullptr;
149   if (pParent)
150     pIDNode = pDocument->GetNodeByID(pParent, wsAttr.AsStringView());
151 
152   if (!pIDNode) {
153     pIDNode = pDocument->GetNodeByID(
154         ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Form)),
155         wsAttr.AsStringView());
156   }
157   if (!pIDNode || !pIDNode->IsWidgetReady())
158     return {};
159 
160   return pIDNode->GetValue(XFA_VALUEPICTURE_Display);
161 }
162