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