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