xref: /aosp_15_r20/external/pdfium/xfa/fxfa/cxfa_textparser.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2017 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textparser.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
10*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
11*3ac0a46fSAndroid Build Coastguard Worker 
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_css.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_csscomputedstyle.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_cssdeclaration.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_cssstyleselector.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/css/cfx_cssstylesheet.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_codepage.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlelement.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/xml/cfx_xmlnode.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/fx_font.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/notreached.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/font/cfgas_fontmgr.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/font/cfgas_gefont.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffapp.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_ffdoc.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_fontmgr.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_textprovider.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/cxfa_texttabstopscontext.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_font.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_measurement.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fxfa/parser/cxfa_para.h"
33*3ac0a46fSAndroid Build Coastguard Worker 
34*3ac0a46fSAndroid Build Coastguard Worker namespace {
35*3ac0a46fSAndroid Build Coastguard Worker 
36*3ac0a46fSAndroid Build Coastguard Worker enum class TabStopStatus {
37*3ac0a46fSAndroid Build Coastguard Worker   Error,
38*3ac0a46fSAndroid Build Coastguard Worker   EOS,
39*3ac0a46fSAndroid Build Coastguard Worker   None,
40*3ac0a46fSAndroid Build Coastguard Worker   Alignment,
41*3ac0a46fSAndroid Build Coastguard Worker   StartLeader,
42*3ac0a46fSAndroid Build Coastguard Worker   Leader,
43*3ac0a46fSAndroid Build Coastguard Worker   Location,
44*3ac0a46fSAndroid Build Coastguard Worker };
45*3ac0a46fSAndroid Build Coastguard Worker 
GetLowerCaseElementAttributeOrDefault(const CFX_XMLElement * pElement,const WideString & wsName,const WideString & wsDefaultValue)46*3ac0a46fSAndroid Build Coastguard Worker WideString GetLowerCaseElementAttributeOrDefault(
47*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLElement* pElement,
48*3ac0a46fSAndroid Build Coastguard Worker     const WideString& wsName,
49*3ac0a46fSAndroid Build Coastguard Worker     const WideString& wsDefaultValue) {
50*3ac0a46fSAndroid Build Coastguard Worker   WideString ws = pElement->GetAttribute(wsName);
51*3ac0a46fSAndroid Build Coastguard Worker   if (ws.IsEmpty())
52*3ac0a46fSAndroid Build Coastguard Worker     ws = wsDefaultValue;
53*3ac0a46fSAndroid Build Coastguard Worker   else
54*3ac0a46fSAndroid Build Coastguard Worker     ws.MakeLower();
55*3ac0a46fSAndroid Build Coastguard Worker   return ws;
56*3ac0a46fSAndroid Build Coastguard Worker }
57*3ac0a46fSAndroid Build Coastguard Worker 
58*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
59*3ac0a46fSAndroid Build Coastguard Worker 
60*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::CXFA_TextParser() = default;
61*3ac0a46fSAndroid Build Coastguard Worker 
62*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::~CXFA_TextParser() = default;
63*3ac0a46fSAndroid Build Coastguard Worker 
Reset()64*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::Reset() {
65*3ac0a46fSAndroid Build Coastguard Worker   m_mapXMLNodeToParseContext.clear();
66*3ac0a46fSAndroid Build Coastguard Worker   m_bParsed = false;
67*3ac0a46fSAndroid Build Coastguard Worker }
68*3ac0a46fSAndroid Build Coastguard Worker 
InitCSSData(CXFA_TextProvider * pTextProvider)69*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::InitCSSData(CXFA_TextProvider* pTextProvider) {
70*3ac0a46fSAndroid Build Coastguard Worker   if (!pTextProvider)
71*3ac0a46fSAndroid Build Coastguard Worker     return;
72*3ac0a46fSAndroid Build Coastguard Worker 
73*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pSelector) {
74*3ac0a46fSAndroid Build Coastguard Worker     m_pSelector = std::make_unique<CFX_CSSStyleSelector>();
75*3ac0a46fSAndroid Build Coastguard Worker 
76*3ac0a46fSAndroid Build Coastguard Worker     CXFA_Font* font = pTextProvider->GetFontIfExists();
77*3ac0a46fSAndroid Build Coastguard Worker     m_pSelector->SetDefaultFontSize(font ? font->GetFontSize() : 10.0f);
78*3ac0a46fSAndroid Build Coastguard Worker   }
79*3ac0a46fSAndroid Build Coastguard Worker 
80*3ac0a46fSAndroid Build Coastguard Worker   if (m_cssInitialized)
81*3ac0a46fSAndroid Build Coastguard Worker     return;
82*3ac0a46fSAndroid Build Coastguard Worker 
83*3ac0a46fSAndroid Build Coastguard Worker   m_cssInitialized = true;
84*3ac0a46fSAndroid Build Coastguard Worker   auto uaSheet = LoadDefaultSheetStyle();
85*3ac0a46fSAndroid Build Coastguard Worker   m_pSelector->SetUAStyleSheet(std::move(uaSheet));
86*3ac0a46fSAndroid Build Coastguard Worker   m_pSelector->UpdateStyleIndex();
87*3ac0a46fSAndroid Build Coastguard Worker }
88*3ac0a46fSAndroid Build Coastguard Worker 
LoadDefaultSheetStyle()89*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CFX_CSSStyleSheet> CXFA_TextParser::LoadDefaultSheetStyle() {
90*3ac0a46fSAndroid Build Coastguard Worker   static const char kStyle[] =
91*3ac0a46fSAndroid Build Coastguard Worker       "html,body,ol,p,ul{display:block}"
92*3ac0a46fSAndroid Build Coastguard Worker       "li{display:list-item}"
93*3ac0a46fSAndroid Build Coastguard Worker       "ol,ul{padding-left:33px;margin:1.12em 0}"
94*3ac0a46fSAndroid Build Coastguard Worker       "ol{list-style-type:decimal}"
95*3ac0a46fSAndroid Build Coastguard Worker       "a{color:#0000ff;text-decoration:underline}"
96*3ac0a46fSAndroid Build Coastguard Worker       "b{font-weight:bolder}"
97*3ac0a46fSAndroid Build Coastguard Worker       "i{font-style:italic}"
98*3ac0a46fSAndroid Build Coastguard Worker       "sup{vertical-align:+15em;font-size:.66em}"
99*3ac0a46fSAndroid Build Coastguard Worker       "sub{vertical-align:-15em;font-size:.66em}";
100*3ac0a46fSAndroid Build Coastguard Worker   WideString ws = WideString::FromASCII(kStyle);
101*3ac0a46fSAndroid Build Coastguard Worker   auto sheet = std::make_unique<CFX_CSSStyleSheet>();
102*3ac0a46fSAndroid Build Coastguard Worker   if (!sheet->LoadBuffer(ws.AsStringView()))
103*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
104*3ac0a46fSAndroid Build Coastguard Worker 
105*3ac0a46fSAndroid Build Coastguard Worker   return sheet;
106*3ac0a46fSAndroid Build Coastguard Worker }
107*3ac0a46fSAndroid Build Coastguard Worker 
CreateRootStyle(CXFA_TextProvider * pTextProvider)108*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_CSSComputedStyle> CXFA_TextParser::CreateRootStyle(
109*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider) {
110*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Para* para = pTextProvider->GetParaIfExists();
111*3ac0a46fSAndroid Build Coastguard Worker   auto pStyle = m_pSelector->CreateComputedStyle(nullptr);
112*3ac0a46fSAndroid Build Coastguard Worker   float fLineHeight = 0;
113*3ac0a46fSAndroid Build Coastguard Worker   float fFontSize = 10;
114*3ac0a46fSAndroid Build Coastguard Worker 
115*3ac0a46fSAndroid Build Coastguard Worker   if (para) {
116*3ac0a46fSAndroid Build Coastguard Worker     fLineHeight = para->GetLineHeight();
117*3ac0a46fSAndroid Build Coastguard Worker     CFX_CSSLength indent;
118*3ac0a46fSAndroid Build Coastguard Worker     indent.Set(CFX_CSSLengthUnit::Point, para->GetTextIndent());
119*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetTextIndent(indent);
120*3ac0a46fSAndroid Build Coastguard Worker     CFX_CSSTextAlign hAlign = CFX_CSSTextAlign::Left;
121*3ac0a46fSAndroid Build Coastguard Worker     switch (para->GetHorizontalAlign()) {
122*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Center:
123*3ac0a46fSAndroid Build Coastguard Worker         hAlign = CFX_CSSTextAlign::Center;
124*3ac0a46fSAndroid Build Coastguard Worker         break;
125*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Right:
126*3ac0a46fSAndroid Build Coastguard Worker         hAlign = CFX_CSSTextAlign::Right;
127*3ac0a46fSAndroid Build Coastguard Worker         break;
128*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Justify:
129*3ac0a46fSAndroid Build Coastguard Worker         hAlign = CFX_CSSTextAlign::Justify;
130*3ac0a46fSAndroid Build Coastguard Worker         break;
131*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::JustifyAll:
132*3ac0a46fSAndroid Build Coastguard Worker         hAlign = CFX_CSSTextAlign::JustifyAll;
133*3ac0a46fSAndroid Build Coastguard Worker         break;
134*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Left:
135*3ac0a46fSAndroid Build Coastguard Worker       case XFA_AttributeValue::Radix:
136*3ac0a46fSAndroid Build Coastguard Worker         break;
137*3ac0a46fSAndroid Build Coastguard Worker       default:
138*3ac0a46fSAndroid Build Coastguard Worker         NOTREACHED_NORETURN();
139*3ac0a46fSAndroid Build Coastguard Worker     }
140*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetTextAlign(hAlign);
141*3ac0a46fSAndroid Build Coastguard Worker     CFX_CSSRect rtMarginWidth;
142*3ac0a46fSAndroid Build Coastguard Worker     rtMarginWidth.left.Set(CFX_CSSLengthUnit::Point, para->GetMarginLeft());
143*3ac0a46fSAndroid Build Coastguard Worker     rtMarginWidth.top.Set(CFX_CSSLengthUnit::Point, para->GetSpaceAbove());
144*3ac0a46fSAndroid Build Coastguard Worker     rtMarginWidth.right.Set(CFX_CSSLengthUnit::Point, para->GetMarginRight());
145*3ac0a46fSAndroid Build Coastguard Worker     rtMarginWidth.bottom.Set(CFX_CSSLengthUnit::Point, para->GetSpaceBelow());
146*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetMarginWidth(rtMarginWidth);
147*3ac0a46fSAndroid Build Coastguard Worker   }
148*3ac0a46fSAndroid Build Coastguard Worker 
149*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
150*3ac0a46fSAndroid Build Coastguard Worker   if (font) {
151*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetColor(font->GetColor());
152*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetFontStyle(font->IsItalic() ? CFX_CSSFontStyle::Italic
153*3ac0a46fSAndroid Build Coastguard Worker                                           : CFX_CSSFontStyle::Normal);
154*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetFontWeight(font->IsBold() ? FXFONT_FW_BOLD : FXFONT_FW_NORMAL);
155*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetNumberVerticalAlign(-font->GetBaselineShift());
156*3ac0a46fSAndroid Build Coastguard Worker     fFontSize = font->GetFontSize();
157*3ac0a46fSAndroid Build Coastguard Worker     CFX_CSSLength letterSpacing;
158*3ac0a46fSAndroid Build Coastguard Worker     letterSpacing.Set(CFX_CSSLengthUnit::Point, font->GetLetterSpacing());
159*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetLetterSpacing(letterSpacing);
160*3ac0a46fSAndroid Build Coastguard Worker     Mask<CFX_CSSTEXTDECORATION> dwDecoration;
161*3ac0a46fSAndroid Build Coastguard Worker     if (font->GetLineThrough() > 0)
162*3ac0a46fSAndroid Build Coastguard Worker       dwDecoration |= CFX_CSSTEXTDECORATION::kLineThrough;
163*3ac0a46fSAndroid Build Coastguard Worker     if (font->GetUnderline() > 1)
164*3ac0a46fSAndroid Build Coastguard Worker       dwDecoration |= CFX_CSSTEXTDECORATION::kDouble;
165*3ac0a46fSAndroid Build Coastguard Worker     else if (font->GetUnderline() > 0)
166*3ac0a46fSAndroid Build Coastguard Worker       dwDecoration |= CFX_CSSTEXTDECORATION::kUnderline;
167*3ac0a46fSAndroid Build Coastguard Worker 
168*3ac0a46fSAndroid Build Coastguard Worker     pStyle->SetTextDecoration(dwDecoration);
169*3ac0a46fSAndroid Build Coastguard Worker   }
170*3ac0a46fSAndroid Build Coastguard Worker   pStyle->SetLineHeight(fLineHeight);
171*3ac0a46fSAndroid Build Coastguard Worker   pStyle->SetFontSize(fFontSize);
172*3ac0a46fSAndroid Build Coastguard Worker   return pStyle;
173*3ac0a46fSAndroid Build Coastguard Worker }
174*3ac0a46fSAndroid Build Coastguard Worker 
CreateStyle(const CFX_CSSComputedStyle * pParentStyle)175*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_CSSComputedStyle> CXFA_TextParser::CreateStyle(
176*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pParentStyle) {
177*3ac0a46fSAndroid Build Coastguard Worker   auto pNewStyle = m_pSelector->CreateComputedStyle(pParentStyle);
178*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(pNewStyle);
179*3ac0a46fSAndroid Build Coastguard Worker   if (!pParentStyle)
180*3ac0a46fSAndroid Build Coastguard Worker     return pNewStyle;
181*3ac0a46fSAndroid Build Coastguard Worker 
182*3ac0a46fSAndroid Build Coastguard Worker   Mask<CFX_CSSTEXTDECORATION> dwDecoration = pParentStyle->GetTextDecoration();
183*3ac0a46fSAndroid Build Coastguard Worker   float fBaseLine = 0;
184*3ac0a46fSAndroid Build Coastguard Worker   if (pParentStyle->GetVerticalAlign() == CFX_CSSVerticalAlign::Number)
185*3ac0a46fSAndroid Build Coastguard Worker     fBaseLine = pParentStyle->GetNumberVerticalAlign();
186*3ac0a46fSAndroid Build Coastguard Worker 
187*3ac0a46fSAndroid Build Coastguard Worker   pNewStyle->SetTextDecoration(dwDecoration);
188*3ac0a46fSAndroid Build Coastguard Worker   pNewStyle->SetNumberVerticalAlign(fBaseLine);
189*3ac0a46fSAndroid Build Coastguard Worker 
190*3ac0a46fSAndroid Build Coastguard Worker   const CFX_CSSRect* pRect = pParentStyle->GetMarginWidth();
191*3ac0a46fSAndroid Build Coastguard Worker   if (pRect)
192*3ac0a46fSAndroid Build Coastguard Worker     pNewStyle->SetMarginWidth(*pRect);
193*3ac0a46fSAndroid Build Coastguard Worker   return pNewStyle;
194*3ac0a46fSAndroid Build Coastguard Worker }
195*3ac0a46fSAndroid Build Coastguard Worker 
ComputeStyle(const CFX_XMLNode * pXMLNode,RetainPtr<const CFX_CSSComputedStyle> pParentStyle)196*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFX_CSSComputedStyle> CXFA_TextParser::ComputeStyle(
197*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLNode* pXMLNode,
198*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CFX_CSSComputedStyle> pParentStyle) {
199*3ac0a46fSAndroid Build Coastguard Worker   auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
200*3ac0a46fSAndroid Build Coastguard Worker   if (it == m_mapXMLNodeToParseContext.end())
201*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
202*3ac0a46fSAndroid Build Coastguard Worker 
203*3ac0a46fSAndroid Build Coastguard Worker   Context* pContext = it->second.get();
204*3ac0a46fSAndroid Build Coastguard Worker   if (!pContext)
205*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
206*3ac0a46fSAndroid Build Coastguard Worker 
207*3ac0a46fSAndroid Build Coastguard Worker   pContext->SetParentStyle(pParentStyle);
208*3ac0a46fSAndroid Build Coastguard Worker 
209*3ac0a46fSAndroid Build Coastguard Worker   auto tagProvider = ParseTagInfo(pXMLNode);
210*3ac0a46fSAndroid Build Coastguard Worker   if (tagProvider->m_bContent)
211*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
212*3ac0a46fSAndroid Build Coastguard Worker 
213*3ac0a46fSAndroid Build Coastguard Worker   auto pStyle = CreateStyle(pParentStyle);
214*3ac0a46fSAndroid Build Coastguard Worker   m_pSelector->ComputeStyle(pContext->GetDecls(),
215*3ac0a46fSAndroid Build Coastguard Worker                             tagProvider->GetAttribute(L"style"),
216*3ac0a46fSAndroid Build Coastguard Worker                             tagProvider->GetAttribute(L"align"), pStyle.Get());
217*3ac0a46fSAndroid Build Coastguard Worker   return pStyle;
218*3ac0a46fSAndroid Build Coastguard Worker }
219*3ac0a46fSAndroid Build Coastguard Worker 
DoParse(const CFX_XMLNode * pXMLContainer,CXFA_TextProvider * pTextProvider)220*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::DoParse(const CFX_XMLNode* pXMLContainer,
221*3ac0a46fSAndroid Build Coastguard Worker                               CXFA_TextProvider* pTextProvider) {
222*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLContainer || !pTextProvider || m_bParsed)
223*3ac0a46fSAndroid Build Coastguard Worker     return;
224*3ac0a46fSAndroid Build Coastguard Worker 
225*3ac0a46fSAndroid Build Coastguard Worker   m_bParsed = true;
226*3ac0a46fSAndroid Build Coastguard Worker   InitCSSData(pTextProvider);
227*3ac0a46fSAndroid Build Coastguard Worker   auto pRootStyle = CreateRootStyle(pTextProvider);
228*3ac0a46fSAndroid Build Coastguard Worker   ParseRichText(pXMLContainer, pRootStyle.Get());
229*3ac0a46fSAndroid Build Coastguard Worker }
230*3ac0a46fSAndroid Build Coastguard Worker 
ParseRichText(const CFX_XMLNode * pXMLNode,const CFX_CSSComputedStyle * pParentStyle)231*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::ParseRichText(const CFX_XMLNode* pXMLNode,
232*3ac0a46fSAndroid Build Coastguard Worker                                     const CFX_CSSComputedStyle* pParentStyle) {
233*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLNode)
234*3ac0a46fSAndroid Build Coastguard Worker     return;
235*3ac0a46fSAndroid Build Coastguard Worker 
236*3ac0a46fSAndroid Build Coastguard Worker   auto tagProvider = ParseTagInfo(pXMLNode);
237*3ac0a46fSAndroid Build Coastguard Worker   if (!tagProvider->m_bTagAvailable)
238*3ac0a46fSAndroid Build Coastguard Worker     return;
239*3ac0a46fSAndroid Build Coastguard Worker 
240*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CFX_CSSComputedStyle> pNewStyle;
241*3ac0a46fSAndroid Build Coastguard Worker   if (!(tagProvider->GetTagName().EqualsASCII("body") &&
242*3ac0a46fSAndroid Build Coastguard Worker         tagProvider->GetTagName().EqualsASCII("html"))) {
243*3ac0a46fSAndroid Build Coastguard Worker     auto pTextContext = std::make_unique<Context>();
244*3ac0a46fSAndroid Build Coastguard Worker     CFX_CSSDisplay eDisplay = CFX_CSSDisplay::Inline;
245*3ac0a46fSAndroid Build Coastguard Worker     if (!tagProvider->m_bContent) {
246*3ac0a46fSAndroid Build Coastguard Worker       auto declArray =
247*3ac0a46fSAndroid Build Coastguard Worker           m_pSelector->MatchDeclarations(tagProvider->GetTagName());
248*3ac0a46fSAndroid Build Coastguard Worker       pNewStyle = CreateStyle(pParentStyle);
249*3ac0a46fSAndroid Build Coastguard Worker       m_pSelector->ComputeStyle(declArray, tagProvider->GetAttribute(L"style"),
250*3ac0a46fSAndroid Build Coastguard Worker                                 tagProvider->GetAttribute(L"align"),
251*3ac0a46fSAndroid Build Coastguard Worker                                 pNewStyle.Get());
252*3ac0a46fSAndroid Build Coastguard Worker 
253*3ac0a46fSAndroid Build Coastguard Worker       if (!declArray.empty())
254*3ac0a46fSAndroid Build Coastguard Worker         pTextContext->SetDecls(std::move(declArray));
255*3ac0a46fSAndroid Build Coastguard Worker 
256*3ac0a46fSAndroid Build Coastguard Worker       eDisplay = pNewStyle->GetDisplay();
257*3ac0a46fSAndroid Build Coastguard Worker     }
258*3ac0a46fSAndroid Build Coastguard Worker     pTextContext->SetDisplay(eDisplay);
259*3ac0a46fSAndroid Build Coastguard Worker     m_mapXMLNodeToParseContext[pXMLNode] = std::move(pTextContext);
260*3ac0a46fSAndroid Build Coastguard Worker   }
261*3ac0a46fSAndroid Build Coastguard Worker 
262*3ac0a46fSAndroid Build Coastguard Worker   for (CFX_XMLNode* pXMLChild = pXMLNode->GetFirstChild(); pXMLChild;
263*3ac0a46fSAndroid Build Coastguard Worker        pXMLChild = pXMLChild->GetNextSibling()) {
264*3ac0a46fSAndroid Build Coastguard Worker     ParseRichText(pXMLChild, pNewStyle.Get());
265*3ac0a46fSAndroid Build Coastguard Worker   }
266*3ac0a46fSAndroid Build Coastguard Worker }
267*3ac0a46fSAndroid Build Coastguard Worker 
TagValidate(const WideString & wsName) const268*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextParser::TagValidate(const WideString& wsName) const {
269*3ac0a46fSAndroid Build Coastguard Worker   static const uint32_t s_XFATagName[] = {
270*3ac0a46fSAndroid Build Coastguard Worker       0x61,        // a
271*3ac0a46fSAndroid Build Coastguard Worker       0x62,        // b
272*3ac0a46fSAndroid Build Coastguard Worker       0x69,        // i
273*3ac0a46fSAndroid Build Coastguard Worker       0x70,        // p
274*3ac0a46fSAndroid Build Coastguard Worker       0x0001f714,  // br
275*3ac0a46fSAndroid Build Coastguard Worker       0x00022a55,  // li
276*3ac0a46fSAndroid Build Coastguard Worker       0x000239bb,  // ol
277*3ac0a46fSAndroid Build Coastguard Worker       0x00025881,  // ul
278*3ac0a46fSAndroid Build Coastguard Worker       0x0bd37faa,  // sub
279*3ac0a46fSAndroid Build Coastguard Worker       0x0bd37fb8,  // sup
280*3ac0a46fSAndroid Build Coastguard Worker       0xa73e3af2,  // span
281*3ac0a46fSAndroid Build Coastguard Worker       0xb182eaae,  // body
282*3ac0a46fSAndroid Build Coastguard Worker       0xdb8ac455,  // html
283*3ac0a46fSAndroid Build Coastguard Worker   };
284*3ac0a46fSAndroid Build Coastguard Worker   return std::binary_search(std::begin(s_XFATagName), std::end(s_XFATagName),
285*3ac0a46fSAndroid Build Coastguard Worker                             FX_HashCode_GetLoweredW(wsName.AsStringView()));
286*3ac0a46fSAndroid Build Coastguard Worker }
287*3ac0a46fSAndroid Build Coastguard Worker 
288*3ac0a46fSAndroid Build Coastguard Worker // static
ParseTagInfo(const CFX_XMLNode * pXMLNode)289*3ac0a46fSAndroid Build Coastguard Worker std::unique_ptr<CXFA_TextParser::TagProvider> CXFA_TextParser::ParseTagInfo(
290*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLNode* pXMLNode) {
291*3ac0a46fSAndroid Build Coastguard Worker   auto tagProvider = std::make_unique<TagProvider>();
292*3ac0a46fSAndroid Build Coastguard Worker   const CFX_XMLElement* pXMLElement = ToXMLElement(pXMLNode);
293*3ac0a46fSAndroid Build Coastguard Worker   if (pXMLElement) {
294*3ac0a46fSAndroid Build Coastguard Worker     WideString wsName = pXMLElement->GetLocalTagName();
295*3ac0a46fSAndroid Build Coastguard Worker     tagProvider->SetTagName(wsName);
296*3ac0a46fSAndroid Build Coastguard Worker     tagProvider->m_bTagAvailable = TagValidate(wsName);
297*3ac0a46fSAndroid Build Coastguard Worker     WideString wsValue = pXMLElement->GetAttribute(L"style");
298*3ac0a46fSAndroid Build Coastguard Worker     if (!wsValue.IsEmpty())
299*3ac0a46fSAndroid Build Coastguard Worker       tagProvider->SetAttribute(L"style", wsValue);
300*3ac0a46fSAndroid Build Coastguard Worker 
301*3ac0a46fSAndroid Build Coastguard Worker     return tagProvider;
302*3ac0a46fSAndroid Build Coastguard Worker   }
303*3ac0a46fSAndroid Build Coastguard Worker   if (pXMLNode->GetType() == CFX_XMLNode::Type::kText) {
304*3ac0a46fSAndroid Build Coastguard Worker     tagProvider->m_bTagAvailable = true;
305*3ac0a46fSAndroid Build Coastguard Worker     tagProvider->m_bContent = true;
306*3ac0a46fSAndroid Build Coastguard Worker   }
307*3ac0a46fSAndroid Build Coastguard Worker   return tagProvider;
308*3ac0a46fSAndroid Build Coastguard Worker }
309*3ac0a46fSAndroid Build Coastguard Worker 
GetVAlign(CXFA_TextProvider * pTextProvider) const310*3ac0a46fSAndroid Build Coastguard Worker XFA_AttributeValue CXFA_TextParser::GetVAlign(
311*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider) const {
312*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Para* para = pTextProvider->GetParaIfExists();
313*3ac0a46fSAndroid Build Coastguard Worker   return para ? para->GetVerticalAlign() : XFA_AttributeValue::Top;
314*3ac0a46fSAndroid Build Coastguard Worker }
315*3ac0a46fSAndroid Build Coastguard Worker 
GetTabInterval(const CFX_CSSComputedStyle * pStyle) const316*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextParser::GetTabInterval(
317*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pStyle) const {
318*3ac0a46fSAndroid Build Coastguard Worker   WideString wsValue;
319*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle && pStyle->GetCustomStyle(L"tab-interval", &wsValue))
320*3ac0a46fSAndroid Build Coastguard Worker     return CXFA_Measurement(wsValue.AsStringView()).ToUnit(XFA_Unit::Pt);
321*3ac0a46fSAndroid Build Coastguard Worker   return 36;
322*3ac0a46fSAndroid Build Coastguard Worker }
323*3ac0a46fSAndroid Build Coastguard Worker 
CountTabs(const CFX_CSSComputedStyle * pStyle) const324*3ac0a46fSAndroid Build Coastguard Worker int32_t CXFA_TextParser::CountTabs(const CFX_CSSComputedStyle* pStyle) const {
325*3ac0a46fSAndroid Build Coastguard Worker   WideString wsValue;
326*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle && pStyle->GetCustomStyle(L"xfa-tab-count", &wsValue))
327*3ac0a46fSAndroid Build Coastguard Worker     return wsValue.GetInteger();
328*3ac0a46fSAndroid Build Coastguard Worker   return 0;
329*3ac0a46fSAndroid Build Coastguard Worker }
330*3ac0a46fSAndroid Build Coastguard Worker 
IsSpaceRun(const CFX_CSSComputedStyle * pStyle) const331*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextParser::IsSpaceRun(const CFX_CSSComputedStyle* pStyle) const {
332*3ac0a46fSAndroid Build Coastguard Worker   WideString wsValue;
333*3ac0a46fSAndroid Build Coastguard Worker   return pStyle && pStyle->GetCustomStyle(L"xfa-spacerun", &wsValue) &&
334*3ac0a46fSAndroid Build Coastguard Worker          wsValue.EqualsASCIINoCase("yes");
335*3ac0a46fSAndroid Build Coastguard Worker }
336*3ac0a46fSAndroid Build Coastguard Worker 
GetFont(CXFA_FFDoc * doc,CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const337*3ac0a46fSAndroid Build Coastguard Worker RetainPtr<CFGAS_GEFont> CXFA_TextParser::GetFont(
338*3ac0a46fSAndroid Build Coastguard Worker     CXFA_FFDoc* doc,
339*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider,
340*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pStyle) const {
341*3ac0a46fSAndroid Build Coastguard Worker   WideString wsFamily = L"Courier";
342*3ac0a46fSAndroid Build Coastguard Worker   uint32_t dwStyle = 0;
343*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
344*3ac0a46fSAndroid Build Coastguard Worker   if (font) {
345*3ac0a46fSAndroid Build Coastguard Worker     wsFamily = font->GetTypeface();
346*3ac0a46fSAndroid Build Coastguard Worker     if (font->IsBold())
347*3ac0a46fSAndroid Build Coastguard Worker       dwStyle |= FXFONT_FORCE_BOLD;
348*3ac0a46fSAndroid Build Coastguard Worker     if (font->IsItalic())
349*3ac0a46fSAndroid Build Coastguard Worker       dwStyle |= FXFONT_FORCE_BOLD;
350*3ac0a46fSAndroid Build Coastguard Worker   }
351*3ac0a46fSAndroid Build Coastguard Worker 
352*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
353*3ac0a46fSAndroid Build Coastguard Worker     absl::optional<WideString> last_family = pStyle->GetLastFontFamily();
354*3ac0a46fSAndroid Build Coastguard Worker     if (last_family.has_value())
355*3ac0a46fSAndroid Build Coastguard Worker       wsFamily = last_family.value();
356*3ac0a46fSAndroid Build Coastguard Worker 
357*3ac0a46fSAndroid Build Coastguard Worker     dwStyle = 0;
358*3ac0a46fSAndroid Build Coastguard Worker     if (pStyle->GetFontWeight() > FXFONT_FW_NORMAL)
359*3ac0a46fSAndroid Build Coastguard Worker       dwStyle |= FXFONT_FORCE_BOLD;
360*3ac0a46fSAndroid Build Coastguard Worker     if (pStyle->GetFontStyle() == CFX_CSSFontStyle::Italic)
361*3ac0a46fSAndroid Build Coastguard Worker       dwStyle |= FXFONT_ITALIC;
362*3ac0a46fSAndroid Build Coastguard Worker   }
363*3ac0a46fSAndroid Build Coastguard Worker 
364*3ac0a46fSAndroid Build Coastguard Worker   CXFA_FontMgr* pFontMgr = doc->GetApp()->GetXFAFontMgr();
365*3ac0a46fSAndroid Build Coastguard Worker   return pFontMgr->GetFont(doc, std::move(wsFamily), dwStyle);
366*3ac0a46fSAndroid Build Coastguard Worker }
367*3ac0a46fSAndroid Build Coastguard Worker 
GetFontSize(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const368*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextParser::GetFontSize(CXFA_TextProvider* pTextProvider,
369*3ac0a46fSAndroid Build Coastguard Worker                                    const CFX_CSSComputedStyle* pStyle) const {
370*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle)
371*3ac0a46fSAndroid Build Coastguard Worker     return pStyle->GetFontSize();
372*3ac0a46fSAndroid Build Coastguard Worker 
373*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
374*3ac0a46fSAndroid Build Coastguard Worker   return font ? font->GetFontSize() : 10;
375*3ac0a46fSAndroid Build Coastguard Worker }
376*3ac0a46fSAndroid Build Coastguard Worker 
GetHorScale(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle,const CFX_XMLNode * pXMLNode) const377*3ac0a46fSAndroid Build Coastguard Worker int32_t CXFA_TextParser::GetHorScale(CXFA_TextProvider* pTextProvider,
378*3ac0a46fSAndroid Build Coastguard Worker                                      const CFX_CSSComputedStyle* pStyle,
379*3ac0a46fSAndroid Build Coastguard Worker                                      const CFX_XMLNode* pXMLNode) const {
380*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
381*3ac0a46fSAndroid Build Coastguard Worker     WideString wsValue;
382*3ac0a46fSAndroid Build Coastguard Worker     if (pStyle->GetCustomStyle(L"xfa-font-horizontal-scale", &wsValue))
383*3ac0a46fSAndroid Build Coastguard Worker       return wsValue.GetInteger();
384*3ac0a46fSAndroid Build Coastguard Worker 
385*3ac0a46fSAndroid Build Coastguard Worker     while (pXMLNode) {
386*3ac0a46fSAndroid Build Coastguard Worker       auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
387*3ac0a46fSAndroid Build Coastguard Worker       if (it != m_mapXMLNodeToParseContext.end()) {
388*3ac0a46fSAndroid Build Coastguard Worker         Context* pContext = it->second.get();
389*3ac0a46fSAndroid Build Coastguard Worker         if (pContext && pContext->GetParentStyle() &&
390*3ac0a46fSAndroid Build Coastguard Worker             pContext->GetParentStyle()->GetCustomStyle(
391*3ac0a46fSAndroid Build Coastguard Worker                 L"xfa-font-horizontal-scale", &wsValue)) {
392*3ac0a46fSAndroid Build Coastguard Worker           return wsValue.GetInteger();
393*3ac0a46fSAndroid Build Coastguard Worker         }
394*3ac0a46fSAndroid Build Coastguard Worker       }
395*3ac0a46fSAndroid Build Coastguard Worker       pXMLNode = pXMLNode->GetParent();
396*3ac0a46fSAndroid Build Coastguard Worker     }
397*3ac0a46fSAndroid Build Coastguard Worker   }
398*3ac0a46fSAndroid Build Coastguard Worker 
399*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
400*3ac0a46fSAndroid Build Coastguard Worker   return font ? static_cast<int32_t>(font->GetHorizontalScale()) : 100;
401*3ac0a46fSAndroid Build Coastguard Worker }
402*3ac0a46fSAndroid Build Coastguard Worker 
GetVerScale(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const403*3ac0a46fSAndroid Build Coastguard Worker int32_t CXFA_TextParser::GetVerScale(CXFA_TextProvider* pTextProvider,
404*3ac0a46fSAndroid Build Coastguard Worker                                      const CFX_CSSComputedStyle* pStyle) const {
405*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
406*3ac0a46fSAndroid Build Coastguard Worker     WideString wsValue;
407*3ac0a46fSAndroid Build Coastguard Worker     if (pStyle->GetCustomStyle(L"xfa-font-vertical-scale", &wsValue))
408*3ac0a46fSAndroid Build Coastguard Worker       return wsValue.GetInteger();
409*3ac0a46fSAndroid Build Coastguard Worker   }
410*3ac0a46fSAndroid Build Coastguard Worker 
411*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
412*3ac0a46fSAndroid Build Coastguard Worker   return font ? static_cast<int32_t>(font->GetVerticalScale()) : 100;
413*3ac0a46fSAndroid Build Coastguard Worker }
414*3ac0a46fSAndroid Build Coastguard Worker 
GetUnderline(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const415*3ac0a46fSAndroid Build Coastguard Worker int32_t CXFA_TextParser::GetUnderline(
416*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider,
417*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pStyle) const {
418*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
419*3ac0a46fSAndroid Build Coastguard Worker   if (!pStyle)
420*3ac0a46fSAndroid Build Coastguard Worker     return font ? font->GetUnderline() : 0;
421*3ac0a46fSAndroid Build Coastguard Worker 
422*3ac0a46fSAndroid Build Coastguard Worker   const Mask<CFX_CSSTEXTDECORATION> dwDecoration = pStyle->GetTextDecoration();
423*3ac0a46fSAndroid Build Coastguard Worker   if (dwDecoration & CFX_CSSTEXTDECORATION::kDouble)
424*3ac0a46fSAndroid Build Coastguard Worker     return 2;
425*3ac0a46fSAndroid Build Coastguard Worker   if (dwDecoration & CFX_CSSTEXTDECORATION::kUnderline)
426*3ac0a46fSAndroid Build Coastguard Worker     return 1;
427*3ac0a46fSAndroid Build Coastguard Worker   return 0;
428*3ac0a46fSAndroid Build Coastguard Worker }
429*3ac0a46fSAndroid Build Coastguard Worker 
GetUnderlinePeriod(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const430*3ac0a46fSAndroid Build Coastguard Worker XFA_AttributeValue CXFA_TextParser::GetUnderlinePeriod(
431*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider,
432*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pStyle) const {
433*3ac0a46fSAndroid Build Coastguard Worker   WideString wsValue;
434*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle && pStyle->GetCustomStyle(L"underlinePeriod", &wsValue)) {
435*3ac0a46fSAndroid Build Coastguard Worker     return wsValue.EqualsASCII("word") ? XFA_AttributeValue::Word
436*3ac0a46fSAndroid Build Coastguard Worker                                        : XFA_AttributeValue::All;
437*3ac0a46fSAndroid Build Coastguard Worker   }
438*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
439*3ac0a46fSAndroid Build Coastguard Worker   return font ? font->GetUnderlinePeriod() : XFA_AttributeValue::All;
440*3ac0a46fSAndroid Build Coastguard Worker }
441*3ac0a46fSAndroid Build Coastguard Worker 
GetLinethrough(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const442*3ac0a46fSAndroid Build Coastguard Worker int32_t CXFA_TextParser::GetLinethrough(
443*3ac0a46fSAndroid Build Coastguard Worker     CXFA_TextProvider* pTextProvider,
444*3ac0a46fSAndroid Build Coastguard Worker     const CFX_CSSComputedStyle* pStyle) const {
445*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
446*3ac0a46fSAndroid Build Coastguard Worker     const Mask<CFX_CSSTEXTDECORATION> dwDecoration =
447*3ac0a46fSAndroid Build Coastguard Worker         pStyle->GetTextDecoration();
448*3ac0a46fSAndroid Build Coastguard Worker     return (dwDecoration & CFX_CSSTEXTDECORATION::kLineThrough) ? 1 : 0;
449*3ac0a46fSAndroid Build Coastguard Worker   }
450*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
451*3ac0a46fSAndroid Build Coastguard Worker   return font ? font->GetLineThrough() : 0;
452*3ac0a46fSAndroid Build Coastguard Worker }
453*3ac0a46fSAndroid Build Coastguard Worker 
GetColor(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const454*3ac0a46fSAndroid Build Coastguard Worker FX_ARGB CXFA_TextParser::GetColor(CXFA_TextProvider* pTextProvider,
455*3ac0a46fSAndroid Build Coastguard Worker                                   const CFX_CSSComputedStyle* pStyle) const {
456*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle)
457*3ac0a46fSAndroid Build Coastguard Worker     return pStyle->GetColor();
458*3ac0a46fSAndroid Build Coastguard Worker 
459*3ac0a46fSAndroid Build Coastguard Worker   CXFA_Font* font = pTextProvider->GetFontIfExists();
460*3ac0a46fSAndroid Build Coastguard Worker   return font ? font->GetColor() : 0xFF000000;
461*3ac0a46fSAndroid Build Coastguard Worker }
462*3ac0a46fSAndroid Build Coastguard Worker 
GetBaseline(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle) const463*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextParser::GetBaseline(CXFA_TextProvider* pTextProvider,
464*3ac0a46fSAndroid Build Coastguard Worker                                    const CFX_CSSComputedStyle* pStyle) const {
465*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
466*3ac0a46fSAndroid Build Coastguard Worker     if (pStyle->GetVerticalAlign() == CFX_CSSVerticalAlign::Number)
467*3ac0a46fSAndroid Build Coastguard Worker       return pStyle->GetNumberVerticalAlign();
468*3ac0a46fSAndroid Build Coastguard Worker   } else {
469*3ac0a46fSAndroid Build Coastguard Worker     CXFA_Font* font = pTextProvider->GetFontIfExists();
470*3ac0a46fSAndroid Build Coastguard Worker     if (font)
471*3ac0a46fSAndroid Build Coastguard Worker       return font->GetBaselineShift();
472*3ac0a46fSAndroid Build Coastguard Worker   }
473*3ac0a46fSAndroid Build Coastguard Worker   return 0;
474*3ac0a46fSAndroid Build Coastguard Worker }
475*3ac0a46fSAndroid Build Coastguard Worker 
GetLineHeight(CXFA_TextProvider * pTextProvider,const CFX_CSSComputedStyle * pStyle,bool bFirst,float fVerScale) const476*3ac0a46fSAndroid Build Coastguard Worker float CXFA_TextParser::GetLineHeight(CXFA_TextProvider* pTextProvider,
477*3ac0a46fSAndroid Build Coastguard Worker                                      const CFX_CSSComputedStyle* pStyle,
478*3ac0a46fSAndroid Build Coastguard Worker                                      bool bFirst,
479*3ac0a46fSAndroid Build Coastguard Worker                                      float fVerScale) const {
480*3ac0a46fSAndroid Build Coastguard Worker   float fLineHeight = 0;
481*3ac0a46fSAndroid Build Coastguard Worker   if (pStyle) {
482*3ac0a46fSAndroid Build Coastguard Worker     fLineHeight = pStyle->GetLineHeight();
483*3ac0a46fSAndroid Build Coastguard Worker   } else {
484*3ac0a46fSAndroid Build Coastguard Worker     CXFA_Para* para = pTextProvider->GetParaIfExists();
485*3ac0a46fSAndroid Build Coastguard Worker     if (para)
486*3ac0a46fSAndroid Build Coastguard Worker       fLineHeight = para->GetLineHeight();
487*3ac0a46fSAndroid Build Coastguard Worker   }
488*3ac0a46fSAndroid Build Coastguard Worker 
489*3ac0a46fSAndroid Build Coastguard Worker   if (bFirst) {
490*3ac0a46fSAndroid Build Coastguard Worker     float fFontSize = GetFontSize(pTextProvider, pStyle);
491*3ac0a46fSAndroid Build Coastguard Worker     if (fLineHeight < 0.1f)
492*3ac0a46fSAndroid Build Coastguard Worker       fLineHeight = fFontSize;
493*3ac0a46fSAndroid Build Coastguard Worker     else
494*3ac0a46fSAndroid Build Coastguard Worker       fLineHeight = std::min(fLineHeight, fFontSize);
495*3ac0a46fSAndroid Build Coastguard Worker   } else if (fLineHeight < 0.1f) {
496*3ac0a46fSAndroid Build Coastguard Worker     fLineHeight = GetFontSize(pTextProvider, pStyle) * 1.2f;
497*3ac0a46fSAndroid Build Coastguard Worker   }
498*3ac0a46fSAndroid Build Coastguard Worker   fLineHeight *= fVerScale;
499*3ac0a46fSAndroid Build Coastguard Worker   return fLineHeight;
500*3ac0a46fSAndroid Build Coastguard Worker }
501*3ac0a46fSAndroid Build Coastguard Worker 
GetEmbeddedObj(const CXFA_TextProvider * pTextProvider,const CFX_XMLNode * pXMLNode)502*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> CXFA_TextParser::GetEmbeddedObj(
503*3ac0a46fSAndroid Build Coastguard Worker     const CXFA_TextProvider* pTextProvider,
504*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLNode* pXMLNode) {
505*3ac0a46fSAndroid Build Coastguard Worker   if (!pXMLNode)
506*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
507*3ac0a46fSAndroid Build Coastguard Worker 
508*3ac0a46fSAndroid Build Coastguard Worker   const CFX_XMLElement* pElement = ToXMLElement(pXMLNode);
509*3ac0a46fSAndroid Build Coastguard Worker   if (!pElement)
510*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
511*3ac0a46fSAndroid Build Coastguard Worker 
512*3ac0a46fSAndroid Build Coastguard Worker   WideString wsAttr = pElement->GetAttribute(L"xfa:embed");
513*3ac0a46fSAndroid Build Coastguard Worker   if (wsAttr.IsEmpty())
514*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
515*3ac0a46fSAndroid Build Coastguard Worker 
516*3ac0a46fSAndroid Build Coastguard Worker   if (wsAttr[0] == L'#')
517*3ac0a46fSAndroid Build Coastguard Worker     wsAttr.Delete(0);
518*3ac0a46fSAndroid Build Coastguard Worker 
519*3ac0a46fSAndroid Build Coastguard Worker   WideString ws =
520*3ac0a46fSAndroid Build Coastguard Worker       GetLowerCaseElementAttributeOrDefault(pElement, L"xfa:embedType", L"som");
521*3ac0a46fSAndroid Build Coastguard Worker   if (!ws.EqualsASCII("uri"))
522*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
523*3ac0a46fSAndroid Build Coastguard Worker 
524*3ac0a46fSAndroid Build Coastguard Worker   ws = GetLowerCaseElementAttributeOrDefault(pElement, L"xfa:embedMode",
525*3ac0a46fSAndroid Build Coastguard Worker                                              L"formatted");
526*3ac0a46fSAndroid Build Coastguard Worker   if (!(ws.EqualsASCII("raw") || ws.EqualsASCII("formatted")))
527*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
528*3ac0a46fSAndroid Build Coastguard Worker 
529*3ac0a46fSAndroid Build Coastguard Worker   return pTextProvider->GetEmbeddedObj(wsAttr);
530*3ac0a46fSAndroid Build Coastguard Worker }
531*3ac0a46fSAndroid Build Coastguard Worker 
GetParseContextFromMap(const CFX_XMLNode * pXMLNode)532*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::Context* CXFA_TextParser::GetParseContextFromMap(
533*3ac0a46fSAndroid Build Coastguard Worker     const CFX_XMLNode* pXMLNode) {
534*3ac0a46fSAndroid Build Coastguard Worker   auto it = m_mapXMLNodeToParseContext.find(pXMLNode);
535*3ac0a46fSAndroid Build Coastguard Worker   return it != m_mapXMLNodeToParseContext.end() ? it->second.get() : nullptr;
536*3ac0a46fSAndroid Build Coastguard Worker }
537*3ac0a46fSAndroid Build Coastguard Worker 
GetTabstops(const CFX_CSSComputedStyle * pStyle,CXFA_TextTabstopsContext * pTabstopContext)538*3ac0a46fSAndroid Build Coastguard Worker bool CXFA_TextParser::GetTabstops(const CFX_CSSComputedStyle* pStyle,
539*3ac0a46fSAndroid Build Coastguard Worker                                   CXFA_TextTabstopsContext* pTabstopContext) {
540*3ac0a46fSAndroid Build Coastguard Worker   if (!pStyle || !pTabstopContext)
541*3ac0a46fSAndroid Build Coastguard Worker     return false;
542*3ac0a46fSAndroid Build Coastguard Worker 
543*3ac0a46fSAndroid Build Coastguard Worker   WideString wsValue;
544*3ac0a46fSAndroid Build Coastguard Worker   if (!pStyle->GetCustomStyle(L"xfa-tab-stops", &wsValue) &&
545*3ac0a46fSAndroid Build Coastguard Worker       !pStyle->GetCustomStyle(L"tab-stops", &wsValue)) {
546*3ac0a46fSAndroid Build Coastguard Worker     return false;
547*3ac0a46fSAndroid Build Coastguard Worker   }
548*3ac0a46fSAndroid Build Coastguard Worker 
549*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const wchar_t> spTabStops = wsValue.span();
550*3ac0a46fSAndroid Build Coastguard Worker   size_t iCur = 0;
551*3ac0a46fSAndroid Build Coastguard Worker   size_t iLast = 0;
552*3ac0a46fSAndroid Build Coastguard Worker   WideString wsAlign;
553*3ac0a46fSAndroid Build Coastguard Worker   TabStopStatus eStatus = TabStopStatus::None;
554*3ac0a46fSAndroid Build Coastguard Worker   while (iCur < spTabStops.size()) {
555*3ac0a46fSAndroid Build Coastguard Worker     wchar_t ch = spTabStops[iCur];
556*3ac0a46fSAndroid Build Coastguard Worker     switch (eStatus) {
557*3ac0a46fSAndroid Build Coastguard Worker       case TabStopStatus::None:
558*3ac0a46fSAndroid Build Coastguard Worker         if (ch <= ' ') {
559*3ac0a46fSAndroid Build Coastguard Worker           iCur++;
560*3ac0a46fSAndroid Build Coastguard Worker         } else {
561*3ac0a46fSAndroid Build Coastguard Worker           eStatus = TabStopStatus::Alignment;
562*3ac0a46fSAndroid Build Coastguard Worker           iLast = iCur;
563*3ac0a46fSAndroid Build Coastguard Worker         }
564*3ac0a46fSAndroid Build Coastguard Worker         break;
565*3ac0a46fSAndroid Build Coastguard Worker       case TabStopStatus::Alignment:
566*3ac0a46fSAndroid Build Coastguard Worker         if (ch == ' ') {
567*3ac0a46fSAndroid Build Coastguard Worker           wsAlign = WideStringView(spTabStops.subspan(iLast, iCur - iLast));
568*3ac0a46fSAndroid Build Coastguard Worker           eStatus = TabStopStatus::StartLeader;
569*3ac0a46fSAndroid Build Coastguard Worker           iCur++;
570*3ac0a46fSAndroid Build Coastguard Worker           while (iCur < spTabStops.size() && spTabStops[iCur] <= ' ')
571*3ac0a46fSAndroid Build Coastguard Worker             iCur++;
572*3ac0a46fSAndroid Build Coastguard Worker           iLast = iCur;
573*3ac0a46fSAndroid Build Coastguard Worker         } else {
574*3ac0a46fSAndroid Build Coastguard Worker           iCur++;
575*3ac0a46fSAndroid Build Coastguard Worker         }
576*3ac0a46fSAndroid Build Coastguard Worker         break;
577*3ac0a46fSAndroid Build Coastguard Worker       case TabStopStatus::StartLeader:
578*3ac0a46fSAndroid Build Coastguard Worker         if (ch != 'l') {
579*3ac0a46fSAndroid Build Coastguard Worker           eStatus = TabStopStatus::Location;
580*3ac0a46fSAndroid Build Coastguard Worker         } else {
581*3ac0a46fSAndroid Build Coastguard Worker           int32_t iCount = 0;
582*3ac0a46fSAndroid Build Coastguard Worker           while (iCur < spTabStops.size()) {
583*3ac0a46fSAndroid Build Coastguard Worker             ch = spTabStops[iCur];
584*3ac0a46fSAndroid Build Coastguard Worker             iCur++;
585*3ac0a46fSAndroid Build Coastguard Worker             if (ch == '(') {
586*3ac0a46fSAndroid Build Coastguard Worker               iCount++;
587*3ac0a46fSAndroid Build Coastguard Worker             } else if (ch == ')') {
588*3ac0a46fSAndroid Build Coastguard Worker               iCount--;
589*3ac0a46fSAndroid Build Coastguard Worker               if (iCount == 0)
590*3ac0a46fSAndroid Build Coastguard Worker                 break;
591*3ac0a46fSAndroid Build Coastguard Worker             }
592*3ac0a46fSAndroid Build Coastguard Worker           }
593*3ac0a46fSAndroid Build Coastguard Worker           while (iCur < spTabStops.size() && spTabStops[iCur] <= ' ')
594*3ac0a46fSAndroid Build Coastguard Worker             iCur++;
595*3ac0a46fSAndroid Build Coastguard Worker 
596*3ac0a46fSAndroid Build Coastguard Worker           iLast = iCur;
597*3ac0a46fSAndroid Build Coastguard Worker           eStatus = TabStopStatus::Location;
598*3ac0a46fSAndroid Build Coastguard Worker         }
599*3ac0a46fSAndroid Build Coastguard Worker         break;
600*3ac0a46fSAndroid Build Coastguard Worker       case TabStopStatus::Location:
601*3ac0a46fSAndroid Build Coastguard Worker         if (ch == ' ') {
602*3ac0a46fSAndroid Build Coastguard Worker           uint32_t dwHashCode = FX_HashCode_GetLoweredW(wsAlign.AsStringView());
603*3ac0a46fSAndroid Build Coastguard Worker           CXFA_Measurement ms(
604*3ac0a46fSAndroid Build Coastguard Worker               WideStringView(spTabStops.subspan(iLast, iCur - iLast)));
605*3ac0a46fSAndroid Build Coastguard Worker           float fPos = ms.ToUnit(XFA_Unit::Pt);
606*3ac0a46fSAndroid Build Coastguard Worker           pTabstopContext->Append(dwHashCode, fPos);
607*3ac0a46fSAndroid Build Coastguard Worker           wsAlign.clear();
608*3ac0a46fSAndroid Build Coastguard Worker           eStatus = TabStopStatus::None;
609*3ac0a46fSAndroid Build Coastguard Worker         }
610*3ac0a46fSAndroid Build Coastguard Worker         iCur++;
611*3ac0a46fSAndroid Build Coastguard Worker         break;
612*3ac0a46fSAndroid Build Coastguard Worker       default:
613*3ac0a46fSAndroid Build Coastguard Worker         break;
614*3ac0a46fSAndroid Build Coastguard Worker     }
615*3ac0a46fSAndroid Build Coastguard Worker   }
616*3ac0a46fSAndroid Build Coastguard Worker 
617*3ac0a46fSAndroid Build Coastguard Worker   if (!wsAlign.IsEmpty()) {
618*3ac0a46fSAndroid Build Coastguard Worker     uint32_t dwHashCode = FX_HashCode_GetLoweredW(wsAlign.AsStringView());
619*3ac0a46fSAndroid Build Coastguard Worker     CXFA_Measurement ms(
620*3ac0a46fSAndroid Build Coastguard Worker         WideStringView(spTabStops.subspan(iLast, iCur - iLast)));
621*3ac0a46fSAndroid Build Coastguard Worker     float fPos = ms.ToUnit(XFA_Unit::Pt);
622*3ac0a46fSAndroid Build Coastguard Worker     pTabstopContext->Append(dwHashCode, fPos);
623*3ac0a46fSAndroid Build Coastguard Worker   }
624*3ac0a46fSAndroid Build Coastguard Worker   return true;
625*3ac0a46fSAndroid Build Coastguard Worker }
626*3ac0a46fSAndroid Build Coastguard Worker 
627*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::TagProvider::TagProvider() = default;
628*3ac0a46fSAndroid Build Coastguard Worker 
629*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::TagProvider::~TagProvider() = default;
630*3ac0a46fSAndroid Build Coastguard Worker 
631*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::Context::Context() = default;
632*3ac0a46fSAndroid Build Coastguard Worker 
633*3ac0a46fSAndroid Build Coastguard Worker CXFA_TextParser::Context::~Context() = default;
634*3ac0a46fSAndroid Build Coastguard Worker 
SetParentStyle(RetainPtr<const CFX_CSSComputedStyle> style)635*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::Context::SetParentStyle(
636*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CFX_CSSComputedStyle> style) {
637*3ac0a46fSAndroid Build Coastguard Worker   m_pParentStyle = std::move(style);
638*3ac0a46fSAndroid Build Coastguard Worker }
639*3ac0a46fSAndroid Build Coastguard Worker 
SetDecls(std::vector<const CFX_CSSDeclaration * > && decl)640*3ac0a46fSAndroid Build Coastguard Worker void CXFA_TextParser::Context::SetDecls(
641*3ac0a46fSAndroid Build Coastguard Worker     std::vector<const CFX_CSSDeclaration*>&& decl) {
642*3ac0a46fSAndroid Build Coastguard Worker   decls_ = std::move(decl);
643*3ac0a46fSAndroid Build Coastguard Worker }
644