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