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